From 066480fbb898ca63a60aacf830086b4d3d07f5d6 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 1 Aug 2012 19:02:58 -0700 Subject: [PATCH 001/516] Add parallel-vectorize prototype. Add llvm_cbuilder. --- llvm_cbuilder/__init__.py | 2 + llvm_cbuilder/builder.py | 515 ++++++++++++++++++++++++++++++++++++ llvm_cbuilder/executor.py | 50 ++++ llvm_cbuilder/shortnames.py | 17 ++ tests/test_isprime.py | 120 +++++++++ tests/test_pthread.py | 79 ++++++ 6 files changed, 783 insertions(+) create mode 100644 llvm_cbuilder/__init__.py create mode 100644 llvm_cbuilder/builder.py create mode 100644 llvm_cbuilder/executor.py create mode 100644 llvm_cbuilder/shortnames.py create mode 100644 tests/test_isprime.py create mode 100644 tests/test_pthread.py diff --git a/llvm_cbuilder/__init__.py b/llvm_cbuilder/__init__.py new file mode 100644 index 0000000..e623129 --- /dev/null +++ b/llvm_cbuilder/__init__.py @@ -0,0 +1,2 @@ +from .builder import CBuilder +from .executor import CExecutor diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py new file mode 100644 index 0000000..ee866df --- /dev/null +++ b/llvm_cbuilder/builder.py @@ -0,0 +1,515 @@ +# +# TODO: Add support for vector. +# + +import contextlib +import llvm.core as lc + + +def _is_int(ty): + return isinstance(ty, lc.IntegerType) + +def _is_real(ty): + tys = [ lc.Type.float(), + lc.Type.double(), + lc.Type.x86_fp80(), + lc.Type.fp128(), + lc.Type.ppc_fp128() ] + return any(ty == x for x in tys) + +def _is_pointer(ty): + return isinstance(ty, lc.PointerType) + +def _is_block_terminated(bb): + instrs = bb.instructions + return len(instrs) > 0 and instrs[-1].is_terminator + +@contextlib.contextmanager +def _change_block_temporarily(builder, bb): + origbb = builder.basic_block + builder.position_at_end(bb) + yield + builder.position_at_end(origbb) + +class _IfElse(object): + def __init__(self, parent, cond): + self.parent = parent + self.cond = cond + self._to_close = [] + + @contextlib.contextmanager + def then(self): + self._bbif = self.parent.function.append_basic_block('if.then') + self._bbelse = self.parent.function.append_basic_block('if.else') + + builder = self.parent.builder + builder.cbranch(self.cond.value, self._bbif, self._bbelse) + + builder.position_at_end(self._bbif) + + yield + + self._to_close.extend([self._bbif, self._bbelse]) + + @contextlib.contextmanager + def otherwise(self): + self.parent.builder.position_at_end(self._bbelse) + yield + + def close(self): + bbend = self.parent.function.append_basic_block('if.end') + builder = self.parent.builder + for bb in self._to_close: + if not _is_block_terminated(bb): + with _change_block_temporarily(builder, bb): + builder.branch(bbend) + builder.position_at_end(bbend) + +class _Loop(object): + def __init__(self, parent): + self.parent = parent + + @contextlib.contextmanager + def condition(self): + builder = self.parent.builder + self._bbcond = self.parent.function.append_basic_block('loop.cond') + self._bbbody = self.parent.function.append_basic_block('loop.body') + self._bbend = self.parent.function.append_basic_block('loop.end') + + builder.branch(self._bbcond) + + builder.position_at_end(self._bbcond) + + def setcond(cond): + builder.cbranch(cond.value, self._bbbody, self._bbend) + + yield setcond + + @contextlib.contextmanager + def body(self): + builder = self.parent.builder + builder.position_at_end(self._bbbody) + + yield self + + if not _is_block_terminated(builder.basic_block): + builder.branch(self._bbcond) + + def break_loop(self): + self.branch(self._bbend) + + def continue_loop(self): + self.branch(self._bbcond) + + def close(self): + self.parent.builder.position_at_end(self._bbend) + + +class CBuilder(object): + ''' + A wrapper class for features in llvm-py package + to allow user to use C-like high-level language contruct easily. + ''' + def __init__(self, function): + self.function = function + self.declare_block = self.function.append_basic_block('decl') + self.first_body_block = self.function.append_basic_block('body') + self.builder = lc.Builder.new(self.first_body_block) + + # prepare arguments + self.args = [] + for arg in function.args: + var = self.var(arg.type, arg, name=arg.name) + self.args.append(var) + + @staticmethod + def new_function(mod, name, ret, args): + functype = lc.Type.function(ret, args) + func = mod.add_function(functype, name=name) + return CBuilder(func) + + def var(self, ty, value=None, name=''): + ''' + Only allocate in the first block + ''' + with _change_block_temporarily(self.builder, self.declare_block): + ptr = self.builder.alloca(ty, name=name) + if value is not None: + if not isinstance(value, lc.Value): + value = self.constant(ty, value).value + self.builder.store(value, ptr) + return CVar(self, ptr) + + def array(self, ty, count, name=''): + with _change_block_temporarily(self.builder, self.declare_block): + if not isinstance(count, lc.Value): + count = self.constant(lc.Type.int(), count).value + ptr = self.builder.alloca_array(ty, count, name=name) + return CArray(self, ptr) + + def ret(self, val=None): + retty = self.function.type.pointee.return_type + if val is not None: + if val.type != retty: + errmsg = "Return type mismatch" + raise TypeError(errmsg) + self.builder.ret(val.value) + else: + if retty != lc.Type.void(): + errmsg = "Cannot return void" + raise TypeError(errmsg) + self.builder.ret_void() + + @contextlib.contextmanager + def ifelse(self, cond): + cb = _IfElse(self, cond) + yield cb + cb.close() + + @contextlib.contextmanager + def loop(self): + cb = _Loop(self) + yield cb + cb.close() + + def position_at_end(self, bb): + self.basic_block = bb + self.builder.position_at_end(bb) + + def close(self): + # Close declaration block + with _change_block_temporarily(self.builder, self.declare_block): + self.builder.branch(self.first_body_block) + + def constant(self, ty, val): + if isinstance(ty, lc.IntegerType): + res = lc.Constant.int(ty, val) + elif ty==lc.Type.float() or ty==lc.Type.double(): + res = lc.Constant.real(ty, val) + else: + raise TypeError("Cannot auto build constant " + "from %s and value %s" % (ty, val)) + return CTemp(self, res) + + def constant_null(self, ty): + res = lc.Constant.null(ty) + return CTemp(self, res) + + def get_intrinsic(self, intrinsic_id, tys): + lfunc = lc.Function.intrinsic(self.function.module, intrinsic_id, tys) + return CFunc(self, lfunc) + + def get_function_named(self, name): + m = self.function.module + func = m.get_function_named(name) + return CFunc(self, func) + + def is_terminated(self): + ''' + Is the current basic-block terminated? + ''' + return _is_block_terminated(self.builder.basic_block) + + +class CValue(object): + ''' + = Signess = + Since LLVM type does not provide signess attribute. This information + is provided in the CValue.unsigned attribute. The default value is + `None`, meaning that this attribute is not set. + + In casting operation, signess information is passed as an optional arg. + + In binary operation, signess of the left operand is used. + ''' + + # Attribute for for integer values. + unsigned = None + + _BINOP_MAP = { + # op-name : (signed int, unsigned int, real) + 'add' : (lc.Builder.add, lc.Builder.add, lc.Builder.fadd), + 'sub' : (lc.Builder.sub, lc.Builder.sub, lc.Builder.fsub), + 'mul' : (lc.Builder.mul, lc.Builder.mul, lc.Builder.fmul), + 'div' : (lc.Builder.sdiv, lc.Builder.udiv, lc.Builder.fdiv), + 'mod' : (lc.Builder.srem, lc.Builder.urem, lc.Builder.frem), + } + + _BITWISE_MAP = { + # op-name : (signed int, unsigned int) + 'lshift' : (lc.Builder.shl, lc.Builder.shl), + 'rshift' : (lc.Builder.lshr, lc.Builder.ashr), + 'and' : (lc.Builder.and_, lc.Builder.and_), + 'or' : (lc.Builder.or_, lc.Builder.or_), + 'xor' : (lc.Builder.xor, lc.Builder.xor), + } + + _CMP_MAP = { + # op-name : (signed int, unsigned int, real) + 'eq' : (lc.ICMP_EQ, lc.ICMP_EQ, lc.FCMP_OEQ), + 'ne' : (lc.ICMP_NE, lc.ICMP_NE, lc.FCMP_ONE), + 'lt' : (lc.ICMP_SLT, lc.ICMP_ULT, lc.FCMP_OLT), + 'le' : (lc.ICMP_SLE, lc.ICMP_ULE, lc.FCMP_OLE), + 'gt' : (lc.ICMP_SGT, lc.ICMP_UGT, lc.FCMP_OGT), + 'ge' : (lc.ICMP_SGE, lc.ICMP_UGE, lc.FCMP_OGE), + } + + def __init__(self, parent): + self.parent = parent + + def _use_binop(self, op): + def wrapped(rhs): + self._ensure_same_type(rhs) + binop = self._BINOP_MAP[op] + if self.is_int: + if not self.unsigned: + idx = 0 + else: + idx = 1 + elif self.is_real: + idx = 2 + else: + errmsg = "Binary operation %s does not support type %s" + raise TypeError(errmsg % (op, self.type)) + res = binop[idx](self.parent.builder, self.value, rhs.value) + return CTemp(self.parent, res) + return wrapped + + def _use_bitwise(self, op): + def wrapped(rhs): + self._ensure_same_type(rhs) + if not self.is_int: + errmsg = "Bitwise operation %s does not support type %s" + raise TypeError(op, self.type) + if not self.unsigned: + idx = 0 + else: + idx = 1 + res = self._BITWISE_MAP[idx](self.parent.builder, + self.value, rhs.value) + return CTemp(self.parent, res) + return wrapped + + def __add__(self, rhs): + return self._use_binop('add')(rhs) + + def __sub__(self, rhs): + return self._use_binop('sub')(rhs) + + def __mul__(self, rhs): + return self._use_binop('mul')(rhs) + + def __div__(self, rhs): + return self._use_binop('div')(rhs) + + def __mod__(self, rhs): + return self._use_binop('mod')(rhs) + + def __lshift__(self, rhs): + return self._use_bitwise('lshift')(rhs) + + def __rshift__(self, rhs): + return self._use_bitwise('rshift')(rhs) + + def __and__(self, rhs): + return self._use_bitwise('and')(rhs) + + def __or__(self, rhs): + return self._use_bitwise('or')(rhs) + + def __xor__(self, rhs): + return self._use_bitwise('xor')(rhs) + + def _ensure_same_type(self, val): + if self.type != val.type: + errmsg = "Type mismatch: %s != %s" + raise TypeError(errmsg % (self.type, val.type)) + + @property + def is_int(self): + return _is_int(self.type) + + @property + def is_real(self): + return _is_real(self.type) + + def cast(self, ty, unsigned=False): + make = lambda X: CTemp(self.parent, X) + if self.type == ty: + return self # pass thru + elif self.is_pointer and _is_pointer(ty): + builder = self.parent.builder + return make(builder.bitcast(self.value, ty)) + elif self.is_int: + if _is_int(ty): + if self.type.width > ty.width: + if not unsigned: + return make(self.parent.builder.sext(self.value, ty)) + else: + return make(self.parent.builder.zext(self.value, ty)) + else: + return make(self.parent.trunc(self.value, ty)) + elif _is_real(ty): + if not unsigned: + return make(self.parent.builder.sitofp(self.value, ty)) + else: + return make(self.parent.builder.uitofp(self.value, ty)) + elif self.is_real: + if not unsigned: + return make(self.parent.builder.fptosi(self.value, ty)) + else: + return make(self.parent.builder.fptoui(self.value, ty)) + + errmsg = "Cast from %s to %s is not possible." + raise TypeError(errmsg % (self.type, ty)) + + def _cmp_op(self, name): + def wrapped(rhs): + make = lambda X: CTemp(self.parent, X) + self._ensure_same_type(rhs) + + flag_bag = self._CMP_MAP[name] + if self.is_int: + comparator = self.parent.builder.icmp + if not self.unsigned: + flag = flag_bag[0] + else: + flag = flag_bag[1] + elif self.is_real: + comparator = self.parent.builder.fcmp + flag = flag_bag[2] + else: + errmsg = "Comparision between %s and %s is not supported." + raise TypeError(errmsg % (self.type, rhs.type)) + + return CTemp(self.parent, comparator(flag, self.value, rhs.value)) + return wrapped + + def __eq__(self, rhs): + return self._cmp_op('eq')(rhs) + + def __ne__(self, rhs): + return self._cmp_op('ne')(rhs) + + def __lt__(self, rhs): + return self._cmp_op('lt')(rhs) + + def __le__(self, rhs): + return self._cmp_op('le')(rhs) + + def __gt__(self, rhs): + return self._cmp_op('gt')(rhs) + + def __ge__(self, rhs): + return self._cmp_op('ge')(rhs) + + + @property + def is_pointer(self): + return _is_pointer(self.type) + + def _ensure_is_pointer(self): + if not self.is_pointer: + raise TypeError("Must be a pointer") + + +class CFunc(CValue): + def __init__(self, parent, func): + super(CFunc, self).__init__(parent) + self.function = func + + def __call__(self, *args): + arg_value = map(lambda x: x.value, args) + res = self.parent.builder.call(self.function, arg_value) + return CTemp(self.parent, res) + + @property + def value(self): + return self.function + + @property + def type(self): + return self.function.type + +class CTemp(CValue): + def __init__(self, parent, value): + super(CTemp, self).__init__(parent) + self.value = value + + @property + def type(self): + return self.value.type + +class CVar(CValue): + def __init__(self, parent, ptr): + super(CVar, self).__init__(parent) + self.ptr = ptr + + def _inplace_op(self, op): + def wrapped(rhs): + res = self._use_binop('add')(rhs) + self.assign(res) + return self + return wrapped + + def __iadd__(self, rhs): + return self._inplace_op('add')(rhs) + + def __isub__(self, rhs): + return self._inplace_op('sub')(rhs) + + def __imul__(self, rhs): + return self._inplace_op('mul')(rhs) + + def __idiv__(self, rhs): + return self._inplace_op('div')(rhs) + + def __imod__(self, rhs): + return self._inplace_op('mod')(rhs) + + @property + def value(self): + return self.parent.builder.load(self.ptr) + + def assign(self, val): + self.parent.builder.store(val.value, self.ptr) + + @property + def type(self): + return self.ptr.type.pointee + + def load(self): + self._ensure_is_pointer() + loaded = self.parent.builder.load(self.value) + return CTemp(self.parent, loaded) + + def store(self, val): + self._ensure_is_pointer() + self.parent.builder.store(val.value, self.value) + + def reference(self): + return CTemp(self.parent, self.ptr) + +class CArray(CValue): + def __init__(self, parent, base): + super(CArray, self).__init__(parent) + self.base_ptr = base + + @property + def value(self): + return self.base_ptr + + @property + def type(self): + return self.base_ptr.type + + def __getitem__(self, idx): + self._ensure_is_pointer() + builder = self.parent.builder + if isinstance(idx, CValue): + idx = idx.value + elif not isinstance(idx, lc.Value): + idx = self.parent.constant(lc.Type.int(), idx).value + ptr = builder.gep(self.value, [idx]) + return CVar(self.parent, ptr) + diff --git a/llvm_cbuilder/executor.py b/llvm_cbuilder/executor.py new file mode 100644 index 0000000..e5aa1c0 --- /dev/null +++ b/llvm_cbuilder/executor.py @@ -0,0 +1,50 @@ +from llvm.core import Type, Module +import llvm.ee as le +import ctypes as ct + +MAP_CTYPES = { +'void' : None, +'bool' : ct.c_bool, +'char' : ct.c_char, +'uchar' : ct.c_ubyte, +'short' : ct.c_short, +'ushort' : ct.c_ushort, +'int' : ct.c_int, +'uint' : ct.c_uint, +'long' : ct.c_long, +'ulong' : ct.c_ulong, + +'int8' : ct.c_int8, +'uint8' : ct.c_uint8, +'int16' : ct.c_int16, +'uint16' : ct.c_uint16, +'int32' : ct.c_int32, +'uint32' : ct.c_uint32, +'int64' : ct.c_int64, +'uint64' : ct.c_uint64, + +'float' : ct.c_float, +'double' : ct.c_double, +'longdouble' : ct.c_longdouble, +} + +class CExecutor(object): + def __init__(self, mod_or_engine): + if isinstance(mod_or_engine, Module): + self.engine = le.ExecutionEngine.new(mod_or_engine) + else: + self.engine = mod_or_engine + + def get_ctype_function(self, fn, typeinfo): + types = [ MAP_CTYPES[s.strip()] for s in typeinfo.split(',') ] + if not types: + retty = None + argtys = [] + else: + retty = types[0] + argtys = types[1:] + + prototype = ct.CFUNCTYPE(retty, *argtys) + fnptr = self.engine.get_pointer_to_function(fn) + return prototype(fnptr) + diff --git a/llvm_cbuilder/shortnames.py b/llvm_cbuilder/shortnames.py new file mode 100644 index 0000000..c0e65ca --- /dev/null +++ b/llvm_cbuilder/shortnames.py @@ -0,0 +1,17 @@ +from llvm.core import Type + +void = Type.void() +char = Type.int(8) +short = Type.int(16) +int = Type.int(32) +int16 = short +int32 = int +int64 = Type.int(64) +float = Type.float() +double = Type.double() + +# pointers + +pointer = Type.pointer + +void_p = pointer(char) diff --git a/tests/test_isprime.py b/tests/test_isprime.py new file mode 100644 index 0000000..5c6b78e --- /dev/null +++ b/tests/test_isprime.py @@ -0,0 +1,120 @@ +from llvm.core import * +from llvm.passes import * +from llvm.ee import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import unittest, logging + +def is_prime(x): + if x <= 2: + return True + if (x % 2) == 0: + return False + for y in range(2, int(1 + x**0.5)): + if (x % y) == 0: + return False + return True + +def gen_is_prime(mod): + functype = Type.function(C.int, [C.int]) + func = mod.add_function(functype, 'isprime') + + cb = CBuilder(func) + + arg = cb.args[0] + + two = cb.constant(C.int, 2) + true = one = cb.constant(C.int, 1) + false = zero = cb.constant(C.int, 0) + + with cb.ifelse( arg <= two ) as ifelse: + with ifelse.then(): + cb.ret(true) + + with cb.ifelse( (arg % two) == zero ) as ifelse: + with ifelse.then(): + cb.ret(false) + + idx = cb.var(C.int, 3, name='idx') + with cb.loop() as loop: + with loop.condition() as setcond: + setcond( idx < arg ) + + with loop.body(): + with cb.ifelse( (arg % idx) == zero ) as ifelse: + with ifelse.then(): + cb.ret(false) + # increment + idx += two + + cb.ret(true) + cb.close() + return func + + +def gen_is_prime_fast(mod): + functype = Type.function(C.int, [C.int]) + func = mod.add_function(functype, 'isprime') + + cb = CBuilder(func) + + arg = cb.args[0] + + two = cb.constant(C.int, 2) + true = one = cb.constant(C.int, 1) + false = zero = cb.constant(C.int, 0) + + with cb.ifelse( arg <= two ) as ifelse: + with ifelse.then(): + cb.ret(true) + + with cb.ifelse( (arg % two) == zero ) as ifelse: + with ifelse.then(): + cb.ret(false) + + idx = cb.var(C.int, 3, name='idx') + sqrt = cb.get_intrinsic(INTR_SQRT, [C.float]) + looplimit = one + sqrt(arg.cast(C.float)).cast(C.int) + with cb.loop() as loop: + with loop.condition() as setcond: + setcond( idx < looplimit ) + + with loop.body(): + with cb.ifelse( (arg % idx) == zero ) as ifelse: + with ifelse.then(): + cb.ret(false) + # increment + idx += two + + cb.ret(true) + cb.close() + return func + +class TestIsPrime(unittest.TestCase): + def test_isprime(self): + mod = Module.new(__name__) + lf_isprime = gen_is_prime(mod) + logging.debug(mod) + mod.verify() + + exe = CExecutor(mod) + func = exe.get_ctype_function(lf_isprime, 'bool, int') + for x in range(2, 1000): + msg = "Failed at x = %d" % x + self.assertEqual(func(x), is_prime(x), msg) + + def test_isprime_fast(self): + mod = Module.new(__name__) + lf_isprime = gen_is_prime_fast(mod) + logging.debug(mod) + mod.verify() + + exe = CExecutor(mod) + func = exe.get_ctype_function(lf_isprime, 'bool, int') + for x in range(2, 1000): + msg = "Failed at x = %d" % x + self.assertEqual(func(x), is_prime(x), msg) + +if __name__ == '__main__': + unittest.main() + diff --git a/tests/test_pthread.py b/tests/test_pthread.py new file mode 100644 index 0000000..e86dbdb --- /dev/null +++ b/tests/test_pthread.py @@ -0,0 +1,79 @@ +from llvm.core import * +from llvm.passes import * +from llvm.ee import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import unittest, logging + +logging.basicConfig(level=logging.DEBUG) + +NUM_OF_THREAD = 4 + +def gen_test_worker(mod): + cb = CBuilder.new_function(mod, 'worker', C.void, [C.pointer(C.int)]) + pval = cb.args[0] + val = pval.load() + one = cb.constant(val.type, 1) + pval.store(val + one) + cb.ret() + cb.close() + +def gen_test_pthread(mod): + cb = CBuilder.new_function(mod, 'manager', C.int, [C.int]) + arg = cb.args[0] + + worker_func = cb.get_function_named('worker') + pthread_create = cb.get_function_named('pthread_create') + pthread_join = cb.get_function_named('pthread_join') + + + NULL = cb.constant_null(C.void_p) + cast_to_null = lambda x: x.cast(C.void_p) + + threads = cb.array(C.void_p, NUM_OF_THREAD) + + for tid in range(NUM_OF_THREAD): + pthread_create_args = [threads[tid].reference(), + NULL, + worker_func, + arg.reference()] + pthread_create(*map(cast_to_null, pthread_create_args)) + + for tid in range(NUM_OF_THREAD): + pthread_join_args = threads[tid], NULL + pthread_join(*map(cast_to_null, pthread_join_args)) + + worker_func(arg.reference()) + + cb.ret(arg) + cb.close() + return cb.function + +class TestPThread(unittest.TestCase): + def test_pthread(self): + mod = Module.new(__name__) + # add pthread functions + + mod.add_function(Type.function(C.int, + [C.void_p, C.void_p, C.void_p, C.void_p]), + 'pthread_create') + + mod.add_function(Type.function(C.int, + [C.void_p, C.void_p]), + 'pthread_join') + + gen_test_worker(mod) + lf_test_pthread = gen_test_pthread(mod) + logging.debug(mod) + mod.verify() + + exe = CExecutor(mod) + exe.engine.get_pointer_to_function(mod.get_function_named('worker')) + func = exe.get_ctype_function(lf_test_pthread, 'int, int') + + inarg = 1234 + self.assertEqual(func(inarg), inarg+NUM_OF_THREAD+1) + +if __name__ == '__main__': + unittest.main() + From 6981206096679347d2db346e93b963844f11aac1 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 1 Aug 2012 20:14:34 -0700 Subject: [PATCH 002/516] Add TODO and README files. --- TODO | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 TODO diff --git a/TODO b/TODO new file mode 100644 index 0000000..9a0e689 --- /dev/null +++ b/TODO @@ -0,0 +1,2 @@ +* add atomic operation to llvm-py +* add volatile load/store to llvm-py From 7238fecc7f9f5d03320b296fe29840c1b04970e5 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 2 Aug 2012 14:20:02 -0700 Subject: [PATCH 003/516] add build & test instruction to README --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..cab0f28 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +A llvm-py Builder wrapper for writing in slightly higher-level constructs. +This is aiming for two usecases: +1. Emit LLVM code in a more human-readable way; +2. Writing low-level code that you can't do it properly/portably with C, e.g + template (generic), atomic operations, memory ordering... + + From 8381b25f6629572755ec3add65f7f4dbc06d26bd Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 3 Aug 2012 16:26:46 -0700 Subject: [PATCH 004/516] Add atomic ops --- TODO | 2 - llvm_cbuilder/builder.py | 108 ++++++++++++++++++++++++++++++++- llvm_cbuilder/executor.py | 2 +- tests/test_atomic_add.py | 115 +++++++++++++++++++++++++++++++++++ tests/test_atomic_ldst.py | 122 ++++++++++++++++++++++++++++++++++++++ tests/test_isprime.py | 5 ++ tests/test_pthread.py | 17 +++++- 7 files changed, 362 insertions(+), 9 deletions(-) delete mode 100644 TODO create mode 100644 tests/test_atomic_add.py create mode 100644 tests/test_atomic_ldst.py diff --git a/TODO b/TODO deleted file mode 100644 index 9a0e689..0000000 --- a/TODO +++ /dev/null @@ -1,2 +0,0 @@ -* add atomic operation to llvm-py -* add volatile load/store to llvm-py diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index ee866df..ce96222 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -4,6 +4,7 @@ import contextlib import llvm.core as lc +import llvm.ee as le def _is_int(ty): @@ -115,6 +116,7 @@ class CBuilder(object): self.declare_block = self.function.append_basic_block('decl') self.first_body_block = self.function.append_basic_block('body') self.builder = lc.Builder.new(self.first_body_block) + self.target_data = le.TargetData.new(self.function.module.data_layout) # prepare arguments self.args = [] @@ -210,6 +212,81 @@ class CBuilder(object): ''' return _is_block_terminated(self.builder.basic_block) + def atomic_cmpxchg(self, ptr, old, val, ordering, crossthread=True): + res = self.builder.atomic_cmpxchg(ptr.value, old.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_xchg(self, ptr, val, ordering, crossthread=True): + res = self.builder.atomic_xchg(ptr.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_add(self, ptr, val, ordering, crossthread=True): + res = self.builder.atomic_add(ptr.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_sub(self, ptr, val, ordering, crossthread=True): + res = self.builder.atomic_sub(ptr.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_and(self, ptr, val, ordering, crossthread=True): + res = self.builder.atomic_and(ptr.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_nand(self, ptr, val, ordering, crossthread=True): + res = self.builder.atomic_nand(ptr.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_or(self, ptr, val, ordering, crossthread=True): + res = self.builder.atomic_or(ptr.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_xor(self, ptr, val, ordering, crossthread=True): + res = self.builder.atomic_xor(ptr.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_max(self, ptr, val, ordering, crossthread=True): + res = self.builder.atomic_max(ptr.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_min(self, ptr, val, ordering, crossthread=True): + res = self.builder.atomic_min(ptr.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_umax(self, ptr, val, ordering, crossthread=True): + res = self.builder.atomic_umax(ptr.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_umin(self, ptr, val, ordering, crossthread=True): + res = self.builder.atomic_umin(ptr.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_load(self, ptr, ordering, align=1, crossthread=True): + res = self.builder.atomic_load(ptr.value, ordering, align, crossthread) + return CTemp(self, res) + + def atomic_store(self, val, ptr, ordering, align=1, crossthread=True): + res = self.builder.atomic_store(val.value, ptr.value, ordering, + align, crossthread) + return CTemp(self, res) + + def fence(self, ordering, crossthread=True): + res = self.builder.fence(ordering, crossthread) + return CTemp(self, res) + + def alignment(self, ty): + return self.target_data.abi_alignment(ty) class CValue(object): ''' @@ -419,7 +496,7 @@ class CFunc(CValue): self.function = func def __call__(self, *args): - arg_value = map(lambda x: x.value, args) + arg_value = list(map(lambda x: x.value, args)) res = self.parent.builder.call(self.function, arg_value) return CTemp(self.parent, res) @@ -441,6 +518,7 @@ class CTemp(CValue): return self.value.type class CVar(CValue): + def __init__(self, parent, ptr): super(CVar, self).__init__(parent) self.ptr = ptr @@ -478,15 +556,39 @@ class CVar(CValue): def type(self): return self.ptr.type.pointee - def load(self): + def load(self, volatile=False): self._ensure_is_pointer() - loaded = self.parent.builder.load(self.value) + loaded = self.parent.builder.load(self.value, volatile=volatile) return CTemp(self.parent, loaded) def store(self, val): self._ensure_is_pointer() self.parent.builder.store(val.value, self.value) + def atomic_load(self, ordering, align=None, crossthread=True, volatile=False): + self._ensure_is_pointer() + if align is None: + align = self.parent.alignment(self.type.pointee) + inst = self.parent.builder.atomic_load(self.value, ordering, align, + crossthread=crossthread, + volatile=volatile) + return CTemp(self.parent, inst) + + def atomic_store(self, value, ordering, align=None, crossthread=True, + volatile=False): + self._ensure_is_pointer() + if align is None: + align = self.parent.alignment(self.type.pointee) + self.parent.builder.atomic_store(value.value, self.value, ordering, + align=align, crossthread=crossthread) + + def atomic_cmpxchg(self, old, new, ordering, crossthread=True, volatile=False): + self._ensure_is_pointer() + inst = self.parent.builder.atomic_cmpxchg(self.value, old.value, + new.value, ordering, + crossthread=crossthread) + return CTemp(self.parent, inst) + def reference(self): return CTemp(self.parent, self.ptr) diff --git a/llvm_cbuilder/executor.py b/llvm_cbuilder/executor.py index e5aa1c0..03324e8 100644 --- a/llvm_cbuilder/executor.py +++ b/llvm_cbuilder/executor.py @@ -31,7 +31,7 @@ MAP_CTYPES = { class CExecutor(object): def __init__(self, mod_or_engine): if isinstance(mod_or_engine, Module): - self.engine = le.ExecutionEngine.new(mod_or_engine) + self.engine = le.EngineBuilder.new(mod_or_engine).create() else: self.engine = mod_or_engine diff --git a/tests/test_atomic_add.py b/tests/test_atomic_add.py new file mode 100644 index 0000000..eb63a44 --- /dev/null +++ b/tests/test_atomic_add.py @@ -0,0 +1,115 @@ +''' +Base on the test_pthread.py and extend to use atomic instructions +''' + +from llvm.core import * +from llvm.passes import * +from llvm.ee import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import unittest, logging + +logging.basicConfig(level=logging.DEBUG) + +NUM_OF_THREAD = 4 +REPEAT = 10000 + +def gen_test_worker(mod): + cb = CBuilder.new_function(mod, 'worker', C.void, [C.pointer(C.int)]) + pval = cb.args[0] + one = cb.constant(pval.type.pointee, 1) + + ct = cb.var(C.int, 0) + limit = cb.constant(C.int, REPEAT) + with cb.loop() as loop: + with loop.condition() as setcond: + setcond( ct < limit ) + + with loop.body(): + cb.atomic_add(pval, one, 'acq_rel') + ct += one + + cb.ret() + cb.close() + return cb.function + +def gen_test_pthread(mod): + cb = CBuilder.new_function(mod, 'manager', C.int, [C.int]) + arg = cb.args[0] + + worker_func = cb.get_function_named('worker') + pthread_create = cb.get_function_named('pthread_create') + pthread_join = cb.get_function_named('pthread_join') + + + NULL = cb.constant_null(C.void_p) + cast_to_null = lambda x: x.cast(C.void_p) + + threads = cb.array(C.void_p, NUM_OF_THREAD) + + for tid in range(NUM_OF_THREAD): + pthread_create_args = [threads[tid].reference(), + NULL, + worker_func, + arg.reference()] + pthread_create(*map(cast_to_null, pthread_create_args)) + + worker_func(arg.reference()) + + for tid in range(NUM_OF_THREAD): + pthread_join_args = threads[tid], NULL + pthread_join(*map(cast_to_null, pthread_join_args)) + + + cb.ret(arg) + cb.close() + return cb.function + +class TestPThread(unittest.TestCase): + def test_pthread(self): + mod = Module.new(__name__) + # add pthread functions + + mod.add_function(Type.function(C.int, + [C.void_p, C.void_p, C.void_p, C.void_p]), + 'pthread_create') + + mod.add_function(Type.function(C.int, + [C.void_p, C.void_p]), + 'pthread_join') + + lf_test_worker = gen_test_worker(mod) + lf_test_pthread = gen_test_pthread(mod) + logging.debug(mod) + mod.verify() + + # optimize + fpm = FunctionPassManager.new(mod) + mpm = PassManager.new() + pmb = PassManagerBuilder.new() + pmb.vectorize = True + pmb.opt_level = 3 + pmb.populate(fpm) + pmb.populate(mpm) + + fpm.run(lf_test_worker) + fpm.run(lf_test_pthread) + mpm.run(mod) + logging.debug(mod) + mod.verify() + + # run + exe = CExecutor(mod) + exe.engine.get_pointer_to_function(mod.get_function_named('worker')) + func = exe.get_ctype_function(lf_test_pthread, 'int, int') + + inarg = 1234 + gold = inarg + (NUM_OF_THREAD + 1) * REPEAT + + for _ in range(1000): # run many many times to catch race condition + self.assertEqual(func(inarg), gold, "Unexpected race condition") + + +if __name__ == '__main__': + unittest.main() + diff --git a/tests/test_atomic_ldst.py b/tests/test_atomic_ldst.py new file mode 100644 index 0000000..147ec59 --- /dev/null +++ b/tests/test_atomic_ldst.py @@ -0,0 +1,122 @@ +''' +Base on the test_pthread.py and extend to use atomic instructions +''' + +from llvm.core import * +from llvm.passes import * +from llvm.ee import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import unittest, logging + +logging.basicConfig(level=logging.DEBUG) + +NUM_OF_THREAD = 4 +REPEAT = 10000 + +def gen_test_worker(mod): + cb = CBuilder.new_function(mod, 'worker', C.void, [C.pointer(C.int)]) + pval = cb.args[0] + one = cb.constant(pval.type.pointee, 1) + + ct = cb.var(C.int, 0) + limit = cb.constant(C.int, REPEAT) + with cb.loop() as loop: + with loop.condition() as setcond: + setcond( ct < limit ) + + with loop.body(): + oldval = pval.atomic_load('acquire') + updated = oldval + one + castmp = pval.atomic_cmpxchg(oldval, updated, 'release') + + with cb.ifelse( castmp == oldval ) as ifelse: + with ifelse.then(): + ct += one + + cb.ret() + cb.close() + return cb.function + +def gen_test_pthread(mod): + cb = CBuilder.new_function(mod, 'manager', C.int, [C.int]) + arg = cb.args[0] + + worker_func = cb.get_function_named('worker') + pthread_create = cb.get_function_named('pthread_create') + pthread_join = cb.get_function_named('pthread_join') + + + NULL = cb.constant_null(C.void_p) + cast_to_null = lambda x: x.cast(C.void_p) + + threads = cb.array(C.void_p, NUM_OF_THREAD) + + for tid in range(NUM_OF_THREAD): + pthread_create_args = [threads[tid].reference(), + NULL, + worker_func, + arg.reference()] + pthread_create(*map(cast_to_null, pthread_create_args)) + + worker_func(arg.reference()) + + for tid in range(NUM_OF_THREAD): + pthread_join_args = threads[tid], NULL + pthread_join(*map(cast_to_null, pthread_join_args)) + + + cb.ret(arg) + cb.close() + return cb.function + +class TestPThread(unittest.TestCase): + def test_pthread(self): + mod = Module.new(__name__) + # add pthread functions + + mod.add_function(Type.function(C.int, + [C.void_p, C.void_p, C.void_p, C.void_p]), + 'pthread_create') + + mod.add_function(Type.function(C.int, + [C.void_p, C.void_p]), + 'pthread_join') + + lf_test_worker = gen_test_worker(mod) + lf_test_pthread = gen_test_pthread(mod) + logging.debug(mod) + mod.verify() + + # optimize + fpm = FunctionPassManager.new(mod) + mpm = PassManager.new() + pmb = PassManagerBuilder.new() + pmb.vectorize = True + pmb.opt_level = 3 + pmb.populate(fpm) + pmb.populate(mpm) + + fpm.run(lf_test_worker) + fpm.run(lf_test_pthread) + mpm.run(mod) + logging.debug(mod) + mod.verify() + + # run + exe = CExecutor(mod) + exe.engine.get_pointer_to_function(mod.get_function_named('worker')) + func = exe.get_ctype_function(lf_test_pthread, 'int, int') + + inarg = 1234 + gold = inarg + (NUM_OF_THREAD + 1) * REPEAT + + for _ in range(1000): # run many many times to catch race condition + res = func(inarg) + self.assertEqual(res, gold, + "Unexpected race condition: res = %d" % res) + + +if __name__ == '__main__': + unittest.main() + diff --git a/tests/test_isprime.py b/tests/test_isprime.py index 5c6b78e..c36c71b 100644 --- a/tests/test_isprime.py +++ b/tests/test_isprime.py @@ -73,8 +73,12 @@ def gen_is_prime_fast(mod): cb.ret(false) idx = cb.var(C.int, 3, name='idx') + sqrt = cb.get_intrinsic(INTR_SQRT, [C.float]) + looplimit = one + sqrt(arg.cast(C.float)).cast(C.int) + + with cb.loop() as loop: with loop.condition() as setcond: setcond( idx < looplimit ) @@ -86,6 +90,7 @@ def gen_is_prime_fast(mod): # increment idx += two + cb.ret(true) cb.close() return func diff --git a/tests/test_pthread.py b/tests/test_pthread.py index e86dbdb..d5212b0 100644 --- a/tests/test_pthread.py +++ b/tests/test_pthread.py @@ -39,12 +39,12 @@ def gen_test_pthread(mod): arg.reference()] pthread_create(*map(cast_to_null, pthread_create_args)) + worker_func(arg.reference()) + for tid in range(NUM_OF_THREAD): pthread_join_args = threads[tid], NULL pthread_join(*map(cast_to_null, pthread_join_args)) - worker_func(arg.reference()) - cb.ret(arg) cb.close() return cb.function @@ -72,7 +72,18 @@ class TestPThread(unittest.TestCase): func = exe.get_ctype_function(lf_test_pthread, 'int, int') inarg = 1234 - self.assertEqual(func(inarg), inarg+NUM_OF_THREAD+1) + gold = inarg + NUM_OF_THREAD + 1 + self.assertLessEqual(func(inarg), gold) + # Cannot determine the exact return value due to untamed race condition + + count_race = 0 + for _ in range(2**12): + if func(inarg) != gold: + count_race += 1 + + if count_race > 0: + logging.info("Race condition occured %d times.", count_race) + logging.info("Race condition is expected.") if __name__ == '__main__': unittest.main() From aebb9857ebf2781ff4f59d6740aa5383ccbe53c5 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 3 Aug 2012 16:31:23 -0700 Subject: [PATCH 005/516] Drop volatile option in atomic ops. Add volatile option to store. --- llvm_cbuilder/builder.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index ce96222..5bc31d1 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -561,28 +561,26 @@ class CVar(CValue): loaded = self.parent.builder.load(self.value, volatile=volatile) return CTemp(self.parent, loaded) - def store(self, val): + def store(self, val, volatile=False): self._ensure_is_pointer() - self.parent.builder.store(val.value, self.value) + self.parent.builder.store(val.value, self.value, volatile=volatile) - def atomic_load(self, ordering, align=None, crossthread=True, volatile=False): + def atomic_load(self, ordering, align=None, crossthread=True): self._ensure_is_pointer() if align is None: align = self.parent.alignment(self.type.pointee) inst = self.parent.builder.atomic_load(self.value, ordering, align, - crossthread=crossthread, - volatile=volatile) + crossthread=crossthread) return CTemp(self.parent, inst) - def atomic_store(self, value, ordering, align=None, crossthread=True, - volatile=False): + def atomic_store(self, value, ordering, align=None, crossthread=True): self._ensure_is_pointer() if align is None: align = self.parent.alignment(self.type.pointee) self.parent.builder.atomic_store(value.value, self.value, ordering, align=align, crossthread=crossthread) - def atomic_cmpxchg(self, old, new, ordering, crossthread=True, volatile=False): + def atomic_cmpxchg(self, old, new, ordering, crossthread=True): self._ensure_is_pointer() inst = self.parent.builder.atomic_cmpxchg(self.value, old.value, new.value, ordering, From f1e10e849f63210b491d1be4b0c548f00330182c Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 3 Aug 2012 17:02:01 -0700 Subject: [PATCH 006/516] Fix __div__ for py3. Add test for nested-loops. --- llvm_cbuilder/builder.py | 3 + tests/test_atomic_add.py | 4 +- ..._atomic_ldst.py => test_atomic_cmpxchg.py} | 4 +- tests/test_nestedloops.py | 128 ++++++++++++++++++ 4 files changed, 135 insertions(+), 4 deletions(-) rename tests/{test_atomic_ldst.py => test_atomic_cmpxchg.py} (97%) create mode 100644 tests/test_nestedloops.py diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 5bc31d1..0582a25 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -379,6 +379,9 @@ class CValue(object): def __div__(self, rhs): return self._use_binop('div')(rhs) + def __truediv__(self, rhs): + return self.__div__(rhs) + def __mod__(self, rhs): return self._use_binop('mod')(rhs) diff --git a/tests/test_atomic_add.py b/tests/test_atomic_add.py index eb63a44..63b795a 100644 --- a/tests/test_atomic_add.py +++ b/tests/test_atomic_add.py @@ -65,8 +65,8 @@ def gen_test_pthread(mod): cb.close() return cb.function -class TestPThread(unittest.TestCase): - def test_pthread(self): +class TestAtomicAdd(unittest.TestCase): + def test_atomic_add(self): mod = Module.new(__name__) # add pthread functions diff --git a/tests/test_atomic_ldst.py b/tests/test_atomic_cmpxchg.py similarity index 97% rename from tests/test_atomic_ldst.py rename to tests/test_atomic_cmpxchg.py index 147ec59..eb2a45b 100644 --- a/tests/test_atomic_ldst.py +++ b/tests/test_atomic_cmpxchg.py @@ -70,8 +70,8 @@ def gen_test_pthread(mod): cb.close() return cb.function -class TestPThread(unittest.TestCase): - def test_pthread(self): +class TestAtomicCmpXchg(unittest.TestCase): + def test_atomic_cmpxchg(self): mod = Module.new(__name__) # add pthread functions diff --git a/tests/test_nestedloops.py b/tests/test_nestedloops.py new file mode 100644 index 0000000..823a54f --- /dev/null +++ b/tests/test_nestedloops.py @@ -0,0 +1,128 @@ +from llvm.core import * +from llvm.passes import * +from llvm.ee import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import unittest, logging + +def nestedloop1(d): + z = 0 + for x in range(100): + for y in range(100): + z += x * d + int(y / d) + return z + +def gen_nestedloop1(mod): + functype = Type.function(C.int, [C.int]) + func = mod.add_function(functype, 'nestedloop1') + + cb = CBuilder(func) + + d = cb.args[0] + x = cb.var(C.int) + y = cb.var(C.int) + z = cb.var(C.int) + + one = cb.constant(C.int, 1) + zero = cb.constant(C.int, 0) + limit = cb.constant(C.int, 100) + + z.assign(zero) + x.assign(zero) + with cb.loop() as outer: + with outer.condition() as setcond: + setcond( x < limit ) + + with outer.body(): + y.assign(zero) + with cb.loop() as inner: + with inner.condition() as setcond: + setcond( y < limit ) + + with inner.body(): + z += x * d + y / d + y += one + x += one + + cb.ret(z) + cb.close() + return func + + +def nestedloop2(d): + z = 0 + for x in range(1, 100): + for y in range(1, 100): + if x > y: + z += int(x / y) * d + else: + z += int(y / x) * d + return z + +def gen_nestedloop2(mod): + functype = Type.function(C.int, [C.int]) + func = mod.add_function(functype, 'nestedloop1') + + cb = CBuilder(func) + + d = cb.args[0] + x = cb.var(C.int) + y = cb.var(C.int) + z = cb.var(C.int) + + one = cb.constant(C.int, 1) + zero = cb.constant(C.int, 0) + limit = cb.constant(C.int, 100) + + z.assign(zero) + x.assign(one) + with cb.loop() as outer: + with outer.condition() as setcond: + setcond( x < limit ) + + with outer.body(): + y.assign(one) + with cb.loop() as inner: + with inner.condition() as setcond: + setcond( y < limit ) + + with inner.body(): + with cb.ifelse(x > y) as ifelse: + with ifelse.then(): + z += x / y * d + with ifelse.otherwise(): + z += y / x * d + y += one + x += one + + cb.ret(z) + cb.close() + return func + + +class TestNestedLoop(unittest.TestCase): + def test_nestedloop1(self): + mod = Module.new(__name__) + lfunc = gen_nestedloop1(mod) + logging.debug(mod) + mod.verify() + + exe = CExecutor(mod) + func = exe.get_ctype_function(lfunc, 'int, int') + for x in range(1, 100): + self.assertEqual(func(x), int(nestedloop1(x))) + + def test_nestedloop2(self): + mod = Module.new(__name__) + lfunc = gen_nestedloop2(mod) + logging.debug(mod) + mod.verify() + + exe = CExecutor(mod) + func = exe.get_ctype_function(lfunc, 'int, int') + for x in range(1, 100): + self.assertEqual(func(x), int(nestedloop2(x))) + +if __name__ == '__main__': + unittest.main() + From 184e4ea1a119b1e29b6fa3764ce75a2fc377867e Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 3 Aug 2012 22:30:54 -0700 Subject: [PATCH 007/516] Add API for structure --- llvm_cbuilder/__init__.py | 3 ++- llvm_cbuilder/builder.py | 36 ++++++++++++++++++++++--- llvm_cbuilder/executor.py | 18 ++++++++----- llvm_cbuilder/shortnames.py | 12 +++++++++ tests/test_struct.py | 52 +++++++++++++++++++++++++++++++++++++ 5 files changed, 109 insertions(+), 12 deletions(-) create mode 100644 tests/test_struct.py diff --git a/llvm_cbuilder/__init__.py b/llvm_cbuilder/__init__.py index e623129..b32e754 100644 --- a/llvm_cbuilder/__init__.py +++ b/llvm_cbuilder/__init__.py @@ -1,2 +1,3 @@ -from .builder import CBuilder +from .builder import * from .executor import CExecutor + diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 0582a25..7dc338b 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -25,6 +25,12 @@ def _is_block_terminated(bb): instrs = bb.instructions return len(instrs) > 0 and instrs[-1].is_terminator +def _is_cstruct(ty): + try: + return issubclass(ty, CStruct) + except TypeError: + return False + @contextlib.contextmanager def _change_block_temporarily(builder, bb): origbb = builder.basic_block @@ -135,11 +141,21 @@ class CBuilder(object): Only allocate in the first block ''' with _change_block_temporarily(self.builder, self.declare_block): + is_cstruct = _is_cstruct(ty) + if is_cstruct: + cstruct = ty + ty = ty.llvm_type() ptr = self.builder.alloca(ty, name=name) - if value is not None: - if not isinstance(value, lc.Value): - value = self.constant(ty, value).value - self.builder.store(value, ptr) + # back to the body + if value is not None: + if isinstance(value, CValue): + value = value.value + if not isinstance(value, lc.Value): + value = self.constant(ty, value).value + self.builder.store(value, ptr) + if is_cstruct: + return cstruct(self, ptr) + else: return CVar(self, ptr) def array(self, ty, count, name=''): @@ -616,3 +632,15 @@ class CArray(CValue): ptr = builder.gep(self.value, [idx]) return CVar(self.parent, ptr) +class CStruct(CValue): + @classmethod + def llvm_type(cls): + return lc.Type.struct([v for k, v in cls._fields_]) + + def __init__(self, parent, ptr): + super(CStruct, self).__init__(parent) + makeind = lambda x: self.parent.constant(lc.Type.int(), x).value + for i, (fd, _) in enumerate(self._fields_): + gep = self.parent.builder.gep(ptr, [makeind(0), makeind(i)]) + setattr(self, fd, CVar(self.parent, gep)) + diff --git a/llvm_cbuilder/executor.py b/llvm_cbuilder/executor.py index 03324e8..a2f558e 100644 --- a/llvm_cbuilder/executor.py +++ b/llvm_cbuilder/executor.py @@ -35,14 +35,18 @@ class CExecutor(object): else: self.engine = mod_or_engine - def get_ctype_function(self, fn, typeinfo): - types = [ MAP_CTYPES[s.strip()] for s in typeinfo.split(',') ] - if not types: - retty = None - argtys = [] + def get_ctype_function(self, fn, *typeinfo): + if len(typeinfo)==1 and isinstance(typeinfo[0], str): + types = [ MAP_CTYPES[s.strip()] for s in typeinfo[0].split(',') ] + if not types: + retty = None + argtys = [] + else: + retty = types[0] + argtys = types[1:] else: - retty = types[0] - argtys = types[1:] + retty = typeinfo[0] + argtys = typeinfo[1:] prototype = ct.CFUNCTYPE(retty, *argtys) fnptr = self.engine.get_pointer_to_function(fn) diff --git a/llvm_cbuilder/shortnames.py b/llvm_cbuilder/shortnames.py index c0e65ca..d3fc5af 100644 --- a/llvm_cbuilder/shortnames.py +++ b/llvm_cbuilder/shortnames.py @@ -7,6 +7,7 @@ int = Type.int(32) int16 = short int32 = int int64 = Type.int(64) + float = Type.float() double = Type.double() @@ -15,3 +16,14 @@ double = Type.double() pointer = Type.pointer void_p = pointer(char) + +# platform dependent + +def _determine_pointer_size(): + from ctypes import sizeof, c_void_p + return sizeof(c_void_p) * 8 + +pointer_size = _determine_pointer_size() + +intp = {32: int32, 64: int64}[pointer_size] + diff --git a/tests/test_struct.py b/tests/test_struct.py new file mode 100644 index 0000000..35048e6 --- /dev/null +++ b/tests/test_struct.py @@ -0,0 +1,52 @@ +from llvm.core import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import unittest, ctypes + +class Vector2D(CStruct): + _fields_ = [ + ('x', C.float), + ('y', C.float), + ] + +class Vector2DCtype(ctypes.Structure): + _fields_ = [ + ('x', ctypes.c_float), + ('y', ctypes.c_float), + ] + +def gen_vector2d_dist(mod): + functype = Type.function(C.float, [C.pointer(Vector2D.llvm_type())]) + func = mod.add_function(functype, 'vector2d_dist') + + cb = CBuilder(func) + vec = cb.var(Vector2D, cb.args[0].load()) + dist = vec.x * vec.x + vec.y * vec.y + + cb.ret(dist) + cb.close() + return func + + +class TestStruct(unittest.TestCase): + def test_vector2d_dist(self): + # prepare module + mod = Module.new('mod') + lfunc = gen_vector2d_dist(mod) + mod.verify() + # run + exe = CExecutor(mod) + func = exe.get_ctype_function(lfunc, ctypes.c_float, ctypes.POINTER(Vector2DCtype)) + + from random import random + pydist = lambda x, y: x * x + y * y + for _ in range(100): + x, y = random(), random() + vec = Vector2DCtype(x=x, y=y) + ans = func(ctypes.pointer(vec)) + gold = pydist(x, y) + + self.assertLess(abs(ans-gold)/gold, 1e-6) + +if __name__ == '__main__': + unittest.main() From b45c768cc5af27cce538d6a25baa92240a848835 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sat, 4 Aug 2012 15:14:09 -0700 Subject: [PATCH 008/516] Fix --- llvm_cbuilder/builder.py | 41 +++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 7dc338b..cb33214 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -103,10 +103,10 @@ class _Loop(object): builder.branch(self._bbcond) def break_loop(self): - self.branch(self._bbend) + self.parent.builder.branch(self._bbend) def continue_loop(self): - self.branch(self._bbcond) + self.parent.builder.branch(self._bbcond) def close(self): self.parent.builder.position_at_end(self._bbend) @@ -542,27 +542,50 @@ class CVar(CValue): super(CVar, self).__init__(parent) self.ptr = ptr - def _inplace_op(self, op): + def _inplace_binop(self, op): def wrapped(rhs): - res = self._use_binop('add')(rhs) + res = self._use_binop(op)(rhs) self.assign(res) return self return wrapped def __iadd__(self, rhs): - return self._inplace_op('add')(rhs) + return self._inplace_binop('add')(rhs) def __isub__(self, rhs): - return self._inplace_op('sub')(rhs) + return self._inplace_binop('sub')(rhs) def __imul__(self, rhs): - return self._inplace_op('mul')(rhs) + return self._inplace_binop('mul')(rhs) def __idiv__(self, rhs): - return self._inplace_op('div')(rhs) + return self._inplace_binop('div')(rhs) def __imod__(self, rhs): - return self._inplace_op('mod')(rhs) + return self._inplace_binop('mod')(rhs) + + + def _inplace_bitwise(self, op): + def wrapped(rhs): + res = self._use_bitwise(op)(rhs) + self.assign(res) + return self + return wrapped + + def __ilshift__(self, rhs): + return self._inplace_bitwise('lshift')(rhs) + + def __irshift__(self, rhs): + return self._inplace_bitwise('rshift')(rhs) + + def __iand__(self, rhs): + return self._inplace_bitwise('and')(rhs) + + def __ior__(self, rhs): + return self._inplace_bitwise('or')(rhs) + + def __ixor__(self, rhs): + return self._inplace_bitwise('xor')(rhs) @property def value(self): From 673ada6a4ea36a8a61a4b8ce0e9739a5716c2b2a Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sat, 4 Aug 2012 15:18:41 -0700 Subject: [PATCH 009/516] Fix and add tests. --- tests/test_isprime.py | 2 +- tests/test_loopcontrol.py | 135 ++++++++++++++++++++++++++++++++++++++ tests/test_nestedloops.py | 2 +- 3 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 tests/test_loopcontrol.py diff --git a/tests/test_isprime.py b/tests/test_isprime.py index c36c71b..bcc0b9c 100644 --- a/tests/test_isprime.py +++ b/tests/test_isprime.py @@ -54,7 +54,7 @@ def gen_is_prime(mod): def gen_is_prime_fast(mod): functype = Type.function(C.int, [C.int]) - func = mod.add_function(functype, 'isprime') + func = mod.add_function(functype, 'isprime_fast') cb = CBuilder(func) diff --git a/tests/test_loopcontrol.py b/tests/test_loopcontrol.py new file mode 100644 index 0000000..7e252bf --- /dev/null +++ b/tests/test_loopcontrol.py @@ -0,0 +1,135 @@ +from llvm.core import * +from llvm.passes import * +from llvm.ee import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import unittest, logging + +def loopbreak(d): + z = 0 + for x in range(100): + for y in range(100): + z += x + y + if z > 50: + break + z -= d + return z + +def gen_loopbreak(mod): + functype = Type.function(C.int, [C.int]) + func = mod.add_function(functype, 'loopbreak') + + cb = CBuilder(func) + + d = cb.args[0] + x = cb.var(C.int) + y = cb.var(C.int) + z = cb.var(C.int) + + one = cb.constant(C.int, 1) + zero = cb.constant(C.int, 0) + limit = cb.constant(C.int, 100) + fifty = cb.constant(C.int, 50) + + z.assign(zero) + x.assign(zero) + with cb.loop() as outer: + with outer.condition() as setcond: + setcond( x < limit ) + + with outer.body(): + y.assign(zero) + with cb.loop() as inner: + with inner.condition() as setcond: + setcond( y < limit ) + + with inner.body(): + z += x + y + with cb.ifelse( z > fifty ) as ifelse: + with ifelse.then(): + inner.break_loop() + y += one + z -= d + x += one + + cb.ret(z) + cb.close() + return func + +def loopcontinue(d): + z = 0 + for x in range(100): + for y in range(100): + z += x + y + if z > 50: + continue + z += d + return z + +def gen_loopcontinue(mod): + functype = Type.function(C.int, [C.int]) + func = mod.add_function(functype, 'loopcontinue') + + cb = CBuilder(func) + + d = cb.args[0] + x = cb.var(C.int) + y = cb.var(C.int) + z = cb.var(C.int) + + one = cb.constant(C.int, 1) + zero = cb.constant(C.int, 0) + limit = cb.constant(C.int, 100) + fifty = cb.constant(C.int, 50) + + z.assign(zero) + x.assign(zero) + with cb.loop() as outer: + with outer.condition() as setcond: + setcond( x < limit ) + + with outer.body(): + y.assign(zero) + with cb.loop() as inner: + with inner.condition() as setcond: + setcond( y < limit ) + + with inner.body(): + z += x + y + y += one + with cb.ifelse( z > fifty ) as ifelse: + with ifelse.then(): + inner.continue_loop() + z += d + x += one + + cb.ret(z) + cb.close() + return func + +class TestLoopControl(unittest.TestCase): + def test_loopbreak(self): + mod = Module.new(__name__) + lfunc = gen_loopbreak(mod) + logging.debug(mod) + mod.verify() + + exe = CExecutor(mod) + func = exe.get_ctype_function(lfunc, 'int, int') + for x in range(100): + self.assertEqual(func(x), loopbreak(x)) + + def test_loopcontinue(self): + mod = Module.new(__name__) + lfunc = gen_loopcontinue(mod) + logging.debug(mod) + mod.verify() + + exe = CExecutor(mod) + func = exe.get_ctype_function(lfunc, 'int, int') + for x in range(100): + self.assertEqual(func(x), loopcontinue(x)) + +if __name__ == '__main__': + unittest.main() + diff --git a/tests/test_nestedloops.py b/tests/test_nestedloops.py index 823a54f..0876bb2 100644 --- a/tests/test_nestedloops.py +++ b/tests/test_nestedloops.py @@ -61,7 +61,7 @@ def nestedloop2(d): def gen_nestedloop2(mod): functype = Type.function(C.int, [C.int]) - func = mod.add_function(functype, 'nestedloop1') + func = mod.add_function(functype, 'nestedloop2') cb = CBuilder(func) From 0654e00ab157ecc964c59fbadb22f4d1244d3fe0 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sat, 4 Aug 2012 19:13:35 -0700 Subject: [PATCH 010/516] Add printf() and friends. Disable logging in old tests. --- llvm_cbuilder/builder.py | 46 ++++++++++++++++++++++++--- tests/test_atomic_add.py | 2 +- tests/test_atomic_cmpxchg.py | 2 +- tests/test_print.py | 60 ++++++++++++++++++++++++++++++++++++ tests/test_pthread.py | 2 +- 5 files changed, 105 insertions(+), 7 deletions(-) create mode 100644 tests/test_print.py diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index cb33214..16f6daf 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -6,7 +6,6 @@ import contextlib import llvm.core as lc import llvm.ee as le - def _is_int(ty): return isinstance(ty, lc.IntegerType) @@ -31,6 +30,9 @@ def _is_cstruct(ty): except TypeError: return False +def _list_values(iterable): + return [i.value for i in iterable] + @contextlib.contextmanager def _change_block_temporarily(builder, bb): origbb = builder.basic_block @@ -111,7 +113,6 @@ class _Loop(object): def close(self): self.parent.builder.position_at_end(self._bbend) - class CBuilder(object): ''' A wrapper class for features in llvm-py package @@ -136,6 +137,32 @@ class CBuilder(object): func = mod.add_function(functype, name=name) return CBuilder(func) + def printf(self, fmt, *args): + mod = self.function.module + int_t = lc.Type.int() + char_ptr_t = lc.Type.pointer(lc.Type.int(8)) + functype = lc.Type.function(int_t, [char_ptr_t], True) + printf = mod.get_or_insert_function(functype, name='printf') + ret = self.builder.call(printf, [fmt.value]+_list_values(args)) + return CTemp(self, ret) + + def debug(self, *args): + type_mapper = { + 'i32': '%d', + 'double': '%e', + } + itemsfmt = [] + items = [] + for i in args: + if isinstance(i, str): + itemsfmt.append(i.replace('%', '%%')) + else: + ty = type_mapper[str(i.type)] + itemsfmt.append(ty) + items.append(i) + fmt = ' '.join(itemsfmt) + '\n' + return self.printf(self.constant_string(fmt), *items) + def var(self, ty, value=None, name=''): ''' Only allocate in the first block @@ -150,7 +177,7 @@ class CBuilder(object): if value is not None: if isinstance(value, CValue): value = value.value - if not isinstance(value, lc.Value): + elif not isinstance(value, lc.Value): value = self.constant(ty, value).value self.builder.store(value, ptr) if is_cstruct: @@ -213,6 +240,16 @@ class CBuilder(object): res = lc.Constant.null(ty) return CTemp(self, res) + def constant_string(self, string): + mod = self.function.module + name = '.conststr.%x' % hash(string) + content = lc.Constant.stringz(string) + globalstr = mod.add_global_variable(content.type, name=name) + globalstr.initializer = content + ptr = mod.add_global_variable(lc.Type.pointer(content.type.element), + name=name+".ptr") + return CTemp(self, globalstr.bitcast(lc.Type.pointer(content.type.element))) + def get_intrinsic(self, intrinsic_id, tys): lfunc = lc.Function.intrinsic(self.function.module, intrinsic_id, tys) return CFunc(self, lfunc) @@ -515,7 +552,7 @@ class CFunc(CValue): self.function = func def __call__(self, *args): - arg_value = list(map(lambda x: x.value, args)) + arg_value = _list_values(args) res = self.parent.builder.call(self.function, arg_value) return CTemp(self.parent, res) @@ -667,3 +704,4 @@ class CStruct(CValue): gep = self.parent.builder.gep(ptr, [makeind(0), makeind(i)]) setattr(self, fd, CVar(self.parent, gep)) + diff --git a/tests/test_atomic_add.py b/tests/test_atomic_add.py index 63b795a..27688e7 100644 --- a/tests/test_atomic_add.py +++ b/tests/test_atomic_add.py @@ -9,7 +9,7 @@ from llvm_cbuilder import * import llvm_cbuilder.shortnames as C import unittest, logging -logging.basicConfig(level=logging.DEBUG) +# logging.basicConfig(level=logging.DEBUG) NUM_OF_THREAD = 4 REPEAT = 10000 diff --git a/tests/test_atomic_cmpxchg.py b/tests/test_atomic_cmpxchg.py index eb2a45b..27fb763 100644 --- a/tests/test_atomic_cmpxchg.py +++ b/tests/test_atomic_cmpxchg.py @@ -9,7 +9,7 @@ from llvm_cbuilder import * import llvm_cbuilder.shortnames as C import unittest, logging -logging.basicConfig(level=logging.DEBUG) +# logging.basicConfig(level=logging.DEBUG) NUM_OF_THREAD = 4 REPEAT = 10000 diff --git a/tests/test_print.py b/tests/test_print.py new file mode 100644 index 0000000..d971e31 --- /dev/null +++ b/tests/test_print.py @@ -0,0 +1,60 @@ +from llvm.core import * +from llvm.passes import * +from llvm.ee import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import sys, unittest, logging +from subprocess import Popen, PIPE + +def gen_debugprint(mod): + functype = Type.function(C.void, []) + func = mod.add_function(functype, 'debugprint') + + cb = CBuilder(func) + fmt = cb.constant_string("Show %d %.3f %.3e\n") + + an_int = cb.constant(C.int, 123) + a_float = cb.constant(C.double, 1.234) + a_double = cb.constant(C.double, 1e-31) + cb.printf(fmt, an_int, a_float, a_double) + + cb.debug('an_int =', an_int, 'a_float =', a_float, 'a_double =', a_double) + + cb.ret() + cb.close() + return func + +def main_debugprint(): + # generate code + mod = Module.new(__name__) + lfunc = gen_debugprint(mod) + logging.debug(mod) + mod.verify() + # run + exe = CExecutor(mod) + func = exe.get_ctype_function(lfunc, 'void') + func() + +class TestPrint(unittest.TestCase): + def test_debugprint(self): + p = Popen(["python", "test_print.py", "-child"], stdout=PIPE) + p.wait() + + lines = p.stdout.read().decode().splitlines(False) + + expect = [ + 'Show 123 1.234 1.000e-31', + 'an_int = 123 a_float = 1.234000e+00 a_double = 1.000000e-31', + ] + self.assertEqual(expect, lines) + + p.stdout.close() + +if __name__ == '__main__': + try: + if sys.argv[1] == '-child': + main_debugprint() + except IndexError: + unittest.main() + + diff --git a/tests/test_pthread.py b/tests/test_pthread.py index d5212b0..d1d3a72 100644 --- a/tests/test_pthread.py +++ b/tests/test_pthread.py @@ -5,7 +5,7 @@ from llvm_cbuilder import * import llvm_cbuilder.shortnames as C import unittest, logging -logging.basicConfig(level=logging.DEBUG) +# logging.basicConfig(level=logging.DEBUG) NUM_OF_THREAD = 4 From 891daa1164d0941a71ebc1629c59429c091579ac Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sun, 5 Aug 2012 21:35:02 -0700 Subject: [PATCH 011/516] Added test implementation of parallel-vectorize (incomplete). Various fix. --- llvm_cbuilder/builder.py | 213 ++++++++++++++++++------ llvm_cbuilder/executor.py | 2 +- llvm_cbuilder/shortnames.py | 1 + parallel_vectorize.py | 318 ++++++++++++++++++++++++++++++++++++ test_parallel_vectorize.py | 73 +++++++++ 5 files changed, 555 insertions(+), 52 deletions(-) create mode 100644 parallel_vectorize.py create mode 100644 test_parallel_vectorize.py diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 16f6daf..ee308d6 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -40,6 +40,10 @@ def _change_block_temporarily(builder, bb): yield builder.position_at_end(origbb) +@contextlib.contextmanager +def _change_block_temporarily_dummy(*args): + yield + class _IfElse(object): def __init__(self, parent, cond): self.parent = parent @@ -58,14 +62,17 @@ class _IfElse(object): yield - self._to_close.extend([self._bbif, self._bbelse]) + self._to_close.extend([self._bbif, self._bbelse, builder.basic_block]) @contextlib.contextmanager def otherwise(self): - self.parent.builder.position_at_end(self._bbelse) + builder = self.parent.builder + builder.position_at_end(self._bbelse) yield + self._to_close.append(builder.basic_block) def close(self): + self._to_close.append(self.parent.builder.basic_block) bbend = self.parent.function.append_basic_block('if.end') builder = self.parent.builder for bb in self._to_close: @@ -111,7 +118,11 @@ class _Loop(object): self.parent.builder.branch(self._bbcond) def close(self): - self.parent.builder.position_at_end(self._bbend) + builder = self.parent.builder +# if not _is_block_terminated(builder.basic_block): +# with _change_block_temporarily(builder, builder.basic_block): +# builder.branch(self._bbend) + builder.position_at_end(self._bbend) class CBuilder(object): ''' @@ -148,7 +159,10 @@ class CBuilder(object): def debug(self, *args): type_mapper = { + 'i8' : '%c', + 'i16': '%hd', 'i32': '%d', + 'i64': '%ld', 'double': '%e', } itemsfmt = [] @@ -185,9 +199,23 @@ class CBuilder(object): else: return CVar(self, ptr) + def var_copy(self, val, name=''): + return self.var(val.type, val, name=name) + def array(self, ty, count, name=''): - with _change_block_temporarily(self.builder, self.declare_block): - if not isinstance(count, lc.Value): + if isinstance(count, int) or isinstance(count, lc.Constant): + contexthelper = _change_block_temporarily + else: + contexthelper = _change_block_temporarily_dummy + + with contexthelper(self.builder, self.declare_block): + is_cstruct = _is_cstruct(ty) + if is_cstruct: + cstruct = ty + ty = ty.llvm_type() + if isinstance(count, CValue): + count = count.value + elif not isinstance(count, lc.Value): count = self.constant(lc.Type.int(), count).value ptr = self.builder.alloca_array(ty, count, name=name) return CArray(self, ptr) @@ -341,6 +369,40 @@ class CBuilder(object): def alignment(self, ty): return self.target_data.abi_alignment(ty) + def unreachable(self): + self.builder.unreachable() + +class CDefinition(CBuilder): + ''' + Inherit this class to for defining functions + ''' + _name_ = 'unamed' # name of the function; should overide in subclass + _retty_ = lc.Type.void() # return type; can overide in subclass + _argtys_ = [] # a list of tuple(name, type); can overide in subclass + + @classmethod + def define(cls, module, **kws): + functype = lc.Type.function(cls._retty_, [v for k, v in cls._argtys_]) + func = module.get_or_insert_function(functype, name=cls._name_) + if not func.is_declaration: # already defined? + raise NameError('Function %s has already been defined' % cls.name) + + # Name all arguments + for i, (name, _) in enumerate(cls._argtys_): + func.args[i].name = name + + # Create builder and populate body + cbuilder = cls(func) + cbuilder.body(*cbuilder.args, **kws) + cbuilder.close() + return func + + def body(self): + ''' + Overide this function to define the body. + ''' + raise NotImplementedError + class CValue(object): ''' = Signess = @@ -475,13 +537,13 @@ class CValue(object): return make(builder.bitcast(self.value, ty)) elif self.is_int: if _is_int(ty): - if self.type.width > ty.width: + if self.type.width < ty.width: if not unsigned: return make(self.parent.builder.sext(self.value, ty)) else: return make(self.parent.builder.zext(self.value, ty)) else: - return make(self.parent.trunc(self.value, ty)) + return make(self.parent.builder.trunc(self.value, ty)) elif _is_real(ty): if not unsigned: return make(self.parent.builder.sitofp(self.value, ty)) @@ -543,7 +605,46 @@ class CValue(object): def _ensure_is_pointer(self): if not self.is_pointer: - raise TypeError("Must be a pointer") + raise TypeError("Must be a pointer; got %s" % self.type) + + def __getitem__(self, idx): + self._ensure_is_pointer() + if not isinstance(idx, CValue): + idx = self.parent.constant(lc.Type.int(), idx) + bldr = self.parent.builder + ptr = bldr.gep(self.value, [idx.value]) + return CVar(self.parent, ptr) + + def load(self, volatile=False): + self._ensure_is_pointer() + loaded = self.parent.builder.load(self.value, volatile=volatile) + return CTemp(self.parent, loaded) + + def store(self, val, volatile=False): + self._ensure_is_pointer() + self.parent.builder.store(val.value, self.value, volatile=volatile) + + def atomic_load(self, ordering, align=None, crossthread=True): + self._ensure_is_pointer() + if align is None: + align = self.parent.alignment(self.type.pointee) + inst = self.parent.builder.atomic_load(self.value, ordering, align, + crossthread=crossthread) + return CTemp(self.parent, inst) + + def atomic_store(self, value, ordering, align=None, crossthread=True): + self._ensure_is_pointer() + if align is None: + align = self.parent.alignment(self.type.pointee) + self.parent.builder.atomic_store(value.ptr, self.value, ordering, + align=align, crossthread=crossthread) + + def atomic_cmpxchg(self, old, new, ordering, crossthread=True): + self._ensure_is_pointer() + inst = self.parent.builder.atomic_cmpxchg(self.value, old.value, + new.value, ordering, + crossthread=crossthread) + return CTemp(self.parent, inst) class CFunc(CValue): @@ -552,8 +653,14 @@ class CFunc(CValue): self.function = func def __call__(self, *args): - arg_value = _list_values(args) - res = self.parent.builder.call(self.function, arg_value) + arg_values = _list_values(args) + ftype = self.function.type.pointee + for i, (exp, got) in enumerate(zip(ftype.args, arg_values)): + if exp != got.type: + raise TypeError("At call to %s, " + "argument %d mismatch: %s != %s" + % (self.function.name, i, exp, got.type)) + res = self.parent.builder.call(self.function, arg_values) return CTemp(self.parent, res) @property @@ -601,7 +708,6 @@ class CVar(CValue): def __imod__(self, rhs): return self._inplace_binop('mod')(rhs) - def _inplace_bitwise(self, op): def wrapped(rhs): res = self._use_bitwise(op)(rhs) @@ -629,46 +735,23 @@ class CVar(CValue): return self.parent.builder.load(self.ptr) def assign(self, val): + self._ensure_same_type(val) self.parent.builder.store(val.value, self.ptr) @property def type(self): return self.ptr.type.pointee - def load(self, volatile=False): - self._ensure_is_pointer() - loaded = self.parent.builder.load(self.value, volatile=volatile) - return CTemp(self.parent, loaded) - - def store(self, val, volatile=False): - self._ensure_is_pointer() - self.parent.builder.store(val.value, self.value, volatile=volatile) - - def atomic_load(self, ordering, align=None, crossthread=True): - self._ensure_is_pointer() - if align is None: - align = self.parent.alignment(self.type.pointee) - inst = self.parent.builder.atomic_load(self.value, ordering, align, - crossthread=crossthread) - return CTemp(self.parent, inst) - - def atomic_store(self, value, ordering, align=None, crossthread=True): - self._ensure_is_pointer() - if align is None: - align = self.parent.alignment(self.type.pointee) - self.parent.builder.atomic_store(value.value, self.value, ordering, - align=align, crossthread=crossthread) - - def atomic_cmpxchg(self, old, new, ordering, crossthread=True): - self._ensure_is_pointer() - inst = self.parent.builder.atomic_cmpxchg(self.value, old.value, - new.value, ordering, - crossthread=crossthread) - return CTemp(self.parent, inst) - def reference(self): return CTemp(self.parent, self.ptr) + def as_struct(self, cstruct_class, volatile=False): + if _is_pointer(self.type): + ptr = self.parent.builder.load(self.ptr, volatile=volatile) + return cstruct_class(self.parent, ptr) + else: + return cstruct_class(self.parent, self.ptr) + class CArray(CValue): def __init__(self, parent, base): super(CArray, self).__init__(parent) @@ -678,19 +761,23 @@ class CArray(CValue): def value(self): return self.base_ptr + def reference(self): + return CTemp(self.parent, self.base_ptr) + @property def type(self): return self.base_ptr.type - def __getitem__(self, idx): - self._ensure_is_pointer() - builder = self.parent.builder - if isinstance(idx, CValue): - idx = idx.value - elif not isinstance(idx, lc.Value): - idx = self.parent.constant(lc.Type.int(), idx).value - ptr = builder.gep(self.value, [idx]) - return CVar(self.parent, ptr) +## Moved to CValue +# def __getitem__(self, idx): +# self._ensure_is_pointer() +# builder = self.parent.builder +# if isinstance(idx, CValue): +# idx = idx.value +# elif not isinstance(idx, lc.Value): +# idx = self.parent.constant(lc.Type.int(), idx).value +# ptr = builder.gep(self.value, [idx]) +# return CVar(self.parent, ptr) class CStruct(CValue): @classmethod @@ -700,8 +787,32 @@ class CStruct(CValue): def __init__(self, parent, ptr): super(CStruct, self).__init__(parent) makeind = lambda x: self.parent.constant(lc.Type.int(), x).value + self.ptr = ptr for i, (fd, _) in enumerate(self._fields_): gep = self.parent.builder.gep(ptr, [makeind(0), makeind(i)]) + gep.name = "%s.%s" % (type(self).__name__, fd) setattr(self, fd, CVar(self.parent, gep)) + def reference(self): + return CTemp(self.parent, self.ptr) + +class CExternal(object): + def __init__(self, cbuilder): + is_func = lambda x: isinstance(x, lc.FunctionType) + non_magic = lambda s: not ( s.startswith('__') and s.endswith('__') ) + + to_declare = [] + for fname in filter(non_magic, vars(type(self))): + ftype = getattr(self, fname) + if is_func(ftype): + to_declare.append((fname, ftype)) + + mod = cbuilder.function.module + for fname, ftype in to_declare: + func = mod.get_or_insert_function(ftype, name=fname) + if func.type.pointee != ftype: + raise NameError("Function has already been declared " + "with a different type: %s != %s" + % (func.type, ftype) ) + setattr(self, fname, CFunc(cbuilder, func)) diff --git a/llvm_cbuilder/executor.py b/llvm_cbuilder/executor.py index a2f558e..bd7d78c 100644 --- a/llvm_cbuilder/executor.py +++ b/llvm_cbuilder/executor.py @@ -31,7 +31,7 @@ MAP_CTYPES = { class CExecutor(object): def __init__(self, mod_or_engine): if isinstance(mod_or_engine, Module): - self.engine = le.EngineBuilder.new(mod_or_engine).create() + self.engine = le.EngineBuilder.new(mod_or_engine).opt(3).create() else: self.engine = mod_or_engine diff --git a/llvm_cbuilder/shortnames.py b/llvm_cbuilder/shortnames.py index d3fc5af..beaaad3 100644 --- a/llvm_cbuilder/shortnames.py +++ b/llvm_cbuilder/shortnames.py @@ -16,6 +16,7 @@ double = Type.double() pointer = Type.pointer void_p = pointer(char) +char_p = pointer(char) # platform dependent diff --git a/parallel_vectorize.py b/parallel_vectorize.py new file mode 100644 index 0000000..1f83ad5 --- /dev/null +++ b/parallel_vectorize.py @@ -0,0 +1,318 @@ +from llvm.core import * +from llvm.passes import * + +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C + +class WorkQueue(CStruct): + _fields_ = [ + ('next', C.intp), + ('last', C.intp), + ('lock', C.int), + ] + + + def Lock(self): + with self.parent.loop() as loop: + with loop.condition() as setcond: + unlocked = self.parent.constant(self.lock.type, 0) + locked = self.parent.constant(self.lock.type, 1) + + res = self.lock.reference().atomic_cmpxchg(unlocked, locked, + ordering='acquire') + setcond( res != unlocked ) + + with loop.body(): + pass + + def Unlock(self): + unlocked = self.parent.constant(self.lock.type, 0) + locked = self.parent.constant(self.lock.type, 1) + + res = self.lock.reference().atomic_cmpxchg(locked, unlocked, + ordering='release') + + with self.parent.ifelse( res != locked ) as ifelse: + with ifelse.then(): + # This shall kill the program + self.parent.unreachable() + + +class ContextCommon(CStruct): + _fields_ = [ + # loop ufunc args + ('args', C.pointer(C.char_p)), + ('dimensions', C.pointer(C.intp)), + ('steps', C.pointer(C.intp)), + ('data', C.void_p), + # specifics for work queues + ('func', C.void_p), + ('num_thread', C.int), + ('workqueues', C.pointer(WorkQueue.llvm_type())), + ] + +class Context(CStruct): + _fields_ = [ + ('common', C.pointer(ContextCommon.llvm_type())), + ('id', C.int), + ('completed', C.intp), + ] + +class ParallelUFunc(CDefinition): + _name_ = 'parallel_ufunc' + _retty_ = C.void + _argtys_ = [ + ('func', C.void_p), + ('worker', C.void_p), + ('args', C.pointer(C.char_p)), + ('dimensions', C.pointer(C.intp)), + ('steps', C.pointer(C.intp)), + ('data', C.void_p), + ] + + def body(self, func, worker, args, dimensions, steps, data, ThreadCount=1): + + + common = self.var(ContextCommon, name='common') + workqueues = self.array(WorkQueue, ThreadCount, name='workqueues') + contexts = self.array(Context, ThreadCount, name='contexts') + + num_thread = self.var(C.int, ThreadCount, name='num_thread') + + common.args.assign(args) + common.dimensions.assign(dimensions) + common.steps.assign(steps) + common.data.assign(data) + common.func.assign(func) + common.num_thread.assign(num_thread.cast(C.int)) + common.workqueues.assign(workqueues.reference()) + + N = dimensions[0] + ChunkSize = self.var_copy(N / num_thread.cast(N.type)) + ChunkSize_NULL = self.constant_null(ChunkSize.type) + with self.ifelse(ChunkSize == ChunkSize_NULL) as ifelse: + with ifelse.then(): + ChunkSize.assign(self.constant(ChunkSize.type, 1)) + num_thread.assign(N.cast(num_thread.type)) + + self._populate_workqueues(workqueues, N, ChunkSize, num_thread) + self._populate_context(contexts, common, num_thread) + + self._dispatch_worker(worker, contexts, num_thread) + + # Check for race condition + total_completed = self.var(C.intp, 0, name='total_completed') + for t in range(ThreadCount): + cur_ctxt = contexts[t].as_struct(Context) + total_completed += cur_ctxt.completed + self.debug(cur_ctxt.id, 'completed', cur_ctxt.completed) + + with self.ifelse( total_completed == N ) as ifelse: + with ifelse.then(): + self.debug("All is well!") + with ifelse.otherwise(): + self.debug("ERROR: race occurred!") + + self.ret() + + def _populate_workqueues(self, workqueues, N, ChunkSize, num_thread): + i = self.var(num_thread.type, 0, name='i') + ONE = self.constant(i.type, 1) + with self.loop() as loop: + with loop.condition() as setcond: + setcond( i < num_thread ) + with loop.body(): + cur_wq = workqueues[i].as_struct(WorkQueue) + cur_wq.next.assign(i.cast(ChunkSize.type) * ChunkSize) + cur_wq.last.assign((i + ONE).cast(ChunkSize.type) * ChunkSize) + cur_wq.lock.assign(self.constant(C.int, 0)) + # increment + i += ONE + # end loop + last_wq = workqueues[num_thread - ONE].as_struct(WorkQueue) + last_wq.last.assign(N) + + def _populate_context(self, contexts, common, num_thread): + i = self.var(num_thread.type, 0, name='i') + ONE = self.constant(i.type, 1) + with self.loop() as loop: + with loop.condition() as setcond: + setcond( i < num_thread ) + with loop.body(): + cur_ctxt = contexts[i].as_struct(Context) + cur_ctxt.common.assign(common.reference()) + cur_ctxt.id.assign(i) + cur_ctxt.completed.assign(self.constant_null( + cur_ctxt.completed.type)) + # increment + i += ONE + + +class ParallelUFuncPosix(ParallelUFunc): + def _dispatch_worker(self, worker, contexts, num_thread): + api = PThreadAPI(self) + NULL = self.constant_null(C.void_p) + + threads = self.array(api.pthread_t, num_thread, name='threads') + + # self.debug("launch threads") + # TODO error handling + + i = self.var(num_thread.type, 0, name='i') + ONE = self.constant(i.type, 1) + with self.loop() as loop: + with loop.condition() as setcond: + setcond( i < num_thread ) + with loop.body(): + api.pthread_create(threads[i].reference(), NULL, worker, + contexts[i].reference().cast(C.void_p)) + i += ONE + + # self.debug("join threads") + i.assign(self.constant_null(i.type)) + with self.loop() as loop: + with loop.condition() as setcond: + setcond( i < num_thread ) + with loop.body(): + api.pthread_join(threads[i], NULL) + i += ONE + # self.debug("closing") + +class UFuncCore(CDefinition): + _name_ = 'ufunc_worker' + _argtys_ = [ + ('context', C.pointer(Context.llvm_type())), + ] + + def body(self, context): + context = context.as_struct(Context) + common = context.common.as_struct(ContextCommon) + tid = context.id + + # self.debug("start thread", tid, "/", common.num_thread) + workqueue = common.workqueues[tid].as_struct(WorkQueue) + + self._do_workqueue(common, workqueue, tid, context.completed) + self._do_work_stealing(common, tid, context.completed) # optional + + self.ret() + + def _do_workqueue(self, common, workqueue, tid, completed): + ''' + Process local workqueue. + ''' + ZERO = self.constant_null(C.int) + + with self.loop() as loop: + with loop.condition() as setcond: + setcond(ZERO == ZERO) # loop forever + + with loop.body(): + workqueue.Lock() + # Critical section + item = self.var_copy(workqueue.next, name='item') + workqueue.next += self.constant(item.type, 1) + last = self.var_copy(workqueue.last, name='last') + # Release + workqueue.Unlock() + + with self.ifelse( item >= last ) as ifelse: + with ifelse.then(): + loop.break_loop() + + self._do_work(common, item, tid, completed) + + def _do_work_stealing(self, common, tid, completed): + ''' + Steal work from other workqueues + ''' + # self.debug("start work stealing", tid) + incomplete_thread_ct = self.var(C.int, 1) + ITC_NULL = self.constant_null(incomplete_thread_ct.type) + with self.loop() as loop: + with loop.condition() as setcond: + setcond( incomplete_thread_ct != ITC_NULL ) + + with loop.body(): + incomplete_thread_ct.assign(ITC_NULL) + self._do_work_stealing_innerloop(common, incomplete_thread_ct, + tid, completed) + + def _do_work_stealing_innerloop(self, common, incomplete_thread_ct, tid, + completed): + i = self.var(C.int, 0) + with self.loop() as loop: + with loop.condition() as setcond: + setcond( i < common.num_thread ) + + with loop.body(): + with self.ifelse( i != tid ) as ifelse: + with ifelse.then(): + otherqueue = common.workqueues[i].as_struct(WorkQueue) + self._do_work_stealing_check(common, otherqueue, + incomplete_thread_ct, tid, + completed) + + # increment + i += self.constant(i.type, 1) + + def _do_work_stealing_check(self, common, otherqueue, + incomplete_thread_ct, tid, completed): + otherqueue.Lock() + ONE = self.constant(otherqueue.last.type, 1) + ITC_ONE = self.constant(incomplete_thread_ct.type, 1) + with self.ifelse(otherqueue.next < otherqueue.last) as ifelse: + with ifelse.then(): + otherqueue.last -= ONE + item = self.var_copy(otherqueue.last) + + otherqueue.Unlock() + # Released + + self._do_work(common, item, tid, completed) + + # Mark incomplete thread + incomplete_thread_ct.assign(ITC_ONE) + + with ifelse.otherwise(): + otherqueue.Unlock() + + def _do_work(self, common, item, tid, completed): + # self.debug(" tid", tid, "item", item) + completed += self.constant(completed.type, 1) + + +class PThreadAPI(CExternal): + pthread_t = C.void_p + + pthread_create = Type.function(C.int, + [C.pointer(pthread_t), # thread_t + C.void_p, # thread attr + C.void_p, # function + C.void_p]) # arg + + pthread_join = Type.function(C.int, [C.void_p, C.void_p]) + + +def _main(): + NUM_THREAD = 2 + module = Module.new(__name__) + + fpm = FunctionPassManager.new(module) + PassManagerBuilder.new().populate(fpm) + + f1 = ParallelUFuncPosix.define(module, ThreadCount=NUM_THREAD) + f2 = UFuncCore.define(module) + #print(module) +# print(f1) + print(f2) + module.verify() + + fpm.run(f1) + fpm.run(f2) + print('optimized'.center(80,'-')) + print(f2) + +if __name__ == '__main__': + _main() + diff --git a/test_parallel_vectorize.py b/test_parallel_vectorize.py new file mode 100644 index 0000000..b3ffb5c --- /dev/null +++ b/test_parallel_vectorize.py @@ -0,0 +1,73 @@ +from parallel_vectorize import * + +''' +void parallel_ufunc(void * func, void * worker, + char **args, npy_intp *dimensions, + npy_intp *steps, void *data) +''' +class Tester(CDefinition): + _name_ = 'tester' + + def body(self): + # depends + module = self.function.module + + ThreadCount = 2 + ArgCount = 2 + WorkCount = 1000000 + + parallel_ufunc = CFunc(self, ParallelUFuncPosix.define(module, + ThreadCount=ThreadCount)) + worker = CFunc(self, UFuncCore.define(module)) + + # real work + NULL = self.constant_null(C.void_p) + + args = self.array(C.char_p, 2, name='args') + + for t in range(ThreadCount): + args_for_thread = self.array(C.double, 4) + args[t].assign(args_for_thread.cast(C.char_p)) + + dims = self.array(C.intp, 1, name='dims') + dims[0].assign(self.constant(C.intp, WorkCount)) + + steps = self.array(C.intp, ArgCount, name='steps') + + for c in range(ArgCount): + steps[c].assign(self.constant(C.intp, 8)) + + parallel_ufunc(NULL, worker.cast(C.void_p), args, dims, steps, NULL) + + self.ret() + +def main(): + NUM_THREAD = 2 + module = Module.new(__name__) + + mpm = PassManager.new() + pmbuilder = PassManagerBuilder.new() + pmbuilder.opt_level = 3 + pmbuilder.populate(mpm) + + fntester = Tester.define(module) + +# print(module) + module.verify() + + mpm.run(module) + + print('optimized'.center(80,'-')) + print(module) + + # run + exe = CExecutor(module) + exe.engine.get_pointer_to_function(fntester) + func = exe.get_ctype_function(fntester, 'void') + + func() + + +if __name__ == '__main__': + main() + From 1594e5456a887caa29e3f2f8628d5bcb27c47590 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 6 Aug 2012 11:35:03 -0700 Subject: [PATCH 012/516] Got test_parallel_vectorize working. --- llvm_cbuilder/builder.py | 56 +++++++- parallel_vectorize.py | 267 +++++++++++++++++++------------------ test_parallel_vectorize.py | 72 ++++++++-- 3 files changed, 253 insertions(+), 142 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index ee308d6..eaa159e 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -5,6 +5,7 @@ import contextlib import llvm.core as lc import llvm.ee as le +from llvm import LLVMException def _is_int(ty): return isinstance(ty, lc.IntegerType) @@ -245,6 +246,44 @@ class CBuilder(object): yield cb cb.close() + @contextlib.contextmanager + def forever(self): + with self.loop() as loop: + with loop.condition() as setcond: + NULL = self.constant_null(lc.Type.int()) + setcond( NULL == NULL ) + with loop.body(): + yield loop + + @contextlib.contextmanager + def for_range(self, *args): + def check_arg(x): + if isinstance(x, int): + return self.constant(lc.Type.int(), x) + if not x.is_int: + raise TypeError(x, "All args must be of integer type.") + return x + + if len(args) == 3: + start, stop, step = map(check_arg, args) + elif len(args) == 2: + start, stop = map(check_arg, args) + step = self.constant(start.type, 1) + elif len(args) == 1: + stop = check_arg(args[0]) + start = self.constant(stop.type, 0) + step = self.constant(stop.type, 1) + else: + raise TypeError("Invalid # of arguments: 1, 2 or 3") + + idx = self.var_copy(start) + with self.loop() as loop: + with loop.condition() as setcond: + setcond( idx < stop ) + with loop.body(): + yield loop, idx + idx += step + def position_at_end(self, bb): self.basic_block = bb self.builder.position_at_end(bb) @@ -270,13 +309,18 @@ class CBuilder(object): def constant_string(self, string): mod = self.function.module - name = '.conststr.%x' % hash(string) + name = '.conststr.%x_%x' % (hash(string), len(string)) content = lc.Constant.stringz(string) - globalstr = mod.add_global_variable(content.type, name=name) - globalstr.initializer = content - ptr = mod.add_global_variable(lc.Type.pointer(content.type.element), - name=name+".ptr") - return CTemp(self, globalstr.bitcast(lc.Type.pointer(content.type.element))) + try: + globalstr = mod.get_global_variable_named(name) + except LLVMException: + globalstr = mod.add_global_variable(content.type, name=name) + globalstr.initializer = content +# ptr = mod.add_global_variable(lc.Type.pointer(content.type.element), +# name=name+".ptr") + return CTemp(self, globalstr.bitcast( + lc.Type.pointer(content.type.element))) + def get_intrinsic(self, intrinsic_id, tys): lfunc = lc.Function.intrinsic(self.function.module, intrinsic_id, tys) diff --git a/parallel_vectorize.py b/parallel_vectorize.py index 1f83ad5..25176b8 100644 --- a/parallel_vectorize.py +++ b/parallel_vectorize.py @@ -1,3 +1,15 @@ +''' +This file implements the code-generator for parallel-vectorize. + +ParallelUFunc is the platform independent base class for generating +the thread dispatcher. This thread dispatcher launches threads +that execute the generated function of UFuncCore. +UFuncCore is subclassed to specialize for the input/output types. +The actual workload is invoked inside the function generated by UFuncCore. +UFuncCore also defines a work-stealing mechanism that allows idle threads +to steal works from other threads. +''' + from llvm.core import * from llvm.passes import * @@ -5,14 +17,21 @@ from llvm_cbuilder import * import llvm_cbuilder.shortnames as C class WorkQueue(CStruct): + ''' + Structure for workqueue for parallel-ufunc. + ''' + _fields_ = [ - ('next', C.intp), - ('last', C.intp), - ('lock', C.int), + ('next', C.intp), # next index of work item + ('last', C.intp), # last index of work item (exlusive) + ('lock', C.int), # for locking the workqueue ] def Lock(self): + ''' + Inline the lock procedure. + ''' with self.parent.loop() as loop: with loop.condition() as setcond: unlocked = self.parent.constant(self.lock.type, 0) @@ -26,6 +45,9 @@ class WorkQueue(CStruct): pass def Unlock(self): + ''' + Inline the unlock procedure. + ''' unlocked = self.parent.constant(self.lock.type, 0) locked = self.parent.constant(self.lock.type, 1) @@ -39,6 +61,9 @@ class WorkQueue(CStruct): class ContextCommon(CStruct): + ''' + Structure for thread-shared context information in parallel-ufunc. + ''' _fields_ = [ # loop ufunc args ('args', C.pointer(C.char_p)), @@ -52,6 +77,9 @@ class ContextCommon(CStruct): ] class Context(CStruct): + ''' + Structure for thread-specific context information in parallel-ufunc. + ''' _fields_ = [ ('common', C.pointer(ContextCommon.llvm_type())), ('id', C.int), @@ -71,14 +99,14 @@ class ParallelUFunc(CDefinition): ] def body(self, func, worker, args, dimensions, steps, data, ThreadCount=1): - - + # Setup variables common = self.var(ContextCommon, name='common') workqueues = self.array(WorkQueue, ThreadCount, name='workqueues') contexts = self.array(Context, ThreadCount, name='contexts') num_thread = self.var(C.int, ThreadCount, name='num_thread') + # Initialize ContextCommon common.args.assign(args) common.dimensions.assign(dimensions) common.steps.assign(steps) @@ -87,6 +115,11 @@ class ParallelUFunc(CDefinition): common.num_thread.assign(num_thread.cast(C.int)) common.workqueues.assign(workqueues.reference()) + # Determine chunksize, initial count of work-items per thread. + # If total_work >= num_thread, equally divide the works. + # If total_work % num_thread != 0, the last thread does all remaining works. + # If total_work < num_thread, each thread does one work, + # and set num_thread to total_work N = dimensions[0] ChunkSize = self.var_copy(N / num_thread.cast(N.type)) ChunkSize_NULL = self.constant_null(ChunkSize.type) @@ -95,60 +128,70 @@ class ParallelUFunc(CDefinition): ChunkSize.assign(self.constant(ChunkSize.type, 1)) num_thread.assign(N.cast(num_thread.type)) + # Populate workqueue for all threads self._populate_workqueues(workqueues, N, ChunkSize, num_thread) + + # Populate contexts for all threads self._populate_context(contexts, common, num_thread) + # Dispatch worker threads self._dispatch_worker(worker, contexts, num_thread) + ## DEBUG ONLY ## # Check for race condition - total_completed = self.var(C.intp, 0, name='total_completed') - for t in range(ThreadCount): - cur_ctxt = contexts[t].as_struct(Context) - total_completed += cur_ctxt.completed - self.debug(cur_ctxt.id, 'completed', cur_ctxt.completed) + if True: + total_completed = self.var(C.intp, 0, name='total_completed') + for t in range(ThreadCount): + cur_ctxt = contexts[t].as_struct(Context) + total_completed += cur_ctxt.completed + self.debug(cur_ctxt.id, 'completed', cur_ctxt.completed) - with self.ifelse( total_completed == N ) as ifelse: - with ifelse.then(): - self.debug("All is well!") - with ifelse.otherwise(): - self.debug("ERROR: race occurred!") + with self.ifelse( total_completed == N ) as ifelse: + with ifelse.then(): + self.debug("All is well!") + with ifelse.otherwise(): + self.debug("ERROR: race occurred! Trigger segfault") + self.unreachable() + # Return self.ret() def _populate_workqueues(self, workqueues, N, ChunkSize, num_thread): - i = self.var(num_thread.type, 0, name='i') - ONE = self.constant(i.type, 1) - with self.loop() as loop: - with loop.condition() as setcond: - setcond( i < num_thread ) - with loop.body(): - cur_wq = workqueues[i].as_struct(WorkQueue) - cur_wq.next.assign(i.cast(ChunkSize.type) * ChunkSize) - cur_wq.last.assign((i + ONE).cast(ChunkSize.type) * ChunkSize) - cur_wq.lock.assign(self.constant(C.int, 0)) - # increment - i += ONE + ''' + Loop over all threads and populate the workqueue for each of them. + ''' + ONE = self.constant(num_thread.type, 1) + with self.for_range(num_thread) as (loop, i): + cur_wq = workqueues[i].as_struct(WorkQueue) + cur_wq.next.assign(i.cast(ChunkSize.type) * ChunkSize) + cur_wq.last.assign((i + ONE).cast(ChunkSize.type) * ChunkSize) + cur_wq.lock.assign(self.constant(C.int, 0)) # end loop last_wq = workqueues[num_thread - ONE].as_struct(WorkQueue) last_wq.last.assign(N) def _populate_context(self, contexts, common, num_thread): - i = self.var(num_thread.type, 0, name='i') - ONE = self.constant(i.type, 1) - with self.loop() as loop: - with loop.condition() as setcond: - setcond( i < num_thread ) - with loop.body(): - cur_ctxt = contexts[i].as_struct(Context) - cur_ctxt.common.assign(common.reference()) - cur_ctxt.id.assign(i) - cur_ctxt.completed.assign(self.constant_null( - cur_ctxt.completed.type)) - # increment - i += ONE + ''' + Loop over all threads and populate contexts for each of them. + ''' + ONE = self.constant(num_thread.type, 1) + with self.for_range(num_thread) as (loop, i): + cur_ctxt = contexts[i].as_struct(Context) + cur_ctxt.common.assign(common.reference()) + cur_ctxt.id.assign(i) + cur_ctxt.completed.assign( + self.constant_null(cur_ctxt.completed.type)) + def _dispatch_worker(self, worker, contexts, num_thread): + ''' + Dispatch worker threads. + ''' + raise NotImplementedError class ParallelUFuncPosix(ParallelUFunc): + ''' + Implements _dispatch_worker to use pthread. + ''' def _dispatch_worker(self, worker, contexts, num_thread): api = PThreadAPI(self) NULL = self.constant_null(C.void_p) @@ -158,27 +201,19 @@ class ParallelUFuncPosix(ParallelUFunc): # self.debug("launch threads") # TODO error handling - i = self.var(num_thread.type, 0, name='i') - ONE = self.constant(i.type, 1) - with self.loop() as loop: - with loop.condition() as setcond: - setcond( i < num_thread ) - with loop.body(): - api.pthread_create(threads[i].reference(), NULL, worker, - contexts[i].reference().cast(C.void_p)) - i += ONE + ONE = self.constant(num_thread.type, 1) + with self.for_range(num_thread) as (loop, i): + api.pthread_create(threads[i].reference(), NULL, worker, + contexts[i].reference().cast(C.void_p)) - # self.debug("join threads") - i.assign(self.constant_null(i.type)) - with self.loop() as loop: - with loop.condition() as setcond: - setcond( i < num_thread ) - with loop.body(): - api.pthread_join(threads[i], NULL) - i += ONE - # self.debug("closing") + with self.for_range(num_thread) as (loop, i): + api.pthread_join(threads[i], NULL) class UFuncCore(CDefinition): + ''' + Generates the workqueue handling and work stealing and invoke + the work function for each work item. + ''' _name_ = 'ufunc_worker' _argtys_ = [ ('context', C.pointer(Context.llvm_type())), @@ -203,64 +238,61 @@ class UFuncCore(CDefinition): ''' ZERO = self.constant_null(C.int) - with self.loop() as loop: - with loop.condition() as setcond: - setcond(ZERO == ZERO) # loop forever + with self.forever() as loop: + workqueue.Lock() + # Critical section + item = self.var_copy(workqueue.next, name='item') + workqueue.next += self.constant(item.type, 1) + last = self.var_copy(workqueue.last, name='last') + # Release + workqueue.Unlock() - with loop.body(): - workqueue.Lock() - # Critical section - item = self.var_copy(workqueue.next, name='item') - workqueue.next += self.constant(item.type, 1) - last = self.var_copy(workqueue.last, name='last') - # Release - workqueue.Unlock() + with self.ifelse( item >= last ) as ifelse: + with ifelse.then(): + loop.break_loop() - with self.ifelse( item >= last ) as ifelse: - with ifelse.then(): - loop.break_loop() - - self._do_work(common, item, tid, completed) + self._do_work(common, item, tid) + completed += self.constant(completed.type, 1) def _do_work_stealing(self, common, tid, completed): ''' - Steal work from other workqueues + Steal work from other workqueues. ''' # self.debug("start work stealing", tid) - incomplete_thread_ct = self.var(C.int, 1) - ITC_NULL = self.constant_null(incomplete_thread_ct.type) + steal_continue = self.var(C.int, 1) + STEAL_STOP = self.constant_null(steal_continue.type) + + # Loop until all workqueues are done. with self.loop() as loop: with loop.condition() as setcond: - setcond( incomplete_thread_ct != ITC_NULL ) + setcond( steal_continue != STEAL_STOP ) with loop.body(): - incomplete_thread_ct.assign(ITC_NULL) - self._do_work_stealing_innerloop(common, incomplete_thread_ct, - tid, completed) + steal_continue.assign(STEAL_STOP) + self._do_work_stealing_innerloop(common, steal_continue, tid, + completed) - def _do_work_stealing_innerloop(self, common, incomplete_thread_ct, tid, + def _do_work_stealing_innerloop(self, common, steal_continue, tid, completed): - i = self.var(C.int, 0) - with self.loop() as loop: - with loop.condition() as setcond: - setcond( i < common.num_thread ) + ''' + Loop over all other threads and try to steal work. + ''' + with self.for_range(common.num_thread) as (loop, i): + with self.ifelse( i != tid ) as ifelse: + with ifelse.then(): + otherqueue = common.workqueues[i].as_struct(WorkQueue) + self._do_work_stealing_check(common, otherqueue, + steal_continue, tid, + completed) - with loop.body(): - with self.ifelse( i != tid ) as ifelse: - with ifelse.then(): - otherqueue = common.workqueues[i].as_struct(WorkQueue) - self._do_work_stealing_check(common, otherqueue, - incomplete_thread_ct, tid, - completed) - - # increment - i += self.constant(i.type, 1) - - def _do_work_stealing_check(self, common, otherqueue, - incomplete_thread_ct, tid, completed): + def _do_work_stealing_check(self, common, otherqueue, steal_continue, tid, + completed): + ''' + Check the workqueue for any remaining work and steal it. + ''' otherqueue.Lock() ONE = self.constant(otherqueue.last.type, 1) - ITC_ONE = self.constant(incomplete_thread_ct.type, 1) + STEAL_CONTINUE = self.constant(steal_continue.type, 1) with self.ifelse(otherqueue.next < otherqueue.last) as ifelse: with ifelse.then(): otherqueue.last -= ONE @@ -269,17 +301,20 @@ class UFuncCore(CDefinition): otherqueue.Unlock() # Released - self._do_work(common, item, tid, completed) + self._do_work(common, item, tid) + completed += self.constant(completed.type, 1) # Mark incomplete thread - incomplete_thread_ct.assign(ITC_ONE) + steal_continue.assign(STEAL_CONTINUE) with ifelse.otherwise(): otherqueue.Unlock() - def _do_work(self, common, item, tid, completed): - # self.debug(" tid", tid, "item", item) - completed += self.constant(completed.type, 1) + def _do_work(self, common, item, tid): + ''' + Prepare to call the actual work function. + ''' + raise NotImplementedError class PThreadAPI(CExternal): @@ -294,25 +329,3 @@ class PThreadAPI(CExternal): pthread_join = Type.function(C.int, [C.void_p, C.void_p]) -def _main(): - NUM_THREAD = 2 - module = Module.new(__name__) - - fpm = FunctionPassManager.new(module) - PassManagerBuilder.new().populate(fpm) - - f1 = ParallelUFuncPosix.define(module, ThreadCount=NUM_THREAD) - f2 = UFuncCore.define(module) - #print(module) -# print(f1) - print(f2) - module.verify() - - fpm.run(f1) - fpm.run(f2) - print('optimized'.center(80,'-')) - print(f2) - -if __name__ == '__main__': - _main() - diff --git a/test_parallel_vectorize.py b/test_parallel_vectorize.py index b3ffb5c..fbcb133 100644 --- a/test_parallel_vectorize.py +++ b/test_parallel_vectorize.py @@ -1,11 +1,40 @@ from parallel_vectorize import * -''' -void parallel_ufunc(void * func, void * worker, - char **args, npy_intp *dimensions, - npy_intp *steps, void *data) -''' + +class Work_D_D(CDefinition): + _name_ = 'copy_d_d' + _retty_ = C.double + _argtys_ = [ + ('inval', C.double), + ] + def body(self, inval): + self.ret(inval / self.constant(inval.type, 2.345)) + +class UFuncCore_D_D(UFuncCore): + ''' + Specialize UFuncCore for double input, double output. + ''' + def _do_work(self, common, item, tid): + ufunc_type = Type.function(C.double, [C.double]) + ufunc_ptr = CFunc(self, common.func.cast(C.pointer(ufunc_type)).value) + + inbase = common.args[0] + outbase = common.args[1] + + instep = common.steps[0] + outstep = common.steps[0] + + indata = inbase[item * instep].reference().cast(C.pointer(C.double)) + outdata = outbase[item * outstep].reference().cast(C.pointer(C.double)) + + res = ufunc_ptr(indata.load()) + outdata.store(res) + + class Tester(CDefinition): + ''' + Generate test. + ''' _name_ = 'tester' def body(self): @@ -14,20 +43,23 @@ class Tester(CDefinition): ThreadCount = 2 ArgCount = 2 - WorkCount = 1000000 + WorkCount = 10000 parallel_ufunc = CFunc(self, ParallelUFuncPosix.define(module, ThreadCount=ThreadCount)) - worker = CFunc(self, UFuncCore.define(module)) + ufunc_core = CFunc(self, UFuncCore_D_D.define(module)) + worker = CFunc(self, Work_D_D.define(module)) # real work NULL = self.constant_null(C.void_p) args = self.array(C.char_p, 2, name='args') + args_double = [] for t in range(ThreadCount): - args_for_thread = self.array(C.double, 4) + args_for_thread = self.array(C.double, WorkCount) args[t].assign(args_for_thread.cast(C.char_p)) + args_double.append(args_for_thread) dims = self.array(C.intp, 1, name='dims') dims[0].assign(self.constant(C.intp, WorkCount)) @@ -37,7 +69,28 @@ class Tester(CDefinition): for c in range(ArgCount): steps[c].assign(self.constant(C.intp, 8)) - parallel_ufunc(NULL, worker.cast(C.void_p), args, dims, steps, NULL) + # populate data + inbase = args_double[0] + + i = self.var(C.intp, 0) + with self.loop() as loop: + with loop.condition() as setcond: + setcond( i < self.constant(C.intp, WorkCount) ) + with loop.body(): + inbase[i].assign(i.cast(C.double)) + i += self.constant(C.intp, 1) + + # call parallel ufunc + parallel_ufunc(worker.cast(C.void_p), ufunc_core.cast(C.void_p), args, + dims, steps, NULL) + + # check error + outbase = args_double[-1] + with self.for_range(self.constant(C.intp, WorkCount)) as (loop, i): + test = outbase[i] != (inbase[i] / self.constant(C.double, 2.345)) + with self.ifelse( test ) as ifelse: + with ifelse.then(): + self.debug("Invalid data at i =", i, outbase[i], inbase[i]) self.ret() @@ -61,6 +114,7 @@ def main(): print(module) # run + print('run') exe = CExecutor(module) exe.engine.get_pointer_to_function(fntester) func = exe.get_ctype_function(fntester, 'void') From c43b27356be5b4bcaa95babfc6185c1bb0c8be65 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 6 Aug 2012 14:23:43 -0700 Subject: [PATCH 013/516] Fix --- llvm_cbuilder/builder.py | 2 +- test_parallel_vectorize.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index eaa159e..661c2b1 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -429,7 +429,7 @@ class CDefinition(CBuilder): functype = lc.Type.function(cls._retty_, [v for k, v in cls._argtys_]) func = module.get_or_insert_function(functype, name=cls._name_) if not func.is_declaration: # already defined? - raise NameError('Function %s has already been defined' % cls.name) + raise NameError('Function %s has already been defined' % cls._name_) # Name all arguments for i, (name, _) in enumerate(cls._argtys_): diff --git a/test_parallel_vectorize.py b/test_parallel_vectorize.py index fbcb133..fd7cc52 100644 --- a/test_parallel_vectorize.py +++ b/test_parallel_vectorize.py @@ -95,7 +95,6 @@ class Tester(CDefinition): self.ret() def main(): - NUM_THREAD = 2 module = Module.new(__name__) mpm = PassManager.new() From fef9c2efbf50d194a9e715f152fd7627fe3870fa Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 6 Aug 2012 14:46:27 -0700 Subject: [PATCH 014/516] Add CBuilder.depends to automatically insert depending function. --- llvm_cbuilder/builder.py | 9 ++++++++- parallel_vectorize.py | 27 +++++++++++++++++++-------- test_parallel_vectorize.py | 10 ++++++---- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 661c2b1..3fce585 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -149,6 +149,13 @@ class CBuilder(object): func = mod.add_function(functype, name=name) return CBuilder(func) + def depends(self, cdef, **kwargs): + try: + func = cdef.define(self.function.module, **kwargs) + except NameError as e: + (func,) = e + return CFunc(self, func) + def printf(self, fmt, *args): mod = self.function.module int_t = lc.Type.int() @@ -429,7 +436,7 @@ class CDefinition(CBuilder): functype = lc.Type.function(cls._retty_, [v for k, v in cls._argtys_]) func = module.get_or_insert_function(functype, name=cls._name_) if not func.is_declaration: # already defined? - raise NameError('Function %s has already been defined' % cls._name_) + raise NameError(func) # Name all arguments for i, (name, _) in enumerate(cls._argtys_): diff --git a/parallel_vectorize.py b/parallel_vectorize.py index 25176b8..42aea26 100644 --- a/parallel_vectorize.py +++ b/parallel_vectorize.py @@ -87,8 +87,15 @@ class Context(CStruct): ] class ParallelUFunc(CDefinition): + ''' + Platform dependent threading function is implemented in + + def _dispatch_worker(self, worker, contexts, num_thread): + ... + + which should be implemented in subclass or mixin. + ''' _name_ = 'parallel_ufunc' - _retty_ = C.void _argtys_ = [ ('func', C.void_p), ('worker', C.void_p), @@ -182,13 +189,7 @@ class ParallelUFunc(CDefinition): cur_ctxt.completed.assign( self.constant_null(cur_ctxt.completed.type)) - def _dispatch_worker(self, worker, contexts, num_thread): - ''' - Dispatch worker threads. - ''' - raise NotImplementedError - -class ParallelUFuncPosix(ParallelUFunc): +class ParallelUFuncPosixMixin(object): ''' Implements _dispatch_worker to use pthread. ''' @@ -316,6 +317,16 @@ class UFuncCore(CDefinition): ''' raise NotImplementedError +class _SpecializedParallelUFunc(ParallelUFunc, ParallelUFuncPosixMixin): + _argtys_ = [ + ('args', C.pointer(C.char_p)), + ('dimensions', C.pointer(C.intp)), + ('steps', C.pointer(C.intp)), + ('data', C.void_p), + ] + + def body(self, args, dimensions, steps, data, ThreadCount=1): + pass class PThreadAPI(CExternal): pthread_t = C.void_p diff --git a/test_parallel_vectorize.py b/test_parallel_vectorize.py index fd7cc52..4fde372 100644 --- a/test_parallel_vectorize.py +++ b/test_parallel_vectorize.py @@ -30,6 +30,8 @@ class UFuncCore_D_D(UFuncCore): res = ufunc_ptr(indata.load()) outdata.store(res) +class ParallelUFuncPosix(ParallelUFunc, ParallelUFuncPosixMixin): + pass class Tester(CDefinition): ''' @@ -45,10 +47,10 @@ class Tester(CDefinition): ArgCount = 2 WorkCount = 10000 - parallel_ufunc = CFunc(self, ParallelUFuncPosix.define(module, - ThreadCount=ThreadCount)) - ufunc_core = CFunc(self, UFuncCore_D_D.define(module)) - worker = CFunc(self, Work_D_D.define(module)) + parallel_ufunc = self.depends(ParallelUFuncPosix, + ThreadCount=ThreadCount) + ufunc_core = self.depends(UFuncCore_D_D) + worker = self.depends(Work_D_D) # real work NULL = self.constant_null(C.void_p) From 150f497ed08be2d5ec82a607513a3bdbefe2dc02 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 6 Aug 2012 15:33:36 -0700 Subject: [PATCH 015/516] Add specializable parallel ufunc. Update test. Some fixes. --- llvm_cbuilder/builder.py | 3 ++- parallel_vectorize.py | 16 ++++++++++++---- test_parallel_vectorize.py | 18 ++++++++++++------ 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 3fce585..88516df 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -434,7 +434,8 @@ class CDefinition(CBuilder): @classmethod def define(cls, module, **kws): functype = lc.Type.function(cls._retty_, [v for k, v in cls._argtys_]) - func = module.get_or_insert_function(functype, name=cls._name_) + name = cls._name_ % kws + func = module.get_or_insert_function(functype, name=name) if not func.is_declaration: # already defined? raise NameError(func) diff --git a/parallel_vectorize.py b/parallel_vectorize.py index 42aea26..2d9421f 100644 --- a/parallel_vectorize.py +++ b/parallel_vectorize.py @@ -95,7 +95,7 @@ class ParallelUFunc(CDefinition): which should be implemented in subclass or mixin. ''' - _name_ = 'parallel_ufunc' + _name_ = 'parallel_ufunc_%(ThreadCount)d' _argtys_ = [ ('func', C.void_p), ('worker', C.void_p), @@ -317,7 +317,9 @@ class UFuncCore(CDefinition): ''' raise NotImplementedError -class _SpecializedParallelUFunc(ParallelUFunc, ParallelUFuncPosixMixin): + +class SpecializedParallelUFunc(CDefinition): + _name_ = 'specialized_parallel_ufunc_%(ThreadCount)d_%(FuncName)s' _argtys_ = [ ('args', C.pointer(C.char_p)), ('dimensions', C.pointer(C.intp)), @@ -325,8 +327,14 @@ class _SpecializedParallelUFunc(ParallelUFunc, ParallelUFuncPosixMixin): ('data', C.void_p), ] - def body(self, args, dimensions, steps, data, ThreadCount=1): - pass + def body(self, args, dimensions, steps, data, + PUFuncDef, CoreDef, Func, FuncName, ThreadCount=1): + pufunc = self.depends(PUFuncDef, ThreadCount=ThreadCount) + core = self.depends(CoreDef) + func = self.depends(Func) + to_void_p = lambda x: x.cast(C.void_p) + pufunc(to_void_p(func), to_void_p(core), args, dimensions, steps, data) + self.ret() class PThreadAPI(CExternal): pthread_t = C.void_p diff --git a/test_parallel_vectorize.py b/test_parallel_vectorize.py index 4fde372..e16d206 100644 --- a/test_parallel_vectorize.py +++ b/test_parallel_vectorize.py @@ -47,10 +47,17 @@ class Tester(CDefinition): ArgCount = 2 WorkCount = 10000 - parallel_ufunc = self.depends(ParallelUFuncPosix, - ThreadCount=ThreadCount) - ufunc_core = self.depends(UFuncCore_D_D) - worker = self.depends(Work_D_D) +# parallel_ufunc = self.depends(ParallelUFuncPosix, +# ThreadCount=ThreadCount) +# ufunc_core = self.depends(UFuncCore_D_D) +# worker = self.depends(Work_D_D) + + sppufunc = self.depends(SpecializedParallelUFunc, + PUFuncDef = ParallelUFuncPosix, + CoreDef = UFuncCore_D_D, + Func = Work_D_D, + FuncName = Work_D_D._name_, + ThreadCount = 2) # real work NULL = self.constant_null(C.void_p) @@ -83,8 +90,7 @@ class Tester(CDefinition): i += self.constant(C.intp, 1) # call parallel ufunc - parallel_ufunc(worker.cast(C.void_p), ufunc_core.cast(C.void_p), args, - dims, steps, NULL) + sppufunc(args, dims, steps, NULL) # check error outbase = args_double[-1] From b5893d4ebb69fe920ae432db7e598aada5de8cda Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 6 Aug 2012 17:02:04 -0700 Subject: [PATCH 016/516] Add test to use numpy.fromfunc. Depends on numpy branch "ufunc-from-function-pointer" in git://github.com/jayvius/numpy.git --- parallel_vectorize.py | 5 ++-- test_parallel_vectorize.py | 11 +++----- test_parallel_vectorize_numpy.py | 46 ++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 10 deletions(-) create mode 100644 test_parallel_vectorize_numpy.py diff --git a/parallel_vectorize.py b/parallel_vectorize.py index 2d9421f..bef04eb 100644 --- a/parallel_vectorize.py +++ b/parallel_vectorize.py @@ -151,11 +151,12 @@ class ParallelUFunc(CDefinition): for t in range(ThreadCount): cur_ctxt = contexts[t].as_struct(Context) total_completed += cur_ctxt.completed - self.debug(cur_ctxt.id, 'completed', cur_ctxt.completed) + # self.debug(cur_ctxt.id, 'completed', cur_ctxt.completed) with self.ifelse( total_completed == N ) as ifelse: with ifelse.then(): - self.debug("All is well!") + # self.debug("All is well!") + pass # keep quite if all is well with ifelse.otherwise(): self.debug("ERROR: race occurred! Trigger segfault") self.unreachable() diff --git a/test_parallel_vectorize.py b/test_parallel_vectorize.py index e16d206..ed2010d 100644 --- a/test_parallel_vectorize.py +++ b/test_parallel_vectorize.py @@ -2,7 +2,7 @@ from parallel_vectorize import * class Work_D_D(CDefinition): - _name_ = 'copy_d_d' + _name_ = 'work_d_d' _retty_ = C.double _argtys_ = [ ('inval', C.double), @@ -47,11 +47,6 @@ class Tester(CDefinition): ArgCount = 2 WorkCount = 10000 -# parallel_ufunc = self.depends(ParallelUFuncPosix, -# ThreadCount=ThreadCount) -# ufunc_core = self.depends(UFuncCore_D_D) -# worker = self.depends(Work_D_D) - sppufunc = self.depends(SpecializedParallelUFunc, PUFuncDef = ParallelUFuncPosix, CoreDef = UFuncCore_D_D, @@ -123,11 +118,11 @@ def main(): # run print('run') exe = CExecutor(module) - exe.engine.get_pointer_to_function(fntester) func = exe.get_ctype_function(fntester, 'void') func() - + # Will not reach here is race condition occurred + print('Good') if __name__ == '__main__': main() diff --git a/test_parallel_vectorize_numpy.py b/test_parallel_vectorize_numpy.py new file mode 100644 index 0000000..dc3557f --- /dev/null +++ b/test_parallel_vectorize_numpy.py @@ -0,0 +1,46 @@ +from test_parallel_vectorize import * + +import numpy as np + +def main(): + module = Module.new(__name__) + sppufunc = SpecializedParallelUFunc.define(module, + PUFuncDef = ParallelUFuncPosix, + CoreDef = UFuncCore_D_D, + Func = Work_D_D, + FuncName = Work_D_D._name_, + ThreadCount = 2) + module.verify() + + mpm = PassManager.new() + pmbuilder = PassManagerBuilder.new() + pmbuilder.opt_level = 3 + pmbuilder.populate(mpm) + + mpm.run(module) +# print module + + # run + + exe = CExecutor(module) + funcptr = exe.engine.get_pointer_to_function(sppufunc) + print("Function pointer: %x" % funcptr) + + ptr_t = long # py2 only + + typenum = np.dtype(np.double).num + ufunc = np.fromfunc([ptr_t(funcptr)], [[typenum, typenum]], 1, 1, [None]) + + x = np.linspace(0., 10., 1000) + x.dtype=np.double +# print x + ans = ufunc(x) +# print ans + + if not ( ans == x/2.345 ).all(): + raise ValueError('Computation failed') + else: + print('Good') + +if __name__ == '__main__': + main() From 01054c726fd9f0f193c8b2842f7c01531384e7ce Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 6 Aug 2012 20:25:36 -0700 Subject: [PATCH 017/516] Add specialize() for cleaner specialization of CDefinition. --- parallel_vectorize.py | 38 ++++++++++++++++++++++++-------- test_parallel_vectorize.py | 11 +++++---- test_parallel_vectorize_numpy.py | 11 +++++---- 3 files changed, 39 insertions(+), 21 deletions(-) diff --git a/parallel_vectorize.py b/parallel_vectorize.py index bef04eb..b5a03f5 100644 --- a/parallel_vectorize.py +++ b/parallel_vectorize.py @@ -95,7 +95,7 @@ class ParallelUFunc(CDefinition): which should be implemented in subclass or mixin. ''' - _name_ = 'parallel_ufunc_%(ThreadCount)d' + #_name_ = 'parallel_ufunc_%(ThreadCount)d' _argtys_ = [ ('func', C.void_p), ('worker', C.void_p), @@ -105,8 +105,18 @@ class ParallelUFunc(CDefinition): ('data', C.void_p), ] - def body(self, func, worker, args, dimensions, steps, data, ThreadCount=1): + @classmethod + def specialize(cls, num_thread): + name = 'parallel_ufunc_%d' % num_thread + newcls = type(name, (cls,), { + '_name_' : name, + 'ThreadCount': num_thread, + }) + return newcls + + def body(self, func, worker, args, dimensions, steps, data): # Setup variables + ThreadCount = self.ThreadCount common = self.var(ContextCommon, name='common') workqueues = self.array(WorkQueue, ThreadCount, name='workqueues') contexts = self.array(Context, ThreadCount, name='contexts') @@ -318,9 +328,7 @@ class UFuncCore(CDefinition): ''' raise NotImplementedError - class SpecializedParallelUFunc(CDefinition): - _name_ = 'specialized_parallel_ufunc_%(ThreadCount)d_%(FuncName)s' _argtys_ = [ ('args', C.pointer(C.char_p)), ('dimensions', C.pointer(C.intp)), @@ -328,15 +336,27 @@ class SpecializedParallelUFunc(CDefinition): ('data', C.void_p), ] - def body(self, args, dimensions, steps, data, - PUFuncDef, CoreDef, Func, FuncName, ThreadCount=1): - pufunc = self.depends(PUFuncDef, ThreadCount=ThreadCount) - core = self.depends(CoreDef) - func = self.depends(Func) + def body(self, args, dimensions, steps, data,): + pufunc = self.depends(self.PUFuncDef) + core = self.depends(self.CoreDef) + func = self.depends(self.FuncDef) to_void_p = lambda x: x.cast(C.void_p) pufunc(to_void_p(func), to_void_p(core), args, dimensions, steps, data) self.ret() + @classmethod + def specialize(cls, pufunc_def, core_def, func_def): + name = 'specialized_%s_%s_%s'% (pufunc_def._name_, + core_def._name_, + func_def._name_) + newcls = type(name, (cls,), { + '_name_' : name, + 'PUFuncDef': pufunc_def, + 'CoreDef' : core_def, + 'FuncDef' : func_def, + }) + return newcls + class PThreadAPI(CExternal): pthread_t = C.void_p diff --git a/test_parallel_vectorize.py b/test_parallel_vectorize.py index ed2010d..ab28363 100644 --- a/test_parallel_vectorize.py +++ b/test_parallel_vectorize.py @@ -14,6 +14,7 @@ class UFuncCore_D_D(UFuncCore): ''' Specialize UFuncCore for double input, double output. ''' + _name_ = UFuncCore._name_ + '_d_d' def _do_work(self, common, item, tid): ufunc_type = Type.function(C.double, [C.double]) ufunc_ptr = CFunc(self, common.func.cast(C.pointer(ufunc_type)).value) @@ -47,12 +48,10 @@ class Tester(CDefinition): ArgCount = 2 WorkCount = 10000 - sppufunc = self.depends(SpecializedParallelUFunc, - PUFuncDef = ParallelUFuncPosix, - CoreDef = UFuncCore_D_D, - Func = Work_D_D, - FuncName = Work_D_D._name_, - ThreadCount = 2) + PUfuncDef = ParallelUFuncPosix.specialize(num_thread=2) + SPUF = SpecializedParallelUFunc.specialize( + PUfuncDef, UFuncCore_D_D, Work_D_D) + sppufunc = self.depends(SPUF) # real work NULL = self.constant_null(C.void_p) diff --git a/test_parallel_vectorize_numpy.py b/test_parallel_vectorize_numpy.py index dc3557f..7b1ca51 100644 --- a/test_parallel_vectorize_numpy.py +++ b/test_parallel_vectorize_numpy.py @@ -4,12 +4,11 @@ import numpy as np def main(): module = Module.new(__name__) - sppufunc = SpecializedParallelUFunc.define(module, - PUFuncDef = ParallelUFuncPosix, - CoreDef = UFuncCore_D_D, - Func = Work_D_D, - FuncName = Work_D_D._name_, - ThreadCount = 2) + PUfuncDef = ParallelUFuncPosix.specialize(num_thread=2) + SPUF = SpecializedParallelUFunc.specialize( + PUfuncDef, UFuncCore_D_D, Work_D_D) + sppufunc = SPUF.define(module) + module.verify() mpm = PassManager.new() From 2acc0709845cdaa571c110c13e9cbaabe229e90f Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 7 Aug 2012 16:55:33 -0700 Subject: [PATCH 018/516] Refactor. Modify the way CDefinition is specialized. --- llvm_cbuilder/builder.py | 92 +++++++++++++++++++++++--------- parallel_vectorize.py | 25 +++------ test_parallel_vectorize.py | 10 ++-- test_parallel_vectorize_numpy.py | 20 +++++-- 4 files changed, 96 insertions(+), 51 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 88516df..e591e9d 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -6,6 +6,7 @@ import contextlib import llvm.core as lc import llvm.ee as le from llvm import LLVMException +from . import shortnames as types def _is_int(ty): return isinstance(ty, lc.IntegerType) @@ -149,18 +150,12 @@ class CBuilder(object): func = mod.add_function(functype, name=name) return CBuilder(func) - def depends(self, cdef, **kwargs): - try: - func = cdef.define(self.function.module, **kwargs) - except NameError as e: - (func,) = e - return CFunc(self, func) + def depends(self, fndecl): + return CFunc(self, fndecl(self.function.module)) def printf(self, fmt, *args): mod = self.function.module - int_t = lc.Type.int() - char_ptr_t = lc.Type.pointer(lc.Type.int(8)) - functype = lc.Type.function(int_t, [char_ptr_t], True) + functype = lc.Type.function(types.int, [types.char_p], True) printf = mod.get_or_insert_function(functype, name='printf') ret = self.builder.call(printf, [fmt.value]+_list_values(args)) return CTemp(self, ret) @@ -224,7 +219,7 @@ class CBuilder(object): if isinstance(count, CValue): count = count.value elif not isinstance(count, lc.Value): - count = self.constant(lc.Type.int(), count).value + count = self.constant(types.int, count).value ptr = self.builder.alloca_array(ty, count, name=name) return CArray(self, ptr) @@ -236,7 +231,7 @@ class CBuilder(object): raise TypeError(errmsg) self.builder.ret(val.value) else: - if retty != lc.Type.void(): + if retty != types.void: errmsg = "Cannot return void" raise TypeError(errmsg) self.builder.ret_void() @@ -257,7 +252,7 @@ class CBuilder(object): def forever(self): with self.loop() as loop: with loop.condition() as setcond: - NULL = self.constant_null(lc.Type.int()) + NULL = self.constant_null(types.int) setcond( NULL == NULL ) with loop.body(): yield loop @@ -266,7 +261,7 @@ class CBuilder(object): def for_range(self, *args): def check_arg(x): if isinstance(x, int): - return self.constant(lc.Type.int(), x) + return self.constant(types.int, x) if not x.is_int: raise TypeError(x, "All args must be of integer type.") return x @@ -303,7 +298,7 @@ class CBuilder(object): def constant(self, ty, val): if isinstance(ty, lc.IntegerType): res = lc.Constant.int(ty, val) - elif ty==lc.Type.float() or ty==lc.Type.double(): + elif ty == types.float or ty == types.double: res = lc.Constant.real(ty, val) else: raise TypeError("Cannot auto build constant " @@ -316,6 +311,8 @@ class CBuilder(object): def constant_string(self, string): mod = self.function.module + # TODO + # Is this a safe way for uniquing identifying string name = '.conststr.%x_%x' % (hash(string), len(string)) content = lc.Constant.stringz(string) try: @@ -323,10 +320,8 @@ class CBuilder(object): except LLVMException: globalstr = mod.add_global_variable(content.type, name=name) globalstr.initializer = content -# ptr = mod.add_global_variable(lc.Type.pointer(content.type.element), -# name=name+".ptr") return CTemp(self, globalstr.bitcast( - lc.Type.pointer(content.type.element))) + types.pointer(content.type.element))) def get_intrinsic(self, intrinsic_id, tys): @@ -423,18 +418,62 @@ class CBuilder(object): def unreachable(self): self.builder.unreachable() +class _DeclareCDef(object): + def __init__(self, cdef): + self.cdef = cdef + + def __str__(self): + return self.cdef._name_ + + def __call__(self, module): + try: + func = self.cdef.define(module) + except NameError as e: + (func,) = e + return func + +class CDeclare(object): + def __init__(self, name, ty, ptr): + self._name = name + self._type = ty + self._ptr = ptr + + def __call__(self, module): + fnptr = types.pointer(self._type) + ptr = lc.Constant.int(types.intp, self._ptr) + ptr = ptr.inttoptr(fnptr) + return ptr + + def __str__(self): + return self._name + class CDefinition(CBuilder): ''' Inherit this class to for defining functions ''' - _name_ = 'unamed' # name of the function; should overide in subclass - _retty_ = lc.Type.void() # return type; can overide in subclass + _name_ = '' # name of the function; should overide in subclass + _retty_ = types.void # return type; can overide in subclass _argtys_ = [] # a list of tuple(name, type); can overide in subclass + def __new__(cls, *args, **kws): + try: + fnsp = getattr(cls, 'specialize') + except AttributeError: + pass + else: + cls = type('%s_Specialized' % cls.__name__, (cls,), {}) + fnsp(*args, **kws) + + obj = object.__new__(_DeclareCDef) + obj.__init__(cls) + return obj + @classmethod - def define(cls, module, **kws): + def define(cls, module): functype = lc.Type.function(cls._retty_, [v for k, v in cls._argtys_]) - name = cls._name_ % kws + name = cls._name_ + if not name: + raise NameError("Function name cannot be empty.") func = module.get_or_insert_function(functype, name=name) if not func.is_declaration: # already defined? raise NameError(func) @@ -444,8 +483,9 @@ class CDefinition(CBuilder): func.args[i].name = name # Create builder and populate body - cbuilder = cls(func) - cbuilder.body(*cbuilder.args, **kws) + cbuilder = object.__new__(cls) + cbuilder.__init__(func) + cbuilder.body(*cbuilder.args) cbuilder.close() return func @@ -662,7 +702,7 @@ class CValue(object): def __getitem__(self, idx): self._ensure_is_pointer() if not isinstance(idx, CValue): - idx = self.parent.constant(lc.Type.int(), idx) + idx = self.parent.constant(types.int, idx) bldr = self.parent.builder ptr = bldr.gep(self.value, [idx.value]) return CVar(self.parent, ptr) @@ -827,7 +867,7 @@ class CArray(CValue): # if isinstance(idx, CValue): # idx = idx.value # elif not isinstance(idx, lc.Value): -# idx = self.parent.constant(lc.Type.int(), idx).value +# idx = self.parent.constant(types.int, idx).value # ptr = builder.gep(self.value, [idx]) # return CVar(self.parent, ptr) @@ -838,7 +878,7 @@ class CStruct(CValue): def __init__(self, parent, ptr): super(CStruct, self).__init__(parent) - makeind = lambda x: self.parent.constant(lc.Type.int(), x).value + makeind = lambda x: self.parent.constant(types.int, x).value self.ptr = ptr for i, (fd, _) in enumerate(self._fields_): gep = self.parent.builder.gep(ptr, [makeind(0), makeind(i)]) diff --git a/parallel_vectorize.py b/parallel_vectorize.py index b5a03f5..4c8daab 100644 --- a/parallel_vectorize.py +++ b/parallel_vectorize.py @@ -95,7 +95,7 @@ class ParallelUFunc(CDefinition): which should be implemented in subclass or mixin. ''' - #_name_ = 'parallel_ufunc_%(ThreadCount)d' + _argtys_ = [ ('func', C.void_p), ('worker', C.void_p), @@ -107,12 +107,9 @@ class ParallelUFunc(CDefinition): @classmethod def specialize(cls, num_thread): - name = 'parallel_ufunc_%d' % num_thread - newcls = type(name, (cls,), { - '_name_' : name, - 'ThreadCount': num_thread, - }) - return newcls + print num_thread + cls._name_ = 'parallel_ufunc_%d' % num_thread + cls.ThreadCount = num_thread def body(self, func, worker, args, dimensions, steps, data): # Setup variables @@ -346,16 +343,10 @@ class SpecializedParallelUFunc(CDefinition): @classmethod def specialize(cls, pufunc_def, core_def, func_def): - name = 'specialized_%s_%s_%s'% (pufunc_def._name_, - core_def._name_, - func_def._name_) - newcls = type(name, (cls,), { - '_name_' : name, - 'PUFuncDef': pufunc_def, - 'CoreDef' : core_def, - 'FuncDef' : func_def, - }) - return newcls + cls._name_ = 'specialized_%s_%s_%s'% (pufunc_def, core_def, func_def) + cls.PUFuncDef = pufunc_def + cls.CoreDef = core_def + cls.FuncDef = func_def class PThreadAPI(CExternal): pthread_t = C.void_p diff --git a/test_parallel_vectorize.py b/test_parallel_vectorize.py index ab28363..54d6b14 100644 --- a/test_parallel_vectorize.py +++ b/test_parallel_vectorize.py @@ -48,10 +48,12 @@ class Tester(CDefinition): ArgCount = 2 WorkCount = 10000 - PUfuncDef = ParallelUFuncPosix.specialize(num_thread=2) - SPUF = SpecializedParallelUFunc.specialize( - PUfuncDef, UFuncCore_D_D, Work_D_D) - sppufunc = self.depends(SPUF) + + spufdef = SpecializedParallelUFunc(ParallelUFuncPosix(num_thread=2), + UFuncCore_D_D(), + Work_D_D()) + + sppufunc = self.depends(spufdef) # real work NULL = self.constant_null(C.void_p) diff --git a/test_parallel_vectorize_numpy.py b/test_parallel_vectorize_numpy.py index 7b1ca51..392c81d 100644 --- a/test_parallel_vectorize_numpy.py +++ b/test_parallel_vectorize_numpy.py @@ -1,13 +1,20 @@ +''' +Test parallel-vectorize with numpy.fromfunc. +Uses the work load from test_parallel_vectorize. +''' + from test_parallel_vectorize import * import numpy as np def main(): module = Module.new(__name__) - PUfuncDef = ParallelUFuncPosix.specialize(num_thread=2) - SPUF = SpecializedParallelUFunc.specialize( - PUfuncDef, UFuncCore_D_D, Work_D_D) - sppufunc = SPUF.define(module) + + spufdef = SpecializedParallelUFunc(ParallelUFuncPosix(num_thread=2), + UFuncCore_D_D(), + Work_D_D()) + + sppufunc = spufdef(module) module.verify() @@ -27,6 +34,11 @@ def main(): ptr_t = long # py2 only + # Becareful that fromfunc does not provide full error checking yet. + # If typenum is out-of-bound, we have nasty memory corruptions. + # For instance, -1 for typenum will cause segfault. + # If elements of type-list (2nd arg) is tuple instead, + # there will also memory corruption. (Seems like code rewrite.) typenum = np.dtype(np.double).num ufunc = np.fromfunc([ptr_t(funcptr)], [[typenum, typenum]], 1, 1, [None]) From 8b45094e20c69f8a5c9aa9ca74de40763d27b8f2 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 7 Aug 2012 16:56:28 -0700 Subject: [PATCH 019/516] Add test that uses function pointer. --- test_parallel_vectorize_numpy_2.py | 69 ++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 test_parallel_vectorize_numpy_2.py diff --git a/test_parallel_vectorize_numpy_2.py b/test_parallel_vectorize_numpy_2.py new file mode 100644 index 0000000..a511980 --- /dev/null +++ b/test_parallel_vectorize_numpy_2.py @@ -0,0 +1,69 @@ +''' +Test parallel-vectorize with numpy.fromfunc. +Uses the work load from test_parallel_vectorize. +This time we pass a function pointer. +''' + +from test_parallel_vectorize import * + +import numpy as np + +def main(): + module = Module.new(__name__) + exe = CExecutor(module) + + workdef = Work_D_D() + workfunc = workdef(module) + + # get pointer to workfunc + workfunc_ptr = exe.engine.get_pointer_to_function(workfunc) + + workdecl = CDeclare(workfunc.name, workfunc.type.pointee, workfunc_ptr) + + spufdef = SpecializedParallelUFunc(ParallelUFuncPosix(num_thread=2), + UFuncCore_D_D(), + workdecl) + + + sppufunc = spufdef(module) + sppufunc.verify() + print(sppufunc) + module.verify() + + mpm = PassManager.new() + pmbuilder = PassManagerBuilder.new() + pmbuilder.opt_level = 3 + pmbuilder.populate(mpm) + + mpm.run(module) + print(module) + + + # run + + funcptr = exe.engine.get_pointer_to_function(sppufunc) + print("Function pointer: %x" % funcptr) + + ptr_t = long # py2 only + + # Becareful that fromfunc does not provide full error checking yet. + # If typenum is out-of-bound, we have nasty memory corruptions. + # For instance, -1 for typenum will cause segfault. + # If elements of type-list (2nd arg) is tuple instead, + # there will also memory corruption. (Seems like code rewrite.) + typenum = np.dtype(np.double).num + ufunc = np.fromfunc([ptr_t(funcptr)], [[typenum, typenum]], 1, 1, [None]) + + x = np.linspace(0., 10., 1000) + x.dtype=np.double +# print x + ans = ufunc(x) +# print ans + + if not ( ans == x/2.345 ).all(): + raise ValueError('Computation failed') + else: + print('Good') + +if __name__ == '__main__': + main() From 68e2359ad2ddefba0dca44831e1c5c53a89122fb Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 8 Aug 2012 15:17:31 -0700 Subject: [PATCH 020/516] cleanup and doc --- llvm_cbuilder/builder.py | 423 ++++++++++++++++++++++++++++++++----- llvm_cbuilder/executor.py | 14 ++ llvm_cbuilder/libc.py | 8 + tests/test_cstr_collide.py | 17 ++ 4 files changed, 406 insertions(+), 56 deletions(-) create mode 100644 llvm_cbuilder/libc.py create mode 100644 tests/test_cstr_collide.py diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index e591e9d..99133e6 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -8,6 +8,10 @@ import llvm.ee as le from llvm import LLVMException from . import shortnames as types +### +# Utilities +### + def _is_int(ty): return isinstance(ty, lc.IntegerType) @@ -47,6 +51,19 @@ def _change_block_temporarily_dummy(*args): yield class _IfElse(object): + '''if-else construct. + + Example + ------- + with cbuilder.ifelse(cond) as ifelse: + with ifelse.then(): + # code when cond is true + # this block is mandatory + with ifelse.otherwise(): + # code when cond is false + # this block is optional + ''' + def __init__(self, parent, cond): self.parent = parent self.cond = cond @@ -84,6 +101,22 @@ class _IfElse(object): builder.position_at_end(bbend) class _Loop(object): + '''while...do loop. + + Example + ------- + with cbuilder.loop() as loop: + with loop.condition() as setcond: + # Put the condition evaluation here + setcond( cond ) # set loop condition + # Do not put code after setcond(...) + with loop.body(): + # Put the code of the loop body here + + Use loop.break_loop() to break out of the loop. + Use loop.continue_loop() to jump the condition evaulation. + ''' + def __init__(self, parent): self.parent = parent @@ -107,9 +140,8 @@ class _Loop(object): def body(self): builder = self.parent.builder builder.position_at_end(self._bbbody) - yield self - + # close last block if not _is_block_terminated(builder.basic_block): builder.branch(self._bbcond) @@ -121,9 +153,6 @@ class _Loop(object): def close(self): builder = self.parent.builder -# if not _is_block_terminated(builder.basic_block): -# with _change_block_temporarily(builder, builder.basic_block): -# builder.branch(self._bbend) builder.position_at_end(self._bbend) class CBuilder(object): @@ -131,14 +160,18 @@ class CBuilder(object): A wrapper class for features in llvm-py package to allow user to use C-like high-level language contruct easily. ''' + def __init__(self, function): + '''constructor + + function : is an empty function to be populating. + ''' self.function = function self.declare_block = self.function.append_basic_block('decl') self.first_body_block = self.function.append_basic_block('body') self.builder = lc.Builder.new(self.first_body_block) self.target_data = le.TargetData.new(self.function.module.data_layout) - - # prepare arguments + # Prepare arguments. Make all function arguments behave like variables. self.args = [] for arg in function.args: var = self.var(arg.type, arg, name=arg.name) @@ -146,21 +179,40 @@ class CBuilder(object): @staticmethod def new_function(mod, name, ret, args): + '''factory method + + Create a new function in the module and return a CBuilder instance. + ''' functype = lc.Type.function(ret, args) func = mod.add_function(functype, name=name) return CBuilder(func) def depends(self, fndecl): + '''add function dependency + + Returns a CFunc instance and define the function if it is not defined. + + fndecl : is a callable that takes a `llvm.core.Module` and returns + a function pointer. + ''' return CFunc(self, fndecl(self.function.module)) def printf(self, fmt, *args): - mod = self.function.module - functype = lc.Type.function(types.int, [types.char_p], True) - printf = mod.get_or_insert_function(functype, name='printf') - ret = self.builder.call(printf, [fmt.value]+_list_values(args)) + '''printf() from libc + + fmt : a character string holding printf format string. + *args : additional variable arguments. + ''' + from .libc import LibC + libc = LibC(self) + ret = libc.printf(fmt, *args) return CTemp(self, ret) def debug(self, *args): + '''debug print + + Use printf to dump the values of all arguments. + ''' type_mapper = { 'i8' : '%c', 'i16': '%hd', @@ -174,17 +226,27 @@ class CBuilder(object): if isinstance(i, str): itemsfmt.append(i.replace('%', '%%')) else: - ty = type_mapper[str(i.type)] + tyname = str(i.type) + if tyname == 'float': + # auto convert float to double + ty = '%e' + i = i.cast(types.double) + else: + ty = type_mapper[tyname] itemsfmt.append(ty) items.append(i) fmt = ' '.join(itemsfmt) + '\n' return self.printf(self.constant_string(fmt), *items) def var(self, ty, value=None, name=''): - ''' - Only allocate in the first block + '''allocate variable on the stack + + ty : variable type + value : [optional] initializer value + name : [optional] name used in LLVM IR ''' with _change_block_temporarily(self.builder, self.declare_block): + # goto the first block is_cstruct = _is_cstruct(ty) if is_cstruct: cstruct = ty @@ -203,27 +265,45 @@ class CBuilder(object): return CVar(self, ptr) def var_copy(self, val, name=''): + '''allocate a new variable by copying another value + + The new variable has the same type and value of `val`. + ''' return self.var(val.type, val, name=name) def array(self, ty, count, name=''): + '''allocate an array on the stack + + ty : array element type + count : array size; can be python int, llvm.core.Constant, or CValue + name : [optional] name used in LLVM IR + ''' if isinstance(count, int) or isinstance(count, lc.Constant): + # Only go to the first block if array size is fixed. contexthelper = _change_block_temporarily else: + # Do not go to the first block if the array size is dynamic. contexthelper = _change_block_temporarily_dummy with contexthelper(self.builder, self.declare_block): - is_cstruct = _is_cstruct(ty) - if is_cstruct: + if _is_cstruct(ty): # array of struct? cstruct = ty ty = ty.llvm_type() + if isinstance(count, CValue): count = count.value elif not isinstance(count, lc.Value): count = self.constant(types.int, count).value + ptr = self.builder.alloca_array(ty, count, name=name) return CArray(self, ptr) def ret(self, val=None): + '''insert return statement + + val : if is `None`, insert return-void + else, return `val` + ''' retty = self.function.type.pointee.return_type if val is not None: if val.type != retty: @@ -238,18 +318,26 @@ class CBuilder(object): @contextlib.contextmanager def ifelse(self, cond): + '''start a if-else block + + cond : branch condition + ''' cb = _IfElse(self, cond) yield cb cb.close() @contextlib.contextmanager def loop(self): + '''start a loop block + ''' cb = _Loop(self) yield cb cb.close() @contextlib.contextmanager def forever(self): + '''start a forever loop block + ''' with self.loop() as loop: with loop.condition() as setcond: NULL = self.constant_null(types.int) @@ -259,6 +347,10 @@ class CBuilder(object): @contextlib.contextmanager def for_range(self, *args): + '''start a for-range block. + + *args : same as arguments of builtin `range()` + ''' def check_arg(x): if isinstance(x, int): return self.constant(types.int, x) @@ -287,15 +379,26 @@ class CBuilder(object): idx += step def position_at_end(self, bb): + '''reposition inserter to the end of basic-block + + bb : a basic block + ''' self.basic_block = bb self.builder.position_at_end(bb) def close(self): + '''end code generation + ''' # Close declaration block with _change_block_temporarily(self.builder, self.declare_block): self.builder.branch(self.first_body_block) def constant(self, ty, val): + '''create a constant + + ty : data type + val : initializer + ''' if isinstance(ty, lc.IntegerType): res = lc.Constant.int(ty, val) elif ty == types.float or ty == types.double: @@ -306,119 +409,239 @@ class CBuilder(object): return CTemp(self, res) def constant_null(self, ty): + '''create a zero filled constant + + ty : data type + ''' res = lc.Constant.null(ty) return CTemp(self, res) def constant_string(self, string): + '''create a constant string + + This will de-duplication string of same content to minimize memory use. + ''' mod = self.function.module - # TODO - # Is this a safe way for uniquing identifying string - name = '.conststr.%x_%x' % (hash(string), len(string)) + collision = 0 + name_fmt = '.conststr.%x.%x' content = lc.Constant.stringz(string) - try: - globalstr = mod.get_global_variable_named(name) - except LLVMException: - globalstr = mod.add_global_variable(content.type, name=name) - globalstr.initializer = content - return CTemp(self, globalstr.bitcast( - types.pointer(content.type.element))) + while True: + name = name_fmt % (hash(string), collision) + try: + # check if the name already exists + globalstr = mod.get_global_variable_named(name) + except LLVMException: + # new constant string + globalstr = mod.add_global_variable(content.type, name=name) + globalstr.initializer = content + globalstr.global_constant = True + else: + # compare existing content + existed = str(globalstr.initializer) + if existed != str(content): + collision += 1 + continue # loop until we resolve the name collision + + return CTemp(self, globalstr.bitcast( + types.pointer(content.type.element))) def get_intrinsic(self, intrinsic_id, tys): + '''get intrinsic function + + intrinsic_id : numerical ID of target intrinsic + tys : type argument for the intrinsic + ''' lfunc = lc.Function.intrinsic(self.function.module, intrinsic_id, tys) return CFunc(self, lfunc) def get_function_named(self, name): + '''get function by name + ''' m = self.function.module func = m.get_function_named(name) return CFunc(self, func) def is_terminated(self): - ''' - Is the current basic-block terminated? + '''is the current basic-block terminated? ''' return _is_block_terminated(self.builder.basic_block) def atomic_cmpxchg(self, ptr, old, val, ordering, crossthread=True): + '''atomic compare-exchange + + ptr : pointer to data + old : old value to compare to + val : new value + ordering : memory ordering as a string + crossthread : set to `False` for single-thread code + + Returns the old value on success. + ''' res = self.builder.atomic_cmpxchg(ptr.value, old.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_xchg(self, ptr, val, ordering, crossthread=True): + '''atomic exchange + + ptr : pointer to data + val : new value + ordering : memory ordering as a string + crossthread : set to `False` for single-thread code + + Returns the old value + ''' + res = self.builder.atomic_xchg(ptr.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_add(self, ptr, val, ordering, crossthread=True): + '''atomic add + + ptr : pointer to data + val : new value + ordering : memory ordering as a string + crossthread : set to `False` for single-thread code + + Returns the computation result of the operation + ''' + res = self.builder.atomic_add(ptr.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_sub(self, ptr, val, ordering, crossthread=True): + '''atomic sub + + See `atomic_add` for parameters documentation + ''' res = self.builder.atomic_sub(ptr.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_and(self, ptr, val, ordering, crossthread=True): + '''atomic bitwise and + + See `atomic_add` for parameters documentation + ''' res = self.builder.atomic_and(ptr.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_nand(self, ptr, val, ordering, crossthread=True): + '''atomic bitwise nand + + See `atomic_add` for parameters documentation + ''' res = self.builder.atomic_nand(ptr.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_or(self, ptr, val, ordering, crossthread=True): + '''atomic bitwise or + + See `atomic_add` for parameters documentation + ''' res = self.builder.atomic_or(ptr.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_xor(self, ptr, val, ordering, crossthread=True): + '''atomic bitwise xor + + See `atomic_add` for parameters documentation + ''' + res = self.builder.atomic_xor(ptr.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_max(self, ptr, val, ordering, crossthread=True): + '''atomic signed maximum between value at `ptr` and `val` + + See `atomic_add` for parameters documentation + ''' res = self.builder.atomic_max(ptr.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_min(self, ptr, val, ordering, crossthread=True): + '''atomic signed minimum between value at `ptr` and `val` + + See `atomic_add` for parameters documentation + ''' res = self.builder.atomic_min(ptr.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_umax(self, ptr, val, ordering, crossthread=True): + '''atomic unsigned maximum between value at `ptr` and `val` + + See `atomic_add` for parameters documentation + ''' res = self.builder.atomic_umax(ptr.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_umin(self, ptr, val, ordering, crossthread=True): + '''atomic unsigned minimum between value at `ptr` and `val` + + See `atomic_add` for parameters documentation + ''' res = self.builder.atomic_umin(ptr.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_load(self, ptr, ordering, align=1, crossthread=True): + '''atomic load + + ptr : pointer to the value to load + align : memory alignment in bytes + See `atomic_add` for other documentation of other parameters + ''' res = self.builder.atomic_load(ptr.value, ordering, align, crossthread) return CTemp(self, res) def atomic_store(self, val, ptr, ordering, align=1, crossthread=True): + '''atomic store + + ptr : pointer to where to store + val : value to store + align : memory alignment in bytes + See `atomic_add` for other documentation of other parameters + ''' + res = self.builder.atomic_store(val.value, ptr.value, ordering, align, crossthread) return CTemp(self, res) def fence(self, ordering, crossthread=True): + '''insert memory fence + ''' res = self.builder.fence(ordering, crossthread) return CTemp(self, res) def alignment(self, ty): + '''get minimum alignment of `ty` + ''' return self.target_data.abi_alignment(ty) def unreachable(self): + '''insert instruction that causes segfault some platform (Intel), + or no-op on others. + + It has no defined semantic. + ''' self.builder.unreachable() class _DeclareCDef(object): + '''create a function a CDefinition to use with `CBuilder.depends` + + An instance of this class is created by the constructor of CDefinition. + Do not use directly. + ''' def __init__(self, cdef): self.cdef = cdef @@ -433,6 +656,9 @@ class _DeclareCDef(object): return func class CDeclare(object): + '''create a function from name, type and pointer to use with + `CBuilder.depends` + ''' def __init__(self, name, ty, ptr): self._name = name self._type = ty @@ -448,33 +674,51 @@ class CDeclare(object): return self._name class CDefinition(CBuilder): - ''' - Inherit this class to for defining functions + '''represents function definition + + Inherit from this class to create a new function definition. + + Class Members + ------------- + _name_ : name of the function + _retty_ : return type + _argtys_ : argument names and types as list of tuples; + e.g. [ ( 'myarg', lc.Type.int() ), ... ] ''' _name_ = '' # name of the function; should overide in subclass _retty_ = types.void # return type; can overide in subclass _argtys_ = [] # a list of tuple(name, type); can overide in subclass def __new__(cls, *args, **kws): - try: - fnsp = getattr(cls, 'specialize') - except AttributeError: - pass - else: + if cls.is_generic(): + # Call specialize if it is defined. cls = type('%s_Specialized' % cls.__name__, (cls,), {}) - fnsp(*args, **kws) + cls.specialize(*args, **kws) obj = object.__new__(_DeclareCDef) obj.__init__(cls) return obj + @classmethod + def is_generic(cls): + '''Is this a generic definition? + ''' + return hasattr(cls, 'specialize') + @classmethod def define(cls, module): + '''define the function in the module. + + Raises NameError if a function of the same name has already been + defined. + ''' functype = lc.Type.function(cls._retty_, [v for k, v in cls._argtys_]) name = cls._name_ if not name: - raise NameError("Function name cannot be empty.") + raise AttributeError("Function name cannot be empty.") + func = module.get_or_insert_function(functype, name=name) + if not func.is_declaration: # already defined? raise NameError(func) @@ -490,25 +734,24 @@ class CDefinition(CBuilder): return func def body(self): - ''' - Overide this function to define the body. + '''overide this function to define the body. ''' raise NotImplementedError class CValue(object): ''' - = Signess = - Since LLVM type does not provide signess attribute. This information + Signedness + ---------- + Since LLVM type does not provide signedness attribute. This information is provided in the CValue.unsigned attribute. The default value is `None`, meaning that this attribute is not set. - In casting operation, signess information is passed as an optional arg. + In casting operation, signednss information is passed as an optional arg. - In binary operation, signess of the left operand is used. + In binary operation, signedness of the left operand is used. ''' - # Attribute for for integer values. - unsigned = None + unsigned = None # attribute for for integer values. _BINOP_MAP = { # op-name : (signed int, unsigned int, real) @@ -542,6 +785,8 @@ class CValue(object): self.parent = parent def _use_binop(self, op): + '''implements binary operations + ''' def wrapped(rhs): self._ensure_same_type(rhs) binop = self._BINOP_MAP[op] @@ -560,6 +805,8 @@ class CValue(object): return wrapped def _use_bitwise(self, op): + '''implements bitwise operations + ''' def wrapped(rhs): self._ensure_same_type(rhs) if not self.is_int: @@ -608,6 +855,10 @@ class CValue(object): return self._use_bitwise('xor')(rhs) def _ensure_same_type(self, val): + '''ensure that this instance has the same type as `val` + + Raises TypeError if `self.type != val.type` + ''' if self.type != val.type: errmsg = "Type mismatch: %s != %s" raise TypeError(errmsg % (self.type, val.type)) @@ -621,6 +872,10 @@ class CValue(object): return _is_real(self.type) def cast(self, ty, unsigned=False): + '''cast to another type + + If `ty == self.type`, then pass thru + ''' make = lambda X: CTemp(self.parent, X) if self.type == ty: return self # pass thru @@ -651,6 +906,8 @@ class CValue(object): raise TypeError(errmsg % (self.type, ty)) def _cmp_op(self, name): + '''implements comparison operations + ''' def wrapped(rhs): make = lambda X: CTemp(self.parent, X) self._ensure_same_type(rhs) @@ -700,6 +957,10 @@ class CValue(object): raise TypeError("Must be a pointer; got %s" % self.type) def __getitem__(self, idx): + '''implement access indexing + + Uses GEP. + ''' self._ensure_is_pointer() if not isinstance(idx, CValue): idx = self.parent.constant(types.int, idx) @@ -708,15 +969,26 @@ class CValue(object): return CVar(self.parent, ptr) def load(self, volatile=False): + '''memory load for pointer types + ''' self._ensure_is_pointer() loaded = self.parent.builder.load(self.value, volatile=volatile) return CTemp(self.parent, loaded) def store(self, val, volatile=False): + '''memory store for pointer types + ''' self._ensure_is_pointer() self.parent.builder.store(val.value, self.value, volatile=volatile) def atomic_load(self, ordering, align=None, crossthread=True): + '''atomic load memory for pointer types + + align : overide to control memory alignment; otherwise the default + alignment of the type is used. + + Other parameters are the same as `CBuilder.atomic_load` + ''' self._ensure_is_pointer() if align is None: align = self.parent.alignment(self.type.pointee) @@ -725,6 +997,13 @@ class CValue(object): return CTemp(self.parent, inst) def atomic_store(self, value, ordering, align=None, crossthread=True): + '''atomic memory store for pointer types + + align : overide to control memory alignment; otherwise the default + alignment of the type is used. + + Other parameters are the same as `CBuilder.atomic_store` + ''' self._ensure_is_pointer() if align is None: align = self.parent.alignment(self.type.pointee) @@ -732,6 +1011,10 @@ class CValue(object): align=align, crossthread=crossthread) def atomic_cmpxchg(self, old, new, ordering, crossthread=True): + '''atomic compare-exchange for pointer types + + Other parameters are the same as `CBuilder.atomic_cmpxchg` + ''' self._ensure_is_pointer() inst = self.parent.builder.atomic_cmpxchg(self.value, old.value, new.value, ordering, @@ -740,11 +1023,17 @@ class CValue(object): class CFunc(CValue): + '''Wraps function pointer + ''' def __init__(self, parent, func): super(CFunc, self).__init__(parent) self.function = func def __call__(self, *args): + '''Call the function with the given arguments + + *args : variable arguments of CValue instances + ''' arg_values = _list_values(args) ftype = self.function.type.pointee for i, (exp, got) in enumerate(zip(ftype.args, arg_values)): @@ -764,6 +1053,8 @@ class CFunc(CValue): return self.function.type class CTemp(CValue): + '''Wraps temporary values + ''' def __init__(self, parent, value): super(CTemp, self).__init__(parent) self.value = value @@ -773,6 +1064,10 @@ class CTemp(CValue): return self.value.type class CVar(CValue): + '''Wraps variables + + Similar to C variables. + ''' def __init__(self, parent, ptr): super(CVar, self).__init__(parent) @@ -827,6 +1122,8 @@ class CVar(CValue): return self.parent.builder.load(self.ptr) def assign(self, val): + '''assign new value to the variable + ''' self._ensure_same_type(val) self.parent.builder.store(val.value, self.ptr) @@ -835,9 +1132,13 @@ class CVar(CValue): return self.ptr.type.pointee def reference(self): + '''get a pointer reference of the variable + ''' return CTemp(self.parent, self.ptr) def as_struct(self, cstruct_class, volatile=False): + '''load a pointer to a structure and assume a structure interface + ''' if _is_pointer(self.type): ptr = self.parent.builder.load(self.ptr, volatile=volatile) return cstruct_class(self.parent, ptr) @@ -845,6 +1146,10 @@ class CVar(CValue): return cstruct_class(self.parent, self.ptr) class CArray(CValue): + '''wraps a array + + Similar to C arrays + ''' def __init__(self, parent, base): super(CArray, self).__init__(parent) self.base_ptr = base @@ -860,18 +1165,17 @@ class CArray(CValue): def type(self): return self.base_ptr.type -## Moved to CValue -# def __getitem__(self, idx): -# self._ensure_is_pointer() -# builder = self.parent.builder -# if isinstance(idx, CValue): -# idx = idx.value -# elif not isinstance(idx, lc.Value): -# idx = self.parent.constant(types.int, idx).value -# ptr = builder.gep(self.value, [idx]) -# return CVar(self.parent, ptr) - class CStruct(CValue): + '''Wraps a structure + + Structure in LLVM can be identified by name of layout. + + Subclass to define a new structure. All fields are defined in the + `_fields_` class attribute as a list of tuple (name, type). + + Can define new methods which gets inlined to the parent CBuilder. + ''' + @classmethod def llvm_type(cls): return lc.Type.struct([v for k, v in cls._fields_]) @@ -883,12 +1187,19 @@ class CStruct(CValue): for i, (fd, _) in enumerate(self._fields_): gep = self.parent.builder.gep(ptr, [makeind(0), makeind(i)]) gep.name = "%s.%s" % (type(self).__name__, fd) + if hasattr(self, fd): + raise AttributeError("Field name shadows another attribute") setattr(self, fd, CVar(self.parent, gep)) def reference(self): return CTemp(self.parent, self.ptr) class CExternal(object): + '''subclass to define external interface + + All class attributes that are `llvm.core.FunctionType` are converted + to `CFunc` instance during instantiation. + ''' def __init__(self, cbuilder): is_func = lambda x: isinstance(x, lc.FunctionType) non_magic = lambda s: not ( s.startswith('__') and s.endswith('__') ) diff --git a/llvm_cbuilder/executor.py b/llvm_cbuilder/executor.py index bd7d78c..acfd13d 100644 --- a/llvm_cbuilder/executor.py +++ b/llvm_cbuilder/executor.py @@ -1,3 +1,7 @@ +''' +This is mostly a convenience module for testing with ctypes. +''' + from llvm.core import Type, Module import llvm.ee as le import ctypes as ct @@ -29,6 +33,8 @@ MAP_CTYPES = { } class CExecutor(object): + '''a convenient class for creating ctype functions from LLVM modules + ''' def __init__(self, mod_or_engine): if isinstance(mod_or_engine, Module): self.engine = le.EngineBuilder.new(mod_or_engine).opt(3).create() @@ -36,6 +42,14 @@ class CExecutor(object): self.engine = mod_or_engine def get_ctype_function(self, fn, *typeinfo): + '''create a ctype function from a LLVM function + + typeinfo : string of types (see `MAP_CTYPES`) or + list of ctypes datatype. + First value is the return type. + A function that takes no argument and return nothing + should use `"void"` or `None`. + ''' if len(typeinfo)==1 and isinstance(typeinfo[0], str): types = [ MAP_CTYPES[s.strip()] for s in typeinfo[0].split(',') ] if not types: diff --git a/llvm_cbuilder/libc.py b/llvm_cbuilder/libc.py new file mode 100644 index 0000000..8d4a5c1 --- /dev/null +++ b/llvm_cbuilder/libc.py @@ -0,0 +1,8 @@ +from .builder import CExternal +import llvm.core as lc +from . import shortnames as types + +class LibC(CExternal): + printf = lc.Type.function(types.int, [types.char_p], True) + # TODO a lot more to add + diff --git a/tests/test_cstr_collide.py b/tests/test_cstr_collide.py new file mode 100644 index 0000000..4a427c6 --- /dev/null +++ b/tests/test_cstr_collide.py @@ -0,0 +1,17 @@ +from llvm.core import * +from llvm_cbuilder import * +from llvm_cbuilder import shortnames as C + +import unittest + +class TestCstrCollide(unittest.TestCase): + def test_same_string(self): + mod = Module.new(__name__) + cb = CBuilder.new_function(mod, 'test_cstr_collide', C.void, []) + + a = cb.constant_string("hello") + b = cb.constant_string("hello") + self.assertEqual(a.value, b.value) + +if __name__ == '__main__': + unittest.main() From 3009d8468f3ca85650852d3777ca1c547c57c06d Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 8 Aug 2012 15:29:16 -0700 Subject: [PATCH 021/516] more cleanup and doc --- README.md | 16 +++++++++++ parallel_vectorize.py | 63 +++++++++++++++++++++++-------------------- 2 files changed, 50 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index cab0f28..a63039a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,23 @@ +llvm_cbuilder +------------- + A llvm-py Builder wrapper for writing in slightly higher-level constructs. This is aiming for two usecases: + 1. Emit LLVM code in a more human-readable way; + 2. Writing low-level code that you can't do it properly/portably with C, e.g template (generic), atomic operations, memory ordering... + +Parallel Vectorize +------------------ + +`parallel_vectorize.py` implements a set of code generator that bases on +llvm_cbuilder to create specialized parallel ufunc. + +See `test_parallel_vectorize_numpy*.py` for testing and demo of the code +with the new `numpy.fromfunc()`. + + diff --git a/parallel_vectorize.py b/parallel_vectorize.py index 4c8daab..f26ad46 100644 --- a/parallel_vectorize.py +++ b/parallel_vectorize.py @@ -17,8 +17,7 @@ from llvm_cbuilder import * import llvm_cbuilder.shortnames as C class WorkQueue(CStruct): - ''' - Structure for workqueue for parallel-ufunc. + '''structure for workqueue for parallel-ufunc. ''' _fields_ = [ @@ -29,8 +28,7 @@ class WorkQueue(CStruct): def Lock(self): - ''' - Inline the lock procedure. + '''inline the lock procedure. ''' with self.parent.loop() as loop: with loop.condition() as setcond: @@ -45,8 +43,7 @@ class WorkQueue(CStruct): pass def Unlock(self): - ''' - Inline the unlock procedure. + '''inline the unlock procedure. ''' unlocked = self.parent.constant(self.lock.type, 0) locked = self.parent.constant(self.lock.type, 1) @@ -61,8 +58,7 @@ class WorkQueue(CStruct): class ContextCommon(CStruct): - ''' - Structure for thread-shared context information in parallel-ufunc. + '''structure for thread-shared context information in parallel-ufunc. ''' _fields_ = [ # loop ufunc args @@ -77,8 +73,7 @@ class ContextCommon(CStruct): ] class Context(CStruct): - ''' - Structure for thread-specific context information in parallel-ufunc. + '''structure for thread-specific context information in parallel-ufunc. ''' _fields_ = [ ('common', C.pointer(ContextCommon.llvm_type())), @@ -87,7 +82,11 @@ class Context(CStruct): ] class ParallelUFunc(CDefinition): - ''' + '''the generic parallel vectorize mechanism + + Can be specialized to the maximum number of threads on the platform. + + Platform dependent threading function is implemented in def _dispatch_worker(self, worker, contexts, num_thread): @@ -107,7 +106,8 @@ class ParallelUFunc(CDefinition): @classmethod def specialize(cls, num_thread): - print num_thread + '''specialize to the maximum # of thread + ''' cls._name_ = 'parallel_ufunc_%d' % num_thread cls.ThreadCount = num_thread @@ -172,8 +172,7 @@ class ParallelUFunc(CDefinition): self.ret() def _populate_workqueues(self, workqueues, N, ChunkSize, num_thread): - ''' - Loop over all threads and populate the workqueue for each of them. + '''loop over all threads and populate the workqueue for each of them. ''' ONE = self.constant(num_thread.type, 1) with self.for_range(num_thread) as (loop, i): @@ -186,8 +185,7 @@ class ParallelUFunc(CDefinition): last_wq.last.assign(N) def _populate_context(self, contexts, common, num_thread): - ''' - Loop over all threads and populate contexts for each of them. + '''loop over all threads and populate contexts for each of them. ''' ONE = self.constant(num_thread.type, 1) with self.for_range(num_thread) as (loop, i): @@ -198,8 +196,7 @@ class ParallelUFunc(CDefinition): self.constant_null(cur_ctxt.completed.type)) class ParallelUFuncPosixMixin(object): - ''' - Implements _dispatch_worker to use pthread. + '''ParallelUFunc mixin that implements _dispatch_worker to use pthread. ''' def _dispatch_worker(self, worker, contexts, num_thread): api = PThreadAPI(self) @@ -219,7 +216,10 @@ class ParallelUFuncPosixMixin(object): api.pthread_join(threads[i], NULL) class UFuncCore(CDefinition): - ''' + '''core work of a ufunc worker thread + + Subclass to implement UFuncCore._do_work + Generates the workqueue handling and work stealing and invoke the work function for each work item. ''' @@ -242,8 +242,7 @@ class UFuncCore(CDefinition): self.ret() def _do_workqueue(self, common, workqueue, tid, completed): - ''' - Process local workqueue. + '''process local workqueue. ''' ZERO = self.constant_null(C.int) @@ -264,8 +263,7 @@ class UFuncCore(CDefinition): completed += self.constant(completed.type, 1) def _do_work_stealing(self, common, tid, completed): - ''' - Steal work from other workqueues. + '''steal work from other workqueues. ''' # self.debug("start work stealing", tid) steal_continue = self.var(C.int, 1) @@ -283,8 +281,7 @@ class UFuncCore(CDefinition): def _do_work_stealing_innerloop(self, common, steal_continue, tid, completed): - ''' - Loop over all other threads and try to steal work. + '''loop over all other threads and try to steal work. ''' with self.for_range(common.num_thread) as (loop, i): with self.ifelse( i != tid ) as ifelse: @@ -296,10 +293,10 @@ class UFuncCore(CDefinition): def _do_work_stealing_check(self, common, otherqueue, steal_continue, tid, completed): - ''' - Check the workqueue for any remaining work and steal it. + '''check the workqueue for any remaining work and steal it. ''' otherqueue.Lock() + # Acquired ONE = self.constant(otherqueue.last.type, 1) STEAL_CONTINUE = self.constant(steal_continue.type, 1) with self.ifelse(otherqueue.next < otherqueue.last) as ifelse: @@ -318,14 +315,18 @@ class UFuncCore(CDefinition): with ifelse.otherwise(): otherqueue.Unlock() + # Released def _do_work(self, common, item, tid): - ''' - Prepare to call the actual work function. + '''prepare to call the actual work function + + Implementation depends on number and type of arguments. ''' raise NotImplementedError class SpecializedParallelUFunc(CDefinition): + '''a generic ufunc that wraps ParallelUFunc, UFuncCore and the workload + ''' _argtys_ = [ ('args', C.pointer(C.char_p)), ('dimensions', C.pointer(C.intp)), @@ -343,12 +344,16 @@ class SpecializedParallelUFunc(CDefinition): @classmethod def specialize(cls, pufunc_def, core_def, func_def): + '''specialize to a combination of ParallelUFunc, UFuncCore and workload + ''' cls._name_ = 'specialized_%s_%s_%s'% (pufunc_def, core_def, func_def) cls.PUFuncDef = pufunc_def cls.CoreDef = core_def cls.FuncDef = func_def class PThreadAPI(CExternal): + '''external declaration of pthread API + ''' pthread_t = C.void_p pthread_create = Type.function(C.int, From 3b0aeea6f28c07acac864c25f90cfde9e0efd15a Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 8 Aug 2012 16:27:57 -0700 Subject: [PATCH 022/516] change CDeclare to CFuncRef --- llvm_cbuilder/builder.py | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 99133e6..3b854b5 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -655,16 +655,36 @@ class _DeclareCDef(object): (func,) = e return func -class CDeclare(object): - '''create a function from name, type and pointer to use with - `CBuilder.depends` +class CFuncRef(object): + '''create a function reference to use with `CBuilder.depends` + + Either from name, type and pointer, + Or from a llvm.core.FunctionType instance ''' - def __init__(self, name, ty, ptr): - self._name = name - self._type = ty - self._ptr = ptr + def __init__(self, *args, **kwargs): + def one_arg(fn): + self._fn = fn + self._name = fn.name + + def three_arg(name, ty, ptr): + self._name = name + self._type = ty + self._ptr = ptr + + try: + three_arg(*args, **kwargs) + self._meth = self._from_pointer + except TypeError: + one_arg(*args, **kwargs) + self._meth = self._from_func def __call__(self, module): + return self._meth() + + def _from_func(self): + return self._fn + + def _from_pointer(self): fnptr = types.pointer(self._type) ptr = lc.Constant.int(types.intp, self._ptr) ptr = ptr.inttoptr(fnptr) From e35b8ca636cf0f4ff0cabb2d523c954aacbd42c6 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 8 Aug 2012 17:32:39 -0700 Subject: [PATCH 023/516] Add some float casting --- llvm_cbuilder/builder.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 3b854b5..15ef477 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -917,10 +917,19 @@ class CValue(object): else: return make(self.parent.builder.uitofp(self.value, ty)) elif self.is_real: - if not unsigned: - return make(self.parent.builder.fptosi(self.value, ty)) + if _is_int(ty): + if not unsigned: + return make(self.parent.builder.fptosi(self.value, ty)) + else: + return make(self.parent.builder.fptoui(self.value, ty)) else: - return make(self.parent.builder.fptoui(self.value, ty)) + if ty == types.double: + assert self.type == types.float + return make(self.parent.builder.fpext(self.value, ty)) + else: + assert ty == types.float + assert self.type == types.double + return make(self.parent.builder.fptrunc(self.value, ty)) errmsg = "Cast from %s to %s is not possible." raise TypeError(errmsg % (self.type, ty)) From b23d7909fbd4b1c59e4320d3025b7ca0a7ce6924 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 8 Aug 2012 17:33:00 -0700 Subject: [PATCH 024/516] add parallel_vectorize_from_func --- parallel_vectorize.py | 84 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/parallel_vectorize.py b/parallel_vectorize.py index f26ad46..f70954b 100644 --- a/parallel_vectorize.py +++ b/parallel_vectorize.py @@ -16,6 +16,8 @@ from llvm.passes import * from llvm_cbuilder import * import llvm_cbuilder.shortnames as C +import sys + class WorkQueue(CStruct): '''structure for workqueue for parallel-ufunc. ''' @@ -365,3 +367,85 @@ class PThreadAPI(CExternal): pthread_join = Type.function(C.int, [C.void_p, C.void_p]) +class UFuncCoreGeneric(UFuncCore): + '''A generic ufunc core worker from LLVM function type + ''' + def _do_work(self, common, item, tid): + ufunc_type = Type.function(self.RETTY, self.ARGTYS) + ufunc_ptr = CFunc(self, common.func.cast(C.pointer(ufunc_type)).value) + + get_offset = lambda B, S, T: B[item * S].reference().cast(C.pointer(T)) + + indata = [] + for i, argty in enumerate(self.ARGTYS): + ptr = get_offset(common.args[i], common.steps[i], argty) + indata.append(ptr.load()) + + out_index = len(self.ARGTYS) + outptr = get_offset(common.args[out_index], common.steps[out_index], + self.RETTY) + + res = ufunc_ptr(*indata) + outptr.store(res) + + @classmethod + def specialize(cls, fntype): + '''specialize to a LLVM function type + + fntype : a LLVM function type (llvm.core.FunctionType) + ''' + cls._name_ = '.'.join([cls._name_] + + map(str, [fntype.return_type] + fntype.args)) + + cls.RETTY = fntype.return_type + cls.ARGTYS = tuple(fntype.args) + + +if sys.platform not in ['win32']: + class ParallelUFuncPlatform(ParallelUFunc, ParallelUFuncPosixMixin): + pass +else: + raise NotImplementedError("Threading for %s" % sys.platform) + + + +def parallel_vectorize_from_func(lfunc, engine=None): + fntype = lfunc.type.pointee + def_spuf = SpecializedParallelUFunc(ParallelUFuncPlatform(num_thread=2), + UFuncCoreGeneric(fntype), + CFuncRef(lfunc)) + spuf = def_spuf(lfunc.module) + if engine is None: + return spuf + else: + import numpy as np + + fptr = engine.get_pointer_to_function(spuf) + inct = len(fntype.args) + outct = 1 + + # TODO refactor + typemap = { + 'i8' : np.uint8, + 'i16' : np.uint16, + 'i32' : np.uint32, + 'i64' : np.uint64, + 'float' : np.float32, + 'double' : np.float64, + } + try: + ptr_t = long + except: + ptr_t = int + assert False, "Having check this yet" + + get_typenum = lambda T:np.dtype(typemap[str(T)]).num + assert fntype.return_type != C.void + tys = list(map(get_typenum, list(fntype.args) + [fntype.return_type])) + # Becareful that fromfunc does not provide full error checking yet. + # If typenum is out-of-bound, we have nasty memory corruptions. + # For instance, -1 for typenum will cause segfault. + # If elements of type-list (2nd arg) is tuple instead, + # there will also memory corruption. (Seems like code rewrite.) + return np.fromfunc([ptr_t(fptr)], [tys], inct, outct, [None]) + From 753f74d48562193ecbd6dc9cd5ec52bdf59fe26c Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 8 Aug 2012 17:33:24 -0700 Subject: [PATCH 025/516] Fix tests --- test_parallel_vectorize.py | 2 +- test_parallel_vectorize_numpy_2.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test_parallel_vectorize.py b/test_parallel_vectorize.py index 54d6b14..1a850f5 100644 --- a/test_parallel_vectorize.py +++ b/test_parallel_vectorize.py @@ -23,7 +23,7 @@ class UFuncCore_D_D(UFuncCore): outbase = common.args[1] instep = common.steps[0] - outstep = common.steps[0] + outstep = common.steps[1] indata = inbase[item * instep].reference().cast(C.pointer(C.double)) outdata = outbase[item * outstep].reference().cast(C.pointer(C.double)) diff --git a/test_parallel_vectorize_numpy_2.py b/test_parallel_vectorize_numpy_2.py index a511980..f846a25 100644 --- a/test_parallel_vectorize_numpy_2.py +++ b/test_parallel_vectorize_numpy_2.py @@ -18,7 +18,7 @@ def main(): # get pointer to workfunc workfunc_ptr = exe.engine.get_pointer_to_function(workfunc) - workdecl = CDeclare(workfunc.name, workfunc.type.pointee, workfunc_ptr) + workdecl = CFuncRef(workfunc.name, workfunc.type.pointee, workfunc_ptr) spufdef = SpecializedParallelUFunc(ParallelUFuncPosix(num_thread=2), UFuncCore_D_D(), From c6d5538eade22fec6587a0177631dcb5fabfa63e Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 8 Aug 2012 17:33:34 -0700 Subject: [PATCH 026/516] Add usecase tests --- test_usecase_1_1.py | 56 +++++++++++++++++++++++++++++++++++++++++++ test_usecase_2_1.py | 58 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 test_usecase_1_1.py create mode 100644 test_usecase_2_1.py diff --git a/test_usecase_1_1.py b/test_usecase_1_1.py new file mode 100644 index 0000000..5cc4d7a --- /dev/null +++ b/test_usecase_1_1.py @@ -0,0 +1,56 @@ +from parallel_vectorize import * +from llvm_cbuilder import shortnames as C +from llvm.core import * +import numpy as np +import unittest +from random import random + +class OneOne(CDefinition): + + def body(self, inval): + self.ret( (inval * inval).cast(self.OUT_TYPE) ) + + @classmethod + def specialize(cls, itype, otype): + cls._name_ = '.'.join(map(str, ['oneone', itype, otype])) + cls._retty_ = otype + cls._argtys_ = [ + ('inval', itype), + ] + cls.OUT_TYPE = otype + + +class TestParallelVectorize(unittest.TestCase): + def test_parallelvectorize_d_d(self): + self.template(C.double, C.double) + + def test_parallelvectorize_d_f(self): + self.template(C.double, C.float) + + def template(self, itype, otype): + module = Module.new(__name__) + exe = CExecutor(module) + + def_oneone = OneOne(itype, otype) + oneone = def_oneone(module) + ufunc = parallel_vectorize_from_func(oneone, exe.engine) + # print(module) + module.verify() + + x = np.linspace(.0, 10., 1000) + x.dtype = np.double + + ans = ufunc(x) + gold = x * x + + for x, y in zip(ans, gold): + if y != 0: + err = abs(x - y)/y + self.assertLess(err, 1e-6) + else: + self.assertEqual(x, y) + + +if __name__ == '__main__': + unittest.main() + diff --git a/test_usecase_2_1.py b/test_usecase_2_1.py new file mode 100644 index 0000000..087ee9f --- /dev/null +++ b/test_usecase_2_1.py @@ -0,0 +1,58 @@ +from parallel_vectorize import * +from llvm_cbuilder import shortnames as C +from llvm.core import * +import numpy as np +import unittest +from random import random + +class TwoOne(CDefinition): + + def body(self, a, b): + self.ret( (a * b).cast(self.OUT_TYPE) ) + + @classmethod + def specialize(cls, itype1, itype2, otype): + cls._name_ = '.'.join(map(str, ['oneone', itype1, itype2, otype])) + cls._retty_ = otype + cls._argtys_ = [ + ('a', itype1), + ('b', itype2), + ] + cls.OUT_TYPE = otype + + +class TestParallelVectorize(unittest.TestCase): + def test_parallelvectorize_dd_d(self): + self.template(C.double, C.double, C.double) + + def test_parallelvectorize_dd_f(self): + self.template(C.double, C.double, C.float) + + def template(self, itype1, itype2, otype): + module = Module.new(__name__) + exe = CExecutor(module) + + def_twoone = TwoOne(itype1, itype2, otype) + twoone = def_twoone(module) + ufunc = parallel_vectorize_from_func(twoone, exe.engine) + # print(module) + module.verify() + + A = np.linspace(.0, 10., 1000) + A.dtype = np.double + B = np.linspace(-10., 0., 1000) + B.dtype = np.double + + ans = ufunc(A, B) + gold = A * B + + for x, y in zip(ans, gold): + if y != 0: + err = abs(x - y)/y + self.assertLess(err, 1e-6) + else: + self.assertEqual(x, y) + +if __name__ == '__main__': + unittest.main() + From 9ccc6782c7b5a9afeeefc2ed6acd13ca30c95c3f Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 8 Aug 2012 17:46:20 -0700 Subject: [PATCH 027/516] Add doc for parallel_vectorize_from_func. Add FunctionAlreadyExists exception. --- llvm_cbuilder/builder.py | 7 +++++-- parallel_vectorize.py | 6 ++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 15ef477..fc4baa3 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -12,6 +12,9 @@ from . import shortnames as types # Utilities ### +class FunctionAlreadyExists(NameError): + pass + def _is_int(ty): return isinstance(ty, lc.IntegerType) @@ -651,7 +654,7 @@ class _DeclareCDef(object): def __call__(self, module): try: func = self.cdef.define(module) - except NameError as e: + except FunctionAlreadyExists as e: (func,) = e return func @@ -740,7 +743,7 @@ class CDefinition(CBuilder): func = module.get_or_insert_function(functype, name=name) if not func.is_declaration: # already defined? - raise NameError(func) + raise FunctionAlreadyExists(func) # Name all arguments for i, (name, _) in enumerate(cls._argtys_): diff --git a/parallel_vectorize.py b/parallel_vectorize.py index f70954b..210dea8 100644 --- a/parallel_vectorize.py +++ b/parallel_vectorize.py @@ -410,6 +410,12 @@ else: def parallel_vectorize_from_func(lfunc, engine=None): + '''create ufunc from a llvm.core.Function + + If engine is given, return a function object which can be called + from python. (This needs Jay's numpy.fromfunc). + Otherwise, return the specialized ufunc as a llvm.core.Function + ''' fntype = lfunc.type.pointee def_spuf = SpecializedParallelUFunc(ParallelUFuncPlatform(num_thread=2), UFuncCoreGeneric(fntype), From 7f84ecbe3b64f7e6438dee212c4c9535d4f5f5d4 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 10 Aug 2012 17:58:54 -0700 Subject: [PATCH 028/516] Add notebook: llvm_cbuilder quick tour --- notebook/llvm_cbuilder_intro.ipynb | 586 +++++++++++++++++++++++++++++ notebook/llvm_cbuilder_intro.pdf | Bin 0 -> 130681 bytes 2 files changed, 586 insertions(+) create mode 100644 notebook/llvm_cbuilder_intro.ipynb create mode 100644 notebook/llvm_cbuilder_intro.pdf diff --git a/notebook/llvm_cbuilder_intro.ipynb b/notebook/llvm_cbuilder_intro.ipynb new file mode 100644 index 0000000..9234f3d --- /dev/null +++ b/notebook/llvm_cbuilder_intro.ipynb @@ -0,0 +1,586 @@ +{ + "metadata": { + "name": "llvm_cbuilder_intro" + }, + "nbformat": 2, + "worksheets": [ + { + "cells": [ + { + "cell_type": "markdown", + "source": [ + "llvm_cbuilder: A Quick Tour", + "---------------------------", + "", + "Writing code generation logic in pure llvmpy requires one to think like a compiler -- ", + "dealing with basic-blocks, branches, SSA, etc.", + "The resulting code looks like assembly code, with no apparent hint about the control-flow.", + "", + "llvm_cbuilder is originally designed to simplify the translation of C code into llvmpy.", + "It provides a simple API for mimicking C programming in Python.", + "With llvm_cbulder, one can write very low-level code, probably even lower-level than C.", + "At the same time, one can use if-else, loop, structures and a bit of OOP." + ] + }, + { + "cell_type": "markdown", + "source": [ + "A Simple Example", + "----------------", + "", + "Let's see some action.", + "We will define a function that calculates the square of a double-precision float." + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "from llvm.core import *", + "from llvm_cbuilder import *", + "import llvm_cbuilder.shortnames as C", + "", + "class Square(CDefinition):", + " # prototype: double square(double x)", + " _name_ = 'square' # function name", + " _retty_ = C.double", + " _argtys_ = [ ('x', C.double) ]", + " ", + " def body(self, x):", + " y = x * x # just write out the expression", + " self.ret(y)" + ], + "language": "python", + "outputs": [], + "prompt_number": 1 + }, + { + "cell_type": "markdown", + "source": [ + "Notice how numerical expressions can be written naturally." + ] + }, + { + "cell_type": "markdown", + "source": [ + "Let's see the emitted code:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "m = Module.new('my_module')", + "llvm_square = Square()(m) # define square() in my_module", + "print(m)" + ], + "language": "python", + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "; ModuleID = 'my_module'", + "", + "define double @square(double %x) {", + "decl:", + " %x1 = alloca double", + " br label %body", + "", + "body: ; preds = %decl", + " store double %x, double* %x1", + " %0 = load double* %x1", + " %1 = load double* %x1", + " %2 = fmul double %0, %1", + " ret double %2", + "}", + "" + ] + } + ], + "prompt_number": 2 + }, + { + "cell_type": "markdown", + "source": [ + "Let's generate a ctype function object to call `square()` in the Python code:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "exe = CExecutor(m)", + "square = exe.get_ctype_function(llvm_square, \"double, double\")", + "result = square(1.2)", + "print(result)" + ], + "language": "python", + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "1.44" + ] + } + ], + "prompt_number": 3 + }, + { + "cell_type": "markdown", + "source": [ + "Control Flow Constructs", + "-----------------------", + "", + "The main strength of llvm_cbuilder is the control-flow constructs. ", + "They use the python \"with\" statement to setup new code blocks to", + "contain different paths of the control flow.", + "", + "The following example demonstrates both the if-else and loop contructs:" + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "class IsPrime(CDefinition):", + " # prototype int isprime(int x)", + " _name_ = 'isprime'", + " _retty_ = C.int", + " _argtys_ = [ ('x', C.int) ]", + " ", + " def body(self, x):", + " two = self.constant(C.int, 2)", + " true = one = self.constant(C.int, 1)", + " false = zero = self.constant(C.int, 0)", + " ", + " with self.ifelse( x <= two ) as ifelse:", + " with ifelse.then():", + " self.ret(true)", + " ", + " with self.ifelse( (x % two) == zero ) as ifelse:", + " with ifelse.then():", + " self.ret(false)", + " ", + " idx = self.var(C.int, 3, name='idx')", + " with self.loop() as loop:", + " with loop.condition() as setcond:", + " setcond( idx < x )", + " ", + " with loop.body():", + " with self.ifelse( (x % idx) == zero ) as ifelse:", + " with ifelse.then():", + " self.ret(false)", + " idx += two", + " self.ret(true)" + ], + "language": "python", + "outputs": [], + "prompt_number": 4 + }, + { + "cell_type": "markdown", + "source": [ + "The code above is quite verbose.", + "It is like writing in Pascal or Ada. ", + "But, it is still easier than writing in llvmpy directly.", + "Take a look at the generated LLVM IR below." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "llvm_isprime = IsPrime()(m)", + "print(llvm_isprime)" + ], + "language": "python", + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "", + "define i32 @isprime(i32 %x) {", + "decl:", + " %x1 = alloca i32", + " %idx = alloca i32", + " br label %body", + "", + "body: ; preds = %decl", + " store i32 %x, i32* %x1", + " %0 = load i32* %x1", + " %1 = icmp sle i32 %0, 2", + " br i1 %1, label %if.then, label %if.else", + "", + "if.then: ; preds = %body", + " ret i32 1", + "", + "if.else: ; preds = %body", + " br label %if.end", + "", + "if.end: ; preds = %if.else", + " %2 = load i32* %x1", + " %3 = srem i32 %2, 2", + " %4 = icmp eq i32 %3, 0", + " br i1 %4, label %if.then2, label %if.else3", + "", + "if.then2: ; preds = %if.end", + " ret i32 0", + "", + "if.else3: ; preds = %if.end", + " br label %if.end4", + "", + "if.end4: ; preds = %if.else3", + " store i32 3, i32* %idx", + " br label %loop.cond", + "", + "loop.cond: ; preds = %if.end7, %if.end4", + " %5 = load i32* %idx", + " %6 = load i32* %x1", + " %7 = icmp slt i32 %5, %6", + " br i1 %7, label %loop.body, label %loop.end", + "", + "loop.body: ; preds = %loop.cond", + " %8 = load i32* %x1", + " %9 = load i32* %idx", + " %10 = srem i32 %8, %9", + " %11 = icmp eq i32 %10, 0", + " br i1 %11, label %if.then5, label %if.else6", + "", + "loop.end: ; preds = %loop.cond", + " ret i32 1", + "", + "if.then5: ; preds = %loop.body", + " ret i32 0", + "", + "if.else6: ; preds = %loop.body", + " br label %if.end7", + "", + "if.end7: ; preds = %if.else6", + " %12 = load i32* %idx", + " %13 = add i32 %12, 2", + " store i32 %13, i32* %idx", + " br label %loop.cond", + "}", + "" + ] + } + ], + "prompt_number": 5 + }, + { + "cell_type": "markdown", + "source": [ + "We'll setup a ctype function object to try it out:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "isprime = exe.get_ctype_function(llvm_isprime, 'int, int')", + "prime_100 = filter(isprime, range(2, 100))", + "print(prime_100)" + ], + "language": "python", + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]" + ] + } + ], + "prompt_number": 6 + }, + { + "cell_type": "markdown", + "source": [ + "Structures", + "----------", + "", + "It is possible to create structures in llvm_cbuilder. ", + "Beware that structures in LLVM are unlike those in C.", + "LLVM type system allows structures to be literal or identified.", + "Literal structures are equivalent iff they have the same elements.", + "Identified structures are equivalent iff they have the same name.", + "In llvm_cbuilder, all structures are, by default, literal types.", + "", + "Here's an example:" + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "class Vector2D(CStruct):", + " _fields_ = [", + " ('x', C.float),", + " ('y', C.float),", + " ]" + ], + "language": "python", + "outputs": [], + "prompt_number": 7 + }, + { + "cell_type": "markdown", + "source": [ + "That's all you need for a structure. Very much like defining structures with ctypes.", + "", + "We can also bind methods to structures which inline code to the caller." + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "class Vector2D(CStruct):", + " _fields_ = [", + " ('x', C.float),", + " ('y', C.float),", + " ]", + " ", + " def add(self, other):", + " self.x += other.x", + " self.y += other.y" + ], + "language": "python", + "outputs": [], + "prompt_number": 8 + }, + { + "cell_type": "markdown", + "source": [ + "Setup a a test function:" + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "class TestVector(CDefinition):", + " _name_ = 'testvector'", + " _retty_ = C.float", + " _argtys_ = [('x', C.float), ", + " ('y', C.float)] ", + " ", + " def body(self, x, y):", + " va = self.var(Vector2D)", + " vb = self.var(Vector2D)", + " va.x.assign(self.constant(C.float, 10))", + " va.y.assign(self.constant(C.float, 20))", + " vb.x.assign(x)", + " vb.y.assign(y)", + " ", + " va.add(vb)", + " ", + " return self.ret(va.x * va.y)", + " " + ], + "language": "python", + "outputs": [], + "prompt_number": 9 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "llvm_testvec = TestVector()(m)", + "testvec = exe.get_ctype_function(llvm_testvec, \"float, float, float\")", + "print(testvec(-8, 5)) # should output 50" + ], + "language": "python", + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "50.0" + ] + } + ], + "prompt_number": 10 + }, + { + "cell_type": "markdown", + "source": [ + "Generic Programming", + "-------------------", + "", + "llvm_cbuilder supports generic function (or template function for C++).", + "When a `CDefinition` defines the `specialize` class method,", + "its constructor will invoke `specialize`.", + "All parameters passed to the constructor are forwarded to `specialize`.", + "", + "The constructor of a generic CDefinition creates a new dynamic class with the original CDefinition subclass as the parent.", + "Thus, `specialize` can modify class attributes without affecting the parent." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "class GenericSquare(CDefinition):", + " @classmethod", + " def specialize(cls, data_type):", + " cls._name_ = '.'.join(['square', str(data_type)]) # set function name", + " cls._retty_ = data_type # set return type", + " cls._argtys_ = [ ('x', data_type) ] # set argument type", + " ", + " def body(self, x):", + " y = x * x # just write out the expression", + " self.ret(y)", + " ", + "llvm_square_int = GenericSquare(data_type=C.int)(m)", + "llvm_square_float = GenericSquare(data_type=C.float)(m)", + "", + "print(llvm_square_int)", + "print(llvm_square_float)" + ], + "language": "python", + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "", + "define i32 @square.i32(i32 %x) {", + "decl:", + " %x1 = alloca i32", + " br label %body", + "", + "body: ; preds = %decl", + " store i32 %x, i32* %x1", + " %0 = load i32* %x1", + " %1 = load i32* %x1", + " %2 = mul i32 %0, %1", + " ret i32 %2", + "}", + "", + "", + "define float @square.float(float %x) {", + "decl:", + " %x1 = alloca float", + " br label %body", + "", + "body: ; preds = %decl", + " store float %x, float* %x1", + " %0 = load float* %x1", + " %1 = load float* %x1", + " %2 = fmul float %0, %1", + " ret float %2", + "}", + "" + ] + } + ], + "prompt_number": 11 + }, + { + "cell_type": "markdown", + "source": [ + "External Functions", + "------------------", + "", + "`CExternal` is a convenient class to help accessing externally-defined functions.", + "", + "We define an external interface to `sqrtf()` in libm." + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "class LibM(CExternal):", + " sqrtf = Type.function(C.float, [C.float])" + ], + "language": "python", + "outputs": [], + "prompt_number": 12 + }, + { + "cell_type": "markdown", + "source": [ + "All class attributes that are `llvm.core.FunctionType` in `CExternal` ", + "are converted to a `CFunc` instance.", + "`CFunc` instances are callable.", + "`CFunc.__call__` generates code that perform the corresponding LLVM function call.", + "", + "The following example demonstrates the usage of `CExternal` and `CFunc`." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "class TestSqrtf(CDefinition):", + " _name_ = 'test_sqrtf'", + " _retty_ = C.float", + " _argtys_ = [('x', C.float)]", + " ", + " def body(self, x):", + " libm = LibM(self) # init the API", + " y = libm.sqrtf(x) # call sqrtf", + " self.ret(y)", + " ", + "llvm_sqrtf = TestSqrtf()(m)", + "sqrtf = exe.get_ctype_function(llvm_sqrtf, 'float, float')", + "print(sqrtf(144))" + ], + "language": "python", + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "12.0" + ] + } + ], + "prompt_number": 13 + }, + { + "cell_type": "markdown", + "source": [ + "Casting", + "-------", + "", + "Unlike C, llvm_cbuilder does not automatically cast variables.", + "It is up to the user to explicit cast types.", + "All binary operations require both operands to be the same type.", + "All values in llvm_cbuilder has a `cast(destty)` method.", + "", + "For example:" + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "class CastExample(CDefinition):", + " _name_ = 'cast_example'", + " _retty_ = C.float", + " _argtys_ = [('x', C.int)]", + " ", + " def body(self, x):", + " y = x.cast(C.float) # cast integer x to float", + " self.ret(y)" + ], + "language": "python", + "outputs": [], + "prompt_number": 14 + }, + { + "cell_type": "markdown", + "source": [ + "More... (TODO)" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/notebook/llvm_cbuilder_intro.pdf b/notebook/llvm_cbuilder_intro.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b647a1548d8c950965013b3fe4535650f814aa88 GIT binary patch literal 130681 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

iN>A%`R~DAGU$ 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

i9zDz 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

ZncP{NN8~whjP*zOezTgtlJrNRE{iZP0>|@V2 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 Tu*h5>M8d&1?!9}JHGcaqKLP57 literal 0 HcmV?d00001 From c1d3044c77848d238f6cfa693665c0e5ba31875f Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sat, 11 Aug 2012 14:06:13 -0700 Subject: [PATCH 029/516] Fix parallel_vectorize_from_func: * use signed integer; * use multiprocessing.cpu_count() to determine # of threads. --- notebook/parallel_vectorize.ipynb | 160 ++++++++++++++++++++++++++++++ parallel_vectorize.py | 18 ++-- 2 files changed, 171 insertions(+), 7 deletions(-) create mode 100644 notebook/parallel_vectorize.ipynb diff --git a/notebook/parallel_vectorize.ipynb b/notebook/parallel_vectorize.ipynb new file mode 100644 index 0000000..b0bdaff --- /dev/null +++ b/notebook/parallel_vectorize.ipynb @@ -0,0 +1,160 @@ +{ + "metadata": { + "name": "parallel_vectorize" + }, + "nbformat": 2, + "worksheets": [ + { + "cells": [ + { + "cell_type": "markdown", + "source": [ + "Parallel Vectorize", + "------------------", + "", + "The `parallel_vectorize.py` module contains a set of llvmpy code generators", + "for creating mulithreaded _ufunc_. ", + "It depends on the new `numpy.fromfunc` for turning arbitrary function pointers into _ufunc_.", + "", + "From LLVM Function", + "------------------", + "", + "The `parallel_vectorize_from_func` method generates multithreaded _ufunc_ from LLVM functions.", + "", + "First, we will implement a workload function:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "from llvm_cbuilder import *", + "from llvm_cbuilder import shortnames as C", + "from llvm.core import *", + "", + "# Implement a workload", + "class Square(CDefinition):", + " _name_ = 'square'", + " _retty_ = C.double # 1 output: double", + " _argtys_ = [('x', C.double)] # 1 input: double", + " ", + " def body(self, x):", + " self.ret(x * x)", + "", + "m = Module.new('my_module')", + "llvm_square = Square()(m) # Generate a llvm function", + "print(llvm_square) " + ], + "language": "python", + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "", + "define double @square(double %x) {", + "decl:", + " %x1 = alloca double", + " br label %body", + "", + "body: ; preds = %decl", + " store double %x, double* %x1", + " %0 = load double* %x1", + " %1 = load double* %x1", + " %2 = fmul double %0, %1", + " ret double %2", + "}", + "" + ] + } + ], + "prompt_number": 1 + }, + { + "cell_type": "markdown", + "source": [ + "Then, we will generate a _ufunc_ from `llvm_square`:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "from llvm.ee import *", + "engine = EngineBuilder.new(m).create() # Generate JIT engine", + "", + "from parallel_vectorize import parallel_vectorize_from_func", + "ufunc_square = parallel_vectorize_from_func(llvm_square, engine) # Generate UFunc" + ], + "language": "python", + "outputs": [], + "prompt_number": 2 + }, + { + "cell_type": "markdown", + "source": [ + "We are ready to use `ufunc_square` as a regular _ufunc_." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import numpy as np", + "A = np.arange(10., dtype=np.double)", + "ufunc_square(A)" + ], + "language": "python", + "outputs": [ + { + "output_type": "pyout", + "prompt_number": 3, + "text": [ + "array([ 0., 1., 4., 9., 16., 25., 36., 49., 64., 81.])" + ] + } + ], + "prompt_number": 3 + }, + { + "cell_type": "markdown", + "source": [ + "Here's another example that uses three inputs:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "class SumOfThree(CDefinition):", + " _name_ = 'sum.of.three'", + " _retty_ = C.int", + " _argtys_ = [('x', C.int),", + " ('y', C.int),", + " ('z', C.int)]", + " def body(self, x, y, z):", + " self.ret( x + y + z )", + "", + "llvm_sum3 = SumOfThree()(m)", + "ufunc_sum3 = parallel_vectorize_from_func(llvm_sum3, engine)", + "A = np.arange(10, dtype=np.int32)", + "B = A * 10", + "C = A * 100", + "ufunc_sum3(A, B, C)" + ], + "language": "python", + "outputs": [ + { + "output_type": "pyout", + "prompt_number": 4, + "text": [ + "array([ 0, 111, 222, 333, 444, 555, 666, 777, 888, 999], dtype=int32)" + ] + } + ], + "prompt_number": 4 + } + ] + } + ] +} \ No newline at end of file diff --git a/parallel_vectorize.py b/parallel_vectorize.py index 210dea8..a3fc743 100644 --- a/parallel_vectorize.py +++ b/parallel_vectorize.py @@ -416,10 +416,14 @@ def parallel_vectorize_from_func(lfunc, engine=None): from python. (This needs Jay's numpy.fromfunc). Otherwise, return the specialized ufunc as a llvm.core.Function ''' + import multiprocessing + NUM_CPU = multiprocessing.cpu_count() + fntype = lfunc.type.pointee - def_spuf = SpecializedParallelUFunc(ParallelUFuncPlatform(num_thread=2), - UFuncCoreGeneric(fntype), - CFuncRef(lfunc)) + def_spuf = SpecializedParallelUFunc( + ParallelUFuncPlatform(num_thread=NUM_CPU), + UFuncCoreGeneric(fntype), + CFuncRef(lfunc)) spuf = def_spuf(lfunc.module) if engine is None: return spuf @@ -432,10 +436,10 @@ def parallel_vectorize_from_func(lfunc, engine=None): # TODO refactor typemap = { - 'i8' : np.uint8, - 'i16' : np.uint16, - 'i32' : np.uint32, - 'i64' : np.uint64, + 'i8' : np.int8, + 'i16' : np.int16, + 'i32' : np.int32, + 'i64' : np.int64, 'float' : np.float32, 'double' : np.float64, } From 1009daf3fa032e94a5ddb26aa933148643c9c90e Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sat, 11 Aug 2012 14:55:35 -0700 Subject: [PATCH 030/516] Add notebook: parallel_vectorize --- notebook/llvm_cbuilder_intro.pdf | Bin 130681 -> 73415 bytes notebook/parallel_vectorize.ipynb | 93 +++++++++++++++++++++++++++++- notebook/parallel_vectorize.pdf | Bin 0 -> 66363 bytes 3 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 notebook/parallel_vectorize.pdf diff --git a/notebook/llvm_cbuilder_intro.pdf b/notebook/llvm_cbuilder_intro.pdf index b647a1548d8c950965013b3fe4535650f814aa88..a7b17d48308c8792bce64c244e7678e19f1fc6df 100644 GIT binary patch literal 73415 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

iN>A%`R~DAGU$ zM-?JOok)cGl{f#S#Y%}|Ksvf&vFZGghfH;8?CAdk=%Aj`8?KK2>A(1@*N1%tXSsX) z)7*PzE5Gd2%E-i#+|*LwY#D(fEP=wtFq2FM6pq_B-`E>svW(Bs`JL2@KVK`*mf>YN z^qfxDnL0^uvt#aDJvg@521@tr=FIT%`xh|QcCp;=AR^U(?4ABD1iN6U0w^d_9EYGk zNvM|ysXJV5XXaCvGdPeO4+8zQx;-^OtFWxhCbDUt>~=s7ah9Km z=clzN*Q{&HuBrj)EsH%Ar!P44s}N>*K0a7klQw1;&{_%mr;|PYgD=Xa#3smi0O^|ni8_6x}7LdL$MyA!t5&LxU z?j9Asp6ISuJE!Buf(5x2ruPDp(Y?{$DSYWOahb3MSxJX|Gv!^gg5h#22 zTkDEcj8}|5m_@+9h9)D&2?;3~f+b=Hx0K5Xyhz}P7gMmWXE9eIs*4WKkHuz&kG%@H zvM@d}m^#WmHq!y7EXl%S%PeIeM}kQwu0-jm-?vRYlzbmdKA3NKdT`;|Y1v=nw6JL5 z|$$i{HpCWL){hUE)sMqFFR;(#J_iV_5KQEFZvmBH;It z)q)tXh|-ISjDi5-%>_w{8ZnB{924Avka)01s7E7|ukfMK%3RwgBcoJ6zY0vLI@Fia z0(`%MdGoKhefZtGf!ka}dIPy^4Qa}jPqS`e>&&M*HC@vJR#W&^V3-<+cDxoH?BnVy z=nfkUUy0Pyx|=Yo)$A0JT@X17#{#lzkL{_zMda6Q;c*(qw-*_zzNe!Y`^EPMJ8~?h z(Z|!r^%4_zO1Aj}CqqLkMqv@N>7hMN(2_N|(NYFX=Z2{Q*Ulh`v1zgwbcEY)aF@lKVe)>C?)Ls2k<4)6c6RNT^5)onTGiUPS!Jkk zwew@BZfz3NXlZDnFYu~&S{qQ@Aicibls@4C{8WW@pcTNs-#P&0gc5TBJcjlJH57cl zwydYbUNLSlN?Ev zWLlFHvvxd=-PqJ4HDR26+vuiM^@S{A-IBzevo6dIcCxQD)%J(P+qa3~Nd zC}>ma*y2d1+!GP*)R*8tJqq`iCntANeoz@K30-w&i%ucXs8IG_KV2V3Ez-V6Xx?8KWnu$Rj*G}X(uBu-9(p?IV zs_s6j&TG!cb*b(Vb(7fJ_>{YNH>l8TPTzBbZTZV_yWZU4Za<-NT{d@2MEHb)-9j@A&0n-tD0kuYC|qf#$Hq7pik+Kxxt_s9P}vmrVbJusiU zl!4*Yy$ePo)nG6)2ENcnsL;LNA#uk<>4+;Bl{0VE6zZ|5Q(_X zYSA(p4_BsNTwJriR2W7nyNDWHNehUZLQC*GVty?tN!VxuG5@^Ev2YPOEKJ#CP6LC# z2(dYN=YIZpZ)D~7E3#OsJeY<^PyfRb=zlSQjY}{g;2sJH&ajf$fWG`f`qlp{DP>dQ95#dF_iw>4q zrMDRvbzXkXj;dROGRP8Cyf5H4)JoKeYq(FG(_=cGG^UhT3znba=U%>GiNB1k2lv|r z;c8OMtU~lmd}dKf)9e-oxy`)6SbQZ`h>r#h!uR~F|2F9oE|7(_$=+5{Xu2wL+NPmG z6T*vG>$Ket9&Vg85#{V*(EJqecbQFCYnV+^;#Adc?zb4JdFJx!DEWFddC3{vbQIMb zik(?(t~Eb#xiP&U*Ya>Q8VaSGQfTg+^ccDKZw#)><#vU5<$-mTin4c=VJ1eSnyUrU zMh>UyF7gMw=xMX8HJJkOe&p--gc6z4{?)8_0sZ^JY!kk+mh2lvt`LoZJyGAhA|d&D z!2QvqzAC$O>@fHP_2D_?<)&^Sb!6)BWt+4Hliz6C%7|uT-f5vMJ~rNgrX0g+JfZ4j zW*{qbbd?1fl%+x0;DIHXSjkml2W!WU9bUD(4^~o@M@iFFzV|L^R`t8{*(RCJ-*%%I zYohY!u;rZ{!i}#Qd3(wzOi-v7XQUvcn!K3mn3VE)3_jhOf(+QlEpKZdv+Qp( zi?X%P0o(~!N}c^e-S)Qu_Bim&hsE_Jt%L^iIR(B}CaTUHG*8oRMtzXLW>#-Vm@wgw z5~&eBikUx8xyQ1klM(2b66tA$H?eC)B3#f$!AcsFgg>^*=!yR(0meoXzJWNvDAxp2HetldZUm2~|Th6~+=y0QeX zqk>+zz8N?mTc?s;E5&V$0h&wwV*|iw4jx$nL+XAUQq{-Eu&r@CJ=xltJ~>a-z!c#b zLtXsqL88>BJ|m!yI}Z%fXoh_2TcZ*KSkV5VFNovniMmsULWbi2i@Hg0sfn%^u-UGc zc?Lz`9s~T4)>>ezUg1xzRs{`l`%URz(g1={3??ms&?sJJpr9rBuOJWdU7Efpq-N|<- z4zt2{A6BCe-~DEOLe~>;Sa=F9;j~I}12BYt$V|7_{#{)~uPL-D@&W@1=}8xK0n3Pr zarvjQD=SAz+C@9b2&wkLwcTq*rq6|lZW@l=WsV*SL;YTSL5gw+k`os4VqxL@SCFWO zFRNXh)9H-Hqu^%6~xBMRW^y4wBTWL5}eYU zj1J2?|8H@neOCMG6l+_d;VBFF0UQ5&M$o03XAh401!e8^lDI%!Pl|<11--Zeqb!ib zC+q#tmCS@nh6Ji8Q@nDTC8=tYv*vpC`mPwJU?Iy^hcB_dwpb`9Yq#T~D#}IEGyfM5 z1h&cU{E0Y87A-u+cbAcU%sxFf)xQV@`xkk1XzUi;smSvO-Ds5T@WyYW zZ~TZwlS)(wH!~WG?A#IhTdiYPUrzGKR{%l_=W%JBz2=gNxMR8~>@0w4=D9)yX0t3#a1&{G$^S`rUqlixcd1+e`}2 z9q0hr%Iyk!Vq#u{QjyZdi`SG15AtnF0wt{dwcM^gAXa*lcrYpsIgXf%k+7aDeyyCn zlu#r}ut8zKkjl0h2b}?fhQGYP5tW3}Q{1*nbcIl_pL0;pA7+wcHl?ThhDKd-)WF{N zcpS>W!|Nqy2c6CL0q^|+S=!`b1rLAcb#%sC=u;NVxO<7RJpE@BeZ(beOV#$NMpfoa zLQflxo@y4UTdaR#pbH5yo(Ta&uT7IAo(2*uY920XlxCfhgIqsk&tB*;{nQ@<4s*i~ zQwce=!w8Tbyw(rEaMr<@yI+aR!$Tp+#et>WfgR`mYB7Cg>i@;uJq3#ngnOc2 zwr$%s_Ofl;#$L8<+qP}nwrz9vnNxSpoSKW*TY2kBb<)+}L(-l6{uHg*c{j9fBT^ub z-KbHV0&LceoQ_7T!#7d9xRWC-CS&gHc5J57SK^XPRwZUNcb4+TA#kv6qgCxfMbI9j zIObJA|K7Joibr@RC4lV!^(8eo`Sn-xtfqn?zogMK*4`m;jXcq=zINDpoHsK)J#MgT zSb1!Axx0*|x}VqXqeM{CEBb2hgK0Je zqN5TFb`>H*TLE9y_xx4)@B`SxE=l$Cmx=FUbPD3zO~6gWjIFz?gj!G=ZYSu*hH#?6 zlBrZT2qBG7aP^^sn}e$INJAle=5OWMBlZo&VZIkgDW|1wyQUCMqY*Ek>mi>cAbrFFB$JUQhvfGfwrYS% zCk0lS`o%f@hGOzwOF&~cjsYA1q>k#$8=W2m)4b>Ltk zVq&jFIX&;g<_dxA*R0+s@UfmnHf#<_3_0)f?-QfXjTfOxqH0z&h|6vtdTIkx(n)vc zwBUW|9?BMNfH{uOB^vL8lQ=l=W1$L~l}j5M!@f@*EN><&4WD%0wQ)t_&dE zo1Jlxw~acaAg|^kpyiLgq0n^ybkcXLH+Z}Cb6`_!hVOax_-Am$gWIX$z8`ky5>P>9 ze{VHq+h_E7GRECIspXlV@tdI0_UM$|G<9#;qK&PEHl^ywz7#1o*_NKvh%}AB@IgH81~y2_lk^{`n6{1dvg*JM&lF-4z7`{1SNNUOPGZ76GF zCt`*-GBE+0?SqC+&o-)9UqI8rri4@4Mv~GTqu{L?*e4CZCoa$3tAwPDFDBJIEE9)B zY|QFNhp2`e*O;28M~cpGQHEWyh-pF?1`T5`1nTVps6EH)b@>l!<}_YsM;fn-dYlS_ z;FYUB51h?mCW|RTv9XMQ2nUNBZet>0v^2bsBPP5MQlI1j*gsA^N@yP^l)+Ztc!~+g z6oL84$P3O%8zVRp0oEYHxD81erGTMb`}*1zYbqcWz#~;?cZbyR%CW0{vTq){51k}& z&~TW}OX#I8vg^6q?}&EFsa~>KvRrk|HmuS$Xv7n9lyENLVU+;<1^sGOHW2kQKt0&az@Yzd!hN@| zubZ9y>>t=~Q>bsU$M}R^XGLeBHh-o(wHIc@0rtP=Q11|FR2t&yu-)6B-E=$DH*24* z-A{JxwKF7j{5k7zADZ7hfpby_A%B$S3X$?+!@l3!XJiHF=bl@(uYi(*CkTH2%8~8K zI3zk4=NTJ~=OB%wWF|^En|1_3juF*2uxNxwAr_x6LKyy$GINWX`1p$PO31CPty3eH zo&AcI2t3ab+!O|(m>KvENdI@~N$F^ejp8V2FuCpujaiZ7*?6mGtYzf4GRT+tYT&6o?Mb%lNp}2Ji)5pf_F%PZ zW9|K$W+GaoXtXo1bu~itcrQf#O2c5#Qf8=;uaKy|zwkhf&Y{bN`A-)@>Es@D)YPaN zH?Ooh1Ki>RZ=(gz$WUN=3qKx6&?&B*Up_RnthQN6RxObaax$zND`Jn%bV*ZJ-nQsR zld2KIxe@4q#GPOFo_E+osC>fYV-$-2yMFD`8Q{Twsj7zP#Nh2&@Ykgj0Y<4!ohYTP zED-VKxEQnL3%oXpH(3B;aL-Pm^O2{S#d@Uves$N4ab{aVmrp%0Nts#x2gOSN`MD{SuVZd#Lf(>eS80)Z0w6NbST>ev-40Joh7=;Ig3WbQS z?G)pPdNew^{6$NZQUL$Vw#>u}n7=*WEx_7p=htiW0X&4aqH$}e zUy!aTp|(28F6uVi%(8K#LDiHo*bQOp4=0+$Q-Z@d93-__;kwKf$>aqOqfN>!M+S_|(c-JP)cq6eE} z1}e6x#tAX@t`F+%&YL+|e;-^Q@+jkE+-0hv6c=@c>dKn+PCr%8qRr3BAMltyu!PMn z?WBZcvcXv0Wm1nwTqZWcN(QW2EY6MGbjG`*ka|1k5_#J^4^j1B5FZ9&@QedbPb3Bq zFxK(vao}-j89^%`%-C&2sg=>I2tw?o&Sm37OGT0Yh~*+gc*u~B!0M>sM1JbyK917P zF%`=*q7yU^_j2hRJBU0H=8L(xii5;jvPTSf&e2ir+^_T+cRs8YjyGOW9W|6jjUdhL zKYr<8eSFwBHKD{mcRPyZpS<^F#no0oNY+e< zOIcApe8O|{{oT*CnY8P=HA4pbN?dc-N~PaaG(+>+lj!#?_Nu>vNeCp*fR128^9<7p z5+Py?k6h&HCxC}mRTqA<&rJ21%_G%pBwZ*CTIo@b2fIASgZVpAE`Zkang=F-iKLxM z)4_+-FzG}W#&;GlWXQ0bJPY2_chHnWY-Qx#W9gmNx>HH5HgsS#g$Qa>6 zpCL?c@!)k&Rx<^zkTMlIbpQi_I=qBs3hK?gPY$9*a6wq<5Q)=tn5ilyRrhR4q%;oU z(*p=5^mPns)nGWDbAzXTAFdJpnC%1ZWaja1~!4(E#3j>N7#Ed@hys}Aq|=WoIdXe)w$Fnz5c4?cZ- zn7V3FTB)*O6pt9?Zw2dv2o%Y^1Z!Vu6dwkANQz%M8W%6<7KQ#)J;_Pi(-Hr@ z&8p%ZvcKJ7Z_oRQKQMS&8!$hoCmY8N$D2elgDpygh>F)jn{8;!Sh{%#28^TkQ`egM zQGQG)-wa8tuCZ`DUtq{%ct8#E-<%V#*LHPnmd^TAglQY!WkX7qLqRHR;p-PxtZGfH+xK{H{!5#8cn0~)S-iBCurF3li8k< z6Lj~u5bEg}bJc4}xr*lvT8uXbgUep6o&=R4>Et{n4RIlzjy$tTqu1l*7Br6^$6GJJ zC!=a!xY2ce(=<@@wBiX7Nl%YL7l-F&@XTaXox|jUJ>>W#+EEHm%U~e+#3AkQ!*jzz z`xvw#U^Ozq^M@#k!OO{%g;7ag=EuQKq4J}xR#ZVq&vNCWXTs0Z6S29%OBoCxj3}(I zX!Ka>Ij&8|(}Q`M^C-STtU=#1KBQOyD#0`qsPz_*V|nkV?~BO6JPk99#w3Aj7@M%h zCK$AlSFl9opCRFhV-C4ELk_Lymz{CtZj~I!aw!f{nul1~#mb#351f>zyOD`v>{R5Ic>f}Fc&3P##QHJsSkjyKxrnICjtjc8{UAQbT^aAn8^(o7pY11#F zNaNK7sB6b0D@*rx*n*eB8YnBnZQ}Zp5|^uq}>zoYx~Zo*4z^-o97Dxtp6<=-$-ldzU{FjGySN|!3%eJ>L?4031nFb~&bk_>1UwS_F9Dss@T&6DA7Mpizfoh5sFxemQ%nH? z)*YboQM#+J)lo2XWPG}#E)PXV&S)(-KUN4ld85V6e-*}5>f$b7(8|8P+)$sfyP)&X z*m^;(wp@lEU!=xT;(MZAS5aj>n}L<3)LKrtt=>^Elca`LJ4cpkVw_wwblxOk!uxpZ zPPDSEgPN0Kr?8W%tIuxPjxuW*QK)8C!{Cd~8i2hra0-XThDin+MJQ475;1IGP*0Rj z?jfmPXwElv5?#_6M}Z|q?H!M(cr=)_$|86+tH2GB=*l7ZL#0FG0F~*{fs;ztR*0}w z8d#sJ|32#k-{#;2-B9#1XeIh3W@bE@ko zT$gF)S3=f;U@d@}+rj#y&$Dj5Zbj%Q)kHcxfHJg4(JYoPK7^OV5dR0MOe73qm0AFQ zw+>=JO`s85Ze#uJyd=$XrE%$CIi6F-)<;Cu+TS2CEGg(V{-~;t&EOa(^7jR;+~mbk)lV zYvV>cYa^m<05MK<`r(l!{Xdyk5}|-FWA8yDqDo%WI7}4D8CFJJ*lDi1#kVvBj6?Q75LfCsF;ODn;PwM;8_vp2TeLD)?TgS*~7J+JHQM4q$reAW-v?99(Xo- z*d~@Zr|pCz0U;H3f8}XP#3yHFFFRtmTX3k4WXNGhB3?$>+pV<*%Fbq-k5R5LMa=C1f6{{JFeMop{NkVxa2{n&(1xt&(e;)~l8Ze4n zE73|x-VLfjk_bb_Z9;wG1%-^1R3&kNyk7%JnuL)NahwvTa9*8wgxEzm4gyuw5^$RC z1Czx~C25y?V>5e=vPx4F?W#Z>ta=*6&}>6~Lehof_IZ^0iI z#)cl`6{}2Tu04%@hm!&}mD2bQI(7Fm5Ix7n3$7WktE?1O3!)2Aq7 z_>zR1vT)+6yVMoyp!F@GF?> z3r%Yz*|~4$olX3p-0mvFUBF8s_XAXe&%g%` zwb^qLEwUrMHczyA3@YE^o$+ zvsYU&E>BY@P)M7f>yKjeyBy)~gsApJz+8yrXu{*xNT-oh1F-wHYf+^Lm`D#~8BK>2 zDTfN6J}_Ub2vYR9hN5DZ^~2$V14s!!AiN=&#FQji)Zj`o;noUzLvcELlFK`Hq<6Ll z*IsYhU#L6KV)y_y)(FTZg%7>fxTa-cA-&ZlVf+s5Bl>tEuEM3W($ASne>9Ad+mqGH zmuyiDK;koH?$bpzYH?JVz>~?7gv+PGKBoMbOjC~nZCmbi>Zscu5jN1#feQB?gktvc zkLLbrblm9AgX5;og*rLccR*aGr!}ZRpD^1JVh;)UM-i-PQw0!{F|s$WREP8uY>(Z!L?o$eZdS* zeo;>NCn{HlZ==Y8$FUP%NthX(FGvwMxM1xSjOS$jEIEpM2cl_IB`=Y$cwXl}e z>b6-M!E4IS(`z#rG*e)IA+Z$&ST-9t?FG$W55%0EKsBZHVk(360kAJ7^hrnP5pXvRqyO>LPK~?eMXa{0<|x zZ))O{>yx-KbluyZFwnESlk+vQf86?A*9_5xJ!V|kOOVeYfV9p1jMbcf>zB{@kqXKU zeIP0#Y5e^w6}2>kI3YDhMn;^JT3~N1!aS(1ADwY zM)*VdoynjY67c)UmNrTOHyZK)Qhxs>pCho|#-3!BKXWdx8wB$u(E_ zKF=twK><9&Gsc>yy9De?e-Y4H9#<(KREAwFR0C5Tu;`_9sjy#;e$#EQN8VJ-dYPxf z=_Uv}SAzKP99BaJ5Aobd5G`;`x6i*{9rCH!gftN%Q2A4NuP}T!Hqs1C{V_T3$NjgV)$zOAjMq`NG?qOR22$HQQG!xUS6 zeQ~a{-Rx5A-gdk40^x`EXEHc^F8@5Y4Zi>GG5C|A3r~Hgv&G6<-))S?*9`)SqKtZu zBQHo6koBnsLvI;0ohi+fy$c(OtPSl$99jN>-jg2t`Udx3uU4|mz9xCUbo$eR+w<)i z>3+PDI!jxfE=j7B(z9cqquW1$vcIS>zrPe%N7<-?^hSca{TaZ5yE5`d@$!@8O+^s6 z$fDRtmaIR4h?l{?!aM|dzoOH&`L~R2a4$SC?>`6@VE%qqpb#EGE{#su#W=3WroXVS z0F%`i7`T@@(80h$CnZlJ=canA>bG-g?N()@TO6x(J+*duooWsIGb-(aifl5d+r$Tg2eM z_=0~9#y`&BA2VUXMDRaVfd2jLq38vij7)5u2{@RU=vWy!|26zakN?p^ z%lyw9_$OQZQxBX?Y*Yz2+348VIobaknZe3I$HvLX0!1(3Y+!9+Bw%Z1Z9?!L^uWJ6 z5frp@BhaE{VxePUWMTYY-4U=caL{pZu(AKIOaAYi0n7i!8T`MB87!RtO)t<%n6?dM zKnS|!364D{Jiy0-BrHZCf%{gl!1r5|icpR+8S`(gy^j;7LK4q)HD#ULpuK2F`JUQ> z=Y0qzHw(%U0OV4KQixQ5hR*|W2I^Lim}3^5r2tS#L0Vc^fNPgY+%fh1 ziY!caM@=Xdj{)%sAJZBGLBc3N2wj#jgoh3aVv>#rpP&c;;YG#|ts70FqHL)WZ@n?? z7J40itXwfYeJNNsskOQx-M%frTE5WS<;F}c z1gtFoPWxAcf(A|||4|SG^wJiFCXNQq7IwD(QG~RDcGkxKzce*i|7(2zm#M+X!pZjk zVQO$PaI*ZjqP+HW*G^hpzT$9=k+zlzQ%%fZ(W>Iki2_@m%pV1_AMt#{dL;00Y|w4m{K;22jueIPmty#oo3H-F7Da z^CJczu*v44&6$UXx(nFHp-F0Yc6&wPUYON41PGuaGAlZp3@*#_W`spw^swC*c1^u6Msa~Ye)=NsHm{Rw&!2(o zgU<_a3tI$+J74qckACRZMNGXX-dj&0FTH-}d$A+lD_iMcsx~O)rUd|1bwGk6sQMvl zvK|OjFCtGrBf_NKU^xRq1RI3VS|jKU1E8(3Iv`*8>N-r(eM|E|(mCMOzQ1*dVE3YR$X2`V*?_hc$59>0_^?;X~a^p8H z=f#Lv{d}Nae9mKFy-AFYEXx$d*c%@~%#+qF48}-2{+q_>x{PKGQFYH0f!J zL1G8$7r0IKE?K(yQTV16*@sO~FCEqaL;3v6#*LgFNz_Wsm&OEg7EdXQyf^G^?T|kJUzQFoxxkkE%0 zQ|;v#CcUUGCJJS-0rRQ^U3yRzl1$5bd{8hB8sG%? zE=JH@=m{~G4&lvIB4lv;mczF#A-67Bs{Q|skc}3{Bk@B2y!@nLNF(ksC z#_0hZXu$B=)IrU?R@}mv6F{_1DSNCSJ@c}R%BZTt#23-K_S5ULR=>($m+FM5Lw#+$ zLP{A>ex27cgRa)2Xop^YRo4dmHczFoUBUrq`5VB$AhbRS2j;YGig|n^bA@AmiYtc4 z`3>8{-`59T$V&SG?nJ^5N_b)9`i0gbVVBJapmWvn>`i~Mj^Bn4qn8CsYN1f##ie2q zYM>9W+hf>?;!7F#>d!VR4X_6(7_{2A-X*kYc2OQ@Qu?M29-DKD$R;ly^Q_a+$3-41 zwhQ8=+{WJ~<1Io*+KTK0cpppWLS1vhf@98S*7DDK@!`?#6Da&pMjFi`9@iorbB90JLGz;sY^5?KJg~15 zh)vWtRLR>WMw(Lo?)S?31Uu}~9PbOeds#~QJ-jT@1v|b|Q@Bnm_RM}a%SlJc@o+hqAKZkSAhRM%kvo#nAZs9FW@Msn zyTknWenA{na*e;Xjk~NQbiXE$Yr$imjp!3_Uy^HWfCL_8^B%>w#L?)|^0dI@{*uuYWch|w&24wDY*WugxYwdU1V{gH^_GKSQ z^?>h^`+CO}jKYuQ-1_79$DY$U;%~{#-wHhFhmMWF2c~*GAVvho_7x88kB&3N4luq^ zZlC4&A>WbkfXWRr-!Z$T@EkcE<@!L*F4`Qd-T`$%(DzHYVfq07Mjo8l?YrK2z5#bZ z`39}-$vJCrfz~F5z6bwS_u=kC+r@p%E5?Fn%}pYGM(u|G`W_m83+ z{{a39I9w}nz~}aZc0j))Ae^s|%3mqvW3f6rL5?86h|q@Q!#$h#*+=z>M-^zvz>FB; zj2Hot86uGxK}k{+A}Y-XS(uMFPyPFWT1msa-+HQFyU7smq!9KRMF-j*Z)Q}GW&pGe zA+jDssvc&ECMXhdU+*S~!}Hhp?inA(JV2aLZ2AyjI2$2?Q4^xjt%O_#qEsD0BAzSb zK!9dQfQKY5Rwlr>!%F$`dLc4kir&}JIbTAKKZQxzQ4ZWK$3h1CJ3h(x-wP%!hNP7UVajmi9A z!&|5b0qXOR&Ilq!Zg(GfmbhIrJ0jlB$fgT|^JU&54Su5Pj@+jRt7XCk>KYZJA_Xz= zQas{nE>SFzk0Bz7)ppXSI`f4m;G*wKb+B`9dM)7$Z*1xinW`+6xNK`v(5krUQQoR3 z>tm{jWPY-495ShmF|>j}&NZHfyh;t2d*>kQL$n$|nlMmiU}!TI3ke6o&=F9lv(#g=jVC9@W~N1%i_+zy z|J;nNyw%{~5D;*SB`O7di1lPLv(76SyVr>Gl8OqP9k##n{~`);uXWQqvQlU6C$1-0 z{>e#j8SCG{>2SZ&qgT=_W5e=UiL`1N#ORWf9r2|V;p0gD8)j*NwlEhJ1 zqQup4)Q28a#`GNOm!3S* z&Q~%ivEY7VoN<&e<7;m$BAzK^!r}w}Go*Ls6-p&sVp?KdqCQ1e(u@NwoTV#qamz^H z0xN@6qd#M|)6V|h*gj)zc-jl>)y;%p*%^PM((0PJOz`3^3GFf^)-%jw>~JxUKC2A= zi6U@8kc$@exx*gCtqZ~0iT^tM z38u$nrGVWg|5;5J-XP%R5u{^6#EL0hP+rG-vpo+d262>aX`MJg_g0ErRS@tiBqk`F zsOO=sJ~Jmrd{(76c+`{u-l14L&~SHbpz_4lN+R_)*(r0RZ*m1wb+1lF^)hRBZ0a76 z0~$4{u;YYs**#j*=Dat!Vbr32J4$n0sC=53PpPr3UCLP#Nm-$7CBf>BQAM(^EFa#U zK#k^LF-vG+rsDR{a95I&DJ(DX5s@}1I)!BdAE%{JFfR@V zyNJsMNkcSc&lMYH>7Y=ca(LS$%m^!?cimPbjN>-cJS9&Dd zr>vD^X~Fu=&9W99bksM}L>x-jWMw8v8%LJMCuWgEKQ+Nwb#EU&Vr$OuFs>b39+(|j zFSO_Eg9$zb)L_+F=m^soB4b#%lMZBFylf)TozlKVD(2m+`WUc(o~q-)GOn<|IUbV% z4EmF#=ILKqSIEGlQ14?qOJ)X+$*9p}I9q502i|&&XWLR(a#5q8WF%G3l=*MrEnMxs zn+Ncs z>0CDz`DcZKQ1SU;8xB-r49FnpS7oC**XfgliP`6DLkGO7Z(r4IYWHkRKBy$aW&BBR z(pURC#dgyP4rR(w?g0*0Al@lYjIR&90G1p4sJ9&F!7lU)SNH9~9k=H$=Ut5bgN<_+ zZ7Jt$Pw-*dIfcg}L33}ooiv%aQeyhTdBSR@Tr$LTsNN`KKY8|d_O0txA9bjn!R&8? zy5koUQ~&$bEE37+EYV@sp*hckbUjN<1MyqAp~Npq3%>-#a?BBOdcrdZp97D;0)A=? zJpQhyHjfL7K!vB*n?nh|KUG{AUY-YrN{sydaj3#C10JGv5cT~&cm;`t0u7meGF2d# zM@`9w+%v;6d3jEeM@mJkB?1S-IAV6z{u3TmijUy(-?HzyqkN}O;Zcqf97bWT*pHk6 zW3eXHTdzAnET6n@|8ejcUVv&qvjzcBn7g5yX*5^M8;p&p4%%1#%XA6y4$GoN^aF8x~f;O>sp7iACpj z6_mW2v+67f`9K7of}nP%I+NRrBX)HiAwZU>q@!O(f{` zi4~UrH18x6(K?lgr*b+K8#LH!a>jIoW~U>CYhJ43S2)rAC6h3#^j@A)iC&(OFR!Yo ziBRD*Dk7Z`m$=1o$@%+{WvHlT=oCfU!HM%c4VKxHUK2TO9%w3|SE5&qzY^)ut)f?Y zyL!8vyYl&z!F0i0iT(k22_R-jA%->TZ6x#0X_{^u5o3?jUq#jJ+Oe`dk`w!es{Qbw zXQ^!~FoC(>tlr&f1V~o2WVaLD>Br8rh$0BEAQQXJ75fWe zF;?Kb=;%m`!)zZU$!>R#7#R>=tM(E=$Y(_%`wV0vw^~L;S*cmVL;oHIO|iQHwfE`Q z%I7Pqck?;wOF#Vk5&LV0QPgpsblwvKLndEDbB<%uAxHiD;q{Q9%oymX8sx-sN;?rw zPOwrUPZodG9+Pi8THJpT`fT-Ce_4&dWAH0Abq+^ii>rtUGxd{WZCUg+}%5Z4xgZXm7wOh2EwN z=c#}TZsR9k!S^f@Xx{D-14%VRuA-W1;B#~MZ#@N2zj=y#sdZtjmpg<+M1aFUXf zv)|8PYR!wq+H~ASQBXCi(WDIW_oMcueekBX3a-eSGHobnxFkoV%iF8;Z7CzOGNtOc zxTr>KGfO`@`r+ZAU!%NT76Y1_IXNdiA|gFgO-^aFTzly#nd|G!`@J>=O@A&JRsO~) zcNR8&Yo?AXyXttJ#%Nk>XsKI8_Y~L(X>FS6F_#2Mrs?-0{#1Ohp6!vx^aNWs%oBtWEuISwI0F+B6VeE8*A!xlV}t~s!_ts|2nlp* ze9F)w2Mp)!&vob1u!!SU!Kwt8{~@+|U;)lRoaT$xEQAE6Xw=%gLaY~AX|ebGH|#lf z9-#8m;g$lkO&ScdGVe)Ko$iWgFmtARFBNR0Ya1I5epTek@j2tE*))9WwRPrOH7^hA zuM@49?6;-^>mmH1LSBCQ_wANhzRr*2gxptsknChz$X4jpM&2T$4>3?bBR8B0@t&10 z9vTKwBhW%feD8n6+_v)&-hvFPwI@oQ0BHq9qcg@5LNQn}7A6}6Q3TNKlp)5jy#572 zJh?VRK^dBHh)0ODO397dtqQ&>e>q>dYNh{-zD=PJdb0YpOH^UW{_`$hw^S2`ygOfI z*C9n2(=FqMth zFHi-9lpH?q{n%33_gC%H&p%y4+F+nZkZha}g4N-wkt*_}g_41UH2(Eo>5e54`w`u! zf+E36sEs6SEpFigq?HfK0hV~bt3eb(#>-uE7*rC~Z5RZ}h_sxG4S41jE~?y{a(Olh$|&zA?2p0CpOIB7RYKU z?>^tRI;NmvN}6dtG`;J|A`}SZ*yB zS~85?RAuK+2W5s~O-5f{Ia;ZzcjCPu_F+ZtHBOLsv4eUc%Ohk|$W2PZVxCMER~xeg z#)2UP6Dy#OCnXzc=MV}5wAm7d(PkOKT)?QzMP|0HOVkQiIVN%?1$!WQRN?Z6y>jyy z+TVJATJGlGQmoGO(c0W;C_hcI62c%0qFH~DPr5uoZ@u+6E}4YlcF`@dy5eDD-^)NrXFDWB^QUO7HblMSFz(=O^iQ3M^8Z%|b= zq<=3>#2uJpG3*m?qr09IhE$B5JaBQD6NR1Q+VSMyx?`uFIxx_vmi zv7m=1hS0DpL#8)fp@W6CwS=I(bz4~}1(U_>rt9pvTBfzD?fN3s)*@=6oDO2VZaQ+5 z_w=}U#d+%jf#(ttc#D9R>d0?|JWBM*uZ5^KlYw^yEcbmn4cb^)DxSwTAW6XZdszeyzecD3Zas0z|%kngAgK zA>b1j@8V_R;rzI=r3$VPfgQ^ELV~N~aOKk(dS>(||AUxIr2r?4J2~D;9EmXv!$&L< zGWIm9^r#%l^ow-wX`ziw<<0v1ci}-pw+eJh!tFE(6Aad2Q zh6wo=%MB@(PLUE4jdM_B1qCX!OGpp~vSAjv5n~Fou9)!Xh=8>{3kDVl@cp`~DS2?i zoBNcJ4R#9AsTIpSTOnuGls!}>R#)j+ezld$(!}EJ`2sc6RrK)4xhrE1NDxa%zzAwl=^?~CRJ<7q*aj+fvxd!<-tlRA^!yO-i~w`H0wEyxOztRlsh$}$ zrvkZbmOi=c*VU0kFnjK;&Jn{yHvjJ1qql`zo4K5F0mSZI>V$a#eH+p zr^uWu3eDF6imu5Kda0q|=Xk-QNL3jY!IUQHv7s*=mLns(t3g-Gg>@QzRQte7FfI)8 z0MrGu(joKV@^b>Aq8;p^i(TV9ZFs14Wr2tfY=OAoibDx4|EyuVxFQ*x>6%iIdFMf$ zQL@^^6vV6k{+olnvZeM{7Rlh|7{*Tszq)$HcKW8HJ4s|6imHZG#>q&}u-Q6#Lni$t zoy3^kx9D}Sk)V;KjC+nKYiS+>mC-m)dH1BIjntTK`>c2WMXu}XHu}wR*V-^9<%++; z{P0nkv8gjqnxRk@xe%kXD7ui*aEP!_8=o>KS@wcUIo(44f*DI(?qpdObzZKZ!8Mhq zk^>c_Rvxl>It3Kbx!I(>5SUi4S!sd)XfV~{!b1RqjsGBGqj#S9H?9@kQX*Xq34e3A zF)AcknZwWvRy{Xhr;&pV$3Vh(nUlhmK8mOVm(iGph)8;3${3-$Gh(FcIc$Q|@v8!$ znl+)p8?O?!uJh-SaRpt6e+rX>(s_*DR^4MduF3FVFGlw}x*EE4FPh$*c9*x&@5lnG zNH~oNxBGg?H+k*)%R#lw(cfCjUI&qs*YVO(8fq8n*MRNC)JW{G+H-k`<(RY_4sHB! z9j+@Vp}~Z&FHlU&LgwT|T!AYYnN@6L{+)gvFq2K$tO=up&+bh%WO7f zgu=)So=GTnW5}Akxrk}kW@&m8ITVi-wxQuEdP*58&2xre^ROD5B5v(g^Z}I^&I?cs z>nQdH_xhQ&<9Z-mzDmm(9Bi8C7`l4eWWh>7K{!d>a0zXSa^Y^{NL39T3t$Zj6OBf7 zRn?6CJw;4Gla9eq$8JS0INycH8;dQXu?JXYz<6Vq`T~5YVpOg0t6`-baOEhVbYi)qeaO2Yi`_me6wO4ZugiVM4%?UgJe?S)nv|16oZ?zOCJ zoN9J;%N7LRo0o4L7!}s|EmbZwvIlL2Ldr;-7#;*lVNtAQLRkyH=sIr{RuEM(SSfIl zd|6G}XQ_Z9*WqE1!pLyT`15d7$v)*PYo)$-WOO#rg3|InJc)7JCPp56V0qi(c0)kb z?N9SabXRHk$|xx`PSJ^}<>txj$yRoB5>Tb5p`deDS?xCln|hsvU|c1uK$Y>9h>a4? zh+U#}v`FYNY8s-+R3uU~{1cp&n`Nfz6_}YsGL~r$dZn%oLQXO&O=yqa#|G+|NN%&= zWtc&;DKc$B#+QRiO%A-M3C$#<_A2=iHx!Vp9|)CzJgTl*vt{vY32poRn}(eXnwuf@ zVY9;{S76zz3qY}78``Tn{*%yzXda=bjD0q-Q?@QZJ23;??PEi8>73L$(tRz+R= zu&7w}((}I`3>`}p^I@f&I6M-25394ZGfRYX- z0B8isNLPH+K^@%q04fQyi^23^y@pgl_Xx&NWWo0I3uMs!g!1LJG5nhA6#oS`MxBTT-!9G$*my-uRe$;uY34p_zCM(1G$U}C7)C9pU z8$++gQ`EHe=sfQh(U>&T6|F>Dw5jl4VL{Xe=c&C^IdPSLp1XoOMlZrX=Y_Z|uf^}^ zb@8RR#b0Av>ueb%-lgAscsQAay`gKb82q=w{`&W1B9hHIE_t8OeUA4CZ|mS@BALEY zS9`s#th~cEeT$pKbu6bphVFGFrvKT|_qF)aKkO!$bwc26rCV4Y-$t*p>(ipmHQKXo zaB*{&eD&p3Vbt(q`_It8!4K?{ws7fX(XsbLJD7z<%s_ap5S4F?@w|L#XYC{}#p#&d zn#9ZDFTK&n!|`Ntu}~xQV|cOlQQa0V$I$7?>B;o(!@tbgvG)evH#AN?vHjolrSFes z)&2to`%kkMs9Jl(w$A>=Y5eH5uRCf3|=5EQ+ z!<@2=v{3k#s1|u6XsM;JcyDNJ+gkEpKGp(zh|%St&85LBZxB?sK&GFk!)5&@n%0Io!@=4{14{dF-o#6T^Fu& zrES}`ZQHgh?aazb+qNogyVAC8+s^#5_U?VU&*^jeyLa3kcica*B1WuOG3UFU`L4i& z{sl)0Hc+G~CvE??PD#dM#hd6f%JRY>q$h&<^K(*Y?Bk1jt1~o52V&giHj|9j8A6X| z^9s#%zTst2NzQqgmNm>~4qFvRYfD*M)2Oy`pW4-_r6Zin=;fOu-2nCnp9(0z{_jMlf5oO_U}yPH#3k*R zmCyVssKARiq?S*QBN*#t7y&#<@?8V4#5({4%_FEVL#zh^TV7EL^wG^j+V)Dva zmU-MlxHj?7?uYgAFojp=L;^vq)JM7KMgMT!okVXkwKg;j3^WCD?#JMn9 zNiaJ<66LxSPMSOTjn!KKvbtFMeB;}}M-c{qc-g#NUT$>e3l?iAS01$Fwe{Pt+_r4^ zN^aM^HYmSkq#07d%!=fOB?It8oGy?p|8b38+M?s#7+E5l!x1@ChR4B}AS5oOlo@jG zkt-+=pCB|q*nWMfxwc>u3yE1XQ(;gDH1(bW?SkdGrPtSm2&SHS#x{6OwS(v4ErpAH znKnX8TdICQelZ>(KmBeNIC5Lp<<$2(XR5i=k2_iNpP|Lb_V;@KD`FhWpQ!pDiE)3j zDgU3O#{EO0*?&;u*jYdEL;J4)M$f>?#`>QicIN4(g}Kmvagjdt<9;fXPYgr+({UR( z7#oTK6aW;ndPxrx2-NBl5bZLvm*^^XlX!feNP3!TeA+7Flnr_*qqk9WnxxU(BMxQ3 zIjQb}xMGG_I~J{dBOJJ2eEH?v%cpJP#gl{4bboYd-^KgjWyJ)J?+YIQ;xE4YL9>rR z&N*CLAi7(CV9g+RmOE7KH$hCkIr8sKX{>ivxG@&JNZ*sIQ5)@=8V_udZ}IpL!p=%T zSt4wCUt2xa`<@Bfbh+pzH}YJQU!hmt(G?li@4eO)A940|yOpYJb|ULpaTvK_HqAi3 zS!;3D*vu@pR?vO7K>n_@+Uk^k^69Jgg-8lu@_t>Kn{WgsK?z9gUhkRwvJUYqh`O|b z(b;^M2fzdCaz%5fQ6}AlMtOI5?s%YlXI13#K}fPIFB$?iHe;gpFPd=()`s@gY3Bam2x z-SA%@B#jA+hT;ABJQzeLGvA#vxKahOT#R!(*s4d$uoy|Wv<0Hzcej_Hc1*w2g@wfiq#vafuGQ@bb{|GuhTTkn><2807Han?n~2m(%?iC@_uM9b7YKdDW_SDY zq#nL-VkccTh4duWv~Q4lHdd%3g`a*hs5MRC9UAk|7fkS;8p<>#YrEaj20o$Z4s>zv zW2_Oi(-BzOU+M8|ML_-vv3YtC{tCr@l8ha(D%~NwPIz#5rX(CYXw#HbK}0KZj&~tQ zQWi+FW%WZByl4f59kh=Pqf>@E*@N#_I`oCap+uDf%!A1NH?*NogjZx-DPc3jcy!--6Ge3#_hrVj=)|=i-zwBNkU+Sh% zNq7ghZ?K+UF+n5-=%l;R>hWdY1*~WLv+~THNl%I+%1BT0Tt3J?_PkVxr|YXnS<)xI zp!0c^@MACqpV6}gYV<+dF!W3h{Cnwjo8O-rH0enAz3 zY0iv?G-RlbCpvV5YY%V{YC;W}#QBA!K?ZKWhf$NZDnKwR&?(p{IzhManL)+B53nDU zOEWdr(B8mnr!hXb#726sRm0A!+MQsxr-j^@<`L`>?=g+-GM7dVBvdPjKw>oqV<&xPt+CIg-wZ7BQ zEWLot$~b zmT>O^f6pWOx@VLgJ~(ob#L8z^O=hCcA)U{SMwLtSshU>4W7^Ir(wx@3(KY24A#dqk)>;>niP8Cqi_Y8e zf=1f6%V}7eH3##Z%8I9i^H<$*AN%)-gAd2|otsYXkFKYigNY1Yk9X693tpeQC+&mA zjK-{m4AY6Qi5Z8i43C%9g$Zn~1KuPrnmesw_9gZK_7(OW_MWBA3~rzM((D+EzL9aB$SuI+Ixl@!=m57K zfP>1TvJRBzUvK=S65n@L6yn@X(*#j}%v@AXvZ*oa*_N;j`7&v<`h_*ugzXF17M#UV z+UD0)sK#IAMJcwT6ZWK^PYRu5f!#_^xO;{JJ}smuOrtve^yp z5XP_Ox5|+{;C0HRTk5-)4rD14J&>0K?vAuQl$R9g0+3gqUpHpVKsul|d@s5mHebvH z*MH#tg59!q1$)Q#2EOQy+9JJFe1yGKSr5wUnwXME_tpKS&IWd{m1IWh4c+MryV-cj z`6&CSTXewl1MxVx?-lqR&?lg?Yhz3C5sD{Bk`4$S&>t@JSy-r7NFbjm zaxgfZY?7oTIMwW{WSx-cZ7*MVuh4c#3Q@F>0Y9brCw)tldJj)#n_#F{n(Oc+Kb9$0 zrj5wYD3)rQaH*)?J|t^5##4b0LL8o)gg8GwJ_h8FRQbFA@RKnS+?>%33&Vkr!s7vE z2tL1mW*%^Uk-0IRD6KX)gv76Qv^`@<`1LU zA)H%IMSSRXZd#-4wFv=U7EJp|j2C&213>_!Tpel=P2JG-Bf#5Z3cN3nIS42@L7LF~ zb&>TyT-2jfY{4~f)?2LvUS@xESYc8LzHCJDoIt3B=vWtSYCGobg8}%yznIfM4`3mbzY%n(E2{|i z;OB@>@FJrDns!8>5nx{vus=hfAqJC!+XmpATkZ*L*NjPQjz~=mfRPPC#@|{5?#AI; zW5*fw1w+(0zCfcSpTad#2dpxdpe~&zHF$nc#T}FR7fZ=c4veU4rVs_EFUI5)f?yy| z0P%!6_UAu%qur;WdW^`;iSQRA@7qK4W)X_c&1@|{Idu@sG}_a0olO-DBx>6AMfUpH zxt{#$=Hhnp`uyH94YZVugv@kANPRmFy}!A>qaujsytq}&bD z3VYs5LI0*z@v98bVM}RY&@NU(#ve+$oQ6HpH#OA9D%no;;Wj`}`fN@aB`A-OF^{Iq zSs7fpN(_yGN*yT?LeSoi>*(8e&P+Rt>rEs`%a-~5Uz` z0LW@2lxlrSRjg(1XX!98XfUbpXoOU)?I`eKpt4`MYc7cy0CVp~w1ksAc`Eo;t$(LW z1+$PZGlKlW;opFzpuE637|@4f1bLsj0T9#el42Bqd8eD31c~DLU9@y3RGSToSEjzS zh11yzn{MZemWfEyJf`;Z{Qb9V2u9z`MGR%!iF^I1OdGA-E(-mpZk`3P#m$m*P1(${ zz%?6FxERa zgxcki{9*|0`6|psJI1x&?5x^Z+Qa-S04T@V+lI>nm}Vdu|B|agrCfD&%n+pp97~Pc zqlb|Z>sDi*kyVRubz*JaJEz5_AvG=BVXjf?+OO3B2v9)>6%?o2m!MoY+FK`6y9)=& zAl{5WlQaqpu#F1#(tz`*`JUvHzZJQ+a0e0z+FDxpebhAo1KuKCTUBmsr z*?)k6BdW674=8)5%Y`sdx!kD+B3DRswEdv13{I4Mv?nJ3dMg;eGz)!aLU`w{`e0h+4eec^~Y^7QEis^8RNpBNtLuJ)kb&7%aGI}Jt z$SaA`;Klebn-En<*%BmpzT6E`!b~P8_9e(8MthXi_PlKDykF#fyaRl(^|r31^p-B` zd^Vn}cq9gYWiYGB;zh0NbUhz);N=|v9)E)Taqz?BMY8wHo)DO|5Uw1J-tssN+su6! z$c!~DO*}lJeHrqESF+hI5#UD%=j^4CJY6rJt2l{GkloPwP-K zAZ)4L@yxAp;Bo(PsdVtHm~S&VM-5iOl^rrIvJvU2Y<)`U1gqqLg@cy( zQC_>q-R-e&!^Nt}F{&gwIkcThCO%umt}i#TZl^iLF~uR|CKUF^Ddb)naFqbg5 zd>ik*0hB@t?{4?!MTFi(V1EAb-4q2e$lSk3HuSt*)bxOybv17uw7IqBBG(0bZs`Kb z{qz*uKWkZDF_y0WHg9p$S+cjH`Rr&#r#%9E)np7D)P`|OW8>#6FmvOxO?i{kLpiD~ zvZW55gkya?K;*jppkZe-u>r4#zY#9}Jz)o-RApyr;X zppT%1qeVF2+1KFn+a}lc8XLDjM7I6 z>cjKAb!eIg#cJUMEF1Oi8gGMBQ4dS_97IQq;Gp?qW0mBN(Ha2@&l+(lI4M&uwjFce z7@=R%l_Xi;=Y`lHur`^DKIpc^nT{ecWG3Rp(qB#M58 zIoZB3EYTY*ul2t3U^j5lz1V8}C_9EH(T^HZ%*mNBv9(=c{2cH^KeY_g63vzuwWKkh z%dOGEmd;Wkq?1edMuYywjt5usvY0e@Iw*u{9QOuUelK!9M7d{4yn> z>(Pix%dRoB^0e{{OWF{lVgy~UzOozD!|3q~?@E@70?+N!$q^yz?yp8*;9)^2500ce zUn59wuQniQ7wIq#wehhYnOE1o&0PP-j}53xQbeyhMwGvcxTI897xFM~C zCb@HFxB0DnDI=uS0Qafe+v1(Z{(YwX%Y(!A3o*{nMZT&yZ|F;hRrRTNGr$8fMBz5S zaqcy0NtH$+PjRtZA1m}=L2IjE4}qfC$lw}^1M)c#-ZKu6ac%GLRqCNAH(lE zBstbTxM%Gkr@io(pye-Rvp_H3Nxr~`j2XnOktFm=hKtX$rSSipDMGeyU!@`$+a|ZF zjPAuGN;b+@@88g+UclV7Zx389j$()>Au$<<QAPk<`EgVr}=VNg$RAy&hfTIeLA2$*L%8zZ8fbk4IToKYk%jWMTv+&E`C zN1(L8QH{SodWaq(H6GlBdQlnta1t8k)iFMnkyd}@eJ|i?b1LAO;oUjWxD@52@s1?z zx<29FetPs~vekXg8?cfz!M>DV8%GCI>}PlMv`cYoXn*(ymG!E2KFP@2nHU_-*y-kY zxRtUJ1&#fZdG%WFLx*t08i+%TiG%HatG!e3>(1z{ezZGZ z!Rnyp)N_x^DP*ut@7;^fRIZ!(8{A7DEx+nTYsQfj&6q%;B5)$x9HX=l;J%UGm)`Jq z!;B|G?Tm=p@iy}y?%97Ta+N{YW zd&s6XiJG#g*`mtW#A!T;{dN(P(Z{QZ#Nn)GCG=soQ#k$sWZE5PRo-3DaHONV025IB zX`#(yW6du@Q29PL1eg8e{oydRfnXytx6QQ2(s%3x(V0Ywgw9g2@#ndu@$;PKtjC-b zJ+VQ%{KY)u&`?K?jgG5>A{R`Q9}_1Fr#5KeOhAz2PTRy&-Hq~XIiQJV`Ajj|un4>g znOe|HN-Psgy390?yP~x_#|gTFxSG*gZ~fW2`n?+`Z8lwQ(X;F0^VRx=-=+h5G0ptZ zXpF}a!>)BoQu!KfB*XzZ^;KH6c?B&gW^`u;UbeWNT~5T-5}I(rFO7J)_yP5bu+Up> z(auK8$Mf@W)a2gnisjAmb771SLwy%vlcJVU1n&?#BJE{Ph1*Z|e2~ZMZb1jBGsum~ zITVKCiKO=WWFm*Af{a6opR_&Zp$F>(mCM0F-G#=f@SFHOAzCRN$M&7Q7oMO5IyfN# zULw{RN>nguZ@Ahh7B>73h0HgFsWpV^z}Qyw@G1&>+Fg}L+RN19I8%XxfYOI75s=Rx ziey-hkwEy{1@4nP)uw-hxSD!*n>{jCHWIpIub=lh#T#fjD`)rf@qxGx7omZh_n(>+ z_u?f;$jKT`nZzvOA%qYcAj8@wNB}DohXBCC!!H|8o+u;G_XOud9cB~YkYA&|reRuM0%ZP8OA(tVo}<5}(PObe$WGA2kIono6i=ZrHD=gD&30t= z(2(103%-Wy@~2qkpQjIKNSWCnHEx*bG$l0N$YQ6i=s2k5U2}*MBlfqJ3%}(Kx~AYb8qd%qK!zBP|ZsTj~h~xvWu;NxT#7>9h-inK_{FOF5bQJ zNvNFh^vyowAHKg4!lyL+BI@elrgx*|^z|}6~6r|5g>?!#$oh&0qUC)@7h{~L%ATfJe~$b!Q>attf1AwX1;O(MM(#zW=BB+ zdXtg5`UZ)@HqcOUyXwyV6rG*B)b#O!FiQ;S-hA=K!k6ikTgNoccb>87kICAikI>~9qhwh!7-Pf8y0u*$@++B%}w*%G))#@OI zE#;%|j>z{0Q4uTE(Ps-uSg(tIh`|THV&4?^SFkjfaF3jzQC!vCTkEzxxTn}%{v255 zQ3&lTRoQD$**D9Is>E&e=|PMN>7z6nN?NyC+R&s~XxCs{)+~fyfDTKJX=(}tjSx&* z&=}UPC#Ux4iI6-KQc8{1H!GdXr@FQT!c26xZQ|kKv?Ccg5qprJXc@TS6cUPSufZRZ z)1llnrN4G0UREHD|Fz=le|8Hh(P(r!maS?3us{8d6)O@_oxE5`Z~;PLbiB;gt}cts zjEs|e6`jTf4+{c&!r!Bkm=RpdoSiIr?BwnzQ#c@4LHHs0P#g(Cx~8=2;!6ZvNYnZ& z86}p8fn`1$EJMMV>MQ-v`^X}U`xlB=WV0rk$ND}p{EReFw`y|fxmphGBUSTF^D`~hx3nKSB^o~BE)xMAwl@y8VI!1@e0kHQyJ$bWz6Z+D5 z;Q2MhOvq(r^(!0(8C97z9fk=SZU_9f)pHux3sla0}Su>w8(nEMNU@9$ZG*an`M11~^j8AY!fs3{y z?%>Id2KD7tpRaV^4+1Svb;}wq?0dTZ44*Av>}Xo6f=h&~0Fm$Ps77?v;mZK2dbkMC zqr#0Kh2E__ixUry8-h4N+_afGTsErL&Uq{ z1hIpCjKvVfrn+~orjt}jE1{YYfPU1-8(63Aw^x~^W?ePR+qbJy=2hOIs+9$Uk?{$yBo(EadHXTbwVgF%>p8LihayYgL5%&sAW=HEy- zQyeL)liNrr7-O(QF_9hl_!}hd#fwU0u&am{O6H{O;TT#SzV24BGm#cX7XvVc-HQ~2 z`pKD?Xju%7_g}fQ?mJ!;g%z)ij{(+B`D8e#gFJZ3@X!KP(t%3*1;XK^Mv~2l6$@EV zpO8^%%_vlKa_6|c00C(?mX9s0G;BNwJp7{0(8)71ahZSaNOaYZG`Dx7e4Vxuug zF$HIcWYe~yYzJ_cQi+(6R)mg{-P_M4O?^!XLD4EcY$fJzO7StNqtyghWlfy)Ln~R#ooz`4kSRy5Y6sa|cEn(~dX{RD=-T z!;RyO161N`2K9W^z5ST|Hh1Mv{sM_ELgS?4@5hYDc?!(p7QNeg&}l+=A=0_xDXF>7 z*K#%zp*;90<*>w3*=E;2D)?mwtkNq?bTl+RiAt=~~E6R{dm zOUsx-8^cErD`5)N@TdClChTyXcS^4xmG3#t3ZTE(b_ZF9{OLLlM;J@Xi261XV|ua| zB4IM+@JT=@;dngt7B+A;mN*hKMQ**xe=JYQXns@I7F0c>)o~pXmH*hMkesjz8r zBrECRV)J1f*9`<1m~;s3gQW;j09QQ3Fx_m6BX&ceh=W7d6H=f}MC&zM>O%-oThIL> zF7^|^E;uBFkTx9ohhX?Gg+d9nYPC0GJ^a`yax|_Pk3nVetU}Tl(eq5V zF@bl-te4jFo*-Dph8|uHCy8w4>*rDXea0=XP~>|s3$)tMa&0O4hJ-Y#uqdLnD8N{y zFGO8J2*BFZ2Dz<77?U&ldZ*J~f4Qrq5()%ar4S6n@C^gM-AnqsR)! zVg*7@GL_*1amW@F`VSJRgv-tecyoW|BPb&puo^8XqgY_AVA?W)8a7#}z9y*40Asvr z^T7b+XdgF>smG&hz)4Nhluu(iQ|evPL09?5Z>P30!VkF-lzzHAwOYdIiZL%)@@AIp ziZK_U6$4UjNrN{CH$~~-?02W^))TO>a+Sk;GJKV=&b>a_Pn9{4;x3N1K zk5{AvvCHlTr?WS+E5!)f+Ycv{^a>%Ht5C~ZLRmxv_T@VhQ%Dx;5+$0LBcPMT22Qih zXUiAYIt=&1rO^krwvqG2OmA;xK@RP=+aK<3AdI6}IOQ*LRl*M;pB65x98KyvJIId@ zr+9V()Oz!G_R$C=Z>L%ZyInu(1Q0NPhIPab*?67m7fZmqv=YhC(2W)S$`u~IsYRzvH; zigtB*MK5un8HLGM-o&g9TQdRuBS()QS}5033M)t&SBgJNFjjB#>+^p>%H zScfTfa)R*CUhoXo^3|c7zO10H1XXC9q(No-BD~YN`+->+K4G%tnL6=&3JiT*OB0iJf78t{!VQM~w%16d#xbr2 z-F%zf?Ap!lyAyL;r7qX49+XQHjE7K|{Q2-!h5(R%7(Vcc`{;sMqxpj+ z`g&s?(4PO+2pAn`X>NHujf_T&&|0P^tn?@`*2PoE3A{>21`av-K)8+q|M7K${r7|CMC4v>yGPm)q#^XHyvGl0(@OKV0@fBRn-b`6U!pC0+q=^ z^ydETmd8_u_k{29Es15TRd7Ic-JLO{j}HLU?cODTSaS4++ZLKsP@>;ztS zLzlZD+{K;^JYzgKqH+nO8;_}HEhfk7xyVn=+w5BQj5kn8KDB^)YzY(!q&3iKmP%Za zYSv?@dK(t^b+~fv)~npAU^0YZ4RfkF)kH~7nynI#P*QWjhA>=L57OEQW2JwEy1d{m zG1fHlFg8f>Ba5XHUndd?ZxB7N3fs+B*Rd@GZOvFd!!i>5l5B$p@BJj>`+SP*ylm{V zA`^7hdd9kh-YR53*K`_UA4C#w7V6+%lxzT88p1zNcvmYRrBOyHGK$AZzlm`NiHgK) zN@0BFe4rZg=@H09>zY3~;S(9pkvvk#mhTXgm`O$*WxK8;)}5F#X*0~kR6t`{A}$tQ zsYx&QO)nN+H_DenJpF0&vcRrDTt^EpfwGTPLan~drJZI@=wgSy0hiu6qX<|bgj&zp z@}_=n+4~ITOsBk8$DgLR=#j&b(rt}7cXGBxoTr%N%?NTyk|@+jk|Dtyfk`P*LdhaR zIj_MY7h|-9UacI1i%G|_*eU7m`<-;Dnh~>FaaXFAPDTj@n5P^KGgL~Fb1%?ww=5^8GZ zgge*ij?tB(Q=3fd0{!y&N{a$N1LsaxXLz|MVO`8oj}(G7FNT(DI?h6%yWK*M0tG`8 zI!?N2_{mdGmi^^HBZB_=dmNe4<~5t^lhqShEvM^`7}w=Hts{xk zK2gV2I=6e+O)N*3abHTshzn3^_{7^Fa`F6OM>+~-XLAir_oSam1Qp7eL*gtg<5~)c z)Kf_d%HqlLg(&9o`8mvGbYu4!@|y!^oD1byBJvB|#L08~d%W{kn732E(Yw)fHwTX- z_>C;`uk^s?G$@cMKe4$!hK(}QVXI@P?rlKvVW zchhk$lskSHNB0Q|8zLajL;}}<(g}m8yoGo~g>dg&7ulA+nnLwr?c6))?3Pz4w5vhg zs7n{ai)BmcEi%jqebBwhS*2I{@e}|2K>r#y(PI3}nRLbSlrd%S3~bbTt+Xt~yn+Mh zseja7FoKeLq#@T*9q|n9faIZKLf`HxBb}wF{VWb2-ZV+3- z6e!8~FFHFk5B)s%x>f`F!2%&710&X}iy(D$(mV#7W*DYBh7<~>hbcJFN(0 z%A;)`8Cfx<9jti-!n*}26si1kjFdw?N$;LVqTO1wxf|D_>803_z$mseXA4*I`JwoF zq+|EQEVW%Gj62;Yqb=^#mXj9hmCdtlU8Bik8uKDnETURiX6n>)$5zfFrS!>hV{U3A zJyCr}sZW(LCVCOWa382ZuacydE{rnrRatG^TfE%P<1d$Fz0lnYx38C0jmo zG~H-Aj~}E{TmYEW{ntqGM&eWxe8lRABVl-co~((eekmmeZs7SdZE89YK0h@LpV-8V zy+4l{%_2)x`JF&slB&{QId{O&4S6&e($I~WDvk>*%wHGd;=4Q=l6L@CWX_&pvi;OI z6G8m_)EwOBOASbFwKU&m4m5#`#DM02DtH$goeTP{3f#&!*ENdUJxvz9N{OQWDHH+9 zeN27wL>P!O54s4$6P&Gu$+Sxj2+S%gwE6d$gPz>280&mjfJLoOspOErmLyUj(2J9Jj|x8 zdewU{B6qm?uZUZ?V;@f!a6H~2-?00SyO`hdxOe<|1Xp9X@ToRG=*3|fjG|SaoOZY| z!LC~14i>}wpulS}`v4d~ykBc`nkj=c*ydMwXBT*fjqP<^NmyUvKjvLO%%Y9EzZg2K zIYbX}ebrO{I7HjvAf;@*EX`v6Oo;ZmC3@#i`AA>>;A9fAYm`AV)&@LCPzViPuF<(264C8bgN~$fVLzgyZ{;016%$0y3#YksS0x-BKyNklke0E6 z7B%mt^+6jQ^i7+Ujb)uTG{8?#OH)M>1@##H0vF@JJ@C0{zBw|&aslT49x|Z)EpLZ= z(bd)Si*Jqh$l<2ih92!lU3FO{AU^G59@%q`Dpj{}5j6%5HhN?%d#0Mz;jW>g_#go*y^*1M;mAU)2s#v)f@-MD#O>!<$1spnvgt+&)Ieym!1;cR2}? zfv5xRq*ZyPWpA4Bv(vo31XlZy&07Xg!Zy<946wzn6Mk_-xi$Qn&ipmY8-VFGxTo6g zi3QUT4=a?r9*nf>VZVz5a+msM-Z_m=mNt_;{grP1%F8`~Uc|rPB#rgiC&|QLaYc<6 zcKHeb_?kiu1sE4}fn z+6oKZBImC&wDs=0+xz>daKh84{SUKG1r|FRi+7*a2dsXTU1Ta6=$Cg^`^Dpre^$#d z|CYi0uL`k#>rVca5bH0=%%4&$7WRKIHvj+AVljMLl(YQyZl)E~|0ZT^ZffR;$MWAg zn^V&>{ONN2H*a%xCK?7tHpahuo3qj}(J-^Iv;DVfEJpUf&-Y)6Wft$TI@Z1#{D5OZL1`{fy?=_w79-sZ^Y#{`?W++30d<$#|H zX9y_PMM5IV{*ejDB@AeRI+8=N|H@Yv`i4LdomHw@zv}t7-s|+6%^p!xQ`8R1z1c2A z$n`Sd(%WAyy2?Av&FD8kgk}SRDo9!a7a2MlH_MT~fa1?Ak9LNsJu2OdJZV5(!?EO9 z4PxoiRK8o^eW8MVqj2@UE7i;1>wHX6(x&au3|k7BfazhNiiQ!h`++1+m80fJFdR%H zM68fbPyjD4>?k5JNKBZ-M3Q^nz%$)hfx~+hZjR61M>=hzTy*OjTA<31e-49;V?vA_ z`|7$H8uP}HaCd)Bh{|gDR(BO@H+u3tA@GHgE>2zf|pC;Z)og*$Hhe}?CL10=&0{#{QH3@9UjAPWtYOIf(e3FP1eA| z*wFF!6KZsLzy0bzU#v!t_cyn5wNLl`|Je5r+w;#IMLu`@+w&syc#OZt^Bc?zc#MC0 zy$B;7<6l}sCOpPJ1!BM7P0rrdP|?^CPm@+oNCb~o$=LPNM_t_dbNm8-+Y0_|EB=S_ zk5<~)$Xx#q>;2y@?JV>Rc&zLU+Mn3|bYTCStpnbF9NXB&==bXT2SwMPnzeslasFPk z|Dh0n&Hl3xe=pjOwH{8g-fYSaJ5V*T0H|DUbJe*pNeTKq!`|93AI zhTow4vz0LXg&_t!hCgxfUn}$%L_X2-7eqeS&|et(zlRovKL_$TyuVe5;rDR<(?$LN z1TFvmR>1I2@c!?{>i|J3X>R0zr^)aKK=J-4EZ(2@|7acxc=UhtQ9SxTdJEnk(^mMS z%{qNvQhsY)|EkD8ET4aM)n{eM1emqXsc6#!<{|whJF#wPQX9Z|w#5?|Y4n zE0qQD4=6J)xIP{)CojC~-n!o5NsA91cu6SFY;y;l9qjLi?hTjTFB`hv?pYs?J4ubU zKFjMqPX~A5`YXpCmges}?%kcbKC2F?odI+{&o_5I?{}6h{x~-;tn6CHcat0I66>_p zv#zhVCz|9d#0S%nSrXt$SPkFa^jl}=Pp&1GX`3%Dbk`%Z1X^&Aj@hOTWS^!LgD(bB z1e@#HwI*)d?j~?Mu#k9tp6<#6M>+<)U+v#6sPFC5?;bCrAbs3kUiaeGDi3J0P&_kl zXGGW;bl2ZcdJJc-w!DOX%?abeJl*p)KJdOxWL&*3ylV5jW(*g$3N99QN`_86a^^c9 z5hu=V4cLYaL~Wqh-b=#P({^eFU1IpU-MN7;Al@RV6efMc9!gv}x_O0n;X&i#&%B+jm-(Kc zcMtFWrve>O!bC5p_p6od*PX_hfCb%qudox^D}?2U_w7Tk)>|*Ijf<CQy(4D%hz!G={Z6D#TyDQ43_Z_2+ zx7Yi#sD+XIhpdlxyCK`|7jHzL@eAIM`+M6Jl=*OTe z(zr_;+ivq;`z0A?9KAQ+)%u?9k*VRQkiH-*IRGlrQDbHcXJ=?Pc2z%#`pzS-A>?xZ zXm3S(9Ub>99}QRe`tAH07cepd9+F&9)`){B$7U3D!4s&8%dM~jg40Q5F-Aj_4b(BI z$vNCtn{&I!i|!-*kgVP*V*gut#!XaQ9bviIyNs4OkdnrfiW0}gPk%(}G&uo(M#wJR zgH+1rb~!*S$~O(?{*oW<(?`&!2|Mcy+1-2PwbjP~cI$Rb{u1{Y)ex9Y`d=|Iqhhd= z;v}JkFAdg-wGM{}pXK)>k=VlxNh%}oiGZk(uuv%3sj8HG0v5*=)(MdOYXxDcyagv_ z&m$L9Qb-l$ZG45zSBnO=MG{a2jjls{Eol3D0oe_BL(>t6!x50K zBkC1;gfwDk%$0t~1J6Vu1m^XSe5werTqwGlP(`S%*(?Zb3;48S0iDD{XNk!blJb?* z^M6VS((m4~>{&M7L8sid}$jQeKX6Dxcavrth-a1a_O-UPx?#0D)t%IS1i z?jXdJ^f1h%%5pqev*jtjz5$#nC6UiuAN(!4QKg!(6;g&7sa}d(g#o&cpe7(+g$_Ej z`0`LQCa?N-P>mA$CcOxzU?x@Lp6{)FMy*s0dsfObPq=owO*zm2`gT9hpiV4lR*dw7 zc?!zwWGrS>iJnsoU_n4xLDJArhw@Ghd5J%`D0NQX_iERER)|e3Nsn#N&9Wz@&}bbn zA`yjdd~Xa@hFbZ9P^G`Ep!d{ z+q`Mfo@PWSFHXKetf#;VW&^+xXb`8t!H>oIrZ5<1azL+2c_ClR$ns2A+p3w*R;8w} z3PRp4N1W6%qa1C@xbvw|K^qH)})g~w!ap-50~6@?(My#Rx~ z+IC!pWU|qlFf^XVRGhuhTQYz$i#zrBeT8k&Ctz3zH6vWhx1lp=Ve;n$LY1TpSFm^pD;dFj9i`Y2xu=dxug z(j;_d1#4k^iyNA-%v&ZJNza~gem3g5cq;}$9~3rL3jEo?#E z&-z8n72yjaoktofzJkq-ucFkSyPr^#CZwFH9^ui3GWG_A*&hZY=f5hp9QT2jm;C4?@jD| zvy64lohP#9j}TuD(TJ5&Qrc*W}(109p-Xj z+0H?7zlP|^HBqRqk^4$rt@hO`kLGCg9Q#y7*73?L1dWAWs zC{k2%KjY^JJs8o#I%TW#G6LsQG67A2I5J#(b~-`mC=q1%pcI77?QXLBEE4_Av??9e zEK+r?nRo)psecN2i8DiahPb~U7e)_%dDcau;M?5|b|5)~V6B+2y$HJ5)nKwE%Tj5G zZ-halQY^cI_`Z;KykY^VEN9qiwYQ9nj+r&O>>1*I0?AZ$+xdW3MMQT5O4RD*?(_zC z)#PZqVynx!9962tG}*qKeTYY%dd;O6HCnNS8+K`~#&&;AVPXm*wHEPAw=x8^R>34c zbwEkJl17t6K|m?f=VpiIsP0>W45TXk%_^WG`mFU1ok*A#cMp2$@}JmZ)p^95CM|8xg!mxg&)MZ$i4b)9TKmSPkJiWGOv>D;&|blA_fz6#C^ zi@Jz$P0j3^`4trefpTGubIp7L3)h#QnV7#A3NtYWZ*hwCu@#+BIr=OTP{K@PikCQ4 zO8daey+G~|NVBgi2+E7j-@2=>pC(7gxz0^WR!WXf7k}&zr$^nJkPEUX<-NBqSesR{ zHJGxfU{i$>AUt$WF7dK&5@CV>^fL_YWul>1!|4m{p50qTr;{dm`Pa?FnSRBa3m|iB z8#sOi9MLcSR=17^ELu7y4t>g_8fyDkOTFYx9diG;MzTz5QEwzWYcZ5rG#AS~m5rmQ zDPKz5iseyBY-w|NavsOtSZwi-mD;q%?DXLqsTpMAYs|Ht+x!wGoFAdX3BZh9k)YH1 zr9Rs^;qykr2D9B6$U?q5L-GG(?Jc0<2)1_71WWMX4hin=n&9pb+#xVH1h?Ss?!k4C zz~JsKVQ>rX9yEcxCg=R;{BQm5+4(H$vg32FXI)B<M=lbk77Qj8X;1c+T6f(S4D(9qbYAo21 z_tnB*#r(b?eqkEQNPnvY#ok7&c=AHf654x1n9xSmyT%Li5W08HAe+j`*bq2Exi}r>k_3bUwXai(TGW&BxDQ zi?<24JR(H5%sX)5RZzobXB^_7`_Ef%dX^ZYCUVy`Dut}`7B z6;Pf*$Jr`P*BC6~HXY=$8HhPbAP{&}Da!B?A|+~#zNWU)ICVLVp+i$i-P}0EZwyg( zLuPWigd6+Gtn;l8om;XLmjOX)B7S^?T@zV* z_pS`(jI8u~*SYVF?AgyJkNRXS#k&Geq%*P_?WEUP48d~64$;_lSvp%#{*neY(9ADk zVp>SN)@x$A=QN8C(o=?`2zCNRs~u%6O_ZG^=`7Jguz?>Pq|ZFA2?aCt!zR159zyu& zTSo#)=0Kpb8HGLd!!G-f9zy!)TW10@=D@LkSJDQa2L{nW0@&ktmL$|+7hA*$N;_yq z-V14luqzX3G@~Gmyq^$7PW^!KTof>mVV_d!d&vd)7QlX&R(x(^xJXhOJ7MD2^`HVl zsacZ5d6~iy4mSoBXM4%@SfgDuhODf{!;4c|Hm3;-YJv1ifho9-9BcdSu2E=|6DMWH zOwJ6vaJ}YFwU6~%Kh?UOA`yxkRdd$uJ;)0orZ9f|29nQ3Os>VcHs%;d0j2RZbQ8loXFg z3n93!68i+@sm^9Acq+V+-ah#`w>lc^oU<7pU+wT@y^gddj68EoVa zh6G?~>H;jH<~2!JGUuOBt}39Ki0A?f+GVEyv&3<^Vw@iD<~cUjNMp0B`)A4AbejF@ z#KY-o_fSv=O>Xq(k`Uoob$-*8?2Lm|p>^Er5p!#>@bBI66I1_7=hf3K zk%`o5G;M0C(ae^B#__#|X}b^R?VUn*o;~z8_SL>RF)7xc8%vOI@7x=V)9$(sO{KdY zO^1gR-kU~e;3rPwLtaM@(7r2Ro5Q`>*)9)mSQgvR`tE;t^XUA+)yv$WxxI8N3E;o+yKB*Y}YbB15Gd&D+E(mTsw_P|pA!$7KS3iKAYzdd!Zp zODCe!*m@_ypaS3D>eiYneA~V`TI~@*OPu{)U7)4pZd$5N7|DZ7)UU-EuuM}0%Zjn5 z(h93K*cJ=edoPdZ$Veb`6IYg8J7OSJgEH3MV%|sV)c4i;4p8XUyJ$2yhOu?EtS5+y z$YCu$c3ktLcdc$mCI&oZb+$6X!*#lUw1=$vvdqwXRWX9B#3U((Q~bu`6IQa`-F%L- zyK{VQ#9v%?C|ehMhfKYQX@{Stzmywf!k0gw4!+l@9tYmmAxB68P1i@$T19fRR+nnA z1Ma77*6+FWqcA1v{H0b&(oWuZXKPvRIRMvg)DCg?*Iq=YD_r=^XSVKPV)QCz>EOvyYCMs8)R&r6-cTeK*H;(c- zynWn*s)Npg&Mx*`@3`&j22g+|qKpkMQYJESmiM!0K=F6_hF1@0!-5B83l)LATtGQ_ zTBvtc$P;1f<>=nxC)NiksY2Hkd*5tA&cJ)YcF$^J&ksUH#8CygaXpOidx&ONwK~2R zSCV2PLb*KrX%&|U^dBd^RnS2neK=sA!n?yxri9dYMuK8d;`GP|Dfp?Pg=$mC+hW`c4Z|O+}3D>iO0yR@%LC)P?F+Sle+PX4gvI$&>Kueg3w&?z5(Ch^N zR~^!H6|6&&(oBxSL8i=>u%~fy<@s+f%O7ST?`Lhqa%uFrBVVu5JvCG;_YH?##TQADDb(r@fy=Eu- za5$F`n9q!Pfmku=|5D?zo#kt}{W9xYD6%8bm5iwN!N(yLZml4Z%q2*H|_0XT7}-g2v~An59H6#l!9I zDp~t&g%PaPWnPLNUcOwiRKdg95!4YXd98l7`f?m;i^#wg zyEmLY^LjY6P9i$CM=^7WnO~|qbdVOn3V1Tbq(x%*=h=NEJcN%@Zf`)6+?NvWe*HK` zfFIxK#l8J0m}krk$9GTRD4PfDwpPC;F{7jY6ISz9vaH5G3ujft12M^Ck?v|~zoyUWJ{+#Whlb>QkqV=b3R(Bm~xQbw!>%Hwbka4@Y`}x19(D1XUpv)Dk2q$84n5- zN#mz2zV!TCa6hGy@291CJIwDL9CGr>yA?sIA0zX}M?SJp76v7Jse>wwl2p5_#V2WiB}jp5{QAi=u4_w0O;jR}0#7i+sd!zyGrX9sTUr z`FY1PXM3&#TyZjsHtIoM*Xz_{5o*r2bXdbE)j4NeJ4Q*85*#yYti7*Ak^Gx4ZEV%gd!Iex_|SJ)bLUSKyiIyg$_OR%ARbBTpSS9I zEpz+#0`HOF8X6!bepxiu{vic)#xpDGSn5}l*RTFA^&XQt0MApm6^oz{y)G(S>+QJz zA)9G=+)Q3n*=CNZQ@#uJr^7})!A>D zChujgmLSf)-`heSvU0PeIu{<;$IQSixwfLFV{;#`GDe*xXWDizv!*$#n*~2{J`EEo z*XbHQ@t)1`MiNAModjWeRbIP1^x61i*DOAOlw8IIPBL2eg*K<#3*|9NdJ zM9(*jR9a^q4($Z^U^H5URc zB4DY%^Mm=M2zCGkt5sy_)RkV8qF0g~7jPW5ySZf3QLfvW=~ips{n}mgqQr!szgh zWG@VKBs=y&em1MuwR()}>(iz#R@h0Yz!exV(s51~3-=DvNX=MaEF@swzrcIKA%LjT zw{gHNjme%Wo}1_)nqFay!=9Rm_s)4SNlbe^J3Ed259o|lhFl@c>nzHu+dF1i$(>*( zz#CR}p#J#O%!`dIL0mkC~2pJmYP@ZYMferQ7Y5sT%JazD3 z0yhAu6j_Zp!V_i5=e}NsaqUf?guYViXzSeeqLnzzODYXj^&AmH+S~g$=xLDfSS8#2>t1Li8!@QXrJN2!1XMXnw)cj?p)KAt)JbVNS!kSas)Yq9 z$|i2D`=U^n$r@z%-vo@%;YHMN($xv61x9}*w~hn#+qxhL(Yw7g-f0s`={*Kh_lI(nX!1fvo}tVU1UTDt z5N&2}0A23bhwk?P-wiQy^zG>M9P)B%0eD`ENh*_L4U0Rn+vC#fh!|B$LouwCtK6Hw zths5iGk!(9mY2zEn~yni`J;Etk)RK6NBW%uId`yUiJ*|35S|mJsBhuNsRR1h$O)Uh z-d+V^!H~sJEOYLGo)9d2S8 zgXN-{sD#I<2!`eINezOYnr+ci(wwOWZEt5I$)3iC+a;5o!Cd^>eb;Bt2_TjHkSPh2KxmHU2e_&k9DVdE_j0&U*QYvLHWy(?%`LyXX~}Er^zl~a^l2exqD*Na&|-9X0nm(8flKk{iix`vBUN`xYN<}ig92yj!A?n; z9~dvU3*wU&vxe{gry~61^xU?Tm3!|{2;KcX_N-ixkTI*id>ld*svq8&~`dQYZo+dpYR!SIwlG38g6F zRxADoll>Pqjx+7$RGc6TZHSCg~1Z|IdZ3`K0-&;DNMff;4t z`}~z&ZW5aHD|)GnFLeo;bup}1%(tZrHrtTT*0-E0$?p5cs( zUqEIj_AoA4q+CogHujL#cC<-L01tOzsrhTnZZw)icJ;@K$j&Jy!c^2Xq^G8cl_lD~ zBYRB};CbF=g^MR-uU92)WNR{fJEwN0tU2l84piW+URbtwhs&11xSX_pz8Tc z$X6RljYoZSpZs7g7t)Q@CeY8gvM#xAW>%3F|G@0<-@Eik@LVjtx4(Sj-D_*=!mj@KpQKpm zkW1t&cW(;2uar<_n_Ng^%k_7xc`+ZjuKw|H8}Dphr=MM(Utc55jTi!3v^+jFHg>K( zUEEBb^#0D#wI{kXP$Sa!dAim&*>x*x7i^Jh9PI4;?VaiO`)PFfR>ZK;@X6(j-H>h_ zRHWNdb-90Wc8jiNd$83zkW03!d3YC>vp)KmaNquUeDcZr4;}~8&m5gy-Dc+sz0s3K zo{guRqV4O&YJ2i|fja1Qy0qus=b~RUPMtkjw@M>ko!=k%*XKTgI~u)9ejPn&`*r#; zt!kd#DtWdVc5j~F56??nUlkax%X*#(HC|6Y1~Twy>sO--5Bzz!`MsaGTfHnrHh+11 zcjbgG;N$b_ELK-YXqOEN>$9>Ft9$?Gr{9?SbW6nZ4o^wfRb`uPZ5q_y=jb$#t=tA+Vtayj+S;#A1gXSY#Q3pR&M5?ti< z@koA}{-{4j#u7}m{>@zz5-P13{&FGNA8qSJwDEPpRuzkL`YNUzHzcCmlQOzs?WVk1 z=Mc?NIB*JIfk29c+7a#?4<|trEl3qr4>Ie^=`cFQr~_{@$j#2GS%9n)U5`>ZE;HJ- zX3x(42ASuxao^PZ&`=lqJbTS;CcQeX6~V$U1s#MN-^6%-g3M@?vEbSie{5tg&0kx1 zoKkBgHh=g-of)BeyIB;uHSJ@3Qo_bZbIvh(*+h*w&f5VeoRSe4E=PP)%pegD=WQ(E z;@X6FdMqeBuNz@D(8|X7*h8=ix%Y*R*k6u7->$raU?{!h{Q#oKfpG|d zN(#ao4FFWYk_Q`saMY~RbOxdPg_3xMl8CAWC}kKQK;mhHrXVeZAoKVCO1iWVqRjt8 zQfdBUK+Vy5n%!Zm4E1KS%v~6d36>`(0uQ;H{mpX@1{{sj<_;zswP14)r`>+kpMnsnNQ+h%h?9sSd{$#WRV-S?z@7e5Z&3+(6Y#=e{Ah?F(Fu}I=r6B8oEeRIzODQcO`R3;%6m9DC z5u#$BB{7j3@_Np*X}k+3LeBcK6HP4a&!Q+d=PFA{918(rP36Y-flf%A7mSFu)#brf zAUo`qN((#S7}0_WX_M&3#9&~CGC@2*SEHaC#+TNhYDxhjej}`cnJb<8@ywjtpxCU_ z^R^~u)iLkMNZq=8*Fsqd6@dl|Ajv-~FAXo!WP=o!-sj-y*m|x7=uaXK=H%e5)gE{_ z?iH3U22#&lZPxBM@ejrS9A? zuCTd?B;^OA%D5E9b-)au&FtS10=Y2+2DhKbT;wX}KS_+cjk()Q43QL@4wyzZWL!U} z{#elXMd-79bmjik_^b^Jgzf37UdcO?!Tn*vpupR@UF5u_9}`8CanwiliRtUhlu3BakWhEZ=6 z&N=O`L@@a7dbA?91hcDy01Tv_oBceY;o_N5?Y?sxn2f@MHS1B1$+hcI3_LnAkw>EY z_fc?U(~JoxRC-Wm9Aajd1gsGUs3pdQtecH)D|ZmQn%P(ZIX{ zYLhfLdZte(LZ&3#3p-H}YcRX6csIkn+m3Ut;Jsf4e%C(<@QD-mnE=yT&jgS({l88C z5kh3$NI)>7nHHi4dhYe=QGQ!8>M_ENzWfyrPwj1KSfbfUBK20$gnn^MX(r zf#JeyoCe*^Z0L&4@^210&;ic8$9Do~EXgU9jF;)VzYG)%-x~H2{x*5>PWTx_p@w5F0u!PxFdm*^TLf$JzUULc9 zbrdiFhbXwc+|372%uEFuW2UVEjqx_?*R+OrUBiKFIZP(2>~T!JX0bsa+*tT$#@fa! zEQyV4y2>@n0~F^0{O!C2Wccd>zPfr}SuIMj+OOwn0xY@waBvMEQ`)^iBYdksme=r_YMVyyhqX3J$8!V?v(x4oSYigX_o)9C%|;W!d6{#QGH8jgPm) z;0#$z^OPyzeNcY^a@{viLd4G9gH`dI9A^ix_?cW>%gwZ)!QyY0AlG><9Ikn`mn%p? z0u=7R@qpbyjMYV;N)&_mf1+-mW%}PL=07SHpaFui;$yg?GY0x`@{4<6`PP=>TjNA|Dj!)l*mj9aG3&s2G*S|S1sGo*P=wc zufXxwWPsNJtJ^?Az;m^;{PjAs?Cw-&6E!W)Q4@CzRq=w@jfah%9&S^7bQY%q!e6-< zK&RHR$gYN7+cle~QJqdna2XePRi|UdDk}tj=7|%m7xMw_jU)}V?enCjAdaVqQ64Oc zU5+QDarUih^D8{pN_ko(K>e`MEqN#ndiM+qD-y;KxG6@YpQSlkYeKyT3t6SqvANdS z=tcnL_u1y)$Qv%}lo5yHl#K-)crs_oIh4w9!U8o8 zoE(&mCbPpS6k5;nv}P8CZ(unPCzcy?M8>c0+jGqtUbB){1{rXsJhogcolV_qa*4I$ zB^EvW^=cd&3u+wiuFBGT&j#!H41wSXY3m_7;8TOhA4l9B%9|7gj zAMPcXqhF#>V%+G7E^$ptmA|v|u9Y#Kho}ZSzak)5n5adO25fE2Id)znCfFmUN^^&{ z_%ib!9h}WBcDh6aZ8fopH8vN$SCoufpwidpXs{pFyOo$0N6J%G=5re8V(a1@KCLqq_yx(6pC%qvf`*Ej$hH;WE}l(6<_m))vd z2oyk`c)K}vcRDox{w&ka1MeJXH#a;gPHULfSOwAXoPmi7z65KlIM28uyUw^`evGJ! z$jEGfg=Q4*7M*Zccv!Wf-f#yjFBmK_7jtjLorg^DQg+v`0$)e1&weAj+`s=*FuLuXPmpY}Q;0BB^}>*wt%|aQV6|Zs}*+d5Gd9a=Owa@;E!i z4?qZV%%rvaTzDkIyZq~An$6R_EC!CmHCi0 zQ_S$A1GMoUs-2i0`=|i1lZWBQ`^T;tF9b4c;|*nnRFyWz;_@ua%Dc-ITl5ePsBv5@ z^o89+<@KbrexPP&XxI2S0zT!Sb6mO4_<$5(#W9=cz<)ZBkr+Rf0^CVqY$_($TQ(UR zb$0f1(!{>g_kazegK%n!$?E!76x?HFOx)g5z;2-dG9b7weID{H-k(XR%-kUI{{fO(7A_HIxk=fDcBNXaj8Y|gR_PK@Af87cp=O?b z`jo-TEGQe1L3WsI`G-TH&4>ruTO{@`a)fw3ds765{eXjMQHs|a1^80bX*%6d`rnz&*#rGIF!cN{j8sP0Irek0_8N#K!Cjt#)~9F97vhQR zD%L*ROmx`)>`y7PJlkm@o{>NW)2>}9UXKLefL-^%w*VfMyxwq}&NKj&a)4Uf*&COW zpfNE4ph0N?{W_<~N$`~i?RU~04bdc#p-pwCri1Me>W(xX-uHPTF2Uayxhy|<66 zGM-OfZ)-Cb9qXgAyE>b*T-vj{T{kA7;w;vVgcNIlZ}-Lyz9$<)P*mszV44Maz5oIb zudiSHUpL#Kk$+9IL)#j>!~UygOM<36gEp<#DgMtn(r5J_?0LaX0~qbV#Q=zbdcFBf z44@5P_qo(C#}eepRY0M_#=jLub4+@sRpZqL3pn8Ey5@i+Y>|8cj3&EeAwZlYGaaR4 zCZ5K4DMJTqTZ(sQr3`Cy$%Hy;2tq4$H#HWQb-b>p8*BaCyCFR$@qm?g7}8WRQbe>l zkSq~u4VFz@3p^s6E6b{a3^bg*2dw;AscJ{_>Hi+5QJC*Bm%~6QQ<#r1el}CF04D|# zP^KXdHU>1{Q5>Ou93ho-G<%^WTp5NjD5~tghiHIc&3_Ehm=XZt7P8F{@H0O+_Oe3( zk36(#1N0WK;lqeH<^jf9X@bQ26K#etR08C2x!j~`(3=7Qhl68DbpeOG>3W(6#F7

i9zDz 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

ZncP{NN8~whjP*zOezTgtlJrNRE{iZP0>|@V2 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 Tu*h5>M8d&1?!9}JHGcaqKLP57 diff --git a/notebook/parallel_vectorize.ipynb b/notebook/parallel_vectorize.ipynb index b0bdaff..518594a 100644 --- a/notebook/parallel_vectorize.ipynb +++ b/notebook/parallel_vectorize.ipynb @@ -78,7 +78,7 @@ }, { "cell_type": "code", - "collapsed": false, + "collapsed": true, "input": [ "from llvm.ee import *", "engine = EngineBuilder.new(m).create() # Generate JIT engine", @@ -153,6 +153,97 @@ } ], "prompt_number": 4 + }, + { + "cell_type": "markdown", + "source": [ + "* * *", + "", + "Internals", + "---------", + "", + "There are four functions behind each multithreaded _ufunc_.", + "", + "1. the workload function (user defined);", + "2. the thread worker function (`UFuncCoreGeneric`);", + "3. the thread manager function (`ParallelUFuncPlatform`);", + "4. the ufunc entry point function (`SpecializedParallelUFunc`).", + "", + "**UFuncCoreGeneric** specializes to a llvm function type.", + "**It currently understands simple builtin scalar types (integers, float, double) only as arguments and return-type for the workload function.**", + "It sends work items to the workload function and performs work-stealing when it has finished its own workqueue.", + "Work-stealing uses atomic compare-exchange (or CAS) instruction to acquire ownership of a workqueue.", + "Work-stealing is implemented in the `UFuncCore._do_work_stealing`.", + "It can be disabled on platform that does not support atomic operations.", + "", + "**ParallelUFuncPlatform** specializes to the maximum number of threads. ", + "It divides all works equally among all threads.", + "Each thread executes the function generated by `UFuncCoreGeneric` once.", + "", + "**SpecializedParallelUFunc** is the specialized _ufunc_ entry point for a specific combination of ", + "workload, UFuncCoreGeneric and ParallelUFuncPlatform.", + "", + "Here's an example that uses `SpecializedParallelUFunc` directly for the `SumOfThree` workload." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import parallel_vectorize as pv", + "# specialize", + "def_spuf = pv.SpecializedParallelUFunc(pv.ParallelUFuncPlatform(num_thread=2),", + " pv.UFuncCoreGeneric(llvm_sum3.type.pointee),", + " CFuncRef(llvm_sum3))", + "# define", + "spuf = def_spuf(m)", + "print(spuf.name)" + ], + "language": "python", + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "specialized_parallel_ufunc_2_ufunc_worker.i32.i32.i32.i32_sum.of.three" + ] + } + ], + "prompt_number": 5 + }, + { + "cell_type": "markdown", + "source": [ + "`CFuncRef` also accepts arbitrary function pointer as long as the function type is provided." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "# specialize", + "fnty = llvm_sum3.type.pointee", + "sum3ptr = engine.get_pointer_to_function(llvm_sum3)", + "print(\"as function pointer: %x\" % sum3ptr)", + "def_spuf = pv.SpecializedParallelUFunc(pv.ParallelUFuncPlatform(num_thread=2),", + " pv.UFuncCoreGeneric(fnty),", + " CFuncRef('sum3.as.ptr', fnty, sum3ptr)) # name, type, ptr", + "# define", + "spuf = def_spuf(m)", + "print(spuf.name)" + ], + "language": "python", + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "as function pointer: 7f0bfc090740", + "specialized_parallel_ufunc_2_ufunc_worker.i32.i32.i32.i32_sum3.as.ptr" + ] + } + ], + "prompt_number": 6 } ] } diff --git a/notebook/parallel_vectorize.pdf b/notebook/parallel_vectorize.pdf new file mode 100644 index 0000000000000000000000000000000000000000..394f3647f8bbc6b2a742f000d9eba3601f4b0fe0 GIT binary patch literal 66363 zcmce71CS-{wq;dy*|yCt+qP}nwr$(CZQHhOyQ^#Zzj*K6nHw<^F>fa0MCQqLc4mJ2 z%Z#&Qt+kUxPDq4?{wFgeN%M8hCnO_29louB1tb?2KCP6ojj59vKGPpa0TLe{pH{@& z%E{Q_&(=!c$ymtP(ALNpl7|P<(aFJB-x|^_YZ-eo=CJL4ruGi5DP@?|zaJauC_&Q? z)IsfNuVoVpm>baL@tZFq)*#tvJms@K?aF}8AiV-D@|lpimkJAZJ~YtPV}S!Fr+@

!vaZmL`9&HMV5usg-miO9%<0JmI*Vv&|k9ONu%m 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 Date: Mon, 13 Aug 2012 15:53:09 -0700 Subject: [PATCH 031/516] reorganize --- README.md | 23 - llvm_cbuilder/__init__.py => __init__.py | 0 llvm_cbuilder/builder.py => builder.py | 0 llvm_cbuilder/executor.py => executor.py | 0 llvm_cbuilder/libc.py => libc.py | 0 notebook/llvm_cbuilder_intro.ipynb | 586 ------------------- notebook/llvm_cbuilder_intro.pdf | Bin 73415 -> 0 bytes notebook/parallel_vectorize.ipynb | 251 -------- notebook/parallel_vectorize.pdf | Bin 66363 -> 0 bytes parallel_vectorize.py | 461 --------------- llvm_cbuilder/shortnames.py => shortnames.py | 0 test_parallel_vectorize.py | 130 ---- test_parallel_vectorize_numpy.py | 57 -- test_parallel_vectorize_numpy_2.py | 69 --- test_usecase_1_1.py | 56 -- test_usecase_2_1.py | 58 -- tests/test_atomic_add.py | 115 ---- tests/test_atomic_cmpxchg.py | 122 ---- tests/test_cstr_collide.py | 17 - tests/test_isprime.py | 125 ---- tests/test_loopcontrol.py | 135 ----- tests/test_nestedloops.py | 128 ---- tests/test_print.py | 60 -- tests/test_pthread.py | 90 --- tests/test_struct.py | 52 -- 25 files changed, 2535 deletions(-) delete mode 100644 README.md rename llvm_cbuilder/__init__.py => __init__.py (100%) rename llvm_cbuilder/builder.py => builder.py (100%) rename llvm_cbuilder/executor.py => executor.py (100%) rename llvm_cbuilder/libc.py => libc.py (100%) delete mode 100644 notebook/llvm_cbuilder_intro.ipynb delete mode 100644 notebook/llvm_cbuilder_intro.pdf delete mode 100644 notebook/parallel_vectorize.ipynb delete mode 100644 notebook/parallel_vectorize.pdf delete mode 100644 parallel_vectorize.py rename llvm_cbuilder/shortnames.py => shortnames.py (100%) delete mode 100644 test_parallel_vectorize.py delete mode 100644 test_parallel_vectorize_numpy.py delete mode 100644 test_parallel_vectorize_numpy_2.py delete mode 100644 test_usecase_1_1.py delete mode 100644 test_usecase_2_1.py delete mode 100644 tests/test_atomic_add.py delete mode 100644 tests/test_atomic_cmpxchg.py delete mode 100644 tests/test_cstr_collide.py delete mode 100644 tests/test_isprime.py delete mode 100644 tests/test_loopcontrol.py delete mode 100644 tests/test_nestedloops.py delete mode 100644 tests/test_print.py delete mode 100644 tests/test_pthread.py delete mode 100644 tests/test_struct.py diff --git a/README.md b/README.md deleted file mode 100644 index a63039a..0000000 --- a/README.md +++ /dev/null @@ -1,23 +0,0 @@ -llvm_cbuilder -------------- - -A llvm-py Builder wrapper for writing in slightly higher-level constructs. -This is aiming for two usecases: - -1. Emit LLVM code in a more human-readable way; - -2. Writing low-level code that you can't do it properly/portably with C, e.g - template (generic), atomic operations, memory ordering... - - - -Parallel Vectorize ------------------- - -`parallel_vectorize.py` implements a set of code generator that bases on -llvm_cbuilder to create specialized parallel ufunc. - -See `test_parallel_vectorize_numpy*.py` for testing and demo of the code -with the new `numpy.fromfunc()`. - - diff --git a/llvm_cbuilder/__init__.py b/__init__.py similarity index 100% rename from llvm_cbuilder/__init__.py rename to __init__.py diff --git a/llvm_cbuilder/builder.py b/builder.py similarity index 100% rename from llvm_cbuilder/builder.py rename to builder.py diff --git a/llvm_cbuilder/executor.py b/executor.py similarity index 100% rename from llvm_cbuilder/executor.py rename to executor.py diff --git a/llvm_cbuilder/libc.py b/libc.py similarity index 100% rename from llvm_cbuilder/libc.py rename to libc.py diff --git a/notebook/llvm_cbuilder_intro.ipynb b/notebook/llvm_cbuilder_intro.ipynb deleted file mode 100644 index 9234f3d..0000000 --- a/notebook/llvm_cbuilder_intro.ipynb +++ /dev/null @@ -1,586 +0,0 @@ -{ - "metadata": { - "name": "llvm_cbuilder_intro" - }, - "nbformat": 2, - "worksheets": [ - { - "cells": [ - { - "cell_type": "markdown", - "source": [ - "llvm_cbuilder: A Quick Tour", - "---------------------------", - "", - "Writing code generation logic in pure llvmpy requires one to think like a compiler -- ", - "dealing with basic-blocks, branches, SSA, etc.", - "The resulting code looks like assembly code, with no apparent hint about the control-flow.", - "", - "llvm_cbuilder is originally designed to simplify the translation of C code into llvmpy.", - "It provides a simple API for mimicking C programming in Python.", - "With llvm_cbulder, one can write very low-level code, probably even lower-level than C.", - "At the same time, one can use if-else, loop, structures and a bit of OOP." - ] - }, - { - "cell_type": "markdown", - "source": [ - "A Simple Example", - "----------------", - "", - "Let's see some action.", - "We will define a function that calculates the square of a double-precision float." - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "from llvm.core import *", - "from llvm_cbuilder import *", - "import llvm_cbuilder.shortnames as C", - "", - "class Square(CDefinition):", - " # prototype: double square(double x)", - " _name_ = 'square' # function name", - " _retty_ = C.double", - " _argtys_ = [ ('x', C.double) ]", - " ", - " def body(self, x):", - " y = x * x # just write out the expression", - " self.ret(y)" - ], - "language": "python", - "outputs": [], - "prompt_number": 1 - }, - { - "cell_type": "markdown", - "source": [ - "Notice how numerical expressions can be written naturally." - ] - }, - { - "cell_type": "markdown", - "source": [ - "Let's see the emitted code:" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "m = Module.new('my_module')", - "llvm_square = Square()(m) # define square() in my_module", - "print(m)" - ], - "language": "python", - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "; ModuleID = 'my_module'", - "", - "define double @square(double %x) {", - "decl:", - " %x1 = alloca double", - " br label %body", - "", - "body: ; preds = %decl", - " store double %x, double* %x1", - " %0 = load double* %x1", - " %1 = load double* %x1", - " %2 = fmul double %0, %1", - " ret double %2", - "}", - "" - ] - } - ], - "prompt_number": 2 - }, - { - "cell_type": "markdown", - "source": [ - "Let's generate a ctype function object to call `square()` in the Python code:" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "exe = CExecutor(m)", - "square = exe.get_ctype_function(llvm_square, \"double, double\")", - "result = square(1.2)", - "print(result)" - ], - "language": "python", - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "1.44" - ] - } - ], - "prompt_number": 3 - }, - { - "cell_type": "markdown", - "source": [ - "Control Flow Constructs", - "-----------------------", - "", - "The main strength of llvm_cbuilder is the control-flow constructs. ", - "They use the python \"with\" statement to setup new code blocks to", - "contain different paths of the control flow.", - "", - "The following example demonstrates both the if-else and loop contructs:" - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "class IsPrime(CDefinition):", - " # prototype int isprime(int x)", - " _name_ = 'isprime'", - " _retty_ = C.int", - " _argtys_ = [ ('x', C.int) ]", - " ", - " def body(self, x):", - " two = self.constant(C.int, 2)", - " true = one = self.constant(C.int, 1)", - " false = zero = self.constant(C.int, 0)", - " ", - " with self.ifelse( x <= two ) as ifelse:", - " with ifelse.then():", - " self.ret(true)", - " ", - " with self.ifelse( (x % two) == zero ) as ifelse:", - " with ifelse.then():", - " self.ret(false)", - " ", - " idx = self.var(C.int, 3, name='idx')", - " with self.loop() as loop:", - " with loop.condition() as setcond:", - " setcond( idx < x )", - " ", - " with loop.body():", - " with self.ifelse( (x % idx) == zero ) as ifelse:", - " with ifelse.then():", - " self.ret(false)", - " idx += two", - " self.ret(true)" - ], - "language": "python", - "outputs": [], - "prompt_number": 4 - }, - { - "cell_type": "markdown", - "source": [ - "The code above is quite verbose.", - "It is like writing in Pascal or Ada. ", - "But, it is still easier than writing in llvmpy directly.", - "Take a look at the generated LLVM IR below." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "llvm_isprime = IsPrime()(m)", - "print(llvm_isprime)" - ], - "language": "python", - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "", - "define i32 @isprime(i32 %x) {", - "decl:", - " %x1 = alloca i32", - " %idx = alloca i32", - " br label %body", - "", - "body: ; preds = %decl", - " store i32 %x, i32* %x1", - " %0 = load i32* %x1", - " %1 = icmp sle i32 %0, 2", - " br i1 %1, label %if.then, label %if.else", - "", - "if.then: ; preds = %body", - " ret i32 1", - "", - "if.else: ; preds = %body", - " br label %if.end", - "", - "if.end: ; preds = %if.else", - " %2 = load i32* %x1", - " %3 = srem i32 %2, 2", - " %4 = icmp eq i32 %3, 0", - " br i1 %4, label %if.then2, label %if.else3", - "", - "if.then2: ; preds = %if.end", - " ret i32 0", - "", - "if.else3: ; preds = %if.end", - " br label %if.end4", - "", - "if.end4: ; preds = %if.else3", - " store i32 3, i32* %idx", - " br label %loop.cond", - "", - "loop.cond: ; preds = %if.end7, %if.end4", - " %5 = load i32* %idx", - " %6 = load i32* %x1", - " %7 = icmp slt i32 %5, %6", - " br i1 %7, label %loop.body, label %loop.end", - "", - "loop.body: ; preds = %loop.cond", - " %8 = load i32* %x1", - " %9 = load i32* %idx", - " %10 = srem i32 %8, %9", - " %11 = icmp eq i32 %10, 0", - " br i1 %11, label %if.then5, label %if.else6", - "", - "loop.end: ; preds = %loop.cond", - " ret i32 1", - "", - "if.then5: ; preds = %loop.body", - " ret i32 0", - "", - "if.else6: ; preds = %loop.body", - " br label %if.end7", - "", - "if.end7: ; preds = %if.else6", - " %12 = load i32* %idx", - " %13 = add i32 %12, 2", - " store i32 %13, i32* %idx", - " br label %loop.cond", - "}", - "" - ] - } - ], - "prompt_number": 5 - }, - { - "cell_type": "markdown", - "source": [ - "We'll setup a ctype function object to try it out:" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "isprime = exe.get_ctype_function(llvm_isprime, 'int, int')", - "prime_100 = filter(isprime, range(2, 100))", - "print(prime_100)" - ], - "language": "python", - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]" - ] - } - ], - "prompt_number": 6 - }, - { - "cell_type": "markdown", - "source": [ - "Structures", - "----------", - "", - "It is possible to create structures in llvm_cbuilder. ", - "Beware that structures in LLVM are unlike those in C.", - "LLVM type system allows structures to be literal or identified.", - "Literal structures are equivalent iff they have the same elements.", - "Identified structures are equivalent iff they have the same name.", - "In llvm_cbuilder, all structures are, by default, literal types.", - "", - "Here's an example:" - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "class Vector2D(CStruct):", - " _fields_ = [", - " ('x', C.float),", - " ('y', C.float),", - " ]" - ], - "language": "python", - "outputs": [], - "prompt_number": 7 - }, - { - "cell_type": "markdown", - "source": [ - "That's all you need for a structure. Very much like defining structures with ctypes.", - "", - "We can also bind methods to structures which inline code to the caller." - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "class Vector2D(CStruct):", - " _fields_ = [", - " ('x', C.float),", - " ('y', C.float),", - " ]", - " ", - " def add(self, other):", - " self.x += other.x", - " self.y += other.y" - ], - "language": "python", - "outputs": [], - "prompt_number": 8 - }, - { - "cell_type": "markdown", - "source": [ - "Setup a a test function:" - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "class TestVector(CDefinition):", - " _name_ = 'testvector'", - " _retty_ = C.float", - " _argtys_ = [('x', C.float), ", - " ('y', C.float)] ", - " ", - " def body(self, x, y):", - " va = self.var(Vector2D)", - " vb = self.var(Vector2D)", - " va.x.assign(self.constant(C.float, 10))", - " va.y.assign(self.constant(C.float, 20))", - " vb.x.assign(x)", - " vb.y.assign(y)", - " ", - " va.add(vb)", - " ", - " return self.ret(va.x * va.y)", - " " - ], - "language": "python", - "outputs": [], - "prompt_number": 9 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "llvm_testvec = TestVector()(m)", - "testvec = exe.get_ctype_function(llvm_testvec, \"float, float, float\")", - "print(testvec(-8, 5)) # should output 50" - ], - "language": "python", - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "50.0" - ] - } - ], - "prompt_number": 10 - }, - { - "cell_type": "markdown", - "source": [ - "Generic Programming", - "-------------------", - "", - "llvm_cbuilder supports generic function (or template function for C++).", - "When a `CDefinition` defines the `specialize` class method,", - "its constructor will invoke `specialize`.", - "All parameters passed to the constructor are forwarded to `specialize`.", - "", - "The constructor of a generic CDefinition creates a new dynamic class with the original CDefinition subclass as the parent.", - "Thus, `specialize` can modify class attributes without affecting the parent." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "class GenericSquare(CDefinition):", - " @classmethod", - " def specialize(cls, data_type):", - " cls._name_ = '.'.join(['square', str(data_type)]) # set function name", - " cls._retty_ = data_type # set return type", - " cls._argtys_ = [ ('x', data_type) ] # set argument type", - " ", - " def body(self, x):", - " y = x * x # just write out the expression", - " self.ret(y)", - " ", - "llvm_square_int = GenericSquare(data_type=C.int)(m)", - "llvm_square_float = GenericSquare(data_type=C.float)(m)", - "", - "print(llvm_square_int)", - "print(llvm_square_float)" - ], - "language": "python", - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "", - "define i32 @square.i32(i32 %x) {", - "decl:", - " %x1 = alloca i32", - " br label %body", - "", - "body: ; preds = %decl", - " store i32 %x, i32* %x1", - " %0 = load i32* %x1", - " %1 = load i32* %x1", - " %2 = mul i32 %0, %1", - " ret i32 %2", - "}", - "", - "", - "define float @square.float(float %x) {", - "decl:", - " %x1 = alloca float", - " br label %body", - "", - "body: ; preds = %decl", - " store float %x, float* %x1", - " %0 = load float* %x1", - " %1 = load float* %x1", - " %2 = fmul float %0, %1", - " ret float %2", - "}", - "" - ] - } - ], - "prompt_number": 11 - }, - { - "cell_type": "markdown", - "source": [ - "External Functions", - "------------------", - "", - "`CExternal` is a convenient class to help accessing externally-defined functions.", - "", - "We define an external interface to `sqrtf()` in libm." - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "class LibM(CExternal):", - " sqrtf = Type.function(C.float, [C.float])" - ], - "language": "python", - "outputs": [], - "prompt_number": 12 - }, - { - "cell_type": "markdown", - "source": [ - "All class attributes that are `llvm.core.FunctionType` in `CExternal` ", - "are converted to a `CFunc` instance.", - "`CFunc` instances are callable.", - "`CFunc.__call__` generates code that perform the corresponding LLVM function call.", - "", - "The following example demonstrates the usage of `CExternal` and `CFunc`." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "class TestSqrtf(CDefinition):", - " _name_ = 'test_sqrtf'", - " _retty_ = C.float", - " _argtys_ = [('x', C.float)]", - " ", - " def body(self, x):", - " libm = LibM(self) # init the API", - " y = libm.sqrtf(x) # call sqrtf", - " self.ret(y)", - " ", - "llvm_sqrtf = TestSqrtf()(m)", - "sqrtf = exe.get_ctype_function(llvm_sqrtf, 'float, float')", - "print(sqrtf(144))" - ], - "language": "python", - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "12.0" - ] - } - ], - "prompt_number": 13 - }, - { - "cell_type": "markdown", - "source": [ - "Casting", - "-------", - "", - "Unlike C, llvm_cbuilder does not automatically cast variables.", - "It is up to the user to explicit cast types.", - "All binary operations require both operands to be the same type.", - "All values in llvm_cbuilder has a `cast(destty)` method.", - "", - "For example:" - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "class CastExample(CDefinition):", - " _name_ = 'cast_example'", - " _retty_ = C.float", - " _argtys_ = [('x', C.int)]", - " ", - " def body(self, x):", - " y = x.cast(C.float) # cast integer x to float", - " self.ret(y)" - ], - "language": "python", - "outputs": [], - "prompt_number": 14 - }, - { - "cell_type": "markdown", - "source": [ - "More... (TODO)" - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/notebook/llvm_cbuilder_intro.pdf b/notebook/llvm_cbuilder_intro.pdf deleted file mode 100644 index a7b17d48308c8792bce64c244e7678e19f1fc6df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 73415 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

!vaZmL`9&HMV5usg-miO9%<0JmI*Vv&|k9ONu%m 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 num_thread, equally divide the works. - # If total_work % num_thread != 0, the last thread does all remaining works. - # If total_work < num_thread, each thread does one work, - # and set num_thread to total_work - N = dimensions[0] - ChunkSize = self.var_copy(N / num_thread.cast(N.type)) - ChunkSize_NULL = self.constant_null(ChunkSize.type) - with self.ifelse(ChunkSize == ChunkSize_NULL) as ifelse: - with ifelse.then(): - ChunkSize.assign(self.constant(ChunkSize.type, 1)) - num_thread.assign(N.cast(num_thread.type)) - - # Populate workqueue for all threads - self._populate_workqueues(workqueues, N, ChunkSize, num_thread) - - # Populate contexts for all threads - self._populate_context(contexts, common, num_thread) - - # Dispatch worker threads - self._dispatch_worker(worker, contexts, num_thread) - - ## DEBUG ONLY ## - # Check for race condition - if True: - total_completed = self.var(C.intp, 0, name='total_completed') - for t in range(ThreadCount): - cur_ctxt = contexts[t].as_struct(Context) - total_completed += cur_ctxt.completed - # self.debug(cur_ctxt.id, 'completed', cur_ctxt.completed) - - with self.ifelse( total_completed == N ) as ifelse: - with ifelse.then(): - # self.debug("All is well!") - pass # keep quite if all is well - with ifelse.otherwise(): - self.debug("ERROR: race occurred! Trigger segfault") - self.unreachable() - - # Return - self.ret() - - def _populate_workqueues(self, workqueues, N, ChunkSize, num_thread): - '''loop over all threads and populate the workqueue for each of them. - ''' - ONE = self.constant(num_thread.type, 1) - with self.for_range(num_thread) as (loop, i): - cur_wq = workqueues[i].as_struct(WorkQueue) - cur_wq.next.assign(i.cast(ChunkSize.type) * ChunkSize) - cur_wq.last.assign((i + ONE).cast(ChunkSize.type) * ChunkSize) - cur_wq.lock.assign(self.constant(C.int, 0)) - # end loop - last_wq = workqueues[num_thread - ONE].as_struct(WorkQueue) - last_wq.last.assign(N) - - def _populate_context(self, contexts, common, num_thread): - '''loop over all threads and populate contexts for each of them. - ''' - ONE = self.constant(num_thread.type, 1) - with self.for_range(num_thread) as (loop, i): - cur_ctxt = contexts[i].as_struct(Context) - cur_ctxt.common.assign(common.reference()) - cur_ctxt.id.assign(i) - cur_ctxt.completed.assign( - self.constant_null(cur_ctxt.completed.type)) - -class ParallelUFuncPosixMixin(object): - '''ParallelUFunc mixin that implements _dispatch_worker to use pthread. - ''' - def _dispatch_worker(self, worker, contexts, num_thread): - api = PThreadAPI(self) - NULL = self.constant_null(C.void_p) - - threads = self.array(api.pthread_t, num_thread, name='threads') - - # self.debug("launch threads") - # TODO error handling - - ONE = self.constant(num_thread.type, 1) - with self.for_range(num_thread) as (loop, i): - api.pthread_create(threads[i].reference(), NULL, worker, - contexts[i].reference().cast(C.void_p)) - - with self.for_range(num_thread) as (loop, i): - api.pthread_join(threads[i], NULL) - -class UFuncCore(CDefinition): - '''core work of a ufunc worker thread - - Subclass to implement UFuncCore._do_work - - Generates the workqueue handling and work stealing and invoke - the work function for each work item. - ''' - _name_ = 'ufunc_worker' - _argtys_ = [ - ('context', C.pointer(Context.llvm_type())), - ] - - def body(self, context): - context = context.as_struct(Context) - common = context.common.as_struct(ContextCommon) - tid = context.id - - # self.debug("start thread", tid, "/", common.num_thread) - workqueue = common.workqueues[tid].as_struct(WorkQueue) - - self._do_workqueue(common, workqueue, tid, context.completed) - self._do_work_stealing(common, tid, context.completed) # optional - - self.ret() - - def _do_workqueue(self, common, workqueue, tid, completed): - '''process local workqueue. - ''' - ZERO = self.constant_null(C.int) - - with self.forever() as loop: - workqueue.Lock() - # Critical section - item = self.var_copy(workqueue.next, name='item') - workqueue.next += self.constant(item.type, 1) - last = self.var_copy(workqueue.last, name='last') - # Release - workqueue.Unlock() - - with self.ifelse( item >= last ) as ifelse: - with ifelse.then(): - loop.break_loop() - - self._do_work(common, item, tid) - completed += self.constant(completed.type, 1) - - def _do_work_stealing(self, common, tid, completed): - '''steal work from other workqueues. - ''' - # self.debug("start work stealing", tid) - steal_continue = self.var(C.int, 1) - STEAL_STOP = self.constant_null(steal_continue.type) - - # Loop until all workqueues are done. - with self.loop() as loop: - with loop.condition() as setcond: - setcond( steal_continue != STEAL_STOP ) - - with loop.body(): - steal_continue.assign(STEAL_STOP) - self._do_work_stealing_innerloop(common, steal_continue, tid, - completed) - - def _do_work_stealing_innerloop(self, common, steal_continue, tid, - completed): - '''loop over all other threads and try to steal work. - ''' - with self.for_range(common.num_thread) as (loop, i): - with self.ifelse( i != tid ) as ifelse: - with ifelse.then(): - otherqueue = common.workqueues[i].as_struct(WorkQueue) - self._do_work_stealing_check(common, otherqueue, - steal_continue, tid, - completed) - - def _do_work_stealing_check(self, common, otherqueue, steal_continue, tid, - completed): - '''check the workqueue for any remaining work and steal it. - ''' - otherqueue.Lock() - # Acquired - ONE = self.constant(otherqueue.last.type, 1) - STEAL_CONTINUE = self.constant(steal_continue.type, 1) - with self.ifelse(otherqueue.next < otherqueue.last) as ifelse: - with ifelse.then(): - otherqueue.last -= ONE - item = self.var_copy(otherqueue.last) - - otherqueue.Unlock() - # Released - - self._do_work(common, item, tid) - completed += self.constant(completed.type, 1) - - # Mark incomplete thread - steal_continue.assign(STEAL_CONTINUE) - - with ifelse.otherwise(): - otherqueue.Unlock() - # Released - - def _do_work(self, common, item, tid): - '''prepare to call the actual work function - - Implementation depends on number and type of arguments. - ''' - raise NotImplementedError - -class SpecializedParallelUFunc(CDefinition): - '''a generic ufunc that wraps ParallelUFunc, UFuncCore and the workload - ''' - _argtys_ = [ - ('args', C.pointer(C.char_p)), - ('dimensions', C.pointer(C.intp)), - ('steps', C.pointer(C.intp)), - ('data', C.void_p), - ] - - def body(self, args, dimensions, steps, data,): - pufunc = self.depends(self.PUFuncDef) - core = self.depends(self.CoreDef) - func = self.depends(self.FuncDef) - to_void_p = lambda x: x.cast(C.void_p) - pufunc(to_void_p(func), to_void_p(core), args, dimensions, steps, data) - self.ret() - - @classmethod - def specialize(cls, pufunc_def, core_def, func_def): - '''specialize to a combination of ParallelUFunc, UFuncCore and workload - ''' - cls._name_ = 'specialized_%s_%s_%s'% (pufunc_def, core_def, func_def) - cls.PUFuncDef = pufunc_def - cls.CoreDef = core_def - cls.FuncDef = func_def - -class PThreadAPI(CExternal): - '''external declaration of pthread API - ''' - pthread_t = C.void_p - - pthread_create = Type.function(C.int, - [C.pointer(pthread_t), # thread_t - C.void_p, # thread attr - C.void_p, # function - C.void_p]) # arg - - pthread_join = Type.function(C.int, [C.void_p, C.void_p]) - - -class UFuncCoreGeneric(UFuncCore): - '''A generic ufunc core worker from LLVM function type - ''' - def _do_work(self, common, item, tid): - ufunc_type = Type.function(self.RETTY, self.ARGTYS) - ufunc_ptr = CFunc(self, common.func.cast(C.pointer(ufunc_type)).value) - - get_offset = lambda B, S, T: B[item * S].reference().cast(C.pointer(T)) - - indata = [] - for i, argty in enumerate(self.ARGTYS): - ptr = get_offset(common.args[i], common.steps[i], argty) - indata.append(ptr.load()) - - out_index = len(self.ARGTYS) - outptr = get_offset(common.args[out_index], common.steps[out_index], - self.RETTY) - - res = ufunc_ptr(*indata) - outptr.store(res) - - @classmethod - def specialize(cls, fntype): - '''specialize to a LLVM function type - - fntype : a LLVM function type (llvm.core.FunctionType) - ''' - cls._name_ = '.'.join([cls._name_] + - map(str, [fntype.return_type] + fntype.args)) - - cls.RETTY = fntype.return_type - cls.ARGTYS = tuple(fntype.args) - - -if sys.platform not in ['win32']: - class ParallelUFuncPlatform(ParallelUFunc, ParallelUFuncPosixMixin): - pass -else: - raise NotImplementedError("Threading for %s" % sys.platform) - - - -def parallel_vectorize_from_func(lfunc, engine=None): - '''create ufunc from a llvm.core.Function - - If engine is given, return a function object which can be called - from python. (This needs Jay's numpy.fromfunc). - Otherwise, return the specialized ufunc as a llvm.core.Function - ''' - import multiprocessing - NUM_CPU = multiprocessing.cpu_count() - - fntype = lfunc.type.pointee - def_spuf = SpecializedParallelUFunc( - ParallelUFuncPlatform(num_thread=NUM_CPU), - UFuncCoreGeneric(fntype), - CFuncRef(lfunc)) - spuf = def_spuf(lfunc.module) - if engine is None: - return spuf - else: - import numpy as np - - fptr = engine.get_pointer_to_function(spuf) - inct = len(fntype.args) - outct = 1 - - # TODO refactor - typemap = { - 'i8' : np.int8, - 'i16' : np.int16, - 'i32' : np.int32, - 'i64' : np.int64, - 'float' : np.float32, - 'double' : np.float64, - } - try: - ptr_t = long - except: - ptr_t = int - assert False, "Having check this yet" - - get_typenum = lambda T:np.dtype(typemap[str(T)]).num - assert fntype.return_type != C.void - tys = list(map(get_typenum, list(fntype.args) + [fntype.return_type])) - # Becareful that fromfunc does not provide full error checking yet. - # If typenum is out-of-bound, we have nasty memory corruptions. - # For instance, -1 for typenum will cause segfault. - # If elements of type-list (2nd arg) is tuple instead, - # there will also memory corruption. (Seems like code rewrite.) - return np.fromfunc([ptr_t(fptr)], [tys], inct, outct, [None]) - diff --git a/llvm_cbuilder/shortnames.py b/shortnames.py similarity index 100% rename from llvm_cbuilder/shortnames.py rename to shortnames.py diff --git a/test_parallel_vectorize.py b/test_parallel_vectorize.py deleted file mode 100644 index 1a850f5..0000000 --- a/test_parallel_vectorize.py +++ /dev/null @@ -1,130 +0,0 @@ -from parallel_vectorize import * - - -class Work_D_D(CDefinition): - _name_ = 'work_d_d' - _retty_ = C.double - _argtys_ = [ - ('inval', C.double), - ] - def body(self, inval): - self.ret(inval / self.constant(inval.type, 2.345)) - -class UFuncCore_D_D(UFuncCore): - ''' - Specialize UFuncCore for double input, double output. - ''' - _name_ = UFuncCore._name_ + '_d_d' - def _do_work(self, common, item, tid): - ufunc_type = Type.function(C.double, [C.double]) - ufunc_ptr = CFunc(self, common.func.cast(C.pointer(ufunc_type)).value) - - inbase = common.args[0] - outbase = common.args[1] - - instep = common.steps[0] - outstep = common.steps[1] - - indata = inbase[item * instep].reference().cast(C.pointer(C.double)) - outdata = outbase[item * outstep].reference().cast(C.pointer(C.double)) - - res = ufunc_ptr(indata.load()) - outdata.store(res) - -class ParallelUFuncPosix(ParallelUFunc, ParallelUFuncPosixMixin): - pass - -class Tester(CDefinition): - ''' - Generate test. - ''' - _name_ = 'tester' - - def body(self): - # depends - module = self.function.module - - ThreadCount = 2 - ArgCount = 2 - WorkCount = 10000 - - - spufdef = SpecializedParallelUFunc(ParallelUFuncPosix(num_thread=2), - UFuncCore_D_D(), - Work_D_D()) - - sppufunc = self.depends(spufdef) - - # real work - NULL = self.constant_null(C.void_p) - - args = self.array(C.char_p, 2, name='args') - - args_double = [] - for t in range(ThreadCount): - args_for_thread = self.array(C.double, WorkCount) - args[t].assign(args_for_thread.cast(C.char_p)) - args_double.append(args_for_thread) - - dims = self.array(C.intp, 1, name='dims') - dims[0].assign(self.constant(C.intp, WorkCount)) - - steps = self.array(C.intp, ArgCount, name='steps') - - for c in range(ArgCount): - steps[c].assign(self.constant(C.intp, 8)) - - # populate data - inbase = args_double[0] - - i = self.var(C.intp, 0) - with self.loop() as loop: - with loop.condition() as setcond: - setcond( i < self.constant(C.intp, WorkCount) ) - with loop.body(): - inbase[i].assign(i.cast(C.double)) - i += self.constant(C.intp, 1) - - # call parallel ufunc - sppufunc(args, dims, steps, NULL) - - # check error - outbase = args_double[-1] - with self.for_range(self.constant(C.intp, WorkCount)) as (loop, i): - test = outbase[i] != (inbase[i] / self.constant(C.double, 2.345)) - with self.ifelse( test ) as ifelse: - with ifelse.then(): - self.debug("Invalid data at i =", i, outbase[i], inbase[i]) - - self.ret() - -def main(): - module = Module.new(__name__) - - mpm = PassManager.new() - pmbuilder = PassManagerBuilder.new() - pmbuilder.opt_level = 3 - pmbuilder.populate(mpm) - - fntester = Tester.define(module) - -# print(module) - module.verify() - - mpm.run(module) - - print('optimized'.center(80,'-')) - print(module) - - # run - print('run') - exe = CExecutor(module) - func = exe.get_ctype_function(fntester, 'void') - - func() - # Will not reach here is race condition occurred - print('Good') - -if __name__ == '__main__': - main() - diff --git a/test_parallel_vectorize_numpy.py b/test_parallel_vectorize_numpy.py deleted file mode 100644 index 392c81d..0000000 --- a/test_parallel_vectorize_numpy.py +++ /dev/null @@ -1,57 +0,0 @@ -''' -Test parallel-vectorize with numpy.fromfunc. -Uses the work load from test_parallel_vectorize. -''' - -from test_parallel_vectorize import * - -import numpy as np - -def main(): - module = Module.new(__name__) - - spufdef = SpecializedParallelUFunc(ParallelUFuncPosix(num_thread=2), - UFuncCore_D_D(), - Work_D_D()) - - sppufunc = spufdef(module) - - module.verify() - - mpm = PassManager.new() - pmbuilder = PassManagerBuilder.new() - pmbuilder.opt_level = 3 - pmbuilder.populate(mpm) - - mpm.run(module) -# print module - - # run - - exe = CExecutor(module) - funcptr = exe.engine.get_pointer_to_function(sppufunc) - print("Function pointer: %x" % funcptr) - - ptr_t = long # py2 only - - # Becareful that fromfunc does not provide full error checking yet. - # If typenum is out-of-bound, we have nasty memory corruptions. - # For instance, -1 for typenum will cause segfault. - # If elements of type-list (2nd arg) is tuple instead, - # there will also memory corruption. (Seems like code rewrite.) - typenum = np.dtype(np.double).num - ufunc = np.fromfunc([ptr_t(funcptr)], [[typenum, typenum]], 1, 1, [None]) - - x = np.linspace(0., 10., 1000) - x.dtype=np.double -# print x - ans = ufunc(x) -# print ans - - if not ( ans == x/2.345 ).all(): - raise ValueError('Computation failed') - else: - print('Good') - -if __name__ == '__main__': - main() diff --git a/test_parallel_vectorize_numpy_2.py b/test_parallel_vectorize_numpy_2.py deleted file mode 100644 index f846a25..0000000 --- a/test_parallel_vectorize_numpy_2.py +++ /dev/null @@ -1,69 +0,0 @@ -''' -Test parallel-vectorize with numpy.fromfunc. -Uses the work load from test_parallel_vectorize. -This time we pass a function pointer. -''' - -from test_parallel_vectorize import * - -import numpy as np - -def main(): - module = Module.new(__name__) - exe = CExecutor(module) - - workdef = Work_D_D() - workfunc = workdef(module) - - # get pointer to workfunc - workfunc_ptr = exe.engine.get_pointer_to_function(workfunc) - - workdecl = CFuncRef(workfunc.name, workfunc.type.pointee, workfunc_ptr) - - spufdef = SpecializedParallelUFunc(ParallelUFuncPosix(num_thread=2), - UFuncCore_D_D(), - workdecl) - - - sppufunc = spufdef(module) - sppufunc.verify() - print(sppufunc) - module.verify() - - mpm = PassManager.new() - pmbuilder = PassManagerBuilder.new() - pmbuilder.opt_level = 3 - pmbuilder.populate(mpm) - - mpm.run(module) - print(module) - - - # run - - funcptr = exe.engine.get_pointer_to_function(sppufunc) - print("Function pointer: %x" % funcptr) - - ptr_t = long # py2 only - - # Becareful that fromfunc does not provide full error checking yet. - # If typenum is out-of-bound, we have nasty memory corruptions. - # For instance, -1 for typenum will cause segfault. - # If elements of type-list (2nd arg) is tuple instead, - # there will also memory corruption. (Seems like code rewrite.) - typenum = np.dtype(np.double).num - ufunc = np.fromfunc([ptr_t(funcptr)], [[typenum, typenum]], 1, 1, [None]) - - x = np.linspace(0., 10., 1000) - x.dtype=np.double -# print x - ans = ufunc(x) -# print ans - - if not ( ans == x/2.345 ).all(): - raise ValueError('Computation failed') - else: - print('Good') - -if __name__ == '__main__': - main() diff --git a/test_usecase_1_1.py b/test_usecase_1_1.py deleted file mode 100644 index 5cc4d7a..0000000 --- a/test_usecase_1_1.py +++ /dev/null @@ -1,56 +0,0 @@ -from parallel_vectorize import * -from llvm_cbuilder import shortnames as C -from llvm.core import * -import numpy as np -import unittest -from random import random - -class OneOne(CDefinition): - - def body(self, inval): - self.ret( (inval * inval).cast(self.OUT_TYPE) ) - - @classmethod - def specialize(cls, itype, otype): - cls._name_ = '.'.join(map(str, ['oneone', itype, otype])) - cls._retty_ = otype - cls._argtys_ = [ - ('inval', itype), - ] - cls.OUT_TYPE = otype - - -class TestParallelVectorize(unittest.TestCase): - def test_parallelvectorize_d_d(self): - self.template(C.double, C.double) - - def test_parallelvectorize_d_f(self): - self.template(C.double, C.float) - - def template(self, itype, otype): - module = Module.new(__name__) - exe = CExecutor(module) - - def_oneone = OneOne(itype, otype) - oneone = def_oneone(module) - ufunc = parallel_vectorize_from_func(oneone, exe.engine) - # print(module) - module.verify() - - x = np.linspace(.0, 10., 1000) - x.dtype = np.double - - ans = ufunc(x) - gold = x * x - - for x, y in zip(ans, gold): - if y != 0: - err = abs(x - y)/y - self.assertLess(err, 1e-6) - else: - self.assertEqual(x, y) - - -if __name__ == '__main__': - unittest.main() - diff --git a/test_usecase_2_1.py b/test_usecase_2_1.py deleted file mode 100644 index 087ee9f..0000000 --- a/test_usecase_2_1.py +++ /dev/null @@ -1,58 +0,0 @@ -from parallel_vectorize import * -from llvm_cbuilder import shortnames as C -from llvm.core import * -import numpy as np -import unittest -from random import random - -class TwoOne(CDefinition): - - def body(self, a, b): - self.ret( (a * b).cast(self.OUT_TYPE) ) - - @classmethod - def specialize(cls, itype1, itype2, otype): - cls._name_ = '.'.join(map(str, ['oneone', itype1, itype2, otype])) - cls._retty_ = otype - cls._argtys_ = [ - ('a', itype1), - ('b', itype2), - ] - cls.OUT_TYPE = otype - - -class TestParallelVectorize(unittest.TestCase): - def test_parallelvectorize_dd_d(self): - self.template(C.double, C.double, C.double) - - def test_parallelvectorize_dd_f(self): - self.template(C.double, C.double, C.float) - - def template(self, itype1, itype2, otype): - module = Module.new(__name__) - exe = CExecutor(module) - - def_twoone = TwoOne(itype1, itype2, otype) - twoone = def_twoone(module) - ufunc = parallel_vectorize_from_func(twoone, exe.engine) - # print(module) - module.verify() - - A = np.linspace(.0, 10., 1000) - A.dtype = np.double - B = np.linspace(-10., 0., 1000) - B.dtype = np.double - - ans = ufunc(A, B) - gold = A * B - - for x, y in zip(ans, gold): - if y != 0: - err = abs(x - y)/y - self.assertLess(err, 1e-6) - else: - self.assertEqual(x, y) - -if __name__ == '__main__': - unittest.main() - diff --git a/tests/test_atomic_add.py b/tests/test_atomic_add.py deleted file mode 100644 index 27688e7..0000000 --- a/tests/test_atomic_add.py +++ /dev/null @@ -1,115 +0,0 @@ -''' -Base on the test_pthread.py and extend to use atomic instructions -''' - -from llvm.core import * -from llvm.passes import * -from llvm.ee import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import unittest, logging - -# logging.basicConfig(level=logging.DEBUG) - -NUM_OF_THREAD = 4 -REPEAT = 10000 - -def gen_test_worker(mod): - cb = CBuilder.new_function(mod, 'worker', C.void, [C.pointer(C.int)]) - pval = cb.args[0] - one = cb.constant(pval.type.pointee, 1) - - ct = cb.var(C.int, 0) - limit = cb.constant(C.int, REPEAT) - with cb.loop() as loop: - with loop.condition() as setcond: - setcond( ct < limit ) - - with loop.body(): - cb.atomic_add(pval, one, 'acq_rel') - ct += one - - cb.ret() - cb.close() - return cb.function - -def gen_test_pthread(mod): - cb = CBuilder.new_function(mod, 'manager', C.int, [C.int]) - arg = cb.args[0] - - worker_func = cb.get_function_named('worker') - pthread_create = cb.get_function_named('pthread_create') - pthread_join = cb.get_function_named('pthread_join') - - - NULL = cb.constant_null(C.void_p) - cast_to_null = lambda x: x.cast(C.void_p) - - threads = cb.array(C.void_p, NUM_OF_THREAD) - - for tid in range(NUM_OF_THREAD): - pthread_create_args = [threads[tid].reference(), - NULL, - worker_func, - arg.reference()] - pthread_create(*map(cast_to_null, pthread_create_args)) - - worker_func(arg.reference()) - - for tid in range(NUM_OF_THREAD): - pthread_join_args = threads[tid], NULL - pthread_join(*map(cast_to_null, pthread_join_args)) - - - cb.ret(arg) - cb.close() - return cb.function - -class TestAtomicAdd(unittest.TestCase): - def test_atomic_add(self): - mod = Module.new(__name__) - # add pthread functions - - mod.add_function(Type.function(C.int, - [C.void_p, C.void_p, C.void_p, C.void_p]), - 'pthread_create') - - mod.add_function(Type.function(C.int, - [C.void_p, C.void_p]), - 'pthread_join') - - lf_test_worker = gen_test_worker(mod) - lf_test_pthread = gen_test_pthread(mod) - logging.debug(mod) - mod.verify() - - # optimize - fpm = FunctionPassManager.new(mod) - mpm = PassManager.new() - pmb = PassManagerBuilder.new() - pmb.vectorize = True - pmb.opt_level = 3 - pmb.populate(fpm) - pmb.populate(mpm) - - fpm.run(lf_test_worker) - fpm.run(lf_test_pthread) - mpm.run(mod) - logging.debug(mod) - mod.verify() - - # run - exe = CExecutor(mod) - exe.engine.get_pointer_to_function(mod.get_function_named('worker')) - func = exe.get_ctype_function(lf_test_pthread, 'int, int') - - inarg = 1234 - gold = inarg + (NUM_OF_THREAD + 1) * REPEAT - - for _ in range(1000): # run many many times to catch race condition - self.assertEqual(func(inarg), gold, "Unexpected race condition") - - -if __name__ == '__main__': - unittest.main() - diff --git a/tests/test_atomic_cmpxchg.py b/tests/test_atomic_cmpxchg.py deleted file mode 100644 index 27fb763..0000000 --- a/tests/test_atomic_cmpxchg.py +++ /dev/null @@ -1,122 +0,0 @@ -''' -Base on the test_pthread.py and extend to use atomic instructions -''' - -from llvm.core import * -from llvm.passes import * -from llvm.ee import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import unittest, logging - -# logging.basicConfig(level=logging.DEBUG) - -NUM_OF_THREAD = 4 -REPEAT = 10000 - -def gen_test_worker(mod): - cb = CBuilder.new_function(mod, 'worker', C.void, [C.pointer(C.int)]) - pval = cb.args[0] - one = cb.constant(pval.type.pointee, 1) - - ct = cb.var(C.int, 0) - limit = cb.constant(C.int, REPEAT) - with cb.loop() as loop: - with loop.condition() as setcond: - setcond( ct < limit ) - - with loop.body(): - oldval = pval.atomic_load('acquire') - updated = oldval + one - castmp = pval.atomic_cmpxchg(oldval, updated, 'release') - - with cb.ifelse( castmp == oldval ) as ifelse: - with ifelse.then(): - ct += one - - cb.ret() - cb.close() - return cb.function - -def gen_test_pthread(mod): - cb = CBuilder.new_function(mod, 'manager', C.int, [C.int]) - arg = cb.args[0] - - worker_func = cb.get_function_named('worker') - pthread_create = cb.get_function_named('pthread_create') - pthread_join = cb.get_function_named('pthread_join') - - - NULL = cb.constant_null(C.void_p) - cast_to_null = lambda x: x.cast(C.void_p) - - threads = cb.array(C.void_p, NUM_OF_THREAD) - - for tid in range(NUM_OF_THREAD): - pthread_create_args = [threads[tid].reference(), - NULL, - worker_func, - arg.reference()] - pthread_create(*map(cast_to_null, pthread_create_args)) - - worker_func(arg.reference()) - - for tid in range(NUM_OF_THREAD): - pthread_join_args = threads[tid], NULL - pthread_join(*map(cast_to_null, pthread_join_args)) - - - cb.ret(arg) - cb.close() - return cb.function - -class TestAtomicCmpXchg(unittest.TestCase): - def test_atomic_cmpxchg(self): - mod = Module.new(__name__) - # add pthread functions - - mod.add_function(Type.function(C.int, - [C.void_p, C.void_p, C.void_p, C.void_p]), - 'pthread_create') - - mod.add_function(Type.function(C.int, - [C.void_p, C.void_p]), - 'pthread_join') - - lf_test_worker = gen_test_worker(mod) - lf_test_pthread = gen_test_pthread(mod) - logging.debug(mod) - mod.verify() - - # optimize - fpm = FunctionPassManager.new(mod) - mpm = PassManager.new() - pmb = PassManagerBuilder.new() - pmb.vectorize = True - pmb.opt_level = 3 - pmb.populate(fpm) - pmb.populate(mpm) - - fpm.run(lf_test_worker) - fpm.run(lf_test_pthread) - mpm.run(mod) - logging.debug(mod) - mod.verify() - - # run - exe = CExecutor(mod) - exe.engine.get_pointer_to_function(mod.get_function_named('worker')) - func = exe.get_ctype_function(lf_test_pthread, 'int, int') - - inarg = 1234 - gold = inarg + (NUM_OF_THREAD + 1) * REPEAT - - for _ in range(1000): # run many many times to catch race condition - res = func(inarg) - self.assertEqual(res, gold, - "Unexpected race condition: res = %d" % res) - - -if __name__ == '__main__': - unittest.main() - diff --git a/tests/test_cstr_collide.py b/tests/test_cstr_collide.py deleted file mode 100644 index 4a427c6..0000000 --- a/tests/test_cstr_collide.py +++ /dev/null @@ -1,17 +0,0 @@ -from llvm.core import * -from llvm_cbuilder import * -from llvm_cbuilder import shortnames as C - -import unittest - -class TestCstrCollide(unittest.TestCase): - def test_same_string(self): - mod = Module.new(__name__) - cb = CBuilder.new_function(mod, 'test_cstr_collide', C.void, []) - - a = cb.constant_string("hello") - b = cb.constant_string("hello") - self.assertEqual(a.value, b.value) - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_isprime.py b/tests/test_isprime.py deleted file mode 100644 index bcc0b9c..0000000 --- a/tests/test_isprime.py +++ /dev/null @@ -1,125 +0,0 @@ -from llvm.core import * -from llvm.passes import * -from llvm.ee import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import unittest, logging - -def is_prime(x): - if x <= 2: - return True - if (x % 2) == 0: - return False - for y in range(2, int(1 + x**0.5)): - if (x % y) == 0: - return False - return True - -def gen_is_prime(mod): - functype = Type.function(C.int, [C.int]) - func = mod.add_function(functype, 'isprime') - - cb = CBuilder(func) - - arg = cb.args[0] - - two = cb.constant(C.int, 2) - true = one = cb.constant(C.int, 1) - false = zero = cb.constant(C.int, 0) - - with cb.ifelse( arg <= two ) as ifelse: - with ifelse.then(): - cb.ret(true) - - with cb.ifelse( (arg % two) == zero ) as ifelse: - with ifelse.then(): - cb.ret(false) - - idx = cb.var(C.int, 3, name='idx') - with cb.loop() as loop: - with loop.condition() as setcond: - setcond( idx < arg ) - - with loop.body(): - with cb.ifelse( (arg % idx) == zero ) as ifelse: - with ifelse.then(): - cb.ret(false) - # increment - idx += two - - cb.ret(true) - cb.close() - return func - - -def gen_is_prime_fast(mod): - functype = Type.function(C.int, [C.int]) - func = mod.add_function(functype, 'isprime_fast') - - cb = CBuilder(func) - - arg = cb.args[0] - - two = cb.constant(C.int, 2) - true = one = cb.constant(C.int, 1) - false = zero = cb.constant(C.int, 0) - - with cb.ifelse( arg <= two ) as ifelse: - with ifelse.then(): - cb.ret(true) - - with cb.ifelse( (arg % two) == zero ) as ifelse: - with ifelse.then(): - cb.ret(false) - - idx = cb.var(C.int, 3, name='idx') - - sqrt = cb.get_intrinsic(INTR_SQRT, [C.float]) - - looplimit = one + sqrt(arg.cast(C.float)).cast(C.int) - - - with cb.loop() as loop: - with loop.condition() as setcond: - setcond( idx < looplimit ) - - with loop.body(): - with cb.ifelse( (arg % idx) == zero ) as ifelse: - with ifelse.then(): - cb.ret(false) - # increment - idx += two - - - cb.ret(true) - cb.close() - return func - -class TestIsPrime(unittest.TestCase): - def test_isprime(self): - mod = Module.new(__name__) - lf_isprime = gen_is_prime(mod) - logging.debug(mod) - mod.verify() - - exe = CExecutor(mod) - func = exe.get_ctype_function(lf_isprime, 'bool, int') - for x in range(2, 1000): - msg = "Failed at x = %d" % x - self.assertEqual(func(x), is_prime(x), msg) - - def test_isprime_fast(self): - mod = Module.new(__name__) - lf_isprime = gen_is_prime_fast(mod) - logging.debug(mod) - mod.verify() - - exe = CExecutor(mod) - func = exe.get_ctype_function(lf_isprime, 'bool, int') - for x in range(2, 1000): - msg = "Failed at x = %d" % x - self.assertEqual(func(x), is_prime(x), msg) - -if __name__ == '__main__': - unittest.main() - diff --git a/tests/test_loopcontrol.py b/tests/test_loopcontrol.py deleted file mode 100644 index 7e252bf..0000000 --- a/tests/test_loopcontrol.py +++ /dev/null @@ -1,135 +0,0 @@ -from llvm.core import * -from llvm.passes import * -from llvm.ee import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import unittest, logging - -def loopbreak(d): - z = 0 - for x in range(100): - for y in range(100): - z += x + y - if z > 50: - break - z -= d - return z - -def gen_loopbreak(mod): - functype = Type.function(C.int, [C.int]) - func = mod.add_function(functype, 'loopbreak') - - cb = CBuilder(func) - - d = cb.args[0] - x = cb.var(C.int) - y = cb.var(C.int) - z = cb.var(C.int) - - one = cb.constant(C.int, 1) - zero = cb.constant(C.int, 0) - limit = cb.constant(C.int, 100) - fifty = cb.constant(C.int, 50) - - z.assign(zero) - x.assign(zero) - with cb.loop() as outer: - with outer.condition() as setcond: - setcond( x < limit ) - - with outer.body(): - y.assign(zero) - with cb.loop() as inner: - with inner.condition() as setcond: - setcond( y < limit ) - - with inner.body(): - z += x + y - with cb.ifelse( z > fifty ) as ifelse: - with ifelse.then(): - inner.break_loop() - y += one - z -= d - x += one - - cb.ret(z) - cb.close() - return func - -def loopcontinue(d): - z = 0 - for x in range(100): - for y in range(100): - z += x + y - if z > 50: - continue - z += d - return z - -def gen_loopcontinue(mod): - functype = Type.function(C.int, [C.int]) - func = mod.add_function(functype, 'loopcontinue') - - cb = CBuilder(func) - - d = cb.args[0] - x = cb.var(C.int) - y = cb.var(C.int) - z = cb.var(C.int) - - one = cb.constant(C.int, 1) - zero = cb.constant(C.int, 0) - limit = cb.constant(C.int, 100) - fifty = cb.constant(C.int, 50) - - z.assign(zero) - x.assign(zero) - with cb.loop() as outer: - with outer.condition() as setcond: - setcond( x < limit ) - - with outer.body(): - y.assign(zero) - with cb.loop() as inner: - with inner.condition() as setcond: - setcond( y < limit ) - - with inner.body(): - z += x + y - y += one - with cb.ifelse( z > fifty ) as ifelse: - with ifelse.then(): - inner.continue_loop() - z += d - x += one - - cb.ret(z) - cb.close() - return func - -class TestLoopControl(unittest.TestCase): - def test_loopbreak(self): - mod = Module.new(__name__) - lfunc = gen_loopbreak(mod) - logging.debug(mod) - mod.verify() - - exe = CExecutor(mod) - func = exe.get_ctype_function(lfunc, 'int, int') - for x in range(100): - self.assertEqual(func(x), loopbreak(x)) - - def test_loopcontinue(self): - mod = Module.new(__name__) - lfunc = gen_loopcontinue(mod) - logging.debug(mod) - mod.verify() - - exe = CExecutor(mod) - func = exe.get_ctype_function(lfunc, 'int, int') - for x in range(100): - self.assertEqual(func(x), loopcontinue(x)) - -if __name__ == '__main__': - unittest.main() - diff --git a/tests/test_nestedloops.py b/tests/test_nestedloops.py deleted file mode 100644 index 0876bb2..0000000 --- a/tests/test_nestedloops.py +++ /dev/null @@ -1,128 +0,0 @@ -from llvm.core import * -from llvm.passes import * -from llvm.ee import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import unittest, logging - -def nestedloop1(d): - z = 0 - for x in range(100): - for y in range(100): - z += x * d + int(y / d) - return z - -def gen_nestedloop1(mod): - functype = Type.function(C.int, [C.int]) - func = mod.add_function(functype, 'nestedloop1') - - cb = CBuilder(func) - - d = cb.args[0] - x = cb.var(C.int) - y = cb.var(C.int) - z = cb.var(C.int) - - one = cb.constant(C.int, 1) - zero = cb.constant(C.int, 0) - limit = cb.constant(C.int, 100) - - z.assign(zero) - x.assign(zero) - with cb.loop() as outer: - with outer.condition() as setcond: - setcond( x < limit ) - - with outer.body(): - y.assign(zero) - with cb.loop() as inner: - with inner.condition() as setcond: - setcond( y < limit ) - - with inner.body(): - z += x * d + y / d - y += one - x += one - - cb.ret(z) - cb.close() - return func - - -def nestedloop2(d): - z = 0 - for x in range(1, 100): - for y in range(1, 100): - if x > y: - z += int(x / y) * d - else: - z += int(y / x) * d - return z - -def gen_nestedloop2(mod): - functype = Type.function(C.int, [C.int]) - func = mod.add_function(functype, 'nestedloop2') - - cb = CBuilder(func) - - d = cb.args[0] - x = cb.var(C.int) - y = cb.var(C.int) - z = cb.var(C.int) - - one = cb.constant(C.int, 1) - zero = cb.constant(C.int, 0) - limit = cb.constant(C.int, 100) - - z.assign(zero) - x.assign(one) - with cb.loop() as outer: - with outer.condition() as setcond: - setcond( x < limit ) - - with outer.body(): - y.assign(one) - with cb.loop() as inner: - with inner.condition() as setcond: - setcond( y < limit ) - - with inner.body(): - with cb.ifelse(x > y) as ifelse: - with ifelse.then(): - z += x / y * d - with ifelse.otherwise(): - z += y / x * d - y += one - x += one - - cb.ret(z) - cb.close() - return func - - -class TestNestedLoop(unittest.TestCase): - def test_nestedloop1(self): - mod = Module.new(__name__) - lfunc = gen_nestedloop1(mod) - logging.debug(mod) - mod.verify() - - exe = CExecutor(mod) - func = exe.get_ctype_function(lfunc, 'int, int') - for x in range(1, 100): - self.assertEqual(func(x), int(nestedloop1(x))) - - def test_nestedloop2(self): - mod = Module.new(__name__) - lfunc = gen_nestedloop2(mod) - logging.debug(mod) - mod.verify() - - exe = CExecutor(mod) - func = exe.get_ctype_function(lfunc, 'int, int') - for x in range(1, 100): - self.assertEqual(func(x), int(nestedloop2(x))) - -if __name__ == '__main__': - unittest.main() - diff --git a/tests/test_print.py b/tests/test_print.py deleted file mode 100644 index d971e31..0000000 --- a/tests/test_print.py +++ /dev/null @@ -1,60 +0,0 @@ -from llvm.core import * -from llvm.passes import * -from llvm.ee import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import sys, unittest, logging -from subprocess import Popen, PIPE - -def gen_debugprint(mod): - functype = Type.function(C.void, []) - func = mod.add_function(functype, 'debugprint') - - cb = CBuilder(func) - fmt = cb.constant_string("Show %d %.3f %.3e\n") - - an_int = cb.constant(C.int, 123) - a_float = cb.constant(C.double, 1.234) - a_double = cb.constant(C.double, 1e-31) - cb.printf(fmt, an_int, a_float, a_double) - - cb.debug('an_int =', an_int, 'a_float =', a_float, 'a_double =', a_double) - - cb.ret() - cb.close() - return func - -def main_debugprint(): - # generate code - mod = Module.new(__name__) - lfunc = gen_debugprint(mod) - logging.debug(mod) - mod.verify() - # run - exe = CExecutor(mod) - func = exe.get_ctype_function(lfunc, 'void') - func() - -class TestPrint(unittest.TestCase): - def test_debugprint(self): - p = Popen(["python", "test_print.py", "-child"], stdout=PIPE) - p.wait() - - lines = p.stdout.read().decode().splitlines(False) - - expect = [ - 'Show 123 1.234 1.000e-31', - 'an_int = 123 a_float = 1.234000e+00 a_double = 1.000000e-31', - ] - self.assertEqual(expect, lines) - - p.stdout.close() - -if __name__ == '__main__': - try: - if sys.argv[1] == '-child': - main_debugprint() - except IndexError: - unittest.main() - - diff --git a/tests/test_pthread.py b/tests/test_pthread.py deleted file mode 100644 index d1d3a72..0000000 --- a/tests/test_pthread.py +++ /dev/null @@ -1,90 +0,0 @@ -from llvm.core import * -from llvm.passes import * -from llvm.ee import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import unittest, logging - -# logging.basicConfig(level=logging.DEBUG) - -NUM_OF_THREAD = 4 - -def gen_test_worker(mod): - cb = CBuilder.new_function(mod, 'worker', C.void, [C.pointer(C.int)]) - pval = cb.args[0] - val = pval.load() - one = cb.constant(val.type, 1) - pval.store(val + one) - cb.ret() - cb.close() - -def gen_test_pthread(mod): - cb = CBuilder.new_function(mod, 'manager', C.int, [C.int]) - arg = cb.args[0] - - worker_func = cb.get_function_named('worker') - pthread_create = cb.get_function_named('pthread_create') - pthread_join = cb.get_function_named('pthread_join') - - - NULL = cb.constant_null(C.void_p) - cast_to_null = lambda x: x.cast(C.void_p) - - threads = cb.array(C.void_p, NUM_OF_THREAD) - - for tid in range(NUM_OF_THREAD): - pthread_create_args = [threads[tid].reference(), - NULL, - worker_func, - arg.reference()] - pthread_create(*map(cast_to_null, pthread_create_args)) - - worker_func(arg.reference()) - - for tid in range(NUM_OF_THREAD): - pthread_join_args = threads[tid], NULL - pthread_join(*map(cast_to_null, pthread_join_args)) - - cb.ret(arg) - cb.close() - return cb.function - -class TestPThread(unittest.TestCase): - def test_pthread(self): - mod = Module.new(__name__) - # add pthread functions - - mod.add_function(Type.function(C.int, - [C.void_p, C.void_p, C.void_p, C.void_p]), - 'pthread_create') - - mod.add_function(Type.function(C.int, - [C.void_p, C.void_p]), - 'pthread_join') - - gen_test_worker(mod) - lf_test_pthread = gen_test_pthread(mod) - logging.debug(mod) - mod.verify() - - exe = CExecutor(mod) - exe.engine.get_pointer_to_function(mod.get_function_named('worker')) - func = exe.get_ctype_function(lf_test_pthread, 'int, int') - - inarg = 1234 - gold = inarg + NUM_OF_THREAD + 1 - self.assertLessEqual(func(inarg), gold) - # Cannot determine the exact return value due to untamed race condition - - count_race = 0 - for _ in range(2**12): - if func(inarg) != gold: - count_race += 1 - - if count_race > 0: - logging.info("Race condition occured %d times.", count_race) - logging.info("Race condition is expected.") - -if __name__ == '__main__': - unittest.main() - diff --git a/tests/test_struct.py b/tests/test_struct.py deleted file mode 100644 index 35048e6..0000000 --- a/tests/test_struct.py +++ /dev/null @@ -1,52 +0,0 @@ -from llvm.core import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import unittest, ctypes - -class Vector2D(CStruct): - _fields_ = [ - ('x', C.float), - ('y', C.float), - ] - -class Vector2DCtype(ctypes.Structure): - _fields_ = [ - ('x', ctypes.c_float), - ('y', ctypes.c_float), - ] - -def gen_vector2d_dist(mod): - functype = Type.function(C.float, [C.pointer(Vector2D.llvm_type())]) - func = mod.add_function(functype, 'vector2d_dist') - - cb = CBuilder(func) - vec = cb.var(Vector2D, cb.args[0].load()) - dist = vec.x * vec.x + vec.y * vec.y - - cb.ret(dist) - cb.close() - return func - - -class TestStruct(unittest.TestCase): - def test_vector2d_dist(self): - # prepare module - mod = Module.new('mod') - lfunc = gen_vector2d_dist(mod) - mod.verify() - # run - exe = CExecutor(mod) - func = exe.get_ctype_function(lfunc, ctypes.c_float, ctypes.POINTER(Vector2DCtype)) - - from random import random - pydist = lambda x, y: x * x + y * y - for _ in range(100): - x, y = random(), random() - vec = Vector2DCtype(x=x, y=y) - ans = func(ctypes.pointer(vec)) - gold = pydist(x, y) - - self.assertLess(abs(ans-gold)/gold, 1e-6) - -if __name__ == '__main__': - unittest.main() From d55bb95d4d98277a2abcf5fbf07c622ea5472b09 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sun, 19 Aug 2012 21:27:28 -0700 Subject: [PATCH 032/516] Add translator to convert python code to llvm cbuilder construct --- translator.py | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 translator.py diff --git a/translator.py b/translator.py new file mode 100644 index 0000000..ac7338f --- /dev/null +++ b/translator.py @@ -0,0 +1,91 @@ +# A handy translator that converts control flow into the appropriate +# llvm_cbuilder constructs +import inspect, functools, ast +import pprint +def translate(func): + # TODO use meta package + wrapper = functools.wraps(func) + source = inspect.getsource(func) + lines = list(source.splitlines()) + + # skip first two lines + first_line_len = len(lines[2]) + indent = first_line_len - len(lines[2].lstrip()) + source = '\n'.join(line[indent:] for line in lines[2:]) + + caller_frame = inspect.currentframe().f_back + + tree = ast.parse(source) + tree = ExpandControlFlow().visit(tree) + tree = ast.fix_missing_locations(tree) + + # prepare locals for execution + local_dict = locals() + local_dict.update(caller_frame.f_locals) + local_dict.update(caller_frame.f_globals) + + + return eval(compile(tree, '', 'exec')) + +_if_else_template = ''' +with self.ifelse(__CONDITION__) as _ifelse_: + with _ifelse_.then(): + __THEN__ + with _ifelse_.otherwise(): + __OTHERWISE__ +''' + +_return_template = 'self.ret(__RETURN__)' + +def load_template(string): + tree = ast.parse(string) # return a Module + return tree.body[0] # get the first item of body + +class ExpandControlFlow(ast.NodeTransformer): + def visit_If(self, node): + condition = node.test + mapping = { + '__CONDITION__' : node.test, + '__THEN__' : node.body, + '__OTHERWISE__' : node.orelse, + } + + ifelse = load_template(_if_else_template) + ifelse = NameReplacer(mapping).visit(ifelse) + newnode = ast.copy_location(ifelse, node) + return self.generic_visit(newnode) + + def visit_Return(self, node): + mapping = {'__RETURN__' : node.value} + ret = load_template(_return_template) + repl = NameReplacer(mapping).visit(ret) + return ast.copy_location(repl, node) + +class NameReplacer(ast.NodeTransformer): + def __init__(self, mapping): + self.mapping = mapping + + def visit_With(self, node): + if (len(node.body)==1 + and isinstance(node.body[0], ast.Expr) + and isinstance(node.body[0].value, ast.Name)): + try: + repl = self.mapping.pop(node.body[0].value.id) + except KeyError: + pass + else: + old = node.body[0] + node.body = repl + return self.generic_visit(node) + + def visit_Name(self, node): + if type(node.ctx) is ast.Load: + try: + repl = self.mapping.pop(node.id) + except KeyError: + pass + else: + if repl is not None and not isinstance(repl, list): + return ast.copy_location(repl, node) + return node + From 562e3c1e463bb52146bcf8010b397f74e21a2376 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sun, 19 Aug 2012 21:35:45 -0700 Subject: [PATCH 033/516] Fix: if-else branch should terminate automatically. Insert unreachable to if.end block if necessary. --- builder.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/builder.py b/builder.py index fc4baa3..7a6ed32 100644 --- a/builder.py +++ b/builder.py @@ -97,11 +97,15 @@ class _IfElse(object): self._to_close.append(self.parent.builder.basic_block) bbend = self.parent.function.append_basic_block('if.end') builder = self.parent.builder + closed_count = 0 for bb in self._to_close: if not _is_block_terminated(bb): with _change_block_temporarily(builder, bb): builder.branch(bbend) + closed_count += 1 builder.position_at_end(bbend) + if not closed_count: + self.parent.unreachable() class _Loop(object): '''while...do loop. From 5319fb8c984f67613b70d58b490818d829779e6a Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 21 Aug 2012 12:25:48 -0500 Subject: [PATCH 034/516] Add initial vector support --- builder.py | 76 ++++++++++++++++++++++++++++++++++++++++++++++----- executor.py | 1 - shortnames.py | 5 ++++ 3 files changed, 74 insertions(+), 8 deletions(-) diff --git a/builder.py b/builder.py index 7a6ed32..57ea551 100644 --- a/builder.py +++ b/builder.py @@ -26,6 +26,14 @@ def _is_real(ty): lc.Type.ppc_fp128() ] return any(ty == x for x in tys) +def _is_vector(ty, of=None): + if isinstance(ty, lc.VectorType): + if of is not None: + return of(ty.element) + return True + else: + return False + def _is_pointer(ty): return isinstance(ty, lc.PointerType) @@ -42,6 +50,11 @@ def _is_cstruct(ty): def _list_values(iterable): return [i.value for i in iterable] +def _auto_coerce_index(cbldr, idx): + if not isinstance(idx, CValue): + idx = cbldr.constant(types.int, idx) + return idx + @contextlib.contextmanager def _change_block_temporarily(builder, bb): origbb = builder.basic_block @@ -892,11 +905,11 @@ class CValue(object): @property def is_int(self): - return _is_int(self.type) + return _is_int(self.type) or _is_vector(self.type, _is_int) @property def is_real(self): - return _is_real(self.type) + return _is_real(self.type) or _is_vector(self.type, _is_real) def cast(self, ty, unsigned=False): '''cast to another type @@ -984,6 +997,10 @@ class CValue(object): return self._cmp_op('ge')(rhs) + @property + def is_vector(self): + return _is_vector(self.type) + @property def is_pointer(self): return _is_pointer(self.type) @@ -992,17 +1009,41 @@ class CValue(object): if not self.is_pointer: raise TypeError("Must be a pointer; got %s" % self.type) + def _ensure_is_vector(self): + if not self.is_vector: + raise TypeError("Must be a vector; got %s" % self.type) + def __getitem__(self, idx): '''implement access indexing Uses GEP. ''' - self._ensure_is_pointer() - if not isinstance(idx, CValue): - idx = self.parent.constant(types.int, idx) bldr = self.parent.builder - ptr = bldr.gep(self.value, [idx.value]) - return CVar(self.parent, ptr) + if self.is_pointer: + if type(idx) is slice: + # just handle case by case + # Case #1: A[idx:] get poointer offset by idx + if not idx.step and not idx.stop: + idx = _auto_coerce_index(self.parent, idx.start) + ptr = bldr.gep(self.value, [idx.value]) + return CArray(self.parent, ptr) + else: # return an variable at idx + idx = _auto_coerce_index(self.parent, idx) + ptr = bldr.gep(self.value, [idx.value]) + return CVar(self.parent, ptr) + elif self.is_vector: + idx = _auto_coerce_index(self.parent, idx) + val = bldr.extract_element(self.value, idx.value) + return CTemp(self.parent, val) + else: + raise TypeError("Must be a pointer or vector; got %s" % self.type) + + def __setitem__(self, idx, val): + self._ensure_is_vector() + idx = _auto_coerce_index(self.parent, idx) + bldr = self.parent.builder + vec = bldr.insert_element(self.value, val.value, idx.value) + bldr.store(vec, self.ptr) def load(self, volatile=False): '''memory load for pointer types @@ -1181,6 +1222,7 @@ class CVar(CValue): else: return cstruct_class(self.parent, self.ptr) + class CArray(CValue): '''wraps a array @@ -1201,6 +1243,26 @@ class CArray(CValue): def type(self): return self.base_ptr.type + def vector_load(self, count): + parent = self.parent + values = [self[i] for i in range(count)] + vec = parent.constant_null(types.vector(self.type.pointee, count)).value + for i, v in enumerate(values): + i = parent.constant(types.int, i) + vec = parent.builder.insert_element(vec, v.value, i.value) + return CTemp(parent, vec) + + def vector_store(self, vec): + if vec.type.element != self.type.pointee: + raise TypeError("Type mismatch; expect %s but got %s" % \ + (vec.type.element, self.type.pointee)) + parent = self.parent + for i in range(vec.type.count): + i = parent.constant(types.int, i) + val = parent.builder.extract_element(vec.value, i.value) + self[i].assign(CTemp(parent, val)) + return self + class CStruct(CValue): '''Wraps a structure diff --git a/executor.py b/executor.py index acfd13d..fedaeae 100644 --- a/executor.py +++ b/executor.py @@ -61,7 +61,6 @@ class CExecutor(object): else: retty = typeinfo[0] argtys = typeinfo[1:] - prototype = ct.CFUNCTYPE(retty, *argtys) fnptr = self.engine.get_pointer_to_function(fn) return prototype(fnptr) diff --git a/shortnames.py b/shortnames.py index beaaad3..012e53d 100644 --- a/shortnames.py +++ b/shortnames.py @@ -28,3 +28,8 @@ pointer_size = _determine_pointer_size() intp = {32: int32, 64: int64}[pointer_size] + +# vector +def vector(ty, ct): + return Type.vector(ty, 4) + From 5513a34e80ff6096e4879bb92a85ca613da9466a Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 21 Aug 2012 14:17:14 -0500 Subject: [PATCH 035/516] Add some doc and cleanup --- translator.py | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/translator.py b/translator.py index ac7338f..a857fc5 100644 --- a/translator.py +++ b/translator.py @@ -8,7 +8,12 @@ def translate(func): source = inspect.getsource(func) lines = list(source.splitlines()) - # skip first two lines + # skip first two lines + # assume they are + # @translate + # def blahblah(): + assert lines[0].lstrip().startswith('@') + assert lines[1].lstrip().startswith('def') first_line_len = len(lines[2]) indent = first_line_len - len(lines[2].lstrip()) source = '\n'.join(line[indent:] for line in lines[2:]) @@ -38,10 +43,18 @@ with self.ifelse(__CONDITION__) as _ifelse_: _return_template = 'self.ret(__RETURN__)' def load_template(string): + ''' + Since ast.parse() returns a ast.Module node, + it is more useful to trim the Module and get to the first item of body + ''' tree = ast.parse(string) # return a Module return tree.body[0] # get the first item of body class ExpandControlFlow(ast.NodeTransformer): + ''' + Expand control flow contructs. + These are the most tedious thing to do in llvm_cbuilder. + ''' def visit_If(self, node): condition = node.test mapping = { @@ -51,22 +64,29 @@ class ExpandControlFlow(ast.NodeTransformer): } ifelse = load_template(_if_else_template) - ifelse = NameReplacer(mapping).visit(ifelse) + ifelse = MacroExpander(mapping).visit(ifelse) newnode = ast.copy_location(ifelse, node) return self.generic_visit(newnode) def visit_Return(self, node): mapping = {'__RETURN__' : node.value} ret = load_template(_return_template) - repl = NameReplacer(mapping).visit(ret) + repl = MacroExpander(mapping).visit(ret) return ast.copy_location(repl, node) -class NameReplacer(ast.NodeTransformer): +class MacroExpander(ast.NodeTransformer): def __init__(self, mapping): self.mapping = mapping def visit_With(self, node): - if (len(node.body)==1 + ''' + Expand X in the following: + with blah: + X + Nothing should go before or after X. + X must be a list of nodes. + ''' + if (len(node.body)==1 # the body of and isinstance(node.body[0], ast.Expr) and isinstance(node.body[0].value, ast.Name)): try: @@ -76,9 +96,12 @@ class NameReplacer(ast.NodeTransformer): else: old = node.body[0] node.body = repl - return self.generic_visit(node) + return self.generic_visit(node) # recursively apply expand all macros def visit_Name(self, node): + ''' + Expand all Name node to simple value + ''' if type(node.ctx) is ast.Load: try: repl = self.mapping.pop(node.id) From 2218f1d49e9f54c8a57a8717c07d4ee4eb7bb0fb Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 21 Aug 2012 17:26:12 -0500 Subject: [PATCH 036/516] Improve vector load store. Changes make llvm emit parallel ld/st instead of scalar ld/st. --- builder.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/builder.py b/builder.py index 57ea551..bfb2791 100644 --- a/builder.py +++ b/builder.py @@ -1245,11 +1245,11 @@ class CArray(CValue): def vector_load(self, count): parent = self.parent + builder = parent.builder values = [self[i] for i in range(count)] - vec = parent.constant_null(types.vector(self.type.pointee, count)).value - for i, v in enumerate(values): - i = parent.constant(types.int, i) - vec = parent.builder.insert_element(vec, v.value, i.value) + + vecty = types.vector(self.type.pointee, count) + vec = builder.load(builder.bitcast(self.base_ptr, types.pointer(vecty))) return CTemp(parent, vec) def vector_store(self, vec): @@ -1257,10 +1257,9 @@ class CArray(CValue): raise TypeError("Type mismatch; expect %s but got %s" % \ (vec.type.element, self.type.pointee)) parent = self.parent - for i in range(vec.type.count): - i = parent.constant(types.int, i) - val = parent.builder.extract_element(vec.value, i.value) - self[i].assign(CTemp(parent, val)) + builder = parent.builder + builder.store(vec.value, builder.bitcast(self.base_ptr, + types.pointer(vec.type))) return self class CStruct(CValue): From 4d773ed5ed0dc7a98e06bba33476b6a2983130ed Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 21 Aug 2012 18:32:44 -0500 Subject: [PATCH 037/516] Add alignment control to vector_load/store. E.g: align=1 for universal alignment. default to aligned. --- builder.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/builder.py b/builder.py index bfb2791..e1489a5 100644 --- a/builder.py +++ b/builder.py @@ -1243,23 +1243,24 @@ class CArray(CValue): def type(self): return self.base_ptr.type - def vector_load(self, count): + def vector_load(self, count, align=0): parent = self.parent builder = parent.builder values = [self[i] for i in range(count)] vecty = types.vector(self.type.pointee, count) - vec = builder.load(builder.bitcast(self.base_ptr, types.pointer(vecty))) + vec = builder.load(builder.bitcast(self.base_ptr, types.pointer(vecty)), + align=align) return CTemp(parent, vec) - def vector_store(self, vec): + def vector_store(self, vec, align=0): if vec.type.element != self.type.pointee: raise TypeError("Type mismatch; expect %s but got %s" % \ (vec.type.element, self.type.pointee)) parent = self.parent builder = parent.builder - builder.store(vec.value, builder.bitcast(self.base_ptr, - types.pointer(vec.type))) + vecptr = builder.bitcast(self.base_ptr, types.pointer(vec.type)) + builder.store(vec.value, vecptr, align=align) return self class CStruct(CValue): From eeda441dac468f6d1fde0ceb62bf28c9ca633773 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 22 Aug 2012 13:22:37 -0500 Subject: [PATCH 038/516] Added stream vectorize. --- builder.py | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/builder.py b/builder.py index e1489a5..b30c363 100644 --- a/builder.py +++ b/builder.py @@ -5,6 +5,7 @@ import contextlib import llvm.core as lc import llvm.ee as le +import llvm.passes as lp from llvm import LLVMException from . import shortnames as types @@ -245,6 +246,9 @@ class CBuilder(object): for i in args: if isinstance(i, str): itemsfmt.append(i.replace('%', '%%')) + elif isinstance(i.type, lc.PointerType): + itemsfmt.append("%p") + items.append(i) else: tyname = str(i.type) if tyname == 'float': @@ -258,6 +262,26 @@ class CBuilder(object): fmt = ' '.join(itemsfmt) + '\n' return self.printf(self.constant_string(fmt), *items) + def sizeof(self, ty): + bldr = self.builder + ptrty = types.pointer(ty) + first = lc.Constant.null(ptrty) + second = bldr.gep(first, [lc.Constant.int(types.intp, 1)]) + + firstint = bldr.ptrtoint(first, types.intp) + secondint = bldr.ptrtoint(second, types.intp) + diff = bldr.sub(secondint, firstint) + return CTemp(self, diff) + + def min(self, x, y): + z = self.var(x.type) + with self.ifelse( x < y ) as ifelse: + with ifelse.then(): + z.assign(x) + with ifelse.otherwise(): + z.assign(y) + return z + def var(self, ty, value=None, name=''): '''allocate variable on the stack @@ -771,6 +795,14 @@ class CDefinition(CBuilder): cbuilder.__init__(func) cbuilder.body(*cbuilder.args) cbuilder.close() + + # optimize + fpm = lp.FunctionPassManager.new(module) + pmb = lp.PassManagerBuilder.new() + pmb.opt_level = 3 + pmb.vectorize = True + pmb.populate(fpm) + fpm.run(func) return func def body(self): @@ -1039,11 +1071,15 @@ class CValue(object): raise TypeError("Must be a pointer or vector; got %s" % self.type) def __setitem__(self, idx, val): - self._ensure_is_vector() idx = _auto_coerce_index(self.parent, idx) bldr = self.parent.builder - vec = bldr.insert_element(self.value, val.value, idx.value) - bldr.store(vec, self.ptr) + if self.is_vector: + vec = bldr.insert_element(self.value, val.value, idx.value) + bldr.store(vec, self.ptr) + elif self.is_pointer: + self[idx].assign(val) + else: + raise TypeError("Must be a pointer or vector; got %s" % self.type) def load(self, volatile=False): '''memory load for pointer types From d3909606576236bfb227bf5341989277df9094ac Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 23 Aug 2012 11:43:24 -0500 Subject: [PATCH 039/516] Add llvm_cbuilder translate features: * handle while loop * handle for loop * handle immediate values Todo: handle "break" and "continue" --- translator.py | 116 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 103 insertions(+), 13 deletions(-) diff --git a/translator.py b/translator.py index a857fc5..c0e9d5f 100644 --- a/translator.py +++ b/translator.py @@ -1,7 +1,10 @@ # A handy translator that converts control flow into the appropriate # llvm_cbuilder constructs import inspect, functools, ast -import pprint +import logging + +logger = logging.getLogger(__name__) + def translate(func): # TODO use meta package wrapper = functools.wraps(func) @@ -29,8 +32,15 @@ def translate(func): local_dict.update(caller_frame.f_locals) local_dict.update(caller_frame.f_globals) + try: + return eval(compile(tree, '', 'exec')) + except: + logger.debug(ast.dump(tree)) + from ArminRonacher import codegen # uses Armin Ronacher's codegen to debug + # http://dev.pocoo.org/hg/sandbox/file/852a1248c8eb/ast/codegen.py + logger.debug(codegen.to_source(tree)) + raise - return eval(compile(tree, '', 'exec')) _if_else_template = ''' with self.ifelse(__CONDITION__) as _ifelse_: @@ -40,14 +50,32 @@ with self.ifelse(__CONDITION__) as _ifelse_: __OTHERWISE__ ''' +_while_template = ''' +with self.loop() as _loop_: + with _loop_.condition() as _setcond_: + _setcond_(__CONDITION__) + with _loop_.body(): + __BODY__ +''' + +_for_range_template = ''' +with self.for_range(*__ARGS__) as (_loop_, __ITER__): + __BODY__ +''' + _return_template = 'self.ret(__RETURN__)' +_const_int_template = 'self.constant(C.int, __VALUE__)' +_const_long_template = 'self.constant(C.long, __VALUE__)' +_const_float_template = 'self.constant(C.double, __VALUE__)' + def load_template(string): ''' Since ast.parse() returns a ast.Module node, it is more useful to trim the Module and get to the first item of body ''' tree = ast.parse(string) # return a Module + assert isinstance(tree, ast.Module) return tree.body[0] # get the first item of body class ExpandControlFlow(ast.NodeTransformer): @@ -55,8 +83,23 @@ class ExpandControlFlow(ast.NodeTransformer): Expand control flow contructs. These are the most tedious thing to do in llvm_cbuilder. ''' + + ## Use breadcumb to track parent nodes + # def __init__(self): + # self.breadcumb = [] + # + # def visit(self, node): + # self.breadcumb.append(node) + # try: + # return super(ExpandControlFlow, self).visit(node) + # finally: + # self.breadcumb.pop() + # + # @property + # def parent(self): + # return self.breadcumb[-2] + def visit_If(self, node): - condition = node.test mapping = { '__CONDITION__' : node.test, '__THEN__' : node.body, @@ -65,8 +108,36 @@ class ExpandControlFlow(ast.NodeTransformer): ifelse = load_template(_if_else_template) ifelse = MacroExpander(mapping).visit(ifelse) - newnode = ast.copy_location(ifelse, node) - return self.generic_visit(newnode) + newnode = self.generic_visit(ifelse) + return ast.copy_location(newnode, node) + + def visit_While(self, node): + mapping = { + '__CONDITION__' : node.test, + '__BODY__' : node.body, + } + whileloop = load_template(_while_template) + whileloop = MacroExpander(mapping).visit(whileloop) + newnode = self.generic_visit(whileloop) + return ast.copy_location(newnode, node) + + def visit_For(self, node): + try: + if node.iter.func.id not in ['range', 'xrange']: + return node + except AttributeError: + return node + + mapping = { + '__ITER__' : node.target, + '__BODY__' : node.body, + '__ARGS__' : ast.Tuple(elts=node.iter.args, ctx=ast.Load()), + } + + forloop = load_template(_for_range_template) + forloop = MacroExpander(mapping).visit(forloop) + newnode = self.generic_visit(forloop) + return ast.copy_location(newnode, node) def visit_Return(self, node): mapping = {'__RETURN__' : node.value} @@ -74,6 +145,24 @@ class ExpandControlFlow(ast.NodeTransformer): repl = MacroExpander(mapping).visit(ret) return ast.copy_location(repl, node) + def visit_Num(self, node): + '''convert immediate values + ''' + typemap = { + int : _const_int_template, + long : _const_long_template, # TODO: disable long for py3 + float : _const_float_template, + } + + template = load_template(typemap[type(node.n)]) + + mapping = { + '__VALUE__' : node, + } + constant = MacroExpander(mapping).visit(template).value + newnode = ast.copy_location(constant, node) + return newnode + class MacroExpander(ast.NodeTransformer): def __init__(self, mapping): self.mapping = mapping @@ -96,19 +185,20 @@ class MacroExpander(ast.NodeTransformer): else: old = node.body[0] node.body = repl + return self.generic_visit(node) # recursively apply expand all macros def visit_Name(self, node): ''' Expand all Name node to simple value ''' - if type(node.ctx) is ast.Load: - try: - repl = self.mapping.pop(node.id) - except KeyError: - pass - else: - if repl is not None and not isinstance(repl, list): - return ast.copy_location(repl, node) + + try: + repl = self.mapping.pop(node.id) + except KeyError: + pass + else: + if repl is not None and not isinstance(repl, list): + return ast.copy_location(repl, node) return node From fb30295e624dc401264e9acfc7f5799e601a12e7 Mon Sep 17 00:00:00 2001 From: bryan Date: Thu, 30 Aug 2012 13:31:50 -0500 Subject: [PATCH 040/516] rename to prevent import collision --- __init__.py | 0 test_atomic_add.py | 115 ++++++++++++++++++++++++++++++ test_atomic_cmpxchg.py | 122 ++++++++++++++++++++++++++++++++ test_cstr_collide.py | 17 +++++ test_isprime.py | 125 +++++++++++++++++++++++++++++++++ test_loopcontrol.py | 135 +++++++++++++++++++++++++++++++++++ test_nestedloops.py | 128 +++++++++++++++++++++++++++++++++ test_print.py | 60 ++++++++++++++++ test_pthread.py | 90 ++++++++++++++++++++++++ test_struct.py | 52 ++++++++++++++ test_translate.py | 94 +++++++++++++++++++++++++ test_vectorarith.py | 156 +++++++++++++++++++++++++++++++++++++++++ 12 files changed, 1094 insertions(+) create mode 100644 __init__.py create mode 100644 test_atomic_add.py create mode 100644 test_atomic_cmpxchg.py create mode 100644 test_cstr_collide.py create mode 100644 test_isprime.py create mode 100644 test_loopcontrol.py create mode 100644 test_nestedloops.py create mode 100644 test_print.py create mode 100644 test_pthread.py create mode 100644 test_struct.py create mode 100644 test_translate.py create mode 100644 test_vectorarith.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test_atomic_add.py b/test_atomic_add.py new file mode 100644 index 0000000..27688e7 --- /dev/null +++ b/test_atomic_add.py @@ -0,0 +1,115 @@ +''' +Base on the test_pthread.py and extend to use atomic instructions +''' + +from llvm.core import * +from llvm.passes import * +from llvm.ee import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import unittest, logging + +# logging.basicConfig(level=logging.DEBUG) + +NUM_OF_THREAD = 4 +REPEAT = 10000 + +def gen_test_worker(mod): + cb = CBuilder.new_function(mod, 'worker', C.void, [C.pointer(C.int)]) + pval = cb.args[0] + one = cb.constant(pval.type.pointee, 1) + + ct = cb.var(C.int, 0) + limit = cb.constant(C.int, REPEAT) + with cb.loop() as loop: + with loop.condition() as setcond: + setcond( ct < limit ) + + with loop.body(): + cb.atomic_add(pval, one, 'acq_rel') + ct += one + + cb.ret() + cb.close() + return cb.function + +def gen_test_pthread(mod): + cb = CBuilder.new_function(mod, 'manager', C.int, [C.int]) + arg = cb.args[0] + + worker_func = cb.get_function_named('worker') + pthread_create = cb.get_function_named('pthread_create') + pthread_join = cb.get_function_named('pthread_join') + + + NULL = cb.constant_null(C.void_p) + cast_to_null = lambda x: x.cast(C.void_p) + + threads = cb.array(C.void_p, NUM_OF_THREAD) + + for tid in range(NUM_OF_THREAD): + pthread_create_args = [threads[tid].reference(), + NULL, + worker_func, + arg.reference()] + pthread_create(*map(cast_to_null, pthread_create_args)) + + worker_func(arg.reference()) + + for tid in range(NUM_OF_THREAD): + pthread_join_args = threads[tid], NULL + pthread_join(*map(cast_to_null, pthread_join_args)) + + + cb.ret(arg) + cb.close() + return cb.function + +class TestAtomicAdd(unittest.TestCase): + def test_atomic_add(self): + mod = Module.new(__name__) + # add pthread functions + + mod.add_function(Type.function(C.int, + [C.void_p, C.void_p, C.void_p, C.void_p]), + 'pthread_create') + + mod.add_function(Type.function(C.int, + [C.void_p, C.void_p]), + 'pthread_join') + + lf_test_worker = gen_test_worker(mod) + lf_test_pthread = gen_test_pthread(mod) + logging.debug(mod) + mod.verify() + + # optimize + fpm = FunctionPassManager.new(mod) + mpm = PassManager.new() + pmb = PassManagerBuilder.new() + pmb.vectorize = True + pmb.opt_level = 3 + pmb.populate(fpm) + pmb.populate(mpm) + + fpm.run(lf_test_worker) + fpm.run(lf_test_pthread) + mpm.run(mod) + logging.debug(mod) + mod.verify() + + # run + exe = CExecutor(mod) + exe.engine.get_pointer_to_function(mod.get_function_named('worker')) + func = exe.get_ctype_function(lf_test_pthread, 'int, int') + + inarg = 1234 + gold = inarg + (NUM_OF_THREAD + 1) * REPEAT + + for _ in range(1000): # run many many times to catch race condition + self.assertEqual(func(inarg), gold, "Unexpected race condition") + + +if __name__ == '__main__': + unittest.main() + diff --git a/test_atomic_cmpxchg.py b/test_atomic_cmpxchg.py new file mode 100644 index 0000000..27fb763 --- /dev/null +++ b/test_atomic_cmpxchg.py @@ -0,0 +1,122 @@ +''' +Base on the test_pthread.py and extend to use atomic instructions +''' + +from llvm.core import * +from llvm.passes import * +from llvm.ee import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import unittest, logging + +# logging.basicConfig(level=logging.DEBUG) + +NUM_OF_THREAD = 4 +REPEAT = 10000 + +def gen_test_worker(mod): + cb = CBuilder.new_function(mod, 'worker', C.void, [C.pointer(C.int)]) + pval = cb.args[0] + one = cb.constant(pval.type.pointee, 1) + + ct = cb.var(C.int, 0) + limit = cb.constant(C.int, REPEAT) + with cb.loop() as loop: + with loop.condition() as setcond: + setcond( ct < limit ) + + with loop.body(): + oldval = pval.atomic_load('acquire') + updated = oldval + one + castmp = pval.atomic_cmpxchg(oldval, updated, 'release') + + with cb.ifelse( castmp == oldval ) as ifelse: + with ifelse.then(): + ct += one + + cb.ret() + cb.close() + return cb.function + +def gen_test_pthread(mod): + cb = CBuilder.new_function(mod, 'manager', C.int, [C.int]) + arg = cb.args[0] + + worker_func = cb.get_function_named('worker') + pthread_create = cb.get_function_named('pthread_create') + pthread_join = cb.get_function_named('pthread_join') + + + NULL = cb.constant_null(C.void_p) + cast_to_null = lambda x: x.cast(C.void_p) + + threads = cb.array(C.void_p, NUM_OF_THREAD) + + for tid in range(NUM_OF_THREAD): + pthread_create_args = [threads[tid].reference(), + NULL, + worker_func, + arg.reference()] + pthread_create(*map(cast_to_null, pthread_create_args)) + + worker_func(arg.reference()) + + for tid in range(NUM_OF_THREAD): + pthread_join_args = threads[tid], NULL + pthread_join(*map(cast_to_null, pthread_join_args)) + + + cb.ret(arg) + cb.close() + return cb.function + +class TestAtomicCmpXchg(unittest.TestCase): + def test_atomic_cmpxchg(self): + mod = Module.new(__name__) + # add pthread functions + + mod.add_function(Type.function(C.int, + [C.void_p, C.void_p, C.void_p, C.void_p]), + 'pthread_create') + + mod.add_function(Type.function(C.int, + [C.void_p, C.void_p]), + 'pthread_join') + + lf_test_worker = gen_test_worker(mod) + lf_test_pthread = gen_test_pthread(mod) + logging.debug(mod) + mod.verify() + + # optimize + fpm = FunctionPassManager.new(mod) + mpm = PassManager.new() + pmb = PassManagerBuilder.new() + pmb.vectorize = True + pmb.opt_level = 3 + pmb.populate(fpm) + pmb.populate(mpm) + + fpm.run(lf_test_worker) + fpm.run(lf_test_pthread) + mpm.run(mod) + logging.debug(mod) + mod.verify() + + # run + exe = CExecutor(mod) + exe.engine.get_pointer_to_function(mod.get_function_named('worker')) + func = exe.get_ctype_function(lf_test_pthread, 'int, int') + + inarg = 1234 + gold = inarg + (NUM_OF_THREAD + 1) * REPEAT + + for _ in range(1000): # run many many times to catch race condition + res = func(inarg) + self.assertEqual(res, gold, + "Unexpected race condition: res = %d" % res) + + +if __name__ == '__main__': + unittest.main() + diff --git a/test_cstr_collide.py b/test_cstr_collide.py new file mode 100644 index 0000000..4a427c6 --- /dev/null +++ b/test_cstr_collide.py @@ -0,0 +1,17 @@ +from llvm.core import * +from llvm_cbuilder import * +from llvm_cbuilder import shortnames as C + +import unittest + +class TestCstrCollide(unittest.TestCase): + def test_same_string(self): + mod = Module.new(__name__) + cb = CBuilder.new_function(mod, 'test_cstr_collide', C.void, []) + + a = cb.constant_string("hello") + b = cb.constant_string("hello") + self.assertEqual(a.value, b.value) + +if __name__ == '__main__': + unittest.main() diff --git a/test_isprime.py b/test_isprime.py new file mode 100644 index 0000000..bcc0b9c --- /dev/null +++ b/test_isprime.py @@ -0,0 +1,125 @@ +from llvm.core import * +from llvm.passes import * +from llvm.ee import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import unittest, logging + +def is_prime(x): + if x <= 2: + return True + if (x % 2) == 0: + return False + for y in range(2, int(1 + x**0.5)): + if (x % y) == 0: + return False + return True + +def gen_is_prime(mod): + functype = Type.function(C.int, [C.int]) + func = mod.add_function(functype, 'isprime') + + cb = CBuilder(func) + + arg = cb.args[0] + + two = cb.constant(C.int, 2) + true = one = cb.constant(C.int, 1) + false = zero = cb.constant(C.int, 0) + + with cb.ifelse( arg <= two ) as ifelse: + with ifelse.then(): + cb.ret(true) + + with cb.ifelse( (arg % two) == zero ) as ifelse: + with ifelse.then(): + cb.ret(false) + + idx = cb.var(C.int, 3, name='idx') + with cb.loop() as loop: + with loop.condition() as setcond: + setcond( idx < arg ) + + with loop.body(): + with cb.ifelse( (arg % idx) == zero ) as ifelse: + with ifelse.then(): + cb.ret(false) + # increment + idx += two + + cb.ret(true) + cb.close() + return func + + +def gen_is_prime_fast(mod): + functype = Type.function(C.int, [C.int]) + func = mod.add_function(functype, 'isprime_fast') + + cb = CBuilder(func) + + arg = cb.args[0] + + two = cb.constant(C.int, 2) + true = one = cb.constant(C.int, 1) + false = zero = cb.constant(C.int, 0) + + with cb.ifelse( arg <= two ) as ifelse: + with ifelse.then(): + cb.ret(true) + + with cb.ifelse( (arg % two) == zero ) as ifelse: + with ifelse.then(): + cb.ret(false) + + idx = cb.var(C.int, 3, name='idx') + + sqrt = cb.get_intrinsic(INTR_SQRT, [C.float]) + + looplimit = one + sqrt(arg.cast(C.float)).cast(C.int) + + + with cb.loop() as loop: + with loop.condition() as setcond: + setcond( idx < looplimit ) + + with loop.body(): + with cb.ifelse( (arg % idx) == zero ) as ifelse: + with ifelse.then(): + cb.ret(false) + # increment + idx += two + + + cb.ret(true) + cb.close() + return func + +class TestIsPrime(unittest.TestCase): + def test_isprime(self): + mod = Module.new(__name__) + lf_isprime = gen_is_prime(mod) + logging.debug(mod) + mod.verify() + + exe = CExecutor(mod) + func = exe.get_ctype_function(lf_isprime, 'bool, int') + for x in range(2, 1000): + msg = "Failed at x = %d" % x + self.assertEqual(func(x), is_prime(x), msg) + + def test_isprime_fast(self): + mod = Module.new(__name__) + lf_isprime = gen_is_prime_fast(mod) + logging.debug(mod) + mod.verify() + + exe = CExecutor(mod) + func = exe.get_ctype_function(lf_isprime, 'bool, int') + for x in range(2, 1000): + msg = "Failed at x = %d" % x + self.assertEqual(func(x), is_prime(x), msg) + +if __name__ == '__main__': + unittest.main() + diff --git a/test_loopcontrol.py b/test_loopcontrol.py new file mode 100644 index 0000000..7e252bf --- /dev/null +++ b/test_loopcontrol.py @@ -0,0 +1,135 @@ +from llvm.core import * +from llvm.passes import * +from llvm.ee import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import unittest, logging + +def loopbreak(d): + z = 0 + for x in range(100): + for y in range(100): + z += x + y + if z > 50: + break + z -= d + return z + +def gen_loopbreak(mod): + functype = Type.function(C.int, [C.int]) + func = mod.add_function(functype, 'loopbreak') + + cb = CBuilder(func) + + d = cb.args[0] + x = cb.var(C.int) + y = cb.var(C.int) + z = cb.var(C.int) + + one = cb.constant(C.int, 1) + zero = cb.constant(C.int, 0) + limit = cb.constant(C.int, 100) + fifty = cb.constant(C.int, 50) + + z.assign(zero) + x.assign(zero) + with cb.loop() as outer: + with outer.condition() as setcond: + setcond( x < limit ) + + with outer.body(): + y.assign(zero) + with cb.loop() as inner: + with inner.condition() as setcond: + setcond( y < limit ) + + with inner.body(): + z += x + y + with cb.ifelse( z > fifty ) as ifelse: + with ifelse.then(): + inner.break_loop() + y += one + z -= d + x += one + + cb.ret(z) + cb.close() + return func + +def loopcontinue(d): + z = 0 + for x in range(100): + for y in range(100): + z += x + y + if z > 50: + continue + z += d + return z + +def gen_loopcontinue(mod): + functype = Type.function(C.int, [C.int]) + func = mod.add_function(functype, 'loopcontinue') + + cb = CBuilder(func) + + d = cb.args[0] + x = cb.var(C.int) + y = cb.var(C.int) + z = cb.var(C.int) + + one = cb.constant(C.int, 1) + zero = cb.constant(C.int, 0) + limit = cb.constant(C.int, 100) + fifty = cb.constant(C.int, 50) + + z.assign(zero) + x.assign(zero) + with cb.loop() as outer: + with outer.condition() as setcond: + setcond( x < limit ) + + with outer.body(): + y.assign(zero) + with cb.loop() as inner: + with inner.condition() as setcond: + setcond( y < limit ) + + with inner.body(): + z += x + y + y += one + with cb.ifelse( z > fifty ) as ifelse: + with ifelse.then(): + inner.continue_loop() + z += d + x += one + + cb.ret(z) + cb.close() + return func + +class TestLoopControl(unittest.TestCase): + def test_loopbreak(self): + mod = Module.new(__name__) + lfunc = gen_loopbreak(mod) + logging.debug(mod) + mod.verify() + + exe = CExecutor(mod) + func = exe.get_ctype_function(lfunc, 'int, int') + for x in range(100): + self.assertEqual(func(x), loopbreak(x)) + + def test_loopcontinue(self): + mod = Module.new(__name__) + lfunc = gen_loopcontinue(mod) + logging.debug(mod) + mod.verify() + + exe = CExecutor(mod) + func = exe.get_ctype_function(lfunc, 'int, int') + for x in range(100): + self.assertEqual(func(x), loopcontinue(x)) + +if __name__ == '__main__': + unittest.main() + diff --git a/test_nestedloops.py b/test_nestedloops.py new file mode 100644 index 0000000..0876bb2 --- /dev/null +++ b/test_nestedloops.py @@ -0,0 +1,128 @@ +from llvm.core import * +from llvm.passes import * +from llvm.ee import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import unittest, logging + +def nestedloop1(d): + z = 0 + for x in range(100): + for y in range(100): + z += x * d + int(y / d) + return z + +def gen_nestedloop1(mod): + functype = Type.function(C.int, [C.int]) + func = mod.add_function(functype, 'nestedloop1') + + cb = CBuilder(func) + + d = cb.args[0] + x = cb.var(C.int) + y = cb.var(C.int) + z = cb.var(C.int) + + one = cb.constant(C.int, 1) + zero = cb.constant(C.int, 0) + limit = cb.constant(C.int, 100) + + z.assign(zero) + x.assign(zero) + with cb.loop() as outer: + with outer.condition() as setcond: + setcond( x < limit ) + + with outer.body(): + y.assign(zero) + with cb.loop() as inner: + with inner.condition() as setcond: + setcond( y < limit ) + + with inner.body(): + z += x * d + y / d + y += one + x += one + + cb.ret(z) + cb.close() + return func + + +def nestedloop2(d): + z = 0 + for x in range(1, 100): + for y in range(1, 100): + if x > y: + z += int(x / y) * d + else: + z += int(y / x) * d + return z + +def gen_nestedloop2(mod): + functype = Type.function(C.int, [C.int]) + func = mod.add_function(functype, 'nestedloop2') + + cb = CBuilder(func) + + d = cb.args[0] + x = cb.var(C.int) + y = cb.var(C.int) + z = cb.var(C.int) + + one = cb.constant(C.int, 1) + zero = cb.constant(C.int, 0) + limit = cb.constant(C.int, 100) + + z.assign(zero) + x.assign(one) + with cb.loop() as outer: + with outer.condition() as setcond: + setcond( x < limit ) + + with outer.body(): + y.assign(one) + with cb.loop() as inner: + with inner.condition() as setcond: + setcond( y < limit ) + + with inner.body(): + with cb.ifelse(x > y) as ifelse: + with ifelse.then(): + z += x / y * d + with ifelse.otherwise(): + z += y / x * d + y += one + x += one + + cb.ret(z) + cb.close() + return func + + +class TestNestedLoop(unittest.TestCase): + def test_nestedloop1(self): + mod = Module.new(__name__) + lfunc = gen_nestedloop1(mod) + logging.debug(mod) + mod.verify() + + exe = CExecutor(mod) + func = exe.get_ctype_function(lfunc, 'int, int') + for x in range(1, 100): + self.assertEqual(func(x), int(nestedloop1(x))) + + def test_nestedloop2(self): + mod = Module.new(__name__) + lfunc = gen_nestedloop2(mod) + logging.debug(mod) + mod.verify() + + exe = CExecutor(mod) + func = exe.get_ctype_function(lfunc, 'int, int') + for x in range(1, 100): + self.assertEqual(func(x), int(nestedloop2(x))) + +if __name__ == '__main__': + unittest.main() + diff --git a/test_print.py b/test_print.py new file mode 100644 index 0000000..fb4a784 --- /dev/null +++ b/test_print.py @@ -0,0 +1,60 @@ +from llvm.core import * +from llvm.passes import * +from llvm.ee import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import sys, unittest, logging +from subprocess import Popen, PIPE + +def gen_debugprint(mod): + functype = Type.function(C.void, []) + func = mod.add_function(functype, 'debugprint') + + cb = CBuilder(func) + fmt = cb.constant_string("Show %d %.3f %.3e\n") + + an_int = cb.constant(C.int, 123) + a_float = cb.constant(C.double, 1.234) + a_double = cb.constant(C.double, 1e-31) + cb.printf(fmt, an_int, a_float, a_double) + + cb.debug('an_int =', an_int, 'a_float =', a_float, 'a_double =', a_double) + + cb.ret() + cb.close() + return func + +def main_debugprint(): + # generate code + mod = Module.new(__name__) + lfunc = gen_debugprint(mod) + logging.debug(mod) + mod.verify() + # run + exe = CExecutor(mod) + func = exe.get_ctype_function(lfunc, 'void') + func() + +class TestPrint(unittest.TestCase): + def test_debugprint(self): + p = Popen(["python", __file__, "-child"], stdout=PIPE) + p.wait() + + lines = p.stdout.read().decode().splitlines(False) + + expect = [ + 'Show 123 1.234 1.000e-31', + 'an_int = 123 a_float = 1.234000e+00 a_double = 1.000000e-31', + ] + self.assertEqual(expect, lines) + + p.stdout.close() + +if __name__ == '__main__': + try: + if sys.argv[1] == '-child': + main_debugprint() + except IndexError: + unittest.main() + + diff --git a/test_pthread.py b/test_pthread.py new file mode 100644 index 0000000..d1d3a72 --- /dev/null +++ b/test_pthread.py @@ -0,0 +1,90 @@ +from llvm.core import * +from llvm.passes import * +from llvm.ee import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import unittest, logging + +# logging.basicConfig(level=logging.DEBUG) + +NUM_OF_THREAD = 4 + +def gen_test_worker(mod): + cb = CBuilder.new_function(mod, 'worker', C.void, [C.pointer(C.int)]) + pval = cb.args[0] + val = pval.load() + one = cb.constant(val.type, 1) + pval.store(val + one) + cb.ret() + cb.close() + +def gen_test_pthread(mod): + cb = CBuilder.new_function(mod, 'manager', C.int, [C.int]) + arg = cb.args[0] + + worker_func = cb.get_function_named('worker') + pthread_create = cb.get_function_named('pthread_create') + pthread_join = cb.get_function_named('pthread_join') + + + NULL = cb.constant_null(C.void_p) + cast_to_null = lambda x: x.cast(C.void_p) + + threads = cb.array(C.void_p, NUM_OF_THREAD) + + for tid in range(NUM_OF_THREAD): + pthread_create_args = [threads[tid].reference(), + NULL, + worker_func, + arg.reference()] + pthread_create(*map(cast_to_null, pthread_create_args)) + + worker_func(arg.reference()) + + for tid in range(NUM_OF_THREAD): + pthread_join_args = threads[tid], NULL + pthread_join(*map(cast_to_null, pthread_join_args)) + + cb.ret(arg) + cb.close() + return cb.function + +class TestPThread(unittest.TestCase): + def test_pthread(self): + mod = Module.new(__name__) + # add pthread functions + + mod.add_function(Type.function(C.int, + [C.void_p, C.void_p, C.void_p, C.void_p]), + 'pthread_create') + + mod.add_function(Type.function(C.int, + [C.void_p, C.void_p]), + 'pthread_join') + + gen_test_worker(mod) + lf_test_pthread = gen_test_pthread(mod) + logging.debug(mod) + mod.verify() + + exe = CExecutor(mod) + exe.engine.get_pointer_to_function(mod.get_function_named('worker')) + func = exe.get_ctype_function(lf_test_pthread, 'int, int') + + inarg = 1234 + gold = inarg + NUM_OF_THREAD + 1 + self.assertLessEqual(func(inarg), gold) + # Cannot determine the exact return value due to untamed race condition + + count_race = 0 + for _ in range(2**12): + if func(inarg) != gold: + count_race += 1 + + if count_race > 0: + logging.info("Race condition occured %d times.", count_race) + logging.info("Race condition is expected.") + +if __name__ == '__main__': + unittest.main() + diff --git a/test_struct.py b/test_struct.py new file mode 100644 index 0000000..35048e6 --- /dev/null +++ b/test_struct.py @@ -0,0 +1,52 @@ +from llvm.core import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import unittest, ctypes + +class Vector2D(CStruct): + _fields_ = [ + ('x', C.float), + ('y', C.float), + ] + +class Vector2DCtype(ctypes.Structure): + _fields_ = [ + ('x', ctypes.c_float), + ('y', ctypes.c_float), + ] + +def gen_vector2d_dist(mod): + functype = Type.function(C.float, [C.pointer(Vector2D.llvm_type())]) + func = mod.add_function(functype, 'vector2d_dist') + + cb = CBuilder(func) + vec = cb.var(Vector2D, cb.args[0].load()) + dist = vec.x * vec.x + vec.y * vec.y + + cb.ret(dist) + cb.close() + return func + + +class TestStruct(unittest.TestCase): + def test_vector2d_dist(self): + # prepare module + mod = Module.new('mod') + lfunc = gen_vector2d_dist(mod) + mod.verify() + # run + exe = CExecutor(mod) + func = exe.get_ctype_function(lfunc, ctypes.c_float, ctypes.POINTER(Vector2DCtype)) + + from random import random + pydist = lambda x, y: x * x + y * y + for _ in range(100): + x, y = random(), random() + vec = Vector2DCtype(x=x, y=y) + ans = func(ctypes.pointer(vec)) + gold = pydist(x, y) + + self.assertLess(abs(ans-gold)/gold, 1e-6) + +if __name__ == '__main__': + unittest.main() diff --git a/test_translate.py b/test_translate.py new file mode 100644 index 0000000..8215bea --- /dev/null +++ b/test_translate.py @@ -0,0 +1,94 @@ + +from llvm.core import Module +from llvm_cbuilder import * +from llvm_cbuilder.translator import translate +import llvm_cbuilder.shortnames as C +import unittest, logging + +#logging.basicConfig(level=logging.DEBUG) + +class FooIf(CDefinition): + _name_ = 'foo' + _retty_ = C.int + _argtys_ = [('x', C.int), + ('y', C.int),] + + def body(self, x, y): + @translate + def _(): + if x > y: + return x - y + else: + return y - x + + +class FooWhile(CDefinition): + _name_ = 'foo' + _retty_ = C.int + _argtys_ = [('x', C.int)] + + def body(self, x): + y = self.var_copy(x) + + @translate + def _(): + while x > 0: + x -= 1 + y += x + return y + +class FooForRange(CDefinition): + _name_ = 'foo' + _retty_ = C.int + _argtys_ = [('x', C.int)] + + def body(self, x): + y = self.var(x.type, 0) + + @translate + def _(): + for i in range(x + 1): + y += i + return y + + +class TestTranslate(unittest.TestCase): + def test_if(self): + mod = Module.new(__name__) + lfoo = FooIf()(mod) + + print(mod) + mod.verify() + + exe = CExecutor(mod) + foo = exe.get_ctype_function(lfoo, 'int, int') + self.assertEqual(foo(10, 20), 20 - 10) + self.assertEqual(foo(23, 17), 23 - 17) + + def test_whileloop(self): + mod = Module.new(__name__) + lfoo = FooWhile()(mod) + + print(mod) + mod.verify() + + exe = CExecutor(mod) + foo = exe.get_ctype_function(lfoo, 'int') + self.assertEqual(foo(10), sum(range(10+1))) + self.assertEqual(foo(1324), sum(range(1324+1))) + + def test_forloop(self): + mod = Module.new(__name__) + lfoo = FooForRange()(mod) + + print(mod) + mod.verify() + + exe = CExecutor(mod) + foo = exe.get_ctype_function(lfoo, 'int') + self.assertEqual(foo(10), sum(range(10+1))) + self.assertEqual(foo(1324), sum(range(1324+1))) + +if __name__ == '__main__': + unittest.main() + diff --git a/test_vectorarith.py b/test_vectorarith.py new file mode 100644 index 0000000..dad9262 --- /dev/null +++ b/test_vectorarith.py @@ -0,0 +1,156 @@ +from llvm_cbuilder import * +from llvm_cbuilder import shortnames as C +from llvm_cbuilder.translator import translate +from ctypes import * +from llvm.core import * +from llvm.passes import * +import numpy as np +import unittest +import logging +floatv4 = C.vector(C.float, 4) + +class VectorArith(CDefinition): + _name_ = 'vector_arith' + _argtys_ = [('a', floatv4), + ('b', floatv4), + ('c', floatv4),] + _retty_ = floatv4 + + def body(self, a, b, c): + ''' + Arguments + --------- + a, b, c -- must be vectors + ''' + @translate + def _(): # write like python in here + return a * b + c + +class VectorArithDriver1(CDefinition): + _name_ = 'vector_arith_driver_1' + _argtys_ = [('A', C.pointer(C.float)), + ('B', C.pointer(C.float)), + ('C', C.pointer(C.float)), + ('D', C.pointer(C.float)), + ('n', C.int),] + + def body(self, Aary, Bary, Cary, Dary, n): + ''' + This version uses vector load to fetch array elements as vectors. + + ''' + vecarith = self.depends(VectorArith()) + elem_per_vec = self.constant(C.int, floatv4.count) + with self.for_range(0, n, elem_per_vec) as (loop, i): + # Aary[i:] offset the array at i + a = Aary[i:].vector_load(4, align=1) # unaligned vector load + b = Bary[i:].vector_load(4, align=1) + c = Cary[i:].vector_load(4, align=1) + r = vecarith(a, b, c) + Dary[i:].vector_store(r, align=1) + # self.debug(r[0], r[1], r[2], r[3]) + self.ret() + + +class VectorArithDriver2(CDefinition): + _name_ = 'vector_arith_driver_2' + _argtys_ = [('A', C.pointer(C.float)), + ('B', C.pointer(C.float)), + ('C', C.pointer(C.float)), + ('D', C.pointer(C.float)), + ('n', C.int),] + + def body(self, Aary, Bary, Cary, Dary, n): + ''' + This version loads element of vector individually. + This style generates scalar ld/st instead of vector ld/st. + ''' + vecarith = self.depends(VectorArith()) + a = self.var(floatv4) + b = self.var(floatv4) + c = self.var(floatv4) + elem_per_vec = self.constant(C.int, floatv4.count) + with self.for_range(0, n, elem_per_vec) as (outer, i): + with self.for_range(elem_per_vec) as (inner, j): + a[j] = Aary[i + j] + b[j] = Bary[i + j] + c[j] = Cary[i + j] + r = vecarith(a, b, c) + Dary[i:].vector_store(r, align=1) + # self.debug(r[0], r[1], r[2], r[3]) + self.ret() + + + +def aligned_zeros(shape, boundary=16, dtype=float, order='C'): + ''' + Is there a better way to allocate aligned memory? + ''' + N = np.prod(shape) + d = np.dtype(dtype) + tmp = np.zeros(N * d.itemsize + boundary, dtype=np.uint8) + address = tmp.__array_interface__['data'][0] + offset = (boundary - address % boundary) % boundary + viewed = tmp[offset:offset + N * d.itemsize].view(dtype=d) + return viewed.reshape(shape, order=order) + +class TestVectorArith(unittest.TestCase): + def test_vector_arith_1(self): + self.run_and_test_udt(VectorArithDriver1(), 16) # aligned for SSE + self.run_and_test_udt(VectorArithDriver1(), 20) # misaligned for SSE + + def test_vector_arith_2(self): + self.run_and_test_udt(VectorArithDriver2(), 16) # aligned for SSE + self.run_and_test_udt(VectorArithDriver2(), 20) # misaligned for SSE + + def run_and_test_udt(self, udt, align): + module = Module.new('mod.test.vectoriarith') + + ldriver = udt(module) + + pm = PassManager.new() + pmb = PassManagerBuilder.new() + pmb.opt = 3 + pmb.vectorize = True + pmb.populate(pm) + pm.run(module) + + print(module.to_native_assembly()) + + exe = CExecutor(module) + + float_p = POINTER(c_float) + + driver = exe.get_ctype_function(ldriver, + None, + float_p, float_p, float_p, + float_p, + c_int) + + # prepare for execution + + n = 4*10 + + Aary = aligned_zeros(n, boundary=align, dtype=np.float32) + Bary = aligned_zeros(n, boundary=align, dtype=np.float32) + Cary = aligned_zeros(n, boundary=align, dtype=np.float32) + Dary = aligned_zeros(n, boundary=align, dtype=np.float32) + + Aary[:] = range(n) + Bary[:] = range(n, 2 * n) + Cary[:] = range(2 * n, 3 * n) + + golden = Aary * Bary + Cary + + getptr = lambda ary: ary.ctypes.data_as(float_p) + + driver(getptr(Aary), getptr(Bary), getptr(Cary), getptr(Dary), n) + + for x, y in zip(golden, Dary): + self.assertEqual(x, y) + + +if __name__ == '__main__': + unittest.main() + + From a046685b2c3499e6f1466058cd5f4c5ae63ff68d Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 30 Aug 2012 12:23:53 -0700 Subject: [PATCH 041/516] Add calling_conv. Set win32 api to use CC_X86_STDCALL. (need testing) --- builder.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/builder.py b/builder.py index b30c363..7aa5d93 100644 --- a/builder.py +++ b/builder.py @@ -1334,6 +1334,9 @@ class CExternal(object): All class attributes that are `llvm.core.FunctionType` are converted to `CFunc` instance during instantiation. ''' + + _calling_convention_ = None # default + def __init__(self, cbuilder): is_func = lambda x: isinstance(x, lc.FunctionType) non_magic = lambda s: not ( s.startswith('__') and s.endswith('__') ) @@ -1347,6 +1350,9 @@ class CExternal(object): mod = cbuilder.function.module for fname, ftype in to_declare: func = mod.get_or_insert_function(ftype, name=fname) + if self._calling_convention_: + func.calling_convention = self._calling_convention_ + if func.type.pointee != ftype: raise NameError("Function has already been declared " "with a different type: %s != %s" From e7b1af043f84c9a2593cf924fc2a72c1dd088506 Mon Sep 17 00:00:00 2001 From: Mark Wiebe Date: Thu, 30 Aug 2012 18:13:03 -0700 Subject: [PATCH 042/516] Use the function's calling convention when doing the call in cbuilder --- builder.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/builder.py b/builder.py index 7aa5d93..daad0c4 100644 --- a/builder.py +++ b/builder.py @@ -1155,6 +1155,8 @@ class CFunc(CValue): "argument %d mismatch: %s != %s" % (self.function.name, i, exp, got.type)) res = self.parent.builder.call(self.function, arg_values) + if hasattr(self.function, 'calling_convention'): + res.calling_convention = self.function.calling_convention return CTemp(self.parent, res) @property From a6e7bcb0159a62c68cc3e67ba7ad75068d371aad Mon Sep 17 00:00:00 2001 From: Mark Wiebe Date: Fri, 31 Aug 2012 10:53:37 -0700 Subject: [PATCH 043/516] Skip tests using pthreads on Windows Note: They were causing hard exits of Python, not exceptions, this is something that will have to be fixed in the future --- test_atomic_add.py | 2 ++ test_atomic_cmpxchg.py | 2 ++ test_pthread.py | 2 ++ 3 files changed, 6 insertions(+) diff --git a/test_atomic_add.py b/test_atomic_add.py index 27688e7..70faa0c 100644 --- a/test_atomic_add.py +++ b/test_atomic_add.py @@ -8,6 +8,7 @@ from llvm.ee import * from llvm_cbuilder import * import llvm_cbuilder.shortnames as C import unittest, logging +import sys # logging.basicConfig(level=logging.DEBUG) @@ -66,6 +67,7 @@ def gen_test_pthread(mod): return cb.function class TestAtomicAdd(unittest.TestCase): + @unittest.skipIf(sys.platform == 'win32', "test uses pthreads, not supported on Windows") def test_atomic_add(self): mod = Module.new(__name__) # add pthread functions diff --git a/test_atomic_cmpxchg.py b/test_atomic_cmpxchg.py index 27fb763..9058e42 100644 --- a/test_atomic_cmpxchg.py +++ b/test_atomic_cmpxchg.py @@ -8,6 +8,7 @@ from llvm.ee import * from llvm_cbuilder import * import llvm_cbuilder.shortnames as C import unittest, logging +import sys # logging.basicConfig(level=logging.DEBUG) @@ -71,6 +72,7 @@ def gen_test_pthread(mod): return cb.function class TestAtomicCmpXchg(unittest.TestCase): + @unittest.skipIf(sys.platform == 'win32', "test uses pthreads, not supported on Windows") def test_atomic_cmpxchg(self): mod = Module.new(__name__) # add pthread functions diff --git a/test_pthread.py b/test_pthread.py index d1d3a72..23a2083 100644 --- a/test_pthread.py +++ b/test_pthread.py @@ -4,6 +4,7 @@ from llvm.ee import * from llvm_cbuilder import * import llvm_cbuilder.shortnames as C import unittest, logging +import sys # logging.basicConfig(level=logging.DEBUG) @@ -50,6 +51,7 @@ def gen_test_pthread(mod): return cb.function class TestPThread(unittest.TestCase): + @unittest.skipIf(sys.platform == 'win32', "pthreads not supported on Windows") def test_pthread(self): mod = Module.new(__name__) # add pthread functions From 428f4ad530c7f8fd3d7e36fadbcc865b796b604f Mon Sep 17 00:00:00 2001 From: Mark Wiebe Date: Fri, 31 Aug 2012 12:18:26 -0700 Subject: [PATCH 044/516] Fix debug print test, make it account for some system printf variations --- test_print.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/test_print.py b/test_print.py index fb4a784..510161a 100644 --- a/test_print.py +++ b/test_print.py @@ -37,15 +37,23 @@ def main_debugprint(): class TestPrint(unittest.TestCase): def test_debugprint(self): - p = Popen(["python", __file__, "-child"], stdout=PIPE) + p = Popen([sys.executable, __file__, "-child"], stdout=PIPE) p.wait() - lines = p.stdout.read().decode().splitlines(False) + # The encode(utf-8) is for Python 3 compatibility + lines = p.stdout.read().encode('utf-8').splitlines(False) - expect = [ - 'Show 123 1.234 1.000e-31', - 'an_int = 123 a_float = 1.234000e+00 a_double = 1.000000e-31', - ] + # Try to account for variations in the system printf + if lines[0].find('e-031') >= 0: + expect = [ + 'Show 123 1.234 1.000e-031', + 'an_int = 123 a_float = 1.234000e+000 a_double = 1.000000e-031', + ] + else: + expect = [ + 'Show 123 1.234 1.000e-31', + 'an_int = 123 a_float = 1.234000e+00 a_double = 1.000000e-31', + ] self.assertEqual(expect, lines) p.stdout.close() From 8505256510a36312a98a4f358db7a22a0c14effe Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 4 Sep 2012 10:05:24 -0700 Subject: [PATCH 045/516] Inline ufunc kernel in vectorize. (Better io throughput) --- builder.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/builder.py b/builder.py index daad0c4..216163c 100644 --- a/builder.py +++ b/builder.py @@ -192,6 +192,7 @@ class CBuilder(object): self.first_body_block = self.function.append_basic_block('body') self.builder = lc.Builder.new(self.first_body_block) self.target_data = le.TargetData.new(self.function.module.data_layout) + self._auto_inline_list = [] # Prepare arguments. Make all function arguments behave like variables. self.args = [] for arg in function.args: @@ -437,6 +438,10 @@ class CBuilder(object): with _change_block_temporarily(self.builder, self.declare_block): self.builder.branch(self.first_body_block) + # Do the auto inlining + for callinst in self._auto_inline_list: + lc.inline_function(callinst) + def constant(self, ty, val): '''create a constant @@ -680,6 +685,9 @@ class CBuilder(object): ''' self.builder.unreachable() + def add_auto_inline(self, callinst): + self._auto_inline_list.append(callinst) + class _DeclareCDef(object): '''create a function a CDefinition to use with `CBuilder.depends` @@ -1142,7 +1150,7 @@ class CFunc(CValue): super(CFunc, self).__init__(parent) self.function = func - def __call__(self, *args): + def __call__(self, *args, **opts): '''Call the function with the given arguments *args : variable arguments of CValue instances @@ -1157,6 +1165,10 @@ class CFunc(CValue): res = self.parent.builder.call(self.function, arg_values) if hasattr(self.function, 'calling_convention'): res.calling_convention = self.function.calling_convention + + if opts.get('inline'): + self.parent.add_auto_inline(res) + return CTemp(self.parent, res) @property From b941ae5f1fb61ac0bd7375ffa0bc526443b32bdb Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 6 Sep 2012 18:25:09 -0700 Subject: [PATCH 046/516] Use non-temporal hint at memory store for vectorizer. Note: LLVM optimizer is smart enough to not use NT write if it is slower. --- builder.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/builder.py b/builder.py index 216163c..6f8cd18 100644 --- a/builder.py +++ b/builder.py @@ -688,6 +688,12 @@ class CBuilder(object): def add_auto_inline(self, callinst): self._auto_inline_list.append(callinst) + + def set_memop_non_temporal(self, ldst): + const_one = self.constant(types.int, 1).value + md = lc.MetaData.get(self.function.module, [const_one]) + ldst.set_metadata('nontemporal', md) + class _DeclareCDef(object): '''create a function a CDefinition to use with `CBuilder.depends` @@ -1096,11 +1102,15 @@ class CValue(object): loaded = self.parent.builder.load(self.value, volatile=volatile) return CTemp(self.parent, loaded) - def store(self, val, volatile=False): + def store(self, val, volatile=False, nontemporal=False): '''memory store for pointer types ''' self._ensure_is_pointer() - self.parent.builder.store(val.value, self.value, volatile=volatile) + inst = self.parent.builder.store(val.value, self.value, + volatile=volatile) + if nontemporal: + self.parent.set_memop_non_temporal(inst) + def atomic_load(self, ordering, align=None, crossthread=True): '''atomic load memory for pointer types @@ -1248,11 +1258,13 @@ class CVar(CValue): def value(self): return self.parent.builder.load(self.ptr) - def assign(self, val): + def assign(self, val, nontemporal=False): '''assign new value to the variable ''' self._ensure_same_type(val) - self.parent.builder.store(val.value, self.ptr) + inst = self.parent.builder.store(val.value, self.ptr) + if nontemporal: + self.parent.set_memop_non_temporal(inst) @property def type(self): From 1e4633c44d83b7b24af3adb2edd416b5311cdd33 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 7 Sep 2012 14:13:04 -0700 Subject: [PATCH 047/516] add invariant variable --- builder.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/builder.py b/builder.py index 6f8cd18..19822e0 100644 --- a/builder.py +++ b/builder.py @@ -1000,6 +1000,17 @@ class CValue(object): errmsg = "Cast from %s to %s is not possible." raise TypeError(errmsg % (self.type, ty)) + def ptrtoint(self): + self._ensure_is_pointer() + builder = self.parent.builder + return CTemp(self.parent, builder.ptrtoint(self.value, types.intp)) + + def inttoptr(self, ty): + if not self.is_int: + raise TypeError("Must be an integer") + builder = self.parent.builder + return CTemp(self.parent, builder.inttoptr(self.value, ty)) + def _cmp_op(self, name): '''implements comparison operations ''' @@ -1095,11 +1106,12 @@ class CValue(object): else: raise TypeError("Must be a pointer or vector; got %s" % self.type) - def load(self, volatile=False): + def load(self, volatile=False, invariant=False): '''memory load for pointer types ''' self._ensure_is_pointer() - loaded = self.parent.builder.load(self.value, volatile=volatile) + loaded = self.parent.builder.load(self.value, volatile=volatile, + invariant=invariant) return CTemp(self.parent, loaded) def store(self, val, volatile=False, nontemporal=False): @@ -1209,6 +1221,7 @@ class CVar(CValue): def __init__(self, parent, ptr): super(CVar, self).__init__(parent) self.ptr = ptr + self.invariant = False def _inplace_binop(self, op): def wrapped(rhs): @@ -1256,11 +1269,12 @@ class CVar(CValue): @property def value(self): - return self.parent.builder.load(self.ptr) + return self.parent.builder.load(self.ptr, invariant=self.invariant) def assign(self, val, nontemporal=False): '''assign new value to the variable ''' + if self.invariant: raise TypeError("Assignment to invariant variable") self._ensure_same_type(val) inst = self.parent.builder.store(val.value, self.ptr) if nontemporal: @@ -1354,6 +1368,7 @@ class CStruct(CValue): def reference(self): return CTemp(self.parent, self.ptr) + class CExternal(object): '''subclass to define external interface @@ -1385,3 +1400,4 @@ class CExternal(object): % (func.type, ftype) ) setattr(self, fname, CFunc(cbuilder, func)) + From af44641bb9fdee819848fb615088e4271ec1eb8b Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 7 Sep 2012 15:07:42 -0700 Subject: [PATCH 048/516] add noalias attribute to parameters --- builder.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/builder.py b/builder.py index 19822e0..a2f7aa9 100644 --- a/builder.py +++ b/builder.py @@ -765,7 +765,7 @@ class CDefinition(CBuilder): ''' _name_ = '' # name of the function; should overide in subclass _retty_ = types.void # return type; can overide in subclass - _argtys_ = [] # a list of tuple(name, type); can overide in subclass + _argtys_ = [] # a list of tuple(name, type, [attributes]); can overide in subclass def __new__(cls, *args, **kws): if cls.is_generic(): @@ -790,7 +790,7 @@ class CDefinition(CBuilder): Raises NameError if a function of the same name has already been defined. ''' - functype = lc.Type.function(cls._retty_, [v for k, v in cls._argtys_]) + functype = lc.Type.function(cls._retty_, [arg[1] for arg in cls._argtys_]) name = cls._name_ if not name: raise AttributeError("Function name cannot be empty.") @@ -801,9 +801,12 @@ class CDefinition(CBuilder): raise FunctionAlreadyExists(func) # Name all arguments - for i, (name, _) in enumerate(cls._argtys_): + for i, arginfo in enumerate(cls._argtys_): + name = arginfo[0] func.args[i].name = name - + if len(arginfo) > 2: + for attr in arginfo[2]: + func.args[i].add_attribute(attr) # Create builder and populate body cbuilder = object.__new__(cls) cbuilder.__init__(func) From 8a159b35f01f600673f059d1bcc29f296db6ec69 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 7 Sep 2012 17:38:56 -0700 Subject: [PATCH 049/516] refactor llvm_cbuilder --- builder.py | 695 +++++++++++++++++++++++++---------------------------- 1 file changed, 329 insertions(+), 366 deletions(-) diff --git a/builder.py b/builder.py index a2f7aa9..f1c1d01 100644 --- a/builder.py +++ b/builder.py @@ -42,6 +42,9 @@ def _is_block_terminated(bb): instrs = bb.instructions return len(instrs) > 0 and instrs[-1].is_terminator +def _is_struct(ty): + return isinstance(ty, lc.StructType) + def _is_cstruct(ty): try: return issubclass(ty, CStruct) @@ -67,6 +70,10 @@ def _change_block_temporarily(builder, bb): def _change_block_temporarily_dummy(*args): yield +class CastError(TypeError): + def __init__(self, orig, to): + super(CastError, self).__init__("Cannot cast from %s to %s" % (orig, to)) + class _IfElse(object): '''if-else construct. @@ -399,7 +406,7 @@ class CBuilder(object): def check_arg(x): if isinstance(x, int): return self.constant(types.int, x) - if not x.is_int: + if not isinstance(x, IntegerValue): raise TypeError(x, "All args must be of integer type.") return x @@ -675,7 +682,11 @@ class CBuilder(object): def alignment(self, ty): '''get minimum alignment of `ty` ''' - return self.target_data.abi_alignment(ty) + return self.abi.abi_alignment(ty) + + @property + def abi(self): + return self.target_data def unreachable(self): '''insert instruction that causes segfault some platform (Intel), @@ -828,301 +839,335 @@ class CDefinition(CBuilder): raise NotImplementedError class CValue(object): - ''' - Signedness - ---------- - Since LLVM type does not provide signedness attribute. This information - is provided in the CValue.unsigned attribute. The default value is - `None`, meaning that this attribute is not set. + def __init__(self, parent, handle): + self.__parent = parent + self.__handle = handle - In casting operation, signednss information is passed as an optional arg. + @property + def handle(self): + return self.__handle - In binary operation, signedness of the left operand is used. - ''' + @property + def parent(self): + return self.__parent - unsigned = None # attribute for for integer values. + def _temp(self, val): + return CTemp(self.parent, val) - _BINOP_MAP = { - # op-name : (signed int, unsigned int, real) - 'add' : (lc.Builder.add, lc.Builder.add, lc.Builder.fadd), - 'sub' : (lc.Builder.sub, lc.Builder.sub, lc.Builder.fsub), - 'mul' : (lc.Builder.mul, lc.Builder.mul, lc.Builder.fmul), - 'div' : (lc.Builder.sdiv, lc.Builder.udiv, lc.Builder.fdiv), - 'mod' : (lc.Builder.srem, lc.Builder.urem, lc.Builder.frem), - } +def _get_operator_provider(ty): + if _is_pointer(ty): + return PointerValue + elif _is_int(ty): + return IntegerValue + elif _is_real(ty): + return RealValue + elif _is_vector(ty): + inner = _get_operator_provider(ty.element) + return type(str(ty), (inner, VectorIndexing), {}) + elif _is_struct(ty): + return StructValue + else: + assert False, (str(ty), type(ty)) - _BITWISE_MAP = { - # op-name : (signed int, unsigned int) - 'lshift' : (lc.Builder.shl, lc.Builder.shl), - 'rshift' : (lc.Builder.lshr, lc.Builder.ashr), - 'and' : (lc.Builder.and_, lc.Builder.and_), - 'or' : (lc.Builder.or_, lc.Builder.or_), - 'xor' : (lc.Builder.xor, lc.Builder.xor), - } +class CTemp(CValue): + def __new__(cls, parent, handle): + meta = _get_operator_provider(handle.type) + base = type(str('%s_%s' % (cls.__name__, handle.type)), (cls, meta), {}) + return object.__new__(base) - _CMP_MAP = { - # op-name : (signed int, unsigned int, real) - 'eq' : (lc.ICMP_EQ, lc.ICMP_EQ, lc.FCMP_OEQ), - 'ne' : (lc.ICMP_NE, lc.ICMP_NE, lc.FCMP_ONE), - 'lt' : (lc.ICMP_SLT, lc.ICMP_ULT, lc.FCMP_OLT), - 'le' : (lc.ICMP_SLE, lc.ICMP_ULE, lc.FCMP_OLE), - 'gt' : (lc.ICMP_SGT, lc.ICMP_UGT, lc.FCMP_OGT), - 'ge' : (lc.ICMP_SGE, lc.ICMP_UGE, lc.FCMP_OGE), - } + def __init__(self, *args, **kws): + super(CTemp, self).__init__(*args, **kws) + self._init_mixin() - def __init__(self, parent): - self.parent = parent + @property + def value(self): + return self.handle - def _use_binop(self, op): - '''implements binary operations - ''' - def wrapped(rhs): - self._ensure_same_type(rhs) - binop = self._BINOP_MAP[op] - if self.is_int: - if not self.unsigned: - idx = 0 - else: - idx = 1 - elif self.is_real: - idx = 2 - else: - errmsg = "Binary operation %s does not support type %s" - raise TypeError(errmsg % (op, self.type)) - res = binop[idx](self.parent.builder, self.value, rhs.value) - return CTemp(self.parent, res) - return wrapped + @property + def type(self): + return self.value.type - def _use_bitwise(self, op): - '''implements bitwise operations - ''' - def wrapped(rhs): - self._ensure_same_type(rhs) - if not self.is_int: - errmsg = "Bitwise operation %s does not support type %s" - raise TypeError(op, self.type) - if not self.unsigned: - idx = 0 - else: - idx = 1 - res = self._BITWISE_MAP[idx](self.parent.builder, - self.value, rhs.value) - return CTemp(self.parent, res) - return wrapped +class CVar(CValue): + def __new__(cls, parent, ptr): + meta = _get_operator_provider(ptr.type.pointee) + base = type(str('%s_%s' % (cls.__name__, ptr.type.pointee)), (cls, meta), {}) + return object.__new__(base) + + def __init__(self, parent, ptr): + super(CVar, self).__init__(parent, ptr) + self._init_mixin() + self.invariant = False + + def reference(self): + return self._temp(self.handle) + + @property + def ref(self): + return self.reference() + + @property + def value(self): + return self.parent.builder.load(self.ref.value, + invariant=self.invariant) + + @property + def type(self): + return self.ref.type.pointee + + def assign(self, val, **kws): + if self.invariant: + raise TypeError("Storing to invariant variable.") + self.parent.builder.store(val.value, self.ref.value, **kws) + return self + + def __iadd__(self, rhs): + return self.assign(self.__add__(rhs)) + + def __isub__(self, rhs): + return self.assign(self.__sub__(rhs)) + + def __imul__(self, rhs): + return self.assign(self.__mul__(rhs)) + + def __idiv__(self, rhs): + return self.assign(self.__div__(rhs)) + + def __imod__(self, rhs): + return self.assign(self.__mod__(rhs)) + + def __ilshift__(self, rhs): + return self.assign(self.__lshift__(rhs)) + + def __irshift__(self, rhs): + return self.assign(self.__rshift__(rhs)) + + def __iand__(self, rhs): + return self.assign(self.__and__(rhs)) + + def __ior__(self, rhs): + return self.assign(self.__or__(rhs)) + + def __ixor__(self, rhs): + return self.assign(self.__xor__(rhs)) + + +class OperatorMixin(object): + def _init_mixin(self): + pass + +class IntegerValue(OperatorMixin): + + def _init_mixin(self): + self._unsigned = False + + def _get_unsigned(self): + return self._unsigned + + def _set_unsigned(self, unsigned): + self._unsigned = bool(unsigned) + + unsigned = property(_get_unsigned, _set_unsigned) def __add__(self, rhs): - return self._use_binop('add')(rhs) + return self._temp(self.parent.builder.add(self.value, rhs.value)) def __sub__(self, rhs): - return self._use_binop('sub')(rhs) + return self._temp(self.parent.builder.sub(self.value, rhs.value)) def __mul__(self, rhs): - return self._use_binop('mul')(rhs) + return self._temp(self.parent.builder.mul(self.value, rhs.value)) def __div__(self, rhs): - return self._use_binop('div')(rhs) - - def __truediv__(self, rhs): - return self.__div__(rhs) + if self.unsigned: + return self._temp(self.parent.builder.udiv(self.value, rhs.value)) + else: + return self._temp(self.parent.builder.sdiv(self.value, rhs.value)) def __mod__(self, rhs): - return self._use_binop('mod')(rhs) + if self.unsigned: + return self._temp(self.parent.builder.urem(self.value, rhs.value)) + else: + return self._temp(self.parent.builder.srem(self.value, rhs.value)) - def __lshift__(self, rhs): - return self._use_bitwise('lshift')(rhs) + def __ilshift__(self, rhs): + return self._temp(self.parent.builder.shl(self.value, rhs.value)) - def __rshift__(self, rhs): - return self._use_bitwise('rshift')(rhs) + def __irshift__(self, rhs): + if self.unsigned: + return self._temp(self.self.parent.builder.lshr(self.value, rhs.value)) + else: + return self._temp(self.parent.builder.ashr(self.value, rhs.value)) - def __and__(self, rhs): - return self._use_bitwise('and')(rhs) + def __iand__(self, rhs): + return self._temp(self.parent.builder.and_(self.value, rhs.value)) - def __or__(self, rhs): - return self._use_bitwise('or')(rhs) + def __ior__(self, rhs): + return self._temp(self.parent.builder.or_(self.value, rhs.value)) - def __xor__(self, rhs): - return self._use_bitwise('xor')(rhs) - - def _ensure_same_type(self, val): - '''ensure that this instance has the same type as `val` - - Raises TypeError if `self.type != val.type` - ''' - if self.type != val.type: - errmsg = "Type mismatch: %s != %s" - raise TypeError(errmsg % (self.type, val.type)) - - @property - def is_int(self): - return _is_int(self.type) or _is_vector(self.type, _is_int) - - @property - def is_real(self): - return _is_real(self.type) or _is_vector(self.type, _is_real) - - def cast(self, ty, unsigned=False): - '''cast to another type - - If `ty == self.type`, then pass thru - ''' - make = lambda X: CTemp(self.parent, X) - if self.type == ty: - return self # pass thru - elif self.is_pointer and _is_pointer(ty): - builder = self.parent.builder - return make(builder.bitcast(self.value, ty)) - elif self.is_int: - if _is_int(ty): - if self.type.width < ty.width: - if not unsigned: - return make(self.parent.builder.sext(self.value, ty)) - else: - return make(self.parent.builder.zext(self.value, ty)) - else: - return make(self.parent.builder.trunc(self.value, ty)) - elif _is_real(ty): - if not unsigned: - return make(self.parent.builder.sitofp(self.value, ty)) - else: - return make(self.parent.builder.uitofp(self.value, ty)) - elif self.is_real: - if _is_int(ty): - if not unsigned: - return make(self.parent.builder.fptosi(self.value, ty)) - else: - return make(self.parent.builder.fptoui(self.value, ty)) - else: - if ty == types.double: - assert self.type == types.float - return make(self.parent.builder.fpext(self.value, ty)) - else: - assert ty == types.float - assert self.type == types.double - return make(self.parent.builder.fptrunc(self.value, ty)) - - errmsg = "Cast from %s to %s is not possible." - raise TypeError(errmsg % (self.type, ty)) - - def ptrtoint(self): - self._ensure_is_pointer() - builder = self.parent.builder - return CTemp(self.parent, builder.ptrtoint(self.value, types.intp)) - - def inttoptr(self, ty): - if not self.is_int: - raise TypeError("Must be an integer") - builder = self.parent.builder - return CTemp(self.parent, builder.inttoptr(self.value, ty)) - - def _cmp_op(self, name): - '''implements comparison operations - ''' - def wrapped(rhs): - make = lambda X: CTemp(self.parent, X) - self._ensure_same_type(rhs) - - flag_bag = self._CMP_MAP[name] - if self.is_int: - comparator = self.parent.builder.icmp - if not self.unsigned: - flag = flag_bag[0] - else: - flag = flag_bag[1] - elif self.is_real: - comparator = self.parent.builder.fcmp - flag = flag_bag[2] - else: - errmsg = "Comparision between %s and %s is not supported." - raise TypeError(errmsg % (self.type, rhs.type)) - - return CTemp(self.parent, comparator(flag, self.value, rhs.value)) - return wrapped - - def __eq__(self, rhs): - return self._cmp_op('eq')(rhs) - - def __ne__(self, rhs): - return self._cmp_op('ne')(rhs) + def __ixor__(self, rhs): + return self._temp(self.parent.builder.xor(self.value, rhs.value)) def __lt__(self, rhs): - return self._cmp_op('lt')(rhs) + if self.unsigned: + return self._temp(self.parent.builder.icmp(lc.ICMP_ULT, self.value, rhs.value)) + else: + return self._temp(self.parent.builder.icmp(lc.ICMP_SLT, self.value, rhs.value)) def __le__(self, rhs): - return self._cmp_op('le')(rhs) + if self.unsigned: + return self._temp(self.parent.builder.icmp(lc.ICMP_ULE, self.value, rhs.value)) + else: + return self._temp(self.parent.builder.icmp(lc.ICMP_SLE, self.value, rhs.value)) + + def __eq__(self, rhs): + return self._temp(self.parent.builder.icmp(lc.ICMP_EQ, self.value, rhs.value)) + + def __ne__(self, rhs): + return self._temp(self.parent.builder.icmp(lc.ICMP_NE, self.value, rhs.value)) def __gt__(self, rhs): - return self._cmp_op('gt')(rhs) + if self.unsigned: + return self._temp(self.parent.builder.icmp(lc.ICMP_UGT, self.value, rhs.value)) + else: + return self._temp(self.parent.builder.icmp(lc.ICMP_SGT, self.value, rhs.value)) def __ge__(self, rhs): - return self._cmp_op('ge')(rhs) + if self.unsigned: + return self._temp(self.parent.builder.icmp(lc.ICMP_UGE, self.value, rhs.value)) + else: + return self._temp(self.parent.builder.icmp(lc.ICMP_SGE, self.value, rhs.value)) + + def cast(self, ty, unsigned=False): + if ty == self.type: + return self._temp(self.value) + + if _is_real(ty): + if self.unsigned or unsigned: + return self._temp(self.parent.builder.uitofp(self.value, ty)) + else: + return self._temp(self.parent.builder.sitofp(self.value, ty)) + elif _is_int(ty): + if self.parent.abi.size(self.type) < self.parent.abi.size(ty): + if self.unsigned or unsigned: + return self._temp(self.parent.builder.zext(self.value, ty)) + else: + return self._temp(self.parent.builder.sext(self.value, ty)) + else: + return self._temp(self.parent.builder.trunc(self.value, ty)) + raise CastError(self.type, ty) + +class RealValue(OperatorMixin): + def __add__(self, rhs): + return self._temp(self.parent.builder.fadd(self.value, rhs.value)) + + def __sub__(self, rhs): + return self._temp(self.parent.builder.fsub(self.value, rhs.value)) + + def __mul__(self, rhs): + return self._temp(self.parent.builder.fmul(self.value, rhs.value)) + + def __div__(self, rhs): + return self._temp(self.parent.builder.fdiv(self.value, rhs.value)) + + def __mod__(self, rhs): + return self._temp(self.parent.builder.frem(self.value, rhs.value)) + + def __lt__(self, rhs): + return self._temp(self.parent.builder.fcmp(lc.FCMP_OLT, self.value, rhs.value)) + + def __le__(self, rhs): + return self._temp(self.parent.builder.fcmp(lc.FCMP_OLE, self.value, rhs.value)) + + def __eq__(self, rhs): + return self._temp(self.parent.builder.fcmp(lc.FCMP_OEQ, self.value, rhs.value)) + + def __ne__(self, rhs): + return self._temp(self.parent.builder.fcmp(lc.FCMP_ONE, self.value, rhs.value)) + + def __gt__(self, rhs): + return self._temp(self.parent.builder.fcmp(lc.FCMP_OGT, self.value, rhs.value)) + + def __ge__(self, rhs): + return self._temp(self.parent.builder.fcmp(lc.FCMP_OGE, self.value, rhs.value)) + + def cast(self, ty, unsigned=False): + if ty == self.type: + return self._temp(self.value) + + if _is_int(ty): + if unsigned: + return self._temp(self.parent.builder.fptoui(self.value, ty)) + else: + return self._temp(self.parent.builder.fptosi(self.value, ty)) + + if _is_real(ty): + if self.parent.abi.size(self.type) > self.parent.abi.size(ty): + return self._temp(self.parent.builder.fptrunc(self.value, ty)) + else: + return self._temp(self.parent.builder.fpext(self.value, ty)) + + raise CastError(self.type, ty) - @property - def is_vector(self): - return _is_vector(self.type) - - @property - def is_pointer(self): - return _is_pointer(self.type) - - def _ensure_is_pointer(self): - if not self.is_pointer: - raise TypeError("Must be a pointer; got %s" % self.type) - - def _ensure_is_vector(self): - if not self.is_vector: - raise TypeError("Must be a vector; got %s" % self.type) - +class PointerIndexing(OperatorMixin): def __getitem__(self, idx): '''implement access indexing Uses GEP. ''' bldr = self.parent.builder - if self.is_pointer: - if type(idx) is slice: - # just handle case by case - # Case #1: A[idx:] get poointer offset by idx - if not idx.step and not idx.stop: - idx = _auto_coerce_index(self.parent, idx.start) - ptr = bldr.gep(self.value, [idx.value]) - return CArray(self.parent, ptr) - else: # return an variable at idx - idx = _auto_coerce_index(self.parent, idx) + if type(idx) is slice: + # just handle case by case + # Case #1: A[idx:] get pointer offset by idx + if not idx.step and not idx.stop: + idx = _auto_coerce_index(self.parent, idx.start) ptr = bldr.gep(self.value, [idx.value]) - return CVar(self.parent, ptr) - elif self.is_vector: + return CArray(self.parent, ptr) + else: # return an variable at idx idx = _auto_coerce_index(self.parent, idx) - val = bldr.extract_element(self.value, idx.value) - return CTemp(self.parent, val) - else: - raise TypeError("Must be a pointer or vector; got %s" % self.type) + ptr = bldr.gep(self.value, [idx.value]) + return CVar(self.parent, ptr) def __setitem__(self, idx, val): idx = _auto_coerce_index(self.parent, idx) bldr = self.parent.builder - if self.is_vector: - vec = bldr.insert_element(self.value, val.value, idx.value) - bldr.store(vec, self.ptr) - elif self.is_pointer: - self[idx].assign(val) - else: - raise TypeError("Must be a pointer or vector; got %s" % self.type) + self[idx].assign(val) - def load(self, volatile=False, invariant=False): - '''memory load for pointer types - ''' - self._ensure_is_pointer() - loaded = self.parent.builder.load(self.value, volatile=volatile, - invariant=invariant) - return CTemp(self.parent, loaded) +class PointerCasting(OperatorMixin): + def cast(self, ty): + if ty == self.type: + return self._temp(self.value) - def store(self, val, volatile=False, nontemporal=False): - '''memory store for pointer types + if _is_pointer(ty): + return self._temp(self.parent.builder.bitcast(self.value, ty)) + raise CastError(self.type, ty) + + + +class VectorIndexing(OperatorMixin): + def __getitem__(self, idx): + '''implement access indexing + + Uses GEP. ''' - self._ensure_is_pointer() - inst = self.parent.builder.store(val.value, self.value, - volatile=volatile) + bldr = self.parent.builder + idx = _auto_coerce_index(self.parent, idx) + val = bldr.extract_element(self.value, idx.value) + return CTemp(self.parent, val) + + def __setitem__(self, idx, val): + idx = _auto_coerce_index(self.parent, idx) + bldr = self.parent.builder + vec = bldr.insert_element(self.value, val.value, idx.value) + bldr.store(vec, self.ref.value) + +class PointerValue(PointerIndexing, PointerCasting): + + def load(self, **kws): + return self._temp(self.parent.builder.load(self.value, **kws)) + + def store(self, val, nontemporal=False, **kws): + inst = self.parent.builder.store(val.value, self.value, **kws) if nontemporal: self.parent.set_memop_non_temporal(inst) @@ -1135,12 +1180,11 @@ class CValue(object): Other parameters are the same as `CBuilder.atomic_load` ''' - self._ensure_is_pointer() if align is None: align = self.parent.alignment(self.type.pointee) inst = self.parent.builder.atomic_load(self.value, ordering, align, crossthread=crossthread) - return CTemp(self.parent, inst) + return self._temp(inst) def atomic_store(self, value, ordering, align=None, crossthread=True): '''atomic memory store for pointer types @@ -1150,7 +1194,6 @@ class CValue(object): Other parameters are the same as `CBuilder.atomic_store` ''' - self._ensure_is_pointer() if align is None: align = self.parent.alignment(self.type.pointee) self.parent.builder.atomic_store(value.ptr, self.value, ordering, @@ -1161,19 +1204,34 @@ class CValue(object): Other parameters are the same as `CBuilder.atomic_cmpxchg` ''' - self._ensure_is_pointer() inst = self.parent.builder.atomic_cmpxchg(self.value, old.value, new.value, ordering, crossthread=crossthread) - return CTemp(self.parent, inst) + return self._temp(inst) + + def as_struct(self, cstruct_class, volatile=False): + '''load a pointer to a structure and assume a structure interface + ''' + ptr = self.parent.builder.load(self.value, volatile=volatile) + return cstruct_class(self.parent, self.value) + +class StructValue(OperatorMixin): + + def as_struct(self, cstruct_class): + '''assume a structure interface + ''' + return cstruct_class(self.parent, self.ref.value) -class CFunc(CValue): +class CFunc(CValue, PointerCasting): '''Wraps function pointer ''' def __init__(self, parent, func): - super(CFunc, self).__init__(parent) - self.function = func + super(CFunc, self).__init__(parent, func) + + @property + def function(self): + return self.handle def __call__(self, *args, **opts): '''Call the function with the given arguments @@ -1188,13 +1246,15 @@ class CFunc(CValue): "argument %d mismatch: %s != %s" % (self.function.name, i, exp, got.type)) res = self.parent.builder.call(self.function, arg_values) + if hasattr(self.function, 'calling_convention'): res.calling_convention = self.function.calling_convention if opts.get('inline'): self.parent.add_auto_inline(res) - return CTemp(self.parent, res) + if ftype.return_type != lc.Type.void(): + return CTemp(self.parent, res) @property def value(self): @@ -1204,123 +1264,25 @@ class CFunc(CValue): def type(self): return self.function.type -class CTemp(CValue): - '''Wraps temporary values - ''' - def __init__(self, parent, value): - super(CTemp, self).__init__(parent) - self.value = value - @property - def type(self): - return self.value.type - -class CVar(CValue): - '''Wraps variables - - Similar to C variables. - ''' - - def __init__(self, parent, ptr): - super(CVar, self).__init__(parent) - self.ptr = ptr - self.invariant = False - - def _inplace_binop(self, op): - def wrapped(rhs): - res = self._use_binop(op)(rhs) - self.assign(res) - return self - return wrapped - - def __iadd__(self, rhs): - return self._inplace_binop('add')(rhs) - - def __isub__(self, rhs): - return self._inplace_binop('sub')(rhs) - - def __imul__(self, rhs): - return self._inplace_binop('mul')(rhs) - - def __idiv__(self, rhs): - return self._inplace_binop('div')(rhs) - - def __imod__(self, rhs): - return self._inplace_binop('mod')(rhs) - - def _inplace_bitwise(self, op): - def wrapped(rhs): - res = self._use_bitwise(op)(rhs) - self.assign(res) - return self - return wrapped - - def __ilshift__(self, rhs): - return self._inplace_bitwise('lshift')(rhs) - - def __irshift__(self, rhs): - return self._inplace_bitwise('rshift')(rhs) - - def __iand__(self, rhs): - return self._inplace_bitwise('and')(rhs) - - def __ior__(self, rhs): - return self._inplace_bitwise('or')(rhs) - - def __ixor__(self, rhs): - return self._inplace_bitwise('xor')(rhs) - - @property - def value(self): - return self.parent.builder.load(self.ptr, invariant=self.invariant) - - def assign(self, val, nontemporal=False): - '''assign new value to the variable - ''' - if self.invariant: raise TypeError("Assignment to invariant variable") - self._ensure_same_type(val) - inst = self.parent.builder.store(val.value, self.ptr) - if nontemporal: - self.parent.set_memop_non_temporal(inst) - - @property - def type(self): - return self.ptr.type.pointee - - def reference(self): - '''get a pointer reference of the variable - ''' - return CTemp(self.parent, self.ptr) - - def as_struct(self, cstruct_class, volatile=False): - '''load a pointer to a structure and assume a structure interface - ''' - if _is_pointer(self.type): - ptr = self.parent.builder.load(self.ptr, volatile=volatile) - return cstruct_class(self.parent, ptr) - else: - return cstruct_class(self.parent, self.ptr) - - -class CArray(CValue): +class CArray(CValue, PointerIndexing, PointerCasting): '''wraps a array Similar to C arrays ''' def __init__(self, parent, base): - super(CArray, self).__init__(parent) - self.base_ptr = base + super(CArray, self).__init__(parent, base) @property def value(self): - return self.base_ptr + return self.handle def reference(self): - return CTemp(self.parent, self.base_ptr) + return self._temp(self.value) @property def type(self): - return self.base_ptr.type + return self.value.type def vector_load(self, count, align=0): parent = self.parent @@ -1328,9 +1290,9 @@ class CArray(CValue): values = [self[i] for i in range(count)] vecty = types.vector(self.type.pointee, count) - vec = builder.load(builder.bitcast(self.base_ptr, types.pointer(vecty)), + vec = builder.load(builder.bitcast(self.value, types.pointer(vecty)), align=align) - return CTemp(parent, vec) + return self._temp(vec) def vector_store(self, vec, align=0): if vec.type.element != self.type.pointee: @@ -1338,10 +1300,11 @@ class CArray(CValue): (vec.type.element, self.type.pointee)) parent = self.parent builder = parent.builder - vecptr = builder.bitcast(self.base_ptr, types.pointer(vec.type)) + vecptr = builder.bitcast(self.value, types.pointer(vec.type)) builder.store(vec.value, vecptr, align=align) return self + class CStruct(CValue): '''Wraps a structure @@ -1358,9 +1321,9 @@ class CStruct(CValue): return lc.Type.struct([v for k, v in cls._fields_]) def __init__(self, parent, ptr): - super(CStruct, self).__init__(parent) + super(CStruct, self).__init__(parent, ptr) makeind = lambda x: self.parent.constant(types.int, x).value - self.ptr = ptr + for i, (fd, _) in enumerate(self._fields_): gep = self.parent.builder.gep(ptr, [makeind(0), makeind(i)]) gep.name = "%s.%s" % (type(self).__name__, fd) @@ -1369,7 +1332,7 @@ class CStruct(CValue): setattr(self, fd, CVar(self.parent, gep)) def reference(self): - return CTemp(self.parent, self.ptr) + return self._temp(self.handle) class CExternal(object): From b0137289b9d2723edb469258beec2ec7ade7d056 Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Fri, 21 Sep 2012 22:39:48 +0200 Subject: [PATCH 050/516] Use meta to decompile python functions into ASTs --- builder.py | 10 +++++++--- translator.py | 20 ++++---------------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/builder.py b/builder.py index f1c1d01..5344d4f 100644 --- a/builder.py +++ b/builder.py @@ -364,9 +364,13 @@ class CBuilder(object): self.builder.ret(val.value) else: if retty != types.void: - errmsg = "Cannot return void" - raise TypeError(errmsg) - self.builder.ret_void() + # errmsg = "Cannot return void" + # raise TypeError(errmsg, retty) + bb = self.function.append_basic_block('unreachable_bb') + self.builder.position_at_end(bb) + self.builder.ret(self.builder.alloca(retty, name='undef')) + else: + self.builder.ret_void() @contextlib.contextmanager def ifelse(self, cond): diff --git a/translator.py b/translator.py index c0e9d5f..e9d9b54 100644 --- a/translator.py +++ b/translator.py @@ -1,5 +1,6 @@ # A handy translator that converts control flow into the appropriate # llvm_cbuilder constructs +from numba.functions import _get_ast import inspect, functools, ast import logging @@ -8,22 +9,9 @@ logger = logging.getLogger(__name__) def translate(func): # TODO use meta package wrapper = functools.wraps(func) - source = inspect.getsource(func) - lines = list(source.splitlines()) - - # skip first two lines - # assume they are - # @translate - # def blahblah(): - assert lines[0].lstrip().startswith('@') - assert lines[1].lstrip().startswith('def') - first_line_len = len(lines[2]) - indent = first_line_len - len(lines[2].lstrip()) - source = '\n'.join(line[indent:] for line in lines[2:]) - caller_frame = inspect.currentframe().f_back - - tree = ast.parse(source) + tree = _get_ast(func) + tree = ast.copy_location(ast.Module(body=tree.body), tree) tree = ExpandControlFlow().visit(tree) tree = ast.fix_missing_locations(tree) @@ -34,7 +22,7 @@ def translate(func): try: return eval(compile(tree, '', 'exec')) - except: + except Exception, e: logger.debug(ast.dump(tree)) from ArminRonacher import codegen # uses Armin Ronacher's codegen to debug # http://dev.pocoo.org/hg/sandbox/file/852a1248c8eb/ast/codegen.py From cd9c5e7c7921a8115b1da077aec56c2ed495a76f Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Fri, 21 Sep 2012 22:39:48 +0200 Subject: [PATCH 051/516] Use meta to decompile python functions into ASTs --- test_translate.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test_translate.py b/test_translate.py index 8215bea..b9e39ea 100644 --- a/test_translate.py +++ b/test_translate.py @@ -8,7 +8,7 @@ import unittest, logging #logging.basicConfig(level=logging.DEBUG) class FooIf(CDefinition): - _name_ = 'foo' + _name_ = 'foo_if' _retty_ = C.int _argtys_ = [('x', C.int), ('y', C.int),] @@ -23,7 +23,7 @@ class FooIf(CDefinition): class FooWhile(CDefinition): - _name_ = 'foo' + _name_ = 'foo_while' _retty_ = C.int _argtys_ = [('x', C.int)] @@ -38,7 +38,7 @@ class FooWhile(CDefinition): return y class FooForRange(CDefinition): - _name_ = 'foo' + _name_ = 'foo_for_range' _retty_ = C.int _argtys_ = [('x', C.int)] From 10b3f188cc79d6e9bbf31eee6b122715cfb22c9b Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Tue, 18 Sep 2012 22:29:23 +0100 Subject: [PATCH 052/516] Some more progress towards CUDA gufuncs --- shortnames.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/shortnames.py b/shortnames.py index 012e53d..06221aa 100644 --- a/shortnames.py +++ b/shortnames.py @@ -1,3 +1,5 @@ +from numba.minivect import minitypes +import numba.decorators from llvm.core import Type void = Type.void() @@ -11,12 +13,15 @@ int64 = Type.int(64) float = Type.float() double = Type.double() +npy_intp = minitypes.npy_intp.to_llvm(numba.decorators.context) + # pointers pointer = Type.pointer void_p = pointer(char) char_p = pointer(char) +npy_intp_p = pointer(npy_intp) # platform dependent From bc03c9a8b7cb7b10b657beabbd24107f99cb7b41 Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Thu, 20 Sep 2012 22:23:09 +0200 Subject: [PATCH 053/516] Fix GC head for debug builds for gufunc fake arrays --- builder.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/builder.py b/builder.py index 5344d4f..b93cccc 100644 --- a/builder.py +++ b/builder.py @@ -1335,6 +1335,8 @@ class CStruct(CValue): raise AttributeError("Field name shadows another attribute") setattr(self, fd, CVar(self.parent, gep)) + self.type = self.llvm_type() + def reference(self): return self._temp(self.handle) From b9584e1071f6079cc8aecee8a36f64ce99565718 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 21 Sep 2012 19:37:10 -0700 Subject: [PATCH 054/516] Fix assertion error in python source due to invalid lineno increment inside llvm_cbuilder.translator. --- translator.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/translator.py b/translator.py index e9d9b54..e3cb5ff 100644 --- a/translator.py +++ b/translator.py @@ -11,9 +11,20 @@ def translate(func): wrapper = functools.wraps(func) caller_frame = inspect.currentframe().f_back tree = _get_ast(func) - tree = ast.copy_location(ast.Module(body=tree.body), tree) + tree = ast.Module(body=tree.body) tree = ExpandControlFlow().visit(tree) - tree = ast.fix_missing_locations(tree) + + # NOTE: A hack to fix assertion error in debug mode due to bad lineno. + # Lineno must increase monotonically for co_lnotab, + # the "line number table" to work correctly. + # This script just set all lineno to 1 and col_offset = to 0. + # This makes it impossible to do traceback, but it is not possible + # anyway since we are dynamically changing the source code. + for node in ast.walk(tree): + # only ast.expr and ast.stmt and their subclass has lineno and col_offset. + if isinstance(node, ast.expr) or isinstance(node, ast.stmt): + node.lineno = 1 + node.col_offset = 0 # prepare locals for execution local_dict = locals() @@ -21,7 +32,8 @@ def translate(func): local_dict.update(caller_frame.f_globals) try: - return eval(compile(tree, '', 'exec')) + compiled = compile(tree, '', 'exec') + return eval(compiled) except Exception, e: logger.debug(ast.dump(tree)) from ArminRonacher import codegen # uses Armin Ronacher's codegen to debug @@ -97,7 +109,7 @@ class ExpandControlFlow(ast.NodeTransformer): ifelse = load_template(_if_else_template) ifelse = MacroExpander(mapping).visit(ifelse) newnode = self.generic_visit(ifelse) - return ast.copy_location(newnode, node) + return newnode def visit_While(self, node): mapping = { @@ -107,7 +119,7 @@ class ExpandControlFlow(ast.NodeTransformer): whileloop = load_template(_while_template) whileloop = MacroExpander(mapping).visit(whileloop) newnode = self.generic_visit(whileloop) - return ast.copy_location(newnode, node) + return newnode def visit_For(self, node): try: @@ -125,13 +137,13 @@ class ExpandControlFlow(ast.NodeTransformer): forloop = load_template(_for_range_template) forloop = MacroExpander(mapping).visit(forloop) newnode = self.generic_visit(forloop) - return ast.copy_location(newnode, node) + return newnode def visit_Return(self, node): mapping = {'__RETURN__' : node.value} ret = load_template(_return_template) repl = MacroExpander(mapping).visit(ret) - return ast.copy_location(repl, node) + return repl def visit_Num(self, node): '''convert immediate values @@ -148,7 +160,7 @@ class ExpandControlFlow(ast.NodeTransformer): '__VALUE__' : node, } constant = MacroExpander(mapping).visit(template).value - newnode = ast.copy_location(constant, node) + newnode = constant return newnode class MacroExpander(ast.NodeTransformer): @@ -187,6 +199,7 @@ class MacroExpander(ast.NodeTransformer): pass else: if repl is not None and not isinstance(repl, list): - return ast.copy_location(repl, node) + return repl return node + From 20a896b20620362e7b3737dc6018b1cf47d84349 Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Mon, 24 Sep 2012 12:21:12 +0100 Subject: [PATCH 055/516] Start on array expressions --- translator.py | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/translator.py b/translator.py index e3cb5ff..8fef17b 100644 --- a/translator.py +++ b/translator.py @@ -1,6 +1,6 @@ # A handy translator that converts control flow into the appropriate # llvm_cbuilder constructs -from numba.functions import _get_ast +from numba.functions import _get_ast, fix_ast_lineno import inspect, functools, ast import logging @@ -13,18 +13,7 @@ def translate(func): tree = _get_ast(func) tree = ast.Module(body=tree.body) tree = ExpandControlFlow().visit(tree) - - # NOTE: A hack to fix assertion error in debug mode due to bad lineno. - # Lineno must increase monotonically for co_lnotab, - # the "line number table" to work correctly. - # This script just set all lineno to 1 and col_offset = to 0. - # This makes it impossible to do traceback, but it is not possible - # anyway since we are dynamically changing the source code. - for node in ast.walk(tree): - # only ast.expr and ast.stmt and their subclass has lineno and col_offset. - if isinstance(node, ast.expr) or isinstance(node, ast.stmt): - node.lineno = 1 - node.col_offset = 0 + fix_ast_lineno(tree) # prepare locals for execution local_dict = locals() From ab0ce0d49aec00a6c92c679b735e2c8418ac16c8 Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Thu, 27 Sep 2012 01:11:35 -0500 Subject: [PATCH 056/516] Update numbapro to handle latest numba changes. --- builder.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/builder.py b/builder.py index b93cccc..2826e1d 100644 --- a/builder.py +++ b/builder.py @@ -911,8 +911,7 @@ class CVar(CValue): @property def value(self): - return self.parent.builder.load(self.ref.value, - invariant=self.invariant) + return self.parent.builder.load(self.ref.value) @property def type(self): From f0ad108e2cf3e8c755dd28334c4496385fe9d624 Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Thu, 27 Sep 2012 16:30:14 +0100 Subject: [PATCH 057/516] Fix some stuff support casting int <-> pointers in llvm_cbuilder assign ndarray type to fake PyArrays --- builder.py | 5 +++++ shortnames.py | 1 + 2 files changed, 6 insertions(+) diff --git a/builder.py b/builder.py index 2826e1d..4a6f23b 100644 --- a/builder.py +++ b/builder.py @@ -1057,6 +1057,11 @@ class IntegerValue(OperatorMixin): return self._temp(self.parent.builder.sext(self.value, ty)) else: return self._temp(self.parent.builder.trunc(self.value, ty)) + elif _is_pointer(ty) and _is_int(self.type): + return self._temp(self.parent.builder.inttoptr(self.value, ty)) + elif _is_int(ty) and _is_pointer(self.type): + return self._temp(self.parent.builder.ptrtoint(self.value, ty)) + raise CastError(self.type, ty) class RealValue(OperatorMixin): diff --git a/shortnames.py b/shortnames.py index 06221aa..2acd69d 100644 --- a/shortnames.py +++ b/shortnames.py @@ -14,6 +14,7 @@ float = Type.float() double = Type.double() npy_intp = minitypes.npy_intp.to_llvm(numba.decorators.context) +py_ssize_t = minitypes.Py_ssize_t.to_llvm(numba.decorators.context) # pointers From cdd26cde580b166acb355b50e968222397812516 Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Wed, 3 Oct 2012 21:42:11 -0500 Subject: [PATCH 058/516] New version number and update README --- README.rst | 2 +- llvm/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index ae8eaa1..e8a5ffc 100644 --- a/README.rst +++ b/README.rst @@ -10,7 +10,7 @@ http://www.llvmpy.org Versions -------- -This package has only been tested with LLVM 3.1, and Python 2.7, (not Python 3.x). +This package has only been tested with LLVM 3.1, and Python 2.7, but it should work with Python 3.x Quickstart ---------- diff --git a/llvm/__init__.py b/llvm/__init__.py index d7461ce..15720f3 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -2,7 +2,7 @@ Common classes related to LLVM. """ -__version__ = '0.8.3' +__version__ = '0.8.4' from weakref import WeakValueDictionary From e42dfd9abb84c88ce722567dc99ed907a46016a4 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 4 Oct 2012 12:59:48 -0500 Subject: [PATCH 059/516] Improve PTX support discovery and make it optional. --- setup.py | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/setup.py b/setup.py index 52029a8..89c9df6 100644 --- a/setup.py +++ b/setup.py @@ -34,6 +34,8 @@ def get_libs_and_objs(components): objs.append(part) return libs, objs +def get_enabled_components(): + return run_llvm_config(['--components']).split() def get_llvm_version(): # get version number; treat it as fixed point @@ -66,32 +68,34 @@ if dynlink: libs_core = ['LLVM-%d.%d' % llvm_version] objs_core = [] else: - if sys.platform == 'win32': - # XXX: If found, the PTX components are returned by llvm-config-win32.py, - # regardless of whether we ask for them. There should be a better way - # eventually. - print('PTX is included on Win32 at if found by llvm-config-win32.py') - ptx_components = [] - elif llvm_version <= (3, 1): # select between PTX & NVPTX - print('Using PTX') - ptx_components = ['ptx', + enabled_components = set(get_enabled_components()) + ptx_components = set(['ptx', 'ptxasmprinter', 'ptxcodegen', 'ptxdesc', - 'ptxinfo'] + 'ptxinfo']) + nvptx_components = set(['nvptx', + 'nvptxasmprinter', + 'nvptxcodegen', + 'nvptxdesc', + 'nvptxinfo']) + + extra_components = [] + if (nvptx_components & enabled_components) == nvptx_components: + print("Using NVPTX") + extra_components.extend(nvptx_components) + elif (ptx_components & enabled_components) == ptx_components: + print("Using PTX") + extra_components.extend(ptx_components) else: - print('Using NVPTX') - ptx_components = ['nvptx', - 'nvptxasmprinter', - 'nvptxcodegen', - 'nvptxdesc', - 'nvptxinfo'] + print("No CUDA support") + libs_core, objs_core = get_libs_and_objs( ['core', 'analysis', 'scalaropts', 'executionengine', 'jit', 'native', 'interpreter', 'bitreader', 'bitwriter', 'instrumentation', 'ipa', 'ipo', 'transformutils', 'asmparser', 'linker', 'support', 'vectorize'] - + ptx_components) + + extra_components) macros = [('__STDC_CONSTANT_MACROS', None), ('__STDC_LIMIT_MACROS', None)] From bba30621f1e4535fe5030a3f841d347e733607a7 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 10 Oct 2012 10:47:56 -0500 Subject: [PATCH 060/516] Allow to_native_object & to_native_assembly to receive an optional fileobj to write to. --- llvm/core.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index da260a3..6ef2fad 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -544,15 +544,29 @@ class Module(llvm.Ownable, llvm.Cacheable): id = property(_get_id, _set_id) - def to_native_object(self): - '''returns byte string of the module as native object code - ''' - return _core.LLVMGetNativeCodeFromModule(self.ptr, 0) + def to_native_object(self, fileobj=None): + '''Outputs the byte string of the module as native object code - def to_native_assembly(self): - '''returns byte string of the module as native assembly code + If a fileobj is given, the output is written to it; + Otherwise, the output is returned ''' - return _core.LLVMGetNativeCodeFromModule(self.ptr, 1) + data = _core.LLVMGetNativeCodeFromModule(self.ptr, 0) + if fileobj is not None: + fileobj.write(data) + else: + return data + + def to_native_assembly(self, fileobj=None): + '''Outputs the byte string of the module as native assembly code + + If a fileobj is given, the output is written to it; + Otherwise, the output is returned + ''' + data = _core.LLVMGetNativeCodeFromModule(self.ptr, 1) + if fileobj is not None: + fileobj.write(data) + else: + return data #===----------------------------------------------------------------------=== # Types From 1c15a9784bcc8cddb625c09653533f0f30c4a326 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sun, 30 Sep 2012 14:40:32 +0100 Subject: [PATCH 061/516] Fix minor problems under Python 3 from running the tests --- llvm/core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index 6ef2fad..6b1b0aa 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -351,7 +351,7 @@ class Module(llvm.Ownable, llvm.Cacheable): a module represented in bitcode. """ - if isinstance(fileobj_or_str, basestring): + if _util.isstring(fileobj_or_str): data = fileobj_or_str else: data = fileobj_or_str.read() @@ -373,7 +373,7 @@ class Module(llvm.Ownable, llvm.Cacheable): a module represented in llvm-ir assembly. """ - if isinstance(fileobj_or_str, basestring): + if _util.isstring(fileobj_or_str): data = fileobj_or_str else: data = fileobj_or_str.read() From aba3e208d29eb85ed60330befa9ea363d75834a7 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sun, 30 Sep 2012 15:07:51 +0100 Subject: [PATCH 062/516] Improve bytes/unicode distinction for reading modules from bitcode & assembly --- llvm/_core.cpp | 4 ++++ llvm/_util.py | 5 +++++ llvm/core.py | 10 ++++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index b8899ef..1ec86aa 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -163,7 +163,11 @@ _wLLVMGetModuleFromAssembly(PyObject *self, PyObject *args) { LLVMPY_TRY const char * str; +#if (PY_MAJOR_VERSION >= 3) + if ( !PyArg_ParseTuple(args, "y", &str) ){ +#else if ( !PyArg_ParseTuple(args, "s", &str) ){ +#endif return NULL; } diff --git a/llvm/_util.py b/llvm/_util.py index 8f06122..da003b0 100644 --- a/llvm/_util.py +++ b/llvm/_util.py @@ -101,3 +101,8 @@ def _isstring_choose(): isstring = _isstring_choose() +try: + unicode_type = unicode +except NameError: # Py3 + unicode_type = str + diff --git a/llvm/core.py b/llvm/core.py index 6b1b0aa..2de3615 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -351,7 +351,9 @@ class Module(llvm.Ownable, llvm.Cacheable): a module represented in bitcode. """ - if _util.isstring(fileobj_or_str): + if isinstance(fileobj_or_str, _util.unicode_type): + data = fileobj_or_str.encode('utf-8') + elif isinstance(fileobj_or_str, bytes): data = fileobj_or_str else: data = fileobj_or_str.read() @@ -373,10 +375,14 @@ class Module(llvm.Ownable, llvm.Cacheable): a module represented in llvm-ir assembly. """ - if _util.isstring(fileobj_or_str): + if isinstance(fileobj_or_str, _util.unicode_type): + data = fileobj_or_str.encode('utf-8') + elif isinstance(fileobj_or_str, bytes): data = fileobj_or_str else: data = fileobj_or_str.read() + if isinstance(data, _util.unicode_type): + data = data.encode() ret = _core.LLVMGetModuleFromAssembly(data) if not ret: raise llvm.LLVMException("Unable to create module from assembly") From 87ffb437d852fbb720a41563febb779c90b7da25 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sun, 30 Sep 2012 15:08:20 +0100 Subject: [PATCH 063/516] Fix a couple of tests for Python 3 --- test/metadata.py | 8 +++++--- test/testall.py | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/test/metadata.py b/test/metadata.py index 4d877ed..90b6ae8 100644 --- a/test/metadata.py +++ b/test/metadata.py @@ -1,3 +1,5 @@ +from __future__ import print_function + import unittest from llvm.core import * @@ -47,7 +49,7 @@ class TestMetaData(unittest.TestCase): ops = [MetaDataString.get(mod, "int"), root] md1 = MetaData.get(mod, ops) MetaData.add_named_operand(mod, 'tbaa', md1) - print md1 + print(md1) ops = [MetaDataString.get(mod, "const float"), root, @@ -55,9 +57,9 @@ class TestMetaData(unittest.TestCase): md2 = MetaData.get(mod, ops) MetaData.add_named_operand(mod, 'tbaa', md2) - print md2 + print(md2) - print mod + print(mod) if __name__ == '__main__': diff --git a/test/testall.py b/test/testall.py index ed7a8a1..3b5f0c3 100644 --- a/test/testall.py +++ b/test/testall.py @@ -79,9 +79,11 @@ def do_module(): class strstream(object): def __init__(self): - self.s = '' + self.s = b'' def write(self, data): + if not isinstance(data, bytes): + data = data.encode('utf-8') self.s += data def read(self): From d1fefe5a6929c14fc289046caa31378cb491c4e8 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 10 Oct 2012 10:58:02 -0500 Subject: [PATCH 064/516] Fix doc about Python3.2 testing --- README.rst | 4 ++-- docs/source/doc/getting_started.rst | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index e8a5ffc..4bda151 100644 --- a/README.rst +++ b/README.rst @@ -10,7 +10,7 @@ http://www.llvmpy.org Versions -------- -This package has only been tested with LLVM 3.1, and Python 2.7, but it should work with Python 3.x +This package has only been tested with LLVM 3.1, and Python 2.7 and Python 3.2. Quickstart ---------- @@ -28,7 +28,7 @@ Quickstart $ python -c "import llvm; llvm.test()" -3. See documentation at 'http://www.llvmpy.org/pages.html' and examples +3. See documentation at 'http://www.llvmpy.org' and examples under 'test'. LICENSE diff --git a/docs/source/doc/getting_started.rst b/docs/source/doc/getting_started.rst index 47e465a..36a408a 100644 --- a/docs/source/doc/getting_started.rst +++ b/docs/source/doc/getting_started.rst @@ -41,9 +41,8 @@ Versions llvmpy 0.8.2 requires version 3.1 of LLVM. It may not work with previous versions. -llvmpy has been built and tested with Python 2.7. It should work with -earlier versions. It has not been tried with Python 3.x (patches -welcome). +llvmpy has been built and tested with Python 2.7 and 3.2. It should work with +earlier versions. Installation From 6d8fbafb54f802c6fcba2b3ea539ac482c4b98b8 Mon Sep 17 00:00:00 2001 From: Jon Riehl Date: Thu, 11 Oct 2012 15:46:56 -0500 Subject: [PATCH 065/516] Moved llnumba out of sandbox. --- __init__.py | 0 byte_control.py | 98 +++++++ byte_flow.py | 218 ++++++++++++++++ byte_translator.py | 525 +++++++++++++++++++++++++++++++++++++ bytecode_visitor.py | 566 ++++++++++++++++++++++++++++++++++++++++ bytetype.py | 41 +++ control_flow.py | 218 ++++++++++++++++ gen_bytecode_visitor.py | 27 ++ nobitey.py | 366 ++++++++++++++++++++++++++ opcode_util.py | 215 +++++++++++++++ phi_injector.py | 131 ++++++++++ pyaddfunc.py | 41 +++ tests/__init__.py | 0 tests/llfuncs.py | 42 +++ tests/llfunctys.py | 23 ++ 15 files changed, 2511 insertions(+) create mode 100644 __init__.py create mode 100644 byte_control.py create mode 100644 byte_flow.py create mode 100644 byte_translator.py create mode 100644 bytecode_visitor.py create mode 100644 bytetype.py create mode 100644 control_flow.py create mode 100644 gen_bytecode_visitor.py create mode 100644 nobitey.py create mode 100644 opcode_util.py create mode 100644 phi_injector.py create mode 100644 pyaddfunc.py create mode 100644 tests/__init__.py create mode 100644 tests/llfuncs.py create mode 100644 tests/llfunctys.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/byte_control.py b/byte_control.py new file mode 100644 index 0000000..8180cf2 --- /dev/null +++ b/byte_control.py @@ -0,0 +1,98 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +import opcode +import opcode_util +import pprint + +from bytecode_visitor import BytecodeFlowVisitor, BenignBytecodeVisitorMixin +from control_flow import ControlFlowGraph + +# ______________________________________________________________________ + +class ControlFlowBuilder (BenignBytecodeVisitorMixin, BytecodeFlowVisitor): + def visit (self, flow, nargs = 0, *args, **kws): + self.nargs = nargs + ret_val = super(ControlFlowBuilder, self).visit(flow, *args, **kws) + del self.nargs + return ret_val + + def enter_flow_object (self, flow): + super(ControlFlowBuilder, self).enter_flow_object(flow) + self.flow = flow + self.cfg = ControlFlowGraph() + for block in flow.keys(): + self.cfg.add_block(block, flow[block]) + + def exit_flow_object (self, flow): + super(ControlFlowBuilder, self).exit_flow_object(flow) + assert self.flow == flow + self.cfg.compute_dataflow() + self.cfg.update_for_ssa() + ret_val = self.cfg + del self.cfg + del self.flow + return ret_val + + def enter_block (self, block): + self.block = block + assert block in self.cfg.blocks + if block == 0: + for local_index in range(self.nargs): + self.op_STORE_FAST(0, opcode.opmap['STORE_FAST'], local_index) + return True + + def _get_next_block (self, block): + return self.block_list[self.block_list.index(block) + 1] + + def exit_block (self, block): + assert block == self.block + del self.block + i, op, opname, arg, args = self.flow[block][-1] + if op in opcode.hasjabs: + self.cfg.add_edge(block, arg) + elif op in opcode.hasjrel: + self.cfg.add_edge(block, i + arg + 3) + elif opname == 'BREAK_LOOP': + self.cfg.add_edge(block, arg) + elif opname != 'RETURN_VALUE': + self.cfg.add_edge(block, self._get_next_block(block)) + if op in opcode_util.hascbranch: + self.cfg.add_edge(block, self._get_next_block(block)) + + def op_LOAD_FAST (self, i, op, arg, *args, **kws): + self.cfg.blocks_reads[self.block].add(arg) + return super(ControlFlowBuilder, self).op_LOAD_FAST(i, op, arg, *args, + **kws) + + def op_STORE_FAST (self, i, op, arg, *args, **kws): + self.cfg.writes_local(self.block, i, arg) + return super(ControlFlowBuilder, self).op_STORE_FAST(i, op, arg, *args, + **kws) + +# ______________________________________________________________________ + +def build_cfg (func): + import byte_flow + return ControlFlowBuilder().visit( + byte_flow.build_flow(func), + opcode_util.get_code_object(func).co_argcount) + +# ______________________________________________________________________ +# Main (self-test) routine + +def main (*args, **kws): + from tests import llfuncs + if not args: + args = ('doslice',) + for arg in args: + build_cfg(getattr(llfuncs, arg)).pprint() + +# ______________________________________________________________________ + +if __name__ == "__main__": + import sys + main(*sys.argv[1:]) + +# ______________________________________________________________________ +# End of byte_control.py diff --git a/byte_flow.py b/byte_flow.py new file mode 100644 index 0000000..6951b26 --- /dev/null +++ b/byte_flow.py @@ -0,0 +1,218 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +import dis +import opcode + +from bytecode_visitor import BytecodeIterVisitor +import opcode_util + +# ______________________________________________________________________ + +class BytecodeFlowBuilder (BytecodeIterVisitor): + def __init__ (self, *args, **kws): + super(BytecodeFlowBuilder, self).__init__(*args, **kws) + om_items = opcode_util.OPCODE_MAP.items() + self.opmap = dict((opcode.opmap[opname], (opname, pops, pushes, stmt)) + for opname, (pops, pushes, stmt) in om_items + if opname in opcode.opmap) + + def _visit_op (self, i, op, arg, opname, pops, pushes, appends): + assert pops is not None + if pops: + if pops < 0: + pops = arg - pops - 1 + stk_args = self.stack[-pops:] + del self.stack[-pops:] + else: + stk_args = [] + ret_val = (i, op, opname, arg, stk_args) + if pushes: + self.stack.append(ret_val) + if appends: + self.block.append(ret_val) + return ret_val + + def _op (self, i, op, arg): + opname, pops, pushes, appends = self.opmap[op] + return self._visit_op(i, op, arg, opname, pops, pushes, appends) + + def enter_code_object (self, co_obj): + labels = dis.findlabels(co_obj.co_code) + labels = opcode_util.extendlabels(co_obj.co_code, labels) + self.blocks = dict((index, []) + for index in labels) + self.stack = [] + self.loop_stack = [] + self.blocks[0] = self.block = [] + + def exit_code_object (self, co_obj): + ret_val = self.blocks + del self.stack + del self.loop_stack + del self.block + del self.blocks + return ret_val + + def visit_op (self, i, op, arg): + if i in self.blocks: + self.block = self.blocks[i] + return super(BytecodeFlowBuilder, self).visit_op(i, op, arg) + + op_BINARY_ADD = _op + op_BINARY_AND = _op + op_BINARY_DIVIDE = _op + op_BINARY_FLOOR_DIVIDE = _op + op_BINARY_LSHIFT = _op + op_BINARY_MODULO = _op + op_BINARY_MULTIPLY = _op + op_BINARY_OR = _op + op_BINARY_POWER = _op + op_BINARY_RSHIFT = _op + op_BINARY_SUBSCR = _op + op_BINARY_SUBTRACT = _op + op_BINARY_TRUE_DIVIDE = _op + op_BINARY_XOR = _op + + def op_BREAK_LOOP (self, i, op, arg): + loop_i, _, loop_arg = self.loop_stack[-1] + assert arg is None + return self._op(i, op, loop_i + loop_arg + 3) + + #op_BUILD_CLASS = _op + op_BUILD_LIST = _op + op_BUILD_MAP = _op + op_BUILD_SLICE = _op + op_BUILD_TUPLE = _op + op_CALL_FUNCTION = _op + op_CALL_FUNCTION_KW = _op + op_CALL_FUNCTION_VAR = _op + op_CALL_FUNCTION_VAR_KW = _op + op_COMPARE_OP = _op + #op_CONTINUE_LOOP = _op + op_DELETE_ATTR = _op + op_DELETE_FAST = _op + op_DELETE_GLOBAL = _op + op_DELETE_NAME = _op + op_DELETE_SLICE = _op + op_DELETE_SUBSCR = _op + + def op_DUP_TOP (self, i, op, arg): + self.stack.append(self.stack[-1]) + + def op_DUP_TOPX (self, i, op, arg): + self.stack += self.stack[-arg:] + + #op_END_FINALLY = _op + op_EXEC_STMT = _op + #op_EXTENDED_ARG = _op + op_FOR_ITER = _op + op_GET_ITER = _op + op_IMPORT_FROM = _op + op_IMPORT_NAME = _op + op_IMPORT_STAR = _op + op_INPLACE_ADD = _op + op_INPLACE_AND = _op + op_INPLACE_DIVIDE = _op + op_INPLACE_FLOOR_DIVIDE = _op + op_INPLACE_LSHIFT = _op + op_INPLACE_MODULO = _op + op_INPLACE_MULTIPLY = _op + op_INPLACE_OR = _op + op_INPLACE_POWER = _op + op_INPLACE_RSHIFT = _op + op_INPLACE_SUBTRACT = _op + op_INPLACE_TRUE_DIVIDE = _op + op_INPLACE_XOR = _op + op_JUMP_ABSOLUTE = _op + op_JUMP_FORWARD = _op + op_JUMP_IF_FALSE = _op + op_JUMP_IF_TRUE = _op + op_LIST_APPEND = _op + op_LOAD_ATTR = _op + op_LOAD_CLOSURE = _op + op_LOAD_CONST = _op + op_LOAD_DEREF = _op + op_LOAD_FAST = _op + op_LOAD_GLOBAL = _op + op_LOAD_LOCALS = _op + op_LOAD_NAME = _op + op_MAKE_CLOSURE = _op + op_MAKE_FUNCTION = _op + op_NOP = _op + + def op_POP_BLOCK (self, i, op, arg): + self.loop_stack.pop() + return self._op(i, op, arg) + + op_POP_JUMP_IF_FALSE = _op + op_POP_JUMP_IF_TRUE = _op + op_POP_TOP = _op + op_PRINT_EXPR = _op + op_PRINT_ITEM = _op + op_PRINT_ITEM_TO = _op + op_PRINT_NEWLINE = _op + op_PRINT_NEWLINE_TO = _op + op_RAISE_VARARGS = _op + op_RETURN_VALUE = _op + + def op_ROT_FOUR (self, i, op, arg): + self.stack[-4:] = (self.stack[-1], self.stack[-4], self.stack[-3], + self.stack[-2]) + + def op_ROT_THREE (self, i, op, arg): + self.stack[-3:] = (self.stack[-1], self.stack[-3], self.stack[-2]) + + def op_ROT_TWO (self, i, op, arg): + self.stack[-2:] = (self.stack[-1], self.stack[-2]) + + #op_SETUP_EXCEPT = _op + #op_SETUP_FINALLY = _op + + def op_SETUP_LOOP (self, i, op, arg): + self.loop_stack.append((i, op, arg)) + self.block.append((i, op, self.opnames[op], arg, [])) + + op_SLICE = _op + #op_STOP_CODE = _op + op_STORE_ATTR = _op + op_STORE_DEREF = _op + op_STORE_FAST = _op + op_STORE_GLOBAL = _op + op_STORE_MAP = _op + op_STORE_NAME = _op + op_STORE_SLICE = _op + op_STORE_SUBSCR = _op + op_UNARY_CONVERT = _op + op_UNARY_INVERT = _op + op_UNARY_NEGATIVE = _op + op_UNARY_NOT = _op + op_UNARY_POSITIVE = _op + op_UNPACK_SEQUENCE = _op + #op_WITH_CLEANUP = _op + op_YIELD_VALUE = _op + +# ______________________________________________________________________ + +def build_flow (func): + return BytecodeFlowBuilder().visit(opcode_util.get_code_object(func)) + +# ______________________________________________________________________ +# Main (self-test) routine + +def main (*args): + import pprint + from tests import llfuncs + if not args: + args = ('doslice',) + for arg in args: + pprint.pprint(build_flow(getattr(llfuncs, arg))) + +# ______________________________________________________________________ + +if __name__ == '__main__': + import sys + main(*sys.argv[1:]) + +# ______________________________________________________________________ +# End of byte_flow.py diff --git a/byte_translator.py b/byte_translator.py new file mode 100644 index 0000000..7954970 --- /dev/null +++ b/byte_translator.py @@ -0,0 +1,525 @@ +#! /usr/bin/env python +# ______________________________________________________________________ +# Module imports + +import opcode + +import llvm.core as lc + +import opcode_util + +import bytetype +from bytecode_visitor import BytecodeFlowVisitor +from byte_flow import BytecodeFlowBuilder +from byte_control import ControlFlowBuilder +from phi_injector import PhiInjector, synthetic_opname + +# ______________________________________________________________________ +# Module data + +# XXX Stolen from numba.translate: + +_compare_mapping_float = {'>':lc.FCMP_OGT, + '<':lc.FCMP_OLT, + '==':lc.FCMP_OEQ, + '>=':lc.FCMP_OGE, + '<=':lc.FCMP_OLE, + '!=':lc.FCMP_ONE} + +_compare_mapping_sint = {'>':lc.ICMP_SGT, + '<':lc.ICMP_SLT, + '==':lc.ICMP_EQ, + '>=':lc.ICMP_SGE, + '<=':lc.ICMP_SLE, + '!=':lc.ICMP_NE} + +# XXX Stolen from numba.llvm_types: + +class LLVMCaster (object): + def build_pointer_cast(_, builder, lval1, lty2): + return builder.bitcast(lval1, lty2) + + def build_int_cast(_, builder, lval1, lty2, unsigned = False): + width1 = lval1.type.width + width2 = lty2.width + ret_val = lval1 + if width2 > width1: + if unsigned: + ret_val = builder.zext(lval1, lty2) + else: + ret_val = builder.sext(lval1, lty2) + elif width2 < width1: + ret_val = builder.trunc(lval1, lty2) + return ret_val + + def build_float_ext(_, builder, lval1, lty2): + return builder.fpext(lval1, lty2) + + def build_float_trunc(_, builder, lval1, lty2): + return builder.fptrunc(lval1, lty2) + + def build_int_to_float_cast(_, builder, lval1, lty2, unsigned = False): + ret_val = None + if unsigned: + ret_val = builder.uitofp(lval1, lty2) + else: + ret_val = builder.sitofp(lval1, lty2) + return ret_val + + def build_float_to_int_cast(_, builder, lval1, lty2, unsigned = False): + ret_val = None + if unsigned: + ret_val = builder.fptoui(lval1, lty2) + else: + ret_val = builder.fptosi(lval1, lty2) + return ret_val + + CAST_MAP = { + lc.TYPE_POINTER : build_pointer_cast, + lc.TYPE_INTEGER: build_int_cast, + (lc.TYPE_FLOAT, lc.TYPE_DOUBLE) : build_float_ext, + (lc.TYPE_DOUBLE, lc.TYPE_FLOAT) : build_float_trunc, + (lc.TYPE_INTEGER, lc.TYPE_FLOAT) : build_int_to_float_cast, + (lc.TYPE_INTEGER, lc.TYPE_DOUBLE) : build_int_to_float_cast, + (lc.TYPE_FLOAT, lc.TYPE_INTEGER) : build_float_to_int_cast, + (lc.TYPE_DOUBLE, lc.TYPE_INTEGER) : build_float_to_int_cast, + + } + + @classmethod + def build_cast(cls, builder, lval1, lty2, *args, **kws): + ret_val = lval1 + lty1 = lval1.type + lkind1 = lty1.kind + lkind2 = lty2.kind + + if lkind1 == lkind2: + + if lkind1 in cls.CAST_MAP: + ret_val = cls.CAST_MAP[lkind1](cls, builder, lval1, lty2, + *args, **kws) + else: + raise NotImplementedError(lkind1) + else: + map_index = (lkind1, lkind2) + if map_index in cls.CAST_MAP: + ret_val = cls.CAST_MAP[map_index](cls, builder, lval1, lty2, + *args, **kws) + else: + raise NotImplementedError(lkind1, lkind2) + return ret_val + +# ______________________________________________________________________ +# Class definitions + +class LLVMTranslator (BytecodeFlowVisitor): + def __init__ (self, llvm_module = None, *args, **kws): + super(LLVMTranslator, self).__init__(*args, **kws) + if llvm_module is None: + llvm_module = lc.Module.new('Translated_Module_%d' % (id(self),)) + self.llvm_module = llvm_module + self.bytecode_flow_builder = BytecodeFlowBuilder() + self.control_flow_builder = ControlFlowBuilder() + self.phi_injector = PhiInjector() + + def translate (self, function, llvm_type = None, env = None): + if llvm_type is None: + llvm_type = lc.Type.function(lvoid, ()) + if env is None: + env = {} + else: + env = env.copy() + env.update((name, method) + for name, method in lc.Builder.__dict__.items() + if not name.startswith('_')) + env.update((name, value) + for name, value in bytetype.__dict__.items() + if not name.startswith('_')) + self.loop_stack = [] + self.llvm_type = llvm_type + self.function = function + self.code_obj = opcode_util.get_code_object(function) + func_globals = getattr(function, 'func_globals', + getattr(function, '__globals__', {})).copy() + func_globals.update(env) + self.globals = func_globals + nargs = self.code_obj.co_argcount + self.cfg = self.control_flow_builder.visit( + self.bytecode_flow_builder.visit(self.code_obj), nargs) + flow = self.phi_injector.visit_cfg(self.cfg, nargs) + ret_val = self.visit(flow) + del self.cfg + del self.globals + del self.code_obj + del self.function + del self.llvm_type + del self.loop_stack + return ret_val + + def enter_flow_object (self, flow): + super(LLVMTranslator, self).enter_flow_object(flow) + self.llvm_function = self.llvm_module.add_function( + self.llvm_type, self.function.__name__) + self.llvm_blocks = {} + self.llvm_definitions = {} + self.pending_phis = {} + for block in self.block_list: + if 0 in self.cfg.blocks_reaching[block]: + bb = self.llvm_function.append_basic_block( + 'BLOCK_%d' % (block,)) + self.llvm_blocks[block] = bb + + def exit_flow_object (self, flow): + super(LLVMTranslator, self).exit_flow_object(flow) + ret_val = self.llvm_function + del self.pending_phis + del self.llvm_definitions + del self.llvm_blocks + del self.llvm_function + return ret_val + + def enter_block (self, block): + ret_val = False + if block in self.llvm_blocks: + self.llvm_block = self.llvm_blocks[block] + self.builder = lc.Builder.new(self.llvm_block) + ret_val = True + return ret_val + + def exit_block (self, block): + del self.llvm_block + del self.builder + + def visit_synthetic_op (self, i, op, arg, *args, **kws): + method = getattr(self, 'op_%s' % (synthetic_opname[op],)) + return method(i, op, arg, *args, **kws) + + def op_REF_ARG (self, i, op, arg, *args, **kws): + return [self.llvm_function.args[arg]] + + def op_BUILD_PHI (self, i, op, arg, *args, **kws): + phi_type = None + incoming = [] + pending = [] + for child_arg in arg: + child_block, _, child_opname, child_arg, _ = child_arg + assert child_opname == 'REF_DEF' + if child_arg in self.llvm_definitions: + child_def = self.llvm_definitions[child_arg] + if phi_type is None: + phi_type = child_def.type + incoming.append((child_block, child_def)) + else: + pending.append((child_arg, child_block)) + phi = self.builder.phi(phi_type) + for block_index, defn in incoming: + phi.add_incoming(defn, self.llvm_blocks[block_index]) + for defn_index, block_index in pending: + if defn_index not in self.pending_phis: + self.pending_phis[defn_index] = [] + self.pending_phis[defn_index].append((phi, block_index)) + return [phi] + + def op_DEFINITION (self, i, op, def_index, *args, **kws): + assert len(args) == 1 + arg = args[0] + if def_index in self.pending_phis: + for phi, block_index in self.pending_phis[def_index]: + phi.add_incoming(arg, self.llvm_blocks[block_index]) + self.llvm_definitions[def_index] = arg + return args + + def op_REF_DEF (self, i, op, arg, *args, **kws): + return [self.llvm_definitions[arg]] + + def op_BINARY_ADD (self, i, op, arg, *args, **kws): + arg1, arg2 = args + if arg1.type.kind == lc.TYPE_INTEGER: + ret_val = [self.builder.add(arg1, arg2)] + elif arg1.type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE): + ret_val = [self.builder.fadd(arg1, arg2)] + elif arg1.type.kind == lc.TYPE_POINTER: + ret_val = [self.builder.gep(arg1, [arg2])] + else: + raise NotImplementedError("LLVMTranslator.op_BINARY_ADD for %r" % + (args,)) + return ret_val + + def op_BINARY_AND (self, i, op, arg, *args, **kws): + return [self.builder.and_(args[0], args[1])] + + def op_BINARY_DIVIDE (self, i, op, arg, *args, **kws): + arg1, arg2 = args + if arg1.type.kind == lc.TYPE_INTEGER: + ret_val = [self.builder.sdiv(arg1, arg2)] + elif arg1.type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE): + ret_val = [self.builder.fdiv(arg1, arg2)] + else: + raise NotImplementedError("LLVMTranslator.op_BINARY_DIVIDE for %r" + % (args,)) + return ret_val + + def op_BINARY_FLOOR_DIVIDE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_BINARY_FLOOR_DIVIDE") + + def op_BINARY_LSHIFT (self, i, op, arg, *args, **kws): + return [self.builder.shl(args[0], args[1])] + + def op_BINARY_MODULO (self, i, op, arg, *args, **kws): + arg1, arg2 = args + if arg1.type.kind == lc.TYPE_INTEGER: + ret_val = [self.builder.srem(arg1, arg2)] + elif arg1.type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE): + ret_val = [self.builder.frem(arg1, arg2)] + else: + raise NotImplementedError("LLVMTranslator.op_BINARY_MODULO for %r" + % (args,)) + return ret_val + + def op_BINARY_MULTIPLY (self, i, op, arg, *args, **kws): + arg1, arg2 = args + if arg1.type.kind == lc.TYPE_INTEGER: + ret_val = [self.builder.mul(arg1, arg2)] + elif arg1.type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE): + ret_val = [self.builder.fmul(arg1, arg2)] + else: + raise NotImplementedError("LLVMTranslator.op_BINARY_MULTIPLY for " + "%r" % (args,)) + return ret_val + + def op_BINARY_OR (self, i, op, arg, *args, **kws): + return [self.builder.or_(args[0], args[1])] + + def op_BINARY_POWER (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_BINARY_POWER") + + def op_BINARY_RSHIFT (self, i, op, arg, *args, **kws): + return [self.builder.lshr(args[0], args[1])] + + def op_BINARY_SUBSCR (self, i, op, arg, *args, **kws): + arr_val = args[0] + index_vals = args[1:] + ret_val = gep_result = self.builder.gep(arr_val, index_vals) + if (gep_result.type.kind == lc.TYPE_POINTER and + gep_result.type.pointee.kind != lc.TYPE_POINTER): + ret_val = self.builder.load(gep_result) + return [ret_val] + + def op_BINARY_SUBTRACT (self, i, op, arg, *args, **kws): + arg1, arg2 = args + if arg1.type.kind == lc.TYPE_INTEGER: + ret_val = [self.builder.sub(arg1, arg2)] + elif arg1.type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE): + ret_val = [self.builder.fsub(arg1, arg2)] + else: + raise NotImplementedError("LLVMTranslator.op_BINARY_SUBTRACT for " + "%r" % (args,)) + return ret_val + + op_BINARY_TRUE_DIVIDE = op_BINARY_DIVIDE + + def op_BINARY_XOR (self, i, op, arg, *args, **kws): + return [self.builder.xor(args[0], args[1])] + + def op_BREAK_LOOP (self, i, op, arg, *args, **kws): + return [self.builder.branch(self.llvm_blocks[arg])] + + def op_BUILD_SLICE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_BUILD_SLICE") + + def op_BUILD_TUPLE (self, i, op, arg, *args, **kws): + return args + + def op_CALL_FUNCTION (self, i, op, arg, *args, **kws): + fn = args[0] + args = args[1:] + if isinstance(fn, lc.Type): + if isinstance(fn, lc.FunctionType): + ret_val = [self.builder.call( + self.llvm_module.get_or_insert_function(fn, fn.__name__), + args)] + else: + assert len(args) == 1 + ret_val = [LLVMCaster.build_cast(self.builder, args[0], fn)] + elif fn.__name__ in lc.Builder.__dict__: + ret_val = [fn(self.builder, *args)] + else: + raise NotImplementedError("Don't know how to call %r!" % (fn,)) + return ret_val + + def op_CALL_FUNCTION_KW (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_CALL_FUNCTION_KW") + + def op_CALL_FUNCTION_VAR (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_CALL_FUNCTION_VAR") + + def op_CALL_FUNCTION_VAR_KW (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_CALL_FUNCTION_VAR_KW") + + def op_COMPARE_OP (self, i, op, arg, *args, **kws): + arg1, arg2 = args + cmp_kind = opcode.cmp_op[arg] + if isinstance(arg1.type, lc.IntegerType): + ret_val = [self.builder.icmp(_compare_mapping_sint[cmp_kind], + arg1, arg2)] + elif arg1.type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE): + ret_val = [self.builder.fcmp(_compare_mapping_float[cmp_kind], + arg1, arg2)] + else: + raise NotImplementedError('Comparison of type %r' % (arg1.type,)) + return ret_val + + def op_CONTINUE_LOOP (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_CONTINUE_LOOP") + + def op_DELETE_ATTR (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_DELETE_ATTR") + + def op_DELETE_SLICE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_DELETE_SLICE") + + def op_FOR_ITER (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_FOR_ITER") + + def op_GET_ITER (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_GET_ITER") + + op_INPLACE_ADD = op_BINARY_ADD + op_INPLACE_AND = op_BINARY_AND + op_INPLACE_DIVIDE = op_BINARY_DIVIDE + op_INPLACE_FLOOR_DIVIDE = op_BINARY_FLOOR_DIVIDE + op_INPLACE_LSHIFT = op_BINARY_LSHIFT + op_INPLACE_MODULO = op_BINARY_MODULO + op_INPLACE_MULTIPLY = op_BINARY_MULTIPLY + op_INPLACE_OR = op_BINARY_OR + op_INPLACE_POWER = op_BINARY_POWER + op_INPLACE_RSHIFT = op_BINARY_RSHIFT + op_INPLACE_SUBTRACT = op_BINARY_SUBTRACT + op_INPLACE_TRUE_DIVIDE = op_BINARY_TRUE_DIVIDE + op_INPLACE_XOR = op_BINARY_XOR + + def op_JUMP_ABSOLUTE (self, i, op, arg, *args, **kws): + return [self.builder.branch(self.llvm_blocks[arg])] + + def op_JUMP_FORWARD (self, i, op, arg, *args, **kws): + return [self.builder.branch(self.llvm_blocks[i + arg + 3])] + + def op_JUMP_IF_FALSE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_JUMP_IF_FALSE") + + def op_JUMP_IF_FALSE_OR_POP (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_JUMP_IF_FALSE_OR_POP") + + def op_JUMP_IF_TRUE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_JUMP_IF_TRUE") + + def op_JUMP_IF_TRUE_OR_POP (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_JUMP_IF_TRUE_OR_POP") + + def op_LOAD_ATTR (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_LOAD_ATTR") + + def op_LOAD_CONST (self, i, op, arg, *args, **kws): + py_val = self.code_obj.co_consts[arg] + if isinstance(py_val, int): + ret_val = [lc.Constant.int(bytetype.lc_int, py_val)] + elif isinstance(py_val, float): + ret_val = [lc.Constant.double(py_val)] + elif py_val == None: + ret_val = [None] + else: + raise NotImplementedError('Constant converstion for %r' % + (py_val,)) + return ret_val + + def op_LOAD_GLOBAL (self, i, op, arg, *args, **kws): + ret_val = self.globals[self.code_obj.co_names[arg]] + if not hasattr(ret_val, '__name__'): + ret_val.__name__ = self.code_obj.co_names[arg] + return [ret_val] + + def op_POP_BLOCK (self, i, op, arg, *args, **kws): + self.loop_stack.pop() + return [self.builder.branch(self.llvm_blocks[i + 1])] + + def op_POP_JUMP_IF_FALSE (self, i, op, arg, *args, **kws): + return [self.builder.cbranch(args[0], self.llvm_blocks[i + 3], + self.llvm_blocks[arg])] + + def op_POP_JUMP_IF_TRUE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_POP_JUMP_IF_TRUE") + + def op_POP_TOP (self, i, op, arg, *args, **kws): + return args + + def op_RETURN_VALUE (self, i, op, arg, *args, **kws): + if args[0] is None: + ret_val = [self.builder.ret_void()] + else: + ret_val = [self.builder.ret(args[0])] + return ret_val + + def op_SETUP_LOOP (self, i, op, arg, *args, **kws): + self.loop_stack.append((i, arg)) + return [self.builder.branch(self.llvm_blocks[i + 3])] + + def op_SLICE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_SLICE") + + def op_STORE_ATTR (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_STORE_ATTR") + + def op_STORE_SLICE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_STORE_SLICE") + + def op_STORE_SUBSCR (self, i, op, arg, *args, **kws): + store_val, arr_val, index_val = args + dest_addr = self.builder.gep(arr_val, [index_val]) + return [self.builder.store(store_val, dest_addr)] + + def op_UNARY_CONVERT (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_UNARY_CONVERT") + + def op_UNARY_INVERT (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_UNARY_INVERT") + + def op_UNARY_NEGATIVE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_UNARY_NEGATIVE") + + def op_UNARY_NOT (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_UNARY_NOT") + + def op_UNARY_POSITIVE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_UNARY_POSITIVE") + +# ______________________________________________________________________ + +def translate_function (func, lltype, llvm_module = None, **kws): + translator = LLVMTranslator(llvm_module) + translator.translate(func, lltype, kws) + return translator + +# ______________________________________________________________________ +# Main (self-test) routine + +def main (*args): + from tests import llfuncs, llfunctys + if not args: + args = ('doslice',) + elif 'all' in args: + args = [llfunc + for llfunc in dir(llfuncs) if not llfunc.startswith('_')] + llvm_module = lc.Module.new('test_module') + for arg in args: + translate_function(getattr(llfuncs, arg), getattr(llfunctys, arg), + llvm_module) + print(llvm_module) + +# ______________________________________________________________________ + +if __name__ == '__main__': + import sys + main(*sys.argv[1:]) + +# ______________________________________________________________________ +# End of byte_translator.py diff --git a/bytecode_visitor.py b/bytecode_visitor.py new file mode 100644 index 0000000..6048ba8 --- /dev/null +++ b/bytecode_visitor.py @@ -0,0 +1,566 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +import itertools + +import opcode +from opcode_util import itercode + +# ______________________________________________________________________ + +class BytecodeVisitor (object): + opnames = [name.split('+')[0] for name in opcode.opname] + + def visit_op (self, i, op, arg, *args, **kws): + if op < 0: + ret_val = self.visit_synthetic_op(i, op, arg, *args, **kws) + else: + method = getattr(self, 'op_' + self.opnames[op]) + ret_val = method(i, op, arg, *args, **kws) + return ret_val + + def visit_synthetic_op (self, i, op, arg, *args, **kws): + raise NotImplementedError( + 'BytecodeVisitor.visit_synthetic_op() must be overloaded if using ' + 'synthetic opcodes.') + + def op_BINARY_ADD (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_ADD") + + def op_BINARY_AND (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_AND") + + def op_BINARY_DIVIDE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_DIVIDE") + + def op_BINARY_FLOOR_DIVIDE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_FLOOR_DIVIDE") + + def op_BINARY_LSHIFT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_LSHIFT") + + def op_BINARY_MODULO (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_MODULO") + + def op_BINARY_MULTIPLY (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_MULTIPLY") + + def op_BINARY_OR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_OR") + + def op_BINARY_POWER (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_POWER") + + def op_BINARY_RSHIFT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_RSHIFT") + + def op_BINARY_SUBSCR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_SUBSCR") + + def op_BINARY_SUBTRACT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_SUBTRACT") + + def op_BINARY_TRUE_DIVIDE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_TRUE_DIVIDE") + + def op_BINARY_XOR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_XOR") + + def op_BREAK_LOOP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BREAK_LOOP") + + def op_BUILD_CLASS (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BUILD_CLASS") + + def op_BUILD_LIST (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BUILD_LIST") + + def op_BUILD_MAP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BUILD_MAP") + + def op_BUILD_SET (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BUILD_SET") + + def op_BUILD_SLICE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BUILD_SLICE") + + def op_BUILD_TUPLE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BUILD_TUPLE") + + def op_CALL_FUNCTION (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_CALL_FUNCTION") + + def op_CALL_FUNCTION_KW (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_CALL_FUNCTION_KW") + + def op_CALL_FUNCTION_VAR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_CALL_FUNCTION_VAR") + + def op_CALL_FUNCTION_VAR_KW (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_CALL_FUNCTION_VAR_KW") + + def op_COMPARE_OP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_COMPARE_OP") + + def op_CONTINUE_LOOP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_CONTINUE_LOOP") + + def op_DELETE_ATTR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_DELETE_ATTR") + + def op_DELETE_DEREF (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_DELETE_DEREF") + + def op_DELETE_FAST (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_DELETE_FAST") + + def op_DELETE_GLOBAL (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_DELETE_GLOBAL") + + def op_DELETE_NAME (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_DELETE_NAME") + + def op_DELETE_SLICE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_DELETE_SLICE") + + def op_DELETE_SUBSCR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_DELETE_SUBSCR") + + def op_DUP_TOP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_DUP_TOP") + + def op_DUP_TOPX (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_DUP_TOPX") + + def op_DUP_TOP_TWO (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_DUP_TOP_TWO") + + def op_END_FINALLY (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_END_FINALLY") + + def op_EXEC_STMT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_EXEC_STMT") + + def op_EXTENDED_ARG (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_EXTENDED_ARG") + + def op_FOR_ITER (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_FOR_ITER") + + def op_GET_ITER (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_GET_ITER") + + def op_IMPORT_FROM (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_IMPORT_FROM") + + def op_IMPORT_NAME (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_IMPORT_NAME") + + def op_IMPORT_STAR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_IMPORT_STAR") + + def op_INPLACE_ADD (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_ADD") + + def op_INPLACE_AND (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_AND") + + def op_INPLACE_DIVIDE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_DIVIDE") + + def op_INPLACE_FLOOR_DIVIDE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_FLOOR_DIVIDE") + + def op_INPLACE_LSHIFT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_LSHIFT") + + def op_INPLACE_MODULO (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_MODULO") + + def op_INPLACE_MULTIPLY (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_MULTIPLY") + + def op_INPLACE_OR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_OR") + + def op_INPLACE_POWER (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_POWER") + + def op_INPLACE_RSHIFT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_RSHIFT") + + def op_INPLACE_SUBTRACT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_SUBTRACT") + + def op_INPLACE_TRUE_DIVIDE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_TRUE_DIVIDE") + + def op_INPLACE_XOR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_XOR") + + def op_JUMP_ABSOLUTE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_JUMP_ABSOLUTE") + + def op_JUMP_FORWARD (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_JUMP_FORWARD") + + def op_JUMP_IF_FALSE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_JUMP_IF_FALSE") + + def op_JUMP_IF_FALSE_OR_POP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_JUMP_IF_FALSE_OR_POP") + + def op_JUMP_IF_TRUE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_JUMP_IF_TRUE") + + def op_JUMP_IF_TRUE_OR_POP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_JUMP_IF_TRUE_OR_POP") + + def op_LIST_APPEND (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_LIST_APPEND") + + def op_LOAD_ATTR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_LOAD_ATTR") + + def op_LOAD_BUILD_CLASS (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_LOAD_BUILD_CLASS") + + def op_LOAD_CLOSURE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_LOAD_CLOSURE") + + def op_LOAD_CONST (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_LOAD_CONST") + + def op_LOAD_DEREF (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_LOAD_DEREF") + + def op_LOAD_FAST (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_LOAD_FAST") + + def op_LOAD_GLOBAL (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_LOAD_GLOBAL") + + def op_LOAD_LOCALS (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_LOAD_LOCALS") + + def op_LOAD_NAME (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_LOAD_NAME") + + def op_MAKE_CLOSURE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_MAKE_CLOSURE") + + def op_MAKE_FUNCTION (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_MAKE_FUNCTION") + + def op_MAP_ADD (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_MAP_ADD") + + def op_NOP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_NOP") + + def op_POP_BLOCK (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_POP_BLOCK") + + def op_POP_EXCEPT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_POP_EXCEPT") + + def op_POP_JUMP_IF_FALSE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_POP_JUMP_IF_FALSE") + + def op_POP_JUMP_IF_TRUE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_POP_JUMP_IF_TRUE") + + def op_POP_TOP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_POP_TOP") + + def op_PRINT_EXPR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_PRINT_EXPR") + + def op_PRINT_ITEM (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_PRINT_ITEM") + + def op_PRINT_ITEM_TO (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_PRINT_ITEM_TO") + + def op_PRINT_NEWLINE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_PRINT_NEWLINE") + + def op_PRINT_NEWLINE_TO (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_PRINT_NEWLINE_TO") + + def op_RAISE_VARARGS (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_RAISE_VARARGS") + + def op_RETURN_VALUE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_RETURN_VALUE") + + def op_ROT_FOUR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_ROT_FOUR") + + def op_ROT_THREE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_ROT_THREE") + + def op_ROT_TWO (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_ROT_TWO") + + def op_SETUP_EXCEPT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_SETUP_EXCEPT") + + def op_SETUP_FINALLY (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_SETUP_FINALLY") + + def op_SETUP_LOOP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_SETUP_LOOP") + + def op_SETUP_WITH (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_SETUP_WITH") + + def op_SET_ADD (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_SET_ADD") + + def op_SLICE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_SLICE") + + def op_STOP_CODE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_STOP_CODE") + + def op_STORE_ATTR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_STORE_ATTR") + + def op_STORE_DEREF (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_STORE_DEREF") + + def op_STORE_FAST (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_STORE_FAST") + + def op_STORE_GLOBAL (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_STORE_GLOBAL") + + def op_STORE_LOCALS (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_STORE_LOCALS") + + def op_STORE_MAP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_STORE_MAP") + + def op_STORE_NAME (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_STORE_NAME") + + def op_STORE_SLICE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_STORE_SLICE") + + def op_STORE_SUBSCR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_STORE_SUBSCR") + + def op_UNARY_CONVERT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_UNARY_CONVERT") + + def op_UNARY_INVERT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_UNARY_INVERT") + + def op_UNARY_NEGATIVE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_UNARY_NEGATIVE") + + def op_UNARY_NOT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_UNARY_NOT") + + def op_UNARY_POSITIVE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_UNARY_POSITIVE") + + def op_UNPACK_EX (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_UNPACK_EX") + + def op_UNPACK_SEQUENCE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_UNPACK_SEQUENCE") + + def op_WITH_CLEANUP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_WITH_CLEANUP") + + def op_YIELD_VALUE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_YIELD_VALUE") + +# ______________________________________________________________________ + +class BytecodeIterVisitor (BytecodeVisitor): + def visit (self, co_obj): + self.enter_code_object(co_obj) + for i, op, arg in itercode(co_obj.co_code): + self.visit_op(i, op, arg) + return self.exit_code_object(co_obj) + + def enter_code_object (self, co_obj): + pass + + def exit_code_object (self, co_obj): + pass + +# ______________________________________________________________________ + +class BytecodeFlowVisitor (BytecodeVisitor): + def visit (self, flow): + self.block_list = list(flow.keys()) + self.block_list.sort() + self.enter_flow_object(flow) + for block in self.block_list: + prelude = self.enter_block(block) + prelude_isa_list = isinstance(prelude, list) + if prelude or prelude_isa_list: + if not prelude_isa_list: + prelude = [] + new_stmts = list(self.visit_op(i, op, arg, *args) + for i, op, _, arg, args in flow[block]) + self.new_flow[block] = list(itertools.chain( + prelude, *new_stmts)) + self.exit_block(block) + del self.block_list + return self.exit_flow_object(flow) + + def visit_op (self, i, op, arg, *args, **kws): + new_args = [] + for child_i, child_op, _, child_arg, child_args in args: + new_args.extend(self.visit_op(child_i, child_op, child_arg, + *child_args)) + ret_val = super(BytecodeFlowVisitor, self).visit_op(i, op, arg, + *new_args) + return ret_val + + def enter_flow_object (self, flow): + self.new_flow = {} + + def exit_flow_object (self, flow): + ret_val = self.new_flow + del self.new_flow + return ret_val + + def enter_block (self, block): + pass + + def exit_block (self, block): + pass + +# ______________________________________________________________________ + +class BenignBytecodeVisitorMixin (object): + def _do_nothing (self, i, op, arg, *args, **kws): + return [(i, op, self.opnames[op], arg, args)] + + op_BINARY_ADD = _do_nothing + op_BINARY_AND = _do_nothing + op_BINARY_DIVIDE = _do_nothing + op_BINARY_FLOOR_DIVIDE = _do_nothing + op_BINARY_LSHIFT = _do_nothing + op_BINARY_MODULO = _do_nothing + op_BINARY_MULTIPLY = _do_nothing + op_BINARY_OR = _do_nothing + op_BINARY_POWER = _do_nothing + op_BINARY_RSHIFT = _do_nothing + op_BINARY_SUBSCR = _do_nothing + op_BINARY_SUBTRACT = _do_nothing + op_BINARY_TRUE_DIVIDE = _do_nothing + op_BINARY_XOR = _do_nothing + op_BREAK_LOOP = _do_nothing + op_BUILD_CLASS = _do_nothing + op_BUILD_LIST = _do_nothing + op_BUILD_MAP = _do_nothing + op_BUILD_SET = _do_nothing + op_BUILD_SLICE = _do_nothing + op_BUILD_TUPLE = _do_nothing + op_CALL_FUNCTION = _do_nothing + op_CALL_FUNCTION_KW = _do_nothing + op_CALL_FUNCTION_VAR = _do_nothing + op_CALL_FUNCTION_VAR_KW = _do_nothing + op_COMPARE_OP = _do_nothing + op_CONTINUE_LOOP = _do_nothing + op_DELETE_ATTR = _do_nothing + op_DELETE_DEREF = _do_nothing + op_DELETE_FAST = _do_nothing + op_DELETE_GLOBAL = _do_nothing + op_DELETE_NAME = _do_nothing + op_DELETE_SLICE = _do_nothing + op_DELETE_SUBSCR = _do_nothing + op_DUP_TOP = _do_nothing + op_DUP_TOPX = _do_nothing + op_DUP_TOP_TWO = _do_nothing + op_END_FINALLY = _do_nothing + op_EXEC_STMT = _do_nothing + op_EXTENDED_ARG = _do_nothing + op_FOR_ITER = _do_nothing + op_GET_ITER = _do_nothing + op_IMPORT_FROM = _do_nothing + op_IMPORT_NAME = _do_nothing + op_IMPORT_STAR = _do_nothing + op_INPLACE_ADD = _do_nothing + op_INPLACE_AND = _do_nothing + op_INPLACE_DIVIDE = _do_nothing + op_INPLACE_FLOOR_DIVIDE = _do_nothing + op_INPLACE_LSHIFT = _do_nothing + op_INPLACE_MODULO = _do_nothing + op_INPLACE_MULTIPLY = _do_nothing + op_INPLACE_OR = _do_nothing + op_INPLACE_POWER = _do_nothing + op_INPLACE_RSHIFT = _do_nothing + op_INPLACE_SUBTRACT = _do_nothing + op_INPLACE_TRUE_DIVIDE = _do_nothing + op_INPLACE_XOR = _do_nothing + op_JUMP_ABSOLUTE = _do_nothing + op_JUMP_FORWARD = _do_nothing + op_JUMP_IF_FALSE = _do_nothing + op_JUMP_IF_FALSE_OR_POP = _do_nothing + op_JUMP_IF_TRUE = _do_nothing + op_JUMP_IF_TRUE_OR_POP = _do_nothing + op_LIST_APPEND = _do_nothing + op_LOAD_ATTR = _do_nothing + op_LOAD_BUILD_CLASS = _do_nothing + op_LOAD_CLOSURE = _do_nothing + op_LOAD_CONST = _do_nothing + op_LOAD_DEREF = _do_nothing + op_LOAD_FAST = _do_nothing + op_LOAD_GLOBAL = _do_nothing + op_LOAD_LOCALS = _do_nothing + op_LOAD_NAME = _do_nothing + op_MAKE_CLOSURE = _do_nothing + op_MAKE_FUNCTION = _do_nothing + op_MAP_ADD = _do_nothing + op_NOP = _do_nothing + op_POP_BLOCK = _do_nothing + op_POP_EXCEPT = _do_nothing + op_POP_JUMP_IF_FALSE = _do_nothing + op_POP_JUMP_IF_TRUE = _do_nothing + op_POP_TOP = _do_nothing + op_PRINT_EXPR = _do_nothing + op_PRINT_ITEM = _do_nothing + op_PRINT_ITEM_TO = _do_nothing + op_PRINT_NEWLINE = _do_nothing + op_PRINT_NEWLINE_TO = _do_nothing + op_RAISE_VARARGS = _do_nothing + op_RETURN_VALUE = _do_nothing + op_ROT_FOUR = _do_nothing + op_ROT_THREE = _do_nothing + op_ROT_TWO = _do_nothing + op_SETUP_EXCEPT = _do_nothing + op_SETUP_FINALLY = _do_nothing + op_SETUP_LOOP = _do_nothing + op_SETUP_WITH = _do_nothing + op_SET_ADD = _do_nothing + op_SLICE = _do_nothing + op_STOP_CODE = _do_nothing + op_STORE_ATTR = _do_nothing + op_STORE_DEREF = _do_nothing + op_STORE_FAST = _do_nothing + op_STORE_GLOBAL = _do_nothing + op_STORE_LOCALS = _do_nothing + op_STORE_MAP = _do_nothing + op_STORE_NAME = _do_nothing + op_STORE_SLICE = _do_nothing + op_STORE_SUBSCR = _do_nothing + op_UNARY_CONVERT = _do_nothing + op_UNARY_INVERT = _do_nothing + op_UNARY_NEGATIVE = _do_nothing + op_UNARY_NOT = _do_nothing + op_UNARY_POSITIVE = _do_nothing + op_UNPACK_EX = _do_nothing + op_UNPACK_SEQUENCE = _do_nothing + op_WITH_CLEANUP = _do_nothing + op_YIELD_VALUE = _do_nothing + +# ______________________________________________________________________ +# End of bytecode_visitor.py diff --git a/bytetype.py b/bytetype.py new file mode 100644 index 0000000..25a0355 --- /dev/null +++ b/bytetype.py @@ -0,0 +1,41 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +import ctypes + +import llvm.core as lc + +# ______________________________________________________________________ + +lvoid = lc.Type.void() +li1 = lc.Type.int(1) +li8 = lc.Type.int(8) +li16 = lc.Type.int(16) +li32 = lc.Type.int(32) +li64 = lc.Type.int(64) +lc_size_t = lc.Type.int(ctypes.sizeof( + getattr(ctypes, 'c_ssize_t', getattr(ctypes, 'c_size_t'))) * 8) +lfloat = lc.Type.float() +ldouble = lc.Type.double() +li8_ptr = lc.Type.pointer(li8) + +lc_int = lc.Type.int(ctypes.sizeof(ctypes.c_int) * 8) +lc_long = lc.Type.int(ctypes.sizeof(ctypes.c_long) * 8) + +l_pyobject_head = [lc_size_t, lc.Type.pointer(li32)] +l_pyobject_head_struct = lc.Type.struct(l_pyobject_head) +l_pyobj_p = l_pyobject_head_struct_p = lc.Type.pointer(l_pyobject_head_struct) + +strlen = lc.Type.function(lc_size_t, (li8_ptr,)) +strncpy = lc.Type.function(li8_ptr, (li8_ptr, li8_ptr, lc_size_t)) +strndup = lc.Type.function(li8_ptr, (li8_ptr, lc_size_t)) +malloc = lc.Type.function(li8_ptr, (lc_size_t,)) +free = lc.Type.function(lvoid, (li8_ptr,)) + +Py_BuildValue = lc.Type.function(l_pyobj_p, [li8_ptr], True) +PyArg_ParseTuple = lc.Type.function(lc_int, [l_pyobj_p, li8_ptr], True) +PyEval_SaveThread = lc.Type.function(li8_ptr, []) +PyEval_RestoreThread = lc.Type.function(lc.Type.void(), [li8_ptr]) + +# ______________________________________________________________________ +# End of bytetype.py diff --git a/control_flow.py b/control_flow.py new file mode 100644 index 0000000..5ea030a --- /dev/null +++ b/control_flow.py @@ -0,0 +1,218 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +import pprint + +# ______________________________________________________________________ + +class ControlFlowGraph (object): + def __init__ (self): + self.blocks = {} + self.blocks_in = {} + self.blocks_out = {} + self.blocks_reads = {} + self.blocks_writes = {} + self.blocks_writer = {} + self.blocks_dom = {} + self.blocks_reaching = {} + + def add_block (self, key, value = None): + self.blocks[key] = value + if key not in self.blocks_in: + self.blocks_in[key] = set() + self.blocks_out[key] = set() + self.blocks_reads[key] = set() + self.blocks_writes[key] = set() + self.blocks_writer[key] = {} + + def add_edge (self, from_block, to_block): + self.blocks_out[from_block].add(to_block) + self.blocks_in[to_block].add(from_block) + + def unlink_unreachables (self): + changed = True + next_blocks = self.blocks.keys() + next_blocks.remove(0) + while changed: + changed = False + blocks = next_blocks + next_blocks = blocks[:] + for block in blocks: + if len(self.blocks_in[block]) == 0: + blocks_out = self.blocks_out[block] + for out_edge in blocks_out: + self.blocks_in[out_edge].discard(block) + blocks_out.clear() + next_blocks.remove(block) + changed = True + + def compute_dataflow (self): + '''Compute the dominator and reaching dataflow relationships + in the CFG.''' + blocks = set(self.blocks.keys()) + nonentry_blocks = blocks.copy() + for block in blocks: + self.blocks_dom[block] = blocks + self.blocks_reaching[block] = set((block,)) + if len(self.blocks_in[block]) == 0: + self.blocks_dom[block] = set((block,)) + nonentry_blocks.remove(block) + changed = True + while changed: + changed = False + for block in nonentry_blocks: + olddom = self.blocks_dom[block] + newdom = set.intersection(*[self.blocks_dom[pred] + for pred in self.blocks_in[block]]) + newdom.add(block) + if newdom != olddom: + changed = True + self.blocks_dom[block] = newdom + oldreaching = self.blocks_reaching[block] + newreaching = set.union( + *[self.blocks_reaching[pred] + for pred in self.blocks_in[block]]) + newreaching.add(block) + if newreaching != oldreaching: + changed = True + self.blocks_reaching[block] = newreaching + return self.blocks_dom, self.blocks_reaching + + def update_for_ssa (self): + '''Modify the blocks_writes map to reflect phi nodes inserted + for static single assignment representations.''' + joins = [block for block in self.blocks.keys() + if len(self.blocks_in[block]) > 1] + changed = True + while changed: + changed = False + for block in joins: + phis_needed = self.phi_needed(block) + for affected_local in phis_needed: + if affected_local not in self.blocks_writes[block]: + changed = True + # NOTE: For this to work, we assume that basic + # blocks are indexed by their instruction + # index in the VM bytecode. + self.writes_local(block, block, affected_local) + if changed: + # Any modifications have invalidated the reaching + # definitions, so delete any memoized results. + if hasattr(self, 'reaching_definitions'): + del self.reaching_definitions + + def idom (self, block): + '''Compute the immediate dominator (idom) of the given block + key. Returns None if the block has no in edges. + + Note that in the case where there are multiple immediate + dominators (a join after a non-loop branch), this returns one + of the predecessors, but is not guaranteed to reliably select + one over the others (depends on the ordering of the set type + iterator).''' + preds = self.blocks_in[block] + npreds = len(preds) + if npreds == 0: + ret_val = None + elif npreds == 1: + ret_val = tuple(preds)[0] + else: + ret_val = [pred for pred in preds + if block not in self.blocks_dom[pred]][0] + return ret_val + + def block_writes_to_writer_map (self, block): + ret_val = {} + for local in self.blocks_writes[block]: + ret_val[local] = block + return ret_val + + def get_reaching_definitions (self, block): + '''Return a nested map for the given block + s.t. ret_val[pred][local] equals the block key for the + definition of local that reaches the argument block via that + predecessor. + + Useful for actually populating phi nodes, once you know you + need them.''' + has_memoized = hasattr(self, 'reaching_definitions') + if has_memoized and block in self.reaching_definitions: + ret_val = self.reaching_definitions[block] + else: + preds = self.blocks_in[block] + ret_val = {} + for pred in preds: + ret_val[pred] = self.block_writes_to_writer_map(pred) + crnt = self.idom(pred) + while crnt != None: + crnt_writer_map = self.block_writes_to_writer_map(crnt) + # This order of update favors the first definitions + # encountered in the traversal since the traversal + # visits blocks in reverse execution order. + crnt_writer_map.update(ret_val[pred]) + ret_val[pred] = crnt_writer_map + crnt = self.idom(crnt) + if not has_memoized: + self.reaching_definitions = {} + self.reaching_definitions[block] = ret_val + return ret_val + + def nreaches (self, block): + '''For each local, find the number of unique reaching + definitions the current block has.''' + reaching_definitions = self.get_reaching_definitions(block) + definition_map = {} + for pred in self.blocks_in[block]: + reaching_from_pred = reaching_definitions[pred] + for local in reaching_from_pred.keys(): + if local not in definition_map: + definition_map[local] = set() + definition_map[local].add(reaching_from_pred[local]) + ret_val = {} + for local in definition_map.keys(): + ret_val[local] = len(definition_map[local]) + return ret_val + + def writes_local (self, block, write_instr_index, local_index): + self.blocks_writes[block].add(local_index) + block_writers = self.blocks_writer[block] + old_index = block_writers.get(local_index, -1) + # This checks for a corner case that would impact + # numba.translate.Translate.build_phi_nodes(). + assert old_index != write_instr_index, ( + "Found corner case for STORE_FAST at a CFG join!") + block_writers[local_index] = max(write_instr_index, old_index) + + def phi_needed (self, join): + '''Return the set of locals that will require a phi node to be + generated at the given join.''' + nreaches = self.nreaches(join) + return set([local for local in nreaches.keys() + if nreaches[local] > 1]) + + def pprint (self, *args, **kws): + pprint.pprint(self.__dict__, *args, **kws) + + def pformat (self, *args, **kws): + return pprint.pformat(self.__dict__, *args, **kws) + + def to_dot (self, graph_name = None): + '''Return a dot (digraph visualizer in Graphviz) graph + description as a string.''' + if graph_name is None: + graph_name = 'CFG_%d' % id(self) + lines_out = [] + for block_index in self.blocks: + lines_out.append( + 'BLOCK_%r [shape=box, label="BLOCK_%r\\nr: %r, w: %r"];' % + (block_index, block_index, + tuple(self.blocks_reads[block_index]), + tuple(self.blocks_writes[block_index]))) + for block_index in self.blocks: + for out_edge in self.blocks_out[block_index]: + lines_out.append('BLOCK_%r -> BLOCK_%r;' % + (block_index, out_edge)) + return 'digraph %s {\n%s\n}\n' % (graph_name, '\n'.join(lines_out)) + +# ______________________________________________________________________ +# End of control_flow.py diff --git a/gen_bytecode_visitor.py b/gen_bytecode_visitor.py new file mode 100644 index 0000000..7f922e2 --- /dev/null +++ b/gen_bytecode_visitor.py @@ -0,0 +1,27 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +import opcode_util + +# ______________________________________________________________________ + +def generate_bytecode_visitor (classname = 'BytecodeVisitor', + baseclass = 'object'): + opnames = list(set((opname.split('+')[0] + for opname in opcode_util.OPCODE_MAP.keys()))) + opnames.sort() + return 'class %s (%s):\n%s\n' % ( + classname, baseclass, + '\n\n'.join((' def op_%s (self, i, op, arg):\n' + ' raise NotImplementedError("%s.op_%s")' % + (opname, classname, opname) + for opname in opnames))) + +# ______________________________________________________________________ + +if __name__ == "__main__": + import sys + print(generate_bytecode_visitor(*sys.argv[1:])) + +# ______________________________________________________________________ +# End of gen_bytecode_visitor.py diff --git a/nobitey.py b/nobitey.py new file mode 100644 index 0000000..bca491e --- /dev/null +++ b/nobitey.py @@ -0,0 +1,366 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +import sys +import os.path +import imp +import io +import types + +import llvm.core as lc +import llvm.ee as le + +import bytetype + +from pyaddfunc import pyaddfunc + +LLVM_TO_INT_PARSE_STR_MAP = { + 8 : 'b', + 16 : 'h', + 32 : 'i', # Note that on 32-bit systems sizeof(int) == sizeof(long) + 64 : 'L', # Seeing sizeof(long long) == 8 on both 32 and 64-bit platforms +} + +LLVM_TO_PARSE_STR_MAP = { + lc.TYPE_FLOAT : 'f', + lc.TYPE_DOUBLE : 'd', +} + +# ______________________________________________________________________ + +# XXX Stolen from numba.translate + +def get_string_constant (module, const_str): + const_name = "__STR_%x" % (hash(const_str),) + try: + ret_val = module.get_global_variable_named(const_name) + except: + lconst_str = lc.Constant.stringz(const_str) + ret_val = module.add_global_variable(lconst_str.type, const_name) + ret_val.initializer = lconst_str + ret_val.linkage = lc.LINKAGE_INTERNAL + return ret_val + +# ______________________________________________________________________ + +class NoBitey (object): + def __init__ (self, target_module = None, type_annotations = None): + if target_module is None: + target_module = lc.Module.new('NoBitey_%d' % id(self)) + if type_annotations is None: + type_annotations = {} + self.target_module = target_module + self.type_aliases = type_annotations # Reserved for future use. + + def _build_parse_string (self, llvm_type): + kind = llvm_type.kind + if kind == lc.TYPE_INTEGER: + ret_val = LLVM_TO_INT_PARSE_STR_MAP[llvm_type.width] + elif kind in LLVM_TO_PARSE_STR_MAP: + ret_val = LLVM_TO_PARSE_STR_MAP[kind] + else: + raise TypeError('Unsupported LLVM type: %s' % str(llvm_type)) + return ret_val + + def build_parse_string (self, llvm_tys): + """Given a set of LLVM types, return a string for parsing + them via PyArg_ParseTuple.""" + return ''.join((self._build_parse_string(ty) + for ty in llvm_tys)) + + def handle_abi_casts (self, builder, result): + if result.type.kind == lc.TYPE_FLOAT: + # NOTE: The C ABI apparently casts floats to doubles when + # an argument must be pushed on the stack, as is the case + # when calling a variable argument function. + # XXX Is there documentation on this where I can find all + # coercion rules? Do we still need some libffi + # integration? + result = builder.fpext(result, bytetype.ldouble) + return result + + def build_wrapper_function (self, llvm_function): + _pyobj_p = bytetype.l_pyobject_head_struct_p + _void_p = _char_p = bytetype.li8_ptr + self.crnt_function = self.target_module.add_function( + lc.Type.function(_pyobj_p, (_pyobj_p, _pyobj_p)), + llvm_function.name + "_wrapper") + entry_block = self.crnt_function.append_basic_block('entry') + args_ok_block = self.crnt_function.append_basic_block('args_ok') + exit_block = self.crnt_function.append_basic_block('exit') + _int32_zero = lc.Constant.int(bytetype.li32, 0) + _Py_BuildValue = self.target_module.get_or_insert_function( + lc.Type.function(_pyobj_p, [_char_p], True), 'Py_BuildValue') + _PyArg_ParseTuple = self.target_module.get_or_insert_function( + lc.Type.function(bytetype.lc_int, [_pyobj_p, _char_p], True), + 'PyArg_ParseTuple') + _PyEval_SaveThread = self.target_module.get_or_insert_function( + lc.Type.function(_void_p, []), 'PyEval_SaveThread') + _PyEval_RestoreThread = self.target_module.get_or_insert_function( + lc.Type.function(lc.Type.void(), [_void_p]), + 'PyEval_RestoreThread') + # __________________________________________________ + # entry: + builder = lc.Builder.new(entry_block) + arg_types = llvm_function.type.pointee.args + parse_str = builder.gep( + get_string_constant( + self.target_module, + self.build_parse_string(arg_types)), + [_int32_zero, _int32_zero]) + parse_args = [builder.alloca(arg_ty) for arg_ty in arg_types] + parse_args.insert(0, parse_str) + parse_args.insert(0, self.crnt_function.args[1]) + parse_result = builder.call(_PyArg_ParseTuple, parse_args) + builder.cbranch(builder.icmp(lc.ICMP_NE, parse_result, _int32_zero), + args_ok_block, exit_block) + # __________________________________________________ + # args_ok: + builder = lc.Builder.new(args_ok_block) + thread_state = builder.call(_PyEval_SaveThread, ()) + target_args = [builder.load(parse_arg) for parse_arg in parse_args[2:]] + result = builder.call(llvm_function, target_args) + result_cast = self.handle_abi_casts(builder, result) + builder.call(_PyEval_RestoreThread, (thread_state,)) + build_str = builder.gep( + get_string_constant( + self.target_module, + self._build_parse_string(result.type)), + [_int32_zero, _int32_zero]) + py_result = builder.call(_Py_BuildValue, [build_str, result_cast]) + builder.branch(exit_block) + # __________________________________________________ + # exit: + builder = lc.Builder.new(exit_block) + rval = builder.phi(bytetype.l_pyobject_head_struct_p) + rval.add_incoming(lc.Constant.null(bytetype.l_pyobject_head_struct_p), + entry_block) + rval.add_incoming(py_result, args_ok_block) + builder.ret(rval) + return self.crnt_function + + def wrap_llvm_module (self, llvm_module, engine = None, py_module = None): + ''' + Shamefully adapted from bitey.bind.wrap_llvm_module(). + ''' + functions = [func for func in llvm_module.functions + if not func.name.startswith("_") + and not func.is_declaration + and func.linkage == lc.LINKAGE_EXTERNAL] + wrappers = [self.build_wrapper_function(func) for func in functions] + if engine is None: + engine = le.ExecutionEngine.new(llvm_module) + if self.target_module != llvm_module: + engine.add_module(self.target_module) + py_wrappers = [pyaddfunc(wrapper.name, + engine.get_pointer_to_function(wrapper)) + for wrapper in wrappers] + if py_module: + for py_wrapper in py_wrappers: + setattr(py_module, py_wrapper.__name__[:-8], py_wrapper) + setattr(py_module, '_llvm_module', llvm_module) + setattr(py_module, '_llvm_engine', engine) + if self.target_module != llvm_module: + setattr(py_module, '_llvm_wrappers', self.target_module) + return engine, py_wrappers + + def wrap_llvm_module_in_python (self, llvm_module, py_module = None): + ''' + Mildly reworked and abstracted bitey.bind.wrap_llvm_bitcode(). + Abstracted to accept any existing LLVM Module object, and + return a Python wrapper module (even if one wasn't originally + specified). + ''' + if py_module is None: + py_module = types.ModuleType(str(llvm_module.id)) + engine = le.ExecutionEngine.new(llvm_module) + self.wrap_llvm_module(llvm_module, engine, py_module) + return py_module + + def wrap_llvm_bitcode (self, bitcode, py_module = None): + ''' + Intended to be drop-in replacement of + bitey.bind.wrap_llvm_bitcode(). + ''' + return self.wrap_llvm_module_in_python( + lc.Module.from_bitcode(io.BytesIO(bitcode)), py_module) + + def wrap_llvm_assembly (self, llvm_asm, py_module = None): + return self.wrap_llvm_module_in_python( + lc.Module.from_assembly(io.BytesIO(llvm_asm)), py_module) + +# ______________________________________________________________________ + +class NoBiteyLoader(object): + """ + Load LLVM compiled bitcode and autogenerate a ctypes binding. + + Initially copied and adapted from bitey.loader module. + """ + def __init__(self, pkg, name, source, preload, postload): + self.package = pkg + self.name = name + self.fullname = '.'.join((pkg,name)) + self.source = source + self.preload = preload + self.postload = postload + + @classmethod + def _check_magic(cls, filename): + if os.path.exists(filename): + magic = open(filename,"rb").read(4) + if magic == b'\xde\xc0\x17\x0b': + return True + elif magic[:2] == b'\x42\x43': + return True + else: + return False + else: + return False + + @classmethod + def build_module(cls, fullname, source_path, source_data, preload=None, + postload=None): + name = fullname.split(".")[-1] + mod = imp.new_module(name) + if preload: + exec(preload, mod.__dict__, mod.__dict__) + type_annotations = getattr(mod, '_type_annotations', None) + nb = NoBitey(type_annotations = type_annotations) + if source_path.endswith(('.o', '.bc')): + nb.wrap_llvm_bitcode(source_data, mod) + elif source_path.endswith('.s'): + nb.wrap_llvm_assembly(source_data, mod) + if postload: + exec(postload, mod.__dict__, mod.__dict__) + return mod + + @classmethod + def find_module(cls, fullname, paths = None): + if paths is None: + paths = sys.path + names = fullname.split('.') + modname = names[-1] + source_paths = None + for f in paths: + path = os.path.join(os.path.realpath(f), modname) + source = path + '.o' + if cls._check_magic(source): + source_paths = path, source + break + source = path + '.bc' + if os.path.exists(source): + source_paths = path, source + break + source = path + '.s' + if os.path.exists(source): + source_paths = path, source + break + if source_paths: + path, source = source_paths + return cls('.'.join(names[:-1]), modname, source, + path + ".pre.py", path + ".post.py") + + def get_code(self, module): + pass + + def get_data(self, module): + pass + + def get_filename(self, name): + return self.source + + def get_source(self, name): + with open(self.source, 'rb') as f: + return f.read() + + def is_package(self, *args, **kw): + return False + + def load_module(self, fullname): + if fullname in sys.modules: + return sys.modules[fullname] + + preload = None + postload = None + + # Get the preload file (if any) + if os.path.exists(self.preload): + with open(self.preload) as f: + preload = f.read() + + # Get the source + with open(self.source, 'rb') as f: + source_data = f.read() + + # Get the postload file (if any) + if os.path.exists(self.postload): + with open(self.postload) as f: + postload = f.read() + + mod = self.build_module(fullname, self.get_filename(None), source_data, + preload, postload) + sys.modules[fullname] = mod + mod.__loader__ = self + mod.__file__ = self.source + return mod + + @classmethod + def install(cls): + if cls not in sys.meta_path: + sys.meta_path.append(cls) + + @classmethod + def remove(cls): + sys.meta_path.remove(cls) + +# ______________________________________________________________________ + +def _mk_add_42 (llvm_module, at_type = bytetype.lc_long): + f = llvm_module.add_function( + lc.Type.function(at_type, [at_type]), 'add_42_%s' % str(at_type)) + block = f.append_basic_block('entry') + builder = lc.Builder.new(block) + if at_type.kind == lc.TYPE_INTEGER: + const_42 = lc.Constant.int(at_type, 42) + add = builder.add + elif at_type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE): + const_42 = lc.Constant.real(at_type, 42.) + add = builder.fadd + else: + raise TypeError('Unsupported type: %s' % str(at_type)) + builder.ret(add(f.args[0], const_42)) + return f + +# ______________________________________________________________________ + +def build_test_module (): + llvm_module = lc.Module.new('nobitey_test') + for ty in (bytetype.li32, bytetype.li64, bytetype.lfloat, + bytetype.ldouble): + fn = _mk_add_42(llvm_module, ty) + return llvm_module + +# ______________________________________________________________________ + +def main (*args): + # Build up a module. + m = build_test_module() + print(m) + wrap_module = NoBitey().wrap_llvm_module_in_python(m) + # Now try running the generated wrappers. + for py_wf_name in ('add_42_i32', 'add_42_i64', 'add_42_float', + 'add_42_double'): + py_wf = getattr(wrap_module, py_wf_name) + for i in range(42): + result = py_wf(i) + expected = i + 42 + assert result == expected, "%r != %r in %r" % ( + result, expected, py_wf) + return wrap_module + +if __name__ == "__main__": + main(*sys.argv[1:]) + +# ______________________________________________________________________ +# End of nobitey.py diff --git a/opcode_util.py b/opcode_util.py new file mode 100644 index 0000000..9bc8f25 --- /dev/null +++ b/opcode_util.py @@ -0,0 +1,215 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +import dis +import opcode + +# ______________________________________________________________________ +# Module data + +hasjump = opcode.hasjrel + opcode.hasjabs +hascbranch = [op for op in hasjump + if 'IF' in opcode.opname[op] + or opcode.opname[op] in ('FOR_ITER', 'SETUP_LOOP')] + +# Since the actual opcode value may change, manage opcode abstraction +# data by opcode name. + +OPCODE_MAP = { + 'BINARY_ADD': (2, 1, None), + 'BINARY_AND': (2, 1, None), + 'BINARY_DIVIDE': (2, 1, None), + 'BINARY_FLOOR_DIVIDE': (2, 1, None), + 'BINARY_LSHIFT': (2, 1, None), + 'BINARY_MODULO': (2, 1, None), + 'BINARY_MULTIPLY': (2, 1, None), + 'BINARY_OR': (2, 1, None), + 'BINARY_POWER': (2, 1, None), + 'BINARY_RSHIFT': (2, 1, None), + 'BINARY_SUBSCR': (2, 1, None), + 'BINARY_SUBTRACT': (2, 1, None), + 'BINARY_TRUE_DIVIDE': (2, 1, None), + 'BINARY_XOR': (2, 1, None), + 'BREAK_LOOP': (0, None, 1), + 'BUILD_CLASS': (None, None, None), + 'BUILD_LIST': (-1, 1, None), + 'BUILD_MAP': (None, None, None), + 'BUILD_SET': (None, None, None), + 'BUILD_SLICE': (None, None, None), + 'BUILD_TUPLE': (-1, 1, None), + 'CALL_FUNCTION': (-2, 1, None), + 'CALL_FUNCTION_KW': (-3, 1, None), + 'CALL_FUNCTION_VAR': (-3, 1, None), + 'CALL_FUNCTION_VAR_KW': (-4, 1, None), + 'COMPARE_OP': (2, 1, None), + 'CONTINUE_LOOP': (None, None, None), + 'DELETE_ATTR': (1, None, 1), + 'DELETE_DEREF': (None, None, None), + 'DELETE_FAST': (0, None, 1), + 'DELETE_GLOBAL': (0, None, 1), + 'DELETE_NAME': (0, None, 1), + 'DELETE_SLICE+0': (1, None, 1), + 'DELETE_SLICE+1': (2, None, 1), + 'DELETE_SLICE+2': (2, None, 1), + 'DELETE_SLICE+3': (3, None, 1), + 'DELETE_SUBSCR': (2, None, 1), + 'DUP_TOP': (None, None, None), + 'DUP_TOPX': (None, None, None), + 'DUP_TOP_TWO': (None, None, None), + 'END_FINALLY': (None, None, None), + 'EXEC_STMT': (None, None, None), + 'EXTENDED_ARG': (None, None, None), + 'FOR_ITER': (1, 1, 1), + 'GET_ITER': (1, 1, None), + 'IMPORT_FROM': (None, None, None), + 'IMPORT_NAME': (None, None, None), + 'IMPORT_STAR': (1, None, 1), + 'INPLACE_ADD': (2, 1, None), + 'INPLACE_AND': (2, 1, None), + 'INPLACE_DIVIDE': (2, 1, None), + 'INPLACE_FLOOR_DIVIDE': (2, 1, None), + 'INPLACE_LSHIFT': (2, 1, None), + 'INPLACE_MODULO': (2, 1, None), + 'INPLACE_MULTIPLY': (2, 1, None), + 'INPLACE_OR': (2, 1, None), + 'INPLACE_POWER': (2, 1, None), + 'INPLACE_RSHIFT': (2, 1, None), + 'INPLACE_SUBTRACT': (2, 1, None), + 'INPLACE_TRUE_DIVIDE': (2, 1, None), + 'INPLACE_XOR': (2, 1, None), + 'JUMP_ABSOLUTE': (0, None, 1), + 'JUMP_FORWARD': (0, None, 1), + 'JUMP_IF_FALSE': (1, None, 1), + 'JUMP_IF_FALSE_OR_POP': (None, None, None), + 'JUMP_IF_TRUE': (1, None, 1), + 'JUMP_IF_TRUE_OR_POP': (None, None, None), + 'LIST_APPEND': (2, 0, 1), + 'LOAD_ATTR': (1, 1, None), + 'LOAD_BUILD_CLASS': (None, None, None), + 'LOAD_CLOSURE': (None, None, None), + 'LOAD_CONST': (0, 1, None), + 'LOAD_DEREF': (0, 1, None), + 'LOAD_FAST': (0, 1, None), + 'LOAD_GLOBAL': (0, 1, None), + 'LOAD_LOCALS': (None, None, None), + 'LOAD_NAME': (0, 1, None), + 'MAKE_CLOSURE': (None, None, None), + 'MAKE_FUNCTION': (None, None, None), + 'MAP_ADD': (None, None, None), + 'NOP': (0, None, None), + 'POP_BLOCK': (0, None, 1), + 'POP_EXCEPT': (None, None, None), + 'POP_JUMP_IF_FALSE': (1, None, 1), + 'POP_JUMP_IF_TRUE': (1, None, 1), + 'POP_TOP': (1, None, 1), + 'PRINT_EXPR': (1, None, 1), + 'PRINT_ITEM': (1, None, 1), + 'PRINT_ITEM_TO': (2, None, 1), + 'PRINT_NEWLINE': (0, None, 1), + 'PRINT_NEWLINE_TO': (1, None, 1), + 'RAISE_VARARGS': (None, None, None), + 'RETURN_VALUE': (1, None, 1), + 'ROT_FOUR': (None, None, None), + 'ROT_THREE': (None, None, None), + 'ROT_TWO': (None, None, None), + 'SETUP_EXCEPT': (None, None, None), + 'SETUP_FINALLY': (None, None, None), + 'SETUP_LOOP': (None, None, None), + 'SETUP_WITH': (None, None, None), + 'SET_ADD': (None, None, None), + 'SLICE+0': (1, 1, None), + 'SLICE+1': (2, 1, None), + 'SLICE+2': (2, 1, None), + 'SLICE+3': (3, 1, None), + 'STOP_CODE': (None, None, None), + 'STORE_ATTR': (2, None, 1), + 'STORE_DEREF': (1, 0, 1), + 'STORE_FAST': (1, None, 1), + 'STORE_GLOBAL': (1, None, 1), + 'STORE_LOCALS': (None, None, None), + 'STORE_MAP': (1, None, 1), + 'STORE_NAME': (1, None, 1), + 'STORE_SLICE+0': (1, None, 1), + 'STORE_SLICE+1': (2, None, 1), + 'STORE_SLICE+2': (2, None, 1), + 'STORE_SLICE+3': (3, None, 1), + 'STORE_SUBSCR': (3, None, 1), + 'UNARY_CONVERT': (1, 1, None), + 'UNARY_INVERT': (1, 1, None), + 'UNARY_NEGATIVE': (1, 1, None), + 'UNARY_NOT': (1, 1, None), + 'UNARY_POSITIVE': (1, 1, None), + 'UNPACK_EX': (None, None, None), + 'UNPACK_SEQUENCE': (None, None, None), + 'WITH_CLEANUP': (None, None, None), + 'YIELD_VALUE': (1, None, 1), +} + +# ______________________________________________________________________ +# Module functions + +def itercode(code): + """Return a generator of byte-offset, opcode, and argument + from a byte-code-string + """ + i = 0 + extended_arg = 0 + if isinstance(code[0], str): + code = [ord(c) for c in code] + n = len(code) + while i < n: + op = code[i] + num = i + i = i + 1 + oparg = None + if op >= opcode.HAVE_ARGUMENT: + oparg = code[i] + (code[i + 1] * 256) + extended_arg + extended_arg = 0 + i = i + 2 + if op == opcode.EXTENDED_ARG: + extended_arg = oparg * 65536 + + delta = yield num, op, oparg + if delta is not None: + abs_rel, dst = delta + assert abs_rel == 'abs' or abs_rel == 'rel' + i = dst if abs_rel == 'abs' else i + dst + +# ______________________________________________________________________ + +def extendlabels(code, labels = None): + """Extend the set of jump target labels to account for the + passthrough targets of conditional branches. + + This allows us to create a control flow graph where there is at + most one branch per basic block. + """ + if labels is None: + labels = [] + if isinstance(code[0], str): + code = [ord(c) for c in code] + n = len(code) + i = 0 + while i < n: + op = code[i] + i += 1 + if op >= dis.HAVE_ARGUMENT: + i += 2 + label = -1 + if op in hasjump: + label = i + if label >= 0: + if label not in labels: + labels.append(label) + elif op == opcode.opmap['BREAK_LOOP']: + if i not in labels: + labels.append(i) + return labels + +# ______________________________________________________________________ + +def get_code_object (func): + return getattr(func, '__code__', getattr(func, 'func_code', None)) + +# ______________________________________________________________________ +# End of opcode_util.py diff --git a/phi_injector.py b/phi_injector.py new file mode 100644 index 0000000..c40abe3 --- /dev/null +++ b/phi_injector.py @@ -0,0 +1,131 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +from bytecode_visitor import BytecodeFlowVisitor, BenignBytecodeVisitorMixin + +# ______________________________________________________________________ + +synthetic_opname = [] +synthetic_opmap = {} + +def def_synth_op (opname): + global synthetic_opname, synthetic_opmap + ret_val = -(len(synthetic_opname) + 1) + synthetic_opname.insert(0, opname) + synthetic_opmap[opname] = ret_val + return ret_val + +REF_ARG = def_synth_op('REF_ARG') +BUILD_PHI = def_synth_op('BUILD_PHI') +DEFINITION = def_synth_op('DEFINITION') +REF_DEF = def_synth_op('REF_DEF') + +# ______________________________________________________________________ + +class PhiInjector (BenignBytecodeVisitorMixin, BytecodeFlowVisitor): + def visit_cfg (self, cfg, nargs = 0, *args, **kws): + self.cfg = cfg + ret_val = self.visit(cfg.blocks, nargs) + del self.cfg + return ret_val + + def visit (self, flow, nargs = 0, *args, **kws): + self.nargs = nargs + self.definitions = [] + self.phis = [] + self.prev_blocks = [] + self.blocks_locals = dict((block, {}) + for block in self.cfg.blocks.keys()) + ret_val = super(PhiInjector, self).visit(flow, *args, **kws) + for block, _, _, args, _ in self.phis: + local = args.pop() + reaching_definitions = self.cfg.reaching_definitions[block] + for prev in reaching_definitions.keys(): + if 0 in self.cfg.blocks_reaching[prev]: + args.append((prev, REF_DEF, 'REF_DEF', + self.blocks_locals[prev][local], ())) + args.sort() + del self.blocks_locals + del self.prev_blocks + del self.phis + del self.definitions + del self.nargs + return ret_val + + def add_definition (self, index, local, arg): + definition_index = len(self.definitions) + definition = (index, DEFINITION, 'DEFINITION', definition_index, + (arg,)) + self.definitions.append(definition) + self.blocks_locals[self.block][local] = definition_index + return definition + + def add_phi (self, index, local): + ret_val = (index, BUILD_PHI, 'BUILD_PHI', [local], ()) + self.phis.append(ret_val) + return ret_val + + def enter_block (self, block): + ret_val = False + if self.prev_blocks: + prev_block = self.prev_blocks[-1] + self.block = block + if block == 0: + if self.nargs > 0: + ret_val = [self.add_definition(-1, arg, + (-1, REF_ARG, 'REF_ARG', arg, + ())) + for arg in range(self.nargs)] + else: + ret_val = True + elif 0 in self.cfg.blocks_reaching[block]: + ret_val = True + prev_block_locals = self.blocks_locals[prev_block] + self.blocks_locals[block] = prev_block_locals.copy() + phis_needed = self.cfg.phi_needed(block) + if phis_needed: + ret_val = [self.add_definition(block, local, + self.add_phi(block, local)) + for local in phis_needed] + return ret_val + + def exit_block (self, block): + if 0 in self.cfg.blocks_reaching[block]: + self.prev_blocks.append(block) + del self.block + + def op_STORE_FAST (self, i, op, arg, *args, **kws): + assert len(args) == 1 + return [self.add_definition(i, arg, args[0])] + + def op_LOAD_FAST (self, i, op, arg, *args, **kws): + return [(i, REF_DEF, 'REF_DEF', self.blocks_locals[self.block][arg], + args)] + +# ______________________________________________________________________ + +def inject_phis (func): + import byte_control + argcount = byte_control.opcode_util.get_code_object(func).co_argcount + cfg = byte_control.build_cfg(func) + return PhiInjector().visit_cfg(cfg, argcount) + +# ______________________________________________________________________ +# Main (self-test) routine + +def main (*args): + import pprint + from tests import llfuncs + if not args: + args = ('doslice',) + for arg in args: + pprint.pprint(inject_phis(getattr(llfuncs, arg))) + +# ______________________________________________________________________ + +if __name__ == "__main__": + import sys + main(*sys.argv[1:]) + +# ______________________________________________________________________ +# End of phi_injector.py diff --git a/pyaddfunc.py b/pyaddfunc.py new file mode 100644 index 0000000..8e09839 --- /dev/null +++ b/pyaddfunc.py @@ -0,0 +1,41 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +import ctypes + +# ______________________________________________________________________ +class PyMethodDef (ctypes.Structure): + _fields_ = [ + ('ml_name', ctypes.c_char_p), + ('ml_meth', ctypes.c_void_p), + ('ml_flags', ctypes.c_int), + ('ml_doc', ctypes.c_char_p), + ] + +PyCFunction_NewEx = ctypes.pythonapi.PyCFunction_NewEx +PyCFunction_NewEx.argtypes = (ctypes.POINTER(PyMethodDef), + ctypes.c_void_p, + ctypes.c_void_p) +PyCFunction_NewEx.restype = ctypes.py_object + +cache = {} # Unsure if this is necessary to keep the PyMethodDef + # structures from being garbage collected. Assuming so... + +def pyaddfunc (func_name, func_ptr, func_doc = None): + global cache + if bytes != str: + func_name = bytes(ord(ch) for ch in func_name) + key = (func_name, func_ptr) + if key in cache: + _, ret_val = cache[key] + else: + mdef = PyMethodDef(bytes(func_name), + func_ptr, + 1, # == METH_VARARGS (hopefully remains so...) + func_doc) + ret_val = PyCFunction_NewEx(ctypes.byref(mdef), 0, 0) + cache[key] = (mdef, ret_val) + return ret_val + +# ______________________________________________________________________ +# End of pyaddfunc.py diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/llfuncs.py b/tests/llfuncs.py new file mode 100644 index 0000000..55e9000 --- /dev/null +++ b/tests/llfuncs.py @@ -0,0 +1,42 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +def doslice (in_string, lower, upper): + l = strlen(in_string) + if lower < 0: + lower += l + if upper < 0: + upper += l + temp_len = upper - lower + if temp_len < 0: + temp_len = 0 + ret_val = alloca_array(li8, temp_len + 1) + strncpy(ret_val, in_string + lower, temp_len) + ret_val[temp_len] = li8(0) + return ret_val + +def ipow (val, exp): + ret_val = 1 + temp = val + w = exp + while w > 0: + if (w & 1) != 0: + ret_val *= temp + # TODO: Overflow check on ret_val + w >>= 1 + if w == 0: break + temp *= temp + # TODO: Overflow check on temp + return ret_val + +def pymod (arg1, arg2): + ret_val = arg1 % arg2 + if ret_val < 0: + if arg2 > 0: + ret_val += arg2 + elif arg2 < 0: + ret_val += arg2 + return ret_val + +# ______________________________________________________________________ +# End of llfuncs.py diff --git a/tests/llfunctys.py b/tests/llfunctys.py new file mode 100644 index 0000000..107b5a3 --- /dev/null +++ b/tests/llfunctys.py @@ -0,0 +1,23 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +import llvm.core as lc + +try: + from llnumba import bytetype +except ImportError: + from numba.llnumba import bytetype + +# ______________________________________________________________________ + +doslice = lc.Type.function(bytetype.li8_ptr, ( + bytetype.li8_ptr, bytetype.lc_size_t, bytetype.lc_size_t)) + +ipow = lc.Type.function(bytetype.li32, (bytetype.li32, + bytetype.li32)) + +pymod = lc.Type.function(bytetype.li32, (bytetype.li32, + bytetype.li32)) + +# ______________________________________________________________________ +# End of llfunctys.py From 6041f2df8443a59d98d71efc6fdf7c74e8e13648 Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Sat, 13 Oct 2012 16:38:19 +0100 Subject: [PATCH 066/516] Add 'numba/minivect/' from commit 'e0f32ee9d15e6f913a8bdcd9214783be2758b7d8' git-subtree-dir: numba/minivect git-subtree-mainline: 1b07f0bbc9cf0898320e1ec303a1906c9c91130d git-subtree-split: e0f32ee9d15e6f913a8bdcd9214783be2758b7d8 From 3f0a4a74f7960b5dbc9d85d6cfa1eb01409ba64a Mon Sep 17 00:00:00 2001 From: Jon Riehl Date: Thu, 11 Oct 2012 15:46:56 -0500 Subject: [PATCH 067/516] Moved llnumba out of sandbox. --- __init__.py | 0 byte_control.py | 98 +++++++ byte_flow.py | 218 ++++++++++++++++ byte_translator.py | 525 +++++++++++++++++++++++++++++++++++++ bytecode_visitor.py | 566 ++++++++++++++++++++++++++++++++++++++++ bytetype.py | 41 +++ control_flow.py | 218 ++++++++++++++++ gen_bytecode_visitor.py | 27 ++ nobitey.py | 366 ++++++++++++++++++++++++++ opcode_util.py | 215 +++++++++++++++ phi_injector.py | 131 ++++++++++ pyaddfunc.py | 41 +++ tests/__init__.py | 0 tests/llfuncs.py | 42 +++ tests/llfunctys.py | 23 ++ 15 files changed, 2511 insertions(+) create mode 100644 __init__.py create mode 100644 byte_control.py create mode 100644 byte_flow.py create mode 100644 byte_translator.py create mode 100644 bytecode_visitor.py create mode 100644 bytetype.py create mode 100644 control_flow.py create mode 100644 gen_bytecode_visitor.py create mode 100644 nobitey.py create mode 100644 opcode_util.py create mode 100644 phi_injector.py create mode 100644 pyaddfunc.py create mode 100644 tests/__init__.py create mode 100644 tests/llfuncs.py create mode 100644 tests/llfunctys.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/byte_control.py b/byte_control.py new file mode 100644 index 0000000..8180cf2 --- /dev/null +++ b/byte_control.py @@ -0,0 +1,98 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +import opcode +import opcode_util +import pprint + +from bytecode_visitor import BytecodeFlowVisitor, BenignBytecodeVisitorMixin +from control_flow import ControlFlowGraph + +# ______________________________________________________________________ + +class ControlFlowBuilder (BenignBytecodeVisitorMixin, BytecodeFlowVisitor): + def visit (self, flow, nargs = 0, *args, **kws): + self.nargs = nargs + ret_val = super(ControlFlowBuilder, self).visit(flow, *args, **kws) + del self.nargs + return ret_val + + def enter_flow_object (self, flow): + super(ControlFlowBuilder, self).enter_flow_object(flow) + self.flow = flow + self.cfg = ControlFlowGraph() + for block in flow.keys(): + self.cfg.add_block(block, flow[block]) + + def exit_flow_object (self, flow): + super(ControlFlowBuilder, self).exit_flow_object(flow) + assert self.flow == flow + self.cfg.compute_dataflow() + self.cfg.update_for_ssa() + ret_val = self.cfg + del self.cfg + del self.flow + return ret_val + + def enter_block (self, block): + self.block = block + assert block in self.cfg.blocks + if block == 0: + for local_index in range(self.nargs): + self.op_STORE_FAST(0, opcode.opmap['STORE_FAST'], local_index) + return True + + def _get_next_block (self, block): + return self.block_list[self.block_list.index(block) + 1] + + def exit_block (self, block): + assert block == self.block + del self.block + i, op, opname, arg, args = self.flow[block][-1] + if op in opcode.hasjabs: + self.cfg.add_edge(block, arg) + elif op in opcode.hasjrel: + self.cfg.add_edge(block, i + arg + 3) + elif opname == 'BREAK_LOOP': + self.cfg.add_edge(block, arg) + elif opname != 'RETURN_VALUE': + self.cfg.add_edge(block, self._get_next_block(block)) + if op in opcode_util.hascbranch: + self.cfg.add_edge(block, self._get_next_block(block)) + + def op_LOAD_FAST (self, i, op, arg, *args, **kws): + self.cfg.blocks_reads[self.block].add(arg) + return super(ControlFlowBuilder, self).op_LOAD_FAST(i, op, arg, *args, + **kws) + + def op_STORE_FAST (self, i, op, arg, *args, **kws): + self.cfg.writes_local(self.block, i, arg) + return super(ControlFlowBuilder, self).op_STORE_FAST(i, op, arg, *args, + **kws) + +# ______________________________________________________________________ + +def build_cfg (func): + import byte_flow + return ControlFlowBuilder().visit( + byte_flow.build_flow(func), + opcode_util.get_code_object(func).co_argcount) + +# ______________________________________________________________________ +# Main (self-test) routine + +def main (*args, **kws): + from tests import llfuncs + if not args: + args = ('doslice',) + for arg in args: + build_cfg(getattr(llfuncs, arg)).pprint() + +# ______________________________________________________________________ + +if __name__ == "__main__": + import sys + main(*sys.argv[1:]) + +# ______________________________________________________________________ +# End of byte_control.py diff --git a/byte_flow.py b/byte_flow.py new file mode 100644 index 0000000..6951b26 --- /dev/null +++ b/byte_flow.py @@ -0,0 +1,218 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +import dis +import opcode + +from bytecode_visitor import BytecodeIterVisitor +import opcode_util + +# ______________________________________________________________________ + +class BytecodeFlowBuilder (BytecodeIterVisitor): + def __init__ (self, *args, **kws): + super(BytecodeFlowBuilder, self).__init__(*args, **kws) + om_items = opcode_util.OPCODE_MAP.items() + self.opmap = dict((opcode.opmap[opname], (opname, pops, pushes, stmt)) + for opname, (pops, pushes, stmt) in om_items + if opname in opcode.opmap) + + def _visit_op (self, i, op, arg, opname, pops, pushes, appends): + assert pops is not None + if pops: + if pops < 0: + pops = arg - pops - 1 + stk_args = self.stack[-pops:] + del self.stack[-pops:] + else: + stk_args = [] + ret_val = (i, op, opname, arg, stk_args) + if pushes: + self.stack.append(ret_val) + if appends: + self.block.append(ret_val) + return ret_val + + def _op (self, i, op, arg): + opname, pops, pushes, appends = self.opmap[op] + return self._visit_op(i, op, arg, opname, pops, pushes, appends) + + def enter_code_object (self, co_obj): + labels = dis.findlabels(co_obj.co_code) + labels = opcode_util.extendlabels(co_obj.co_code, labels) + self.blocks = dict((index, []) + for index in labels) + self.stack = [] + self.loop_stack = [] + self.blocks[0] = self.block = [] + + def exit_code_object (self, co_obj): + ret_val = self.blocks + del self.stack + del self.loop_stack + del self.block + del self.blocks + return ret_val + + def visit_op (self, i, op, arg): + if i in self.blocks: + self.block = self.blocks[i] + return super(BytecodeFlowBuilder, self).visit_op(i, op, arg) + + op_BINARY_ADD = _op + op_BINARY_AND = _op + op_BINARY_DIVIDE = _op + op_BINARY_FLOOR_DIVIDE = _op + op_BINARY_LSHIFT = _op + op_BINARY_MODULO = _op + op_BINARY_MULTIPLY = _op + op_BINARY_OR = _op + op_BINARY_POWER = _op + op_BINARY_RSHIFT = _op + op_BINARY_SUBSCR = _op + op_BINARY_SUBTRACT = _op + op_BINARY_TRUE_DIVIDE = _op + op_BINARY_XOR = _op + + def op_BREAK_LOOP (self, i, op, arg): + loop_i, _, loop_arg = self.loop_stack[-1] + assert arg is None + return self._op(i, op, loop_i + loop_arg + 3) + + #op_BUILD_CLASS = _op + op_BUILD_LIST = _op + op_BUILD_MAP = _op + op_BUILD_SLICE = _op + op_BUILD_TUPLE = _op + op_CALL_FUNCTION = _op + op_CALL_FUNCTION_KW = _op + op_CALL_FUNCTION_VAR = _op + op_CALL_FUNCTION_VAR_KW = _op + op_COMPARE_OP = _op + #op_CONTINUE_LOOP = _op + op_DELETE_ATTR = _op + op_DELETE_FAST = _op + op_DELETE_GLOBAL = _op + op_DELETE_NAME = _op + op_DELETE_SLICE = _op + op_DELETE_SUBSCR = _op + + def op_DUP_TOP (self, i, op, arg): + self.stack.append(self.stack[-1]) + + def op_DUP_TOPX (self, i, op, arg): + self.stack += self.stack[-arg:] + + #op_END_FINALLY = _op + op_EXEC_STMT = _op + #op_EXTENDED_ARG = _op + op_FOR_ITER = _op + op_GET_ITER = _op + op_IMPORT_FROM = _op + op_IMPORT_NAME = _op + op_IMPORT_STAR = _op + op_INPLACE_ADD = _op + op_INPLACE_AND = _op + op_INPLACE_DIVIDE = _op + op_INPLACE_FLOOR_DIVIDE = _op + op_INPLACE_LSHIFT = _op + op_INPLACE_MODULO = _op + op_INPLACE_MULTIPLY = _op + op_INPLACE_OR = _op + op_INPLACE_POWER = _op + op_INPLACE_RSHIFT = _op + op_INPLACE_SUBTRACT = _op + op_INPLACE_TRUE_DIVIDE = _op + op_INPLACE_XOR = _op + op_JUMP_ABSOLUTE = _op + op_JUMP_FORWARD = _op + op_JUMP_IF_FALSE = _op + op_JUMP_IF_TRUE = _op + op_LIST_APPEND = _op + op_LOAD_ATTR = _op + op_LOAD_CLOSURE = _op + op_LOAD_CONST = _op + op_LOAD_DEREF = _op + op_LOAD_FAST = _op + op_LOAD_GLOBAL = _op + op_LOAD_LOCALS = _op + op_LOAD_NAME = _op + op_MAKE_CLOSURE = _op + op_MAKE_FUNCTION = _op + op_NOP = _op + + def op_POP_BLOCK (self, i, op, arg): + self.loop_stack.pop() + return self._op(i, op, arg) + + op_POP_JUMP_IF_FALSE = _op + op_POP_JUMP_IF_TRUE = _op + op_POP_TOP = _op + op_PRINT_EXPR = _op + op_PRINT_ITEM = _op + op_PRINT_ITEM_TO = _op + op_PRINT_NEWLINE = _op + op_PRINT_NEWLINE_TO = _op + op_RAISE_VARARGS = _op + op_RETURN_VALUE = _op + + def op_ROT_FOUR (self, i, op, arg): + self.stack[-4:] = (self.stack[-1], self.stack[-4], self.stack[-3], + self.stack[-2]) + + def op_ROT_THREE (self, i, op, arg): + self.stack[-3:] = (self.stack[-1], self.stack[-3], self.stack[-2]) + + def op_ROT_TWO (self, i, op, arg): + self.stack[-2:] = (self.stack[-1], self.stack[-2]) + + #op_SETUP_EXCEPT = _op + #op_SETUP_FINALLY = _op + + def op_SETUP_LOOP (self, i, op, arg): + self.loop_stack.append((i, op, arg)) + self.block.append((i, op, self.opnames[op], arg, [])) + + op_SLICE = _op + #op_STOP_CODE = _op + op_STORE_ATTR = _op + op_STORE_DEREF = _op + op_STORE_FAST = _op + op_STORE_GLOBAL = _op + op_STORE_MAP = _op + op_STORE_NAME = _op + op_STORE_SLICE = _op + op_STORE_SUBSCR = _op + op_UNARY_CONVERT = _op + op_UNARY_INVERT = _op + op_UNARY_NEGATIVE = _op + op_UNARY_NOT = _op + op_UNARY_POSITIVE = _op + op_UNPACK_SEQUENCE = _op + #op_WITH_CLEANUP = _op + op_YIELD_VALUE = _op + +# ______________________________________________________________________ + +def build_flow (func): + return BytecodeFlowBuilder().visit(opcode_util.get_code_object(func)) + +# ______________________________________________________________________ +# Main (self-test) routine + +def main (*args): + import pprint + from tests import llfuncs + if not args: + args = ('doslice',) + for arg in args: + pprint.pprint(build_flow(getattr(llfuncs, arg))) + +# ______________________________________________________________________ + +if __name__ == '__main__': + import sys + main(*sys.argv[1:]) + +# ______________________________________________________________________ +# End of byte_flow.py diff --git a/byte_translator.py b/byte_translator.py new file mode 100644 index 0000000..7954970 --- /dev/null +++ b/byte_translator.py @@ -0,0 +1,525 @@ +#! /usr/bin/env python +# ______________________________________________________________________ +# Module imports + +import opcode + +import llvm.core as lc + +import opcode_util + +import bytetype +from bytecode_visitor import BytecodeFlowVisitor +from byte_flow import BytecodeFlowBuilder +from byte_control import ControlFlowBuilder +from phi_injector import PhiInjector, synthetic_opname + +# ______________________________________________________________________ +# Module data + +# XXX Stolen from numba.translate: + +_compare_mapping_float = {'>':lc.FCMP_OGT, + '<':lc.FCMP_OLT, + '==':lc.FCMP_OEQ, + '>=':lc.FCMP_OGE, + '<=':lc.FCMP_OLE, + '!=':lc.FCMP_ONE} + +_compare_mapping_sint = {'>':lc.ICMP_SGT, + '<':lc.ICMP_SLT, + '==':lc.ICMP_EQ, + '>=':lc.ICMP_SGE, + '<=':lc.ICMP_SLE, + '!=':lc.ICMP_NE} + +# XXX Stolen from numba.llvm_types: + +class LLVMCaster (object): + def build_pointer_cast(_, builder, lval1, lty2): + return builder.bitcast(lval1, lty2) + + def build_int_cast(_, builder, lval1, lty2, unsigned = False): + width1 = lval1.type.width + width2 = lty2.width + ret_val = lval1 + if width2 > width1: + if unsigned: + ret_val = builder.zext(lval1, lty2) + else: + ret_val = builder.sext(lval1, lty2) + elif width2 < width1: + ret_val = builder.trunc(lval1, lty2) + return ret_val + + def build_float_ext(_, builder, lval1, lty2): + return builder.fpext(lval1, lty2) + + def build_float_trunc(_, builder, lval1, lty2): + return builder.fptrunc(lval1, lty2) + + def build_int_to_float_cast(_, builder, lval1, lty2, unsigned = False): + ret_val = None + if unsigned: + ret_val = builder.uitofp(lval1, lty2) + else: + ret_val = builder.sitofp(lval1, lty2) + return ret_val + + def build_float_to_int_cast(_, builder, lval1, lty2, unsigned = False): + ret_val = None + if unsigned: + ret_val = builder.fptoui(lval1, lty2) + else: + ret_val = builder.fptosi(lval1, lty2) + return ret_val + + CAST_MAP = { + lc.TYPE_POINTER : build_pointer_cast, + lc.TYPE_INTEGER: build_int_cast, + (lc.TYPE_FLOAT, lc.TYPE_DOUBLE) : build_float_ext, + (lc.TYPE_DOUBLE, lc.TYPE_FLOAT) : build_float_trunc, + (lc.TYPE_INTEGER, lc.TYPE_FLOAT) : build_int_to_float_cast, + (lc.TYPE_INTEGER, lc.TYPE_DOUBLE) : build_int_to_float_cast, + (lc.TYPE_FLOAT, lc.TYPE_INTEGER) : build_float_to_int_cast, + (lc.TYPE_DOUBLE, lc.TYPE_INTEGER) : build_float_to_int_cast, + + } + + @classmethod + def build_cast(cls, builder, lval1, lty2, *args, **kws): + ret_val = lval1 + lty1 = lval1.type + lkind1 = lty1.kind + lkind2 = lty2.kind + + if lkind1 == lkind2: + + if lkind1 in cls.CAST_MAP: + ret_val = cls.CAST_MAP[lkind1](cls, builder, lval1, lty2, + *args, **kws) + else: + raise NotImplementedError(lkind1) + else: + map_index = (lkind1, lkind2) + if map_index in cls.CAST_MAP: + ret_val = cls.CAST_MAP[map_index](cls, builder, lval1, lty2, + *args, **kws) + else: + raise NotImplementedError(lkind1, lkind2) + return ret_val + +# ______________________________________________________________________ +# Class definitions + +class LLVMTranslator (BytecodeFlowVisitor): + def __init__ (self, llvm_module = None, *args, **kws): + super(LLVMTranslator, self).__init__(*args, **kws) + if llvm_module is None: + llvm_module = lc.Module.new('Translated_Module_%d' % (id(self),)) + self.llvm_module = llvm_module + self.bytecode_flow_builder = BytecodeFlowBuilder() + self.control_flow_builder = ControlFlowBuilder() + self.phi_injector = PhiInjector() + + def translate (self, function, llvm_type = None, env = None): + if llvm_type is None: + llvm_type = lc.Type.function(lvoid, ()) + if env is None: + env = {} + else: + env = env.copy() + env.update((name, method) + for name, method in lc.Builder.__dict__.items() + if not name.startswith('_')) + env.update((name, value) + for name, value in bytetype.__dict__.items() + if not name.startswith('_')) + self.loop_stack = [] + self.llvm_type = llvm_type + self.function = function + self.code_obj = opcode_util.get_code_object(function) + func_globals = getattr(function, 'func_globals', + getattr(function, '__globals__', {})).copy() + func_globals.update(env) + self.globals = func_globals + nargs = self.code_obj.co_argcount + self.cfg = self.control_flow_builder.visit( + self.bytecode_flow_builder.visit(self.code_obj), nargs) + flow = self.phi_injector.visit_cfg(self.cfg, nargs) + ret_val = self.visit(flow) + del self.cfg + del self.globals + del self.code_obj + del self.function + del self.llvm_type + del self.loop_stack + return ret_val + + def enter_flow_object (self, flow): + super(LLVMTranslator, self).enter_flow_object(flow) + self.llvm_function = self.llvm_module.add_function( + self.llvm_type, self.function.__name__) + self.llvm_blocks = {} + self.llvm_definitions = {} + self.pending_phis = {} + for block in self.block_list: + if 0 in self.cfg.blocks_reaching[block]: + bb = self.llvm_function.append_basic_block( + 'BLOCK_%d' % (block,)) + self.llvm_blocks[block] = bb + + def exit_flow_object (self, flow): + super(LLVMTranslator, self).exit_flow_object(flow) + ret_val = self.llvm_function + del self.pending_phis + del self.llvm_definitions + del self.llvm_blocks + del self.llvm_function + return ret_val + + def enter_block (self, block): + ret_val = False + if block in self.llvm_blocks: + self.llvm_block = self.llvm_blocks[block] + self.builder = lc.Builder.new(self.llvm_block) + ret_val = True + return ret_val + + def exit_block (self, block): + del self.llvm_block + del self.builder + + def visit_synthetic_op (self, i, op, arg, *args, **kws): + method = getattr(self, 'op_%s' % (synthetic_opname[op],)) + return method(i, op, arg, *args, **kws) + + def op_REF_ARG (self, i, op, arg, *args, **kws): + return [self.llvm_function.args[arg]] + + def op_BUILD_PHI (self, i, op, arg, *args, **kws): + phi_type = None + incoming = [] + pending = [] + for child_arg in arg: + child_block, _, child_opname, child_arg, _ = child_arg + assert child_opname == 'REF_DEF' + if child_arg in self.llvm_definitions: + child_def = self.llvm_definitions[child_arg] + if phi_type is None: + phi_type = child_def.type + incoming.append((child_block, child_def)) + else: + pending.append((child_arg, child_block)) + phi = self.builder.phi(phi_type) + for block_index, defn in incoming: + phi.add_incoming(defn, self.llvm_blocks[block_index]) + for defn_index, block_index in pending: + if defn_index not in self.pending_phis: + self.pending_phis[defn_index] = [] + self.pending_phis[defn_index].append((phi, block_index)) + return [phi] + + def op_DEFINITION (self, i, op, def_index, *args, **kws): + assert len(args) == 1 + arg = args[0] + if def_index in self.pending_phis: + for phi, block_index in self.pending_phis[def_index]: + phi.add_incoming(arg, self.llvm_blocks[block_index]) + self.llvm_definitions[def_index] = arg + return args + + def op_REF_DEF (self, i, op, arg, *args, **kws): + return [self.llvm_definitions[arg]] + + def op_BINARY_ADD (self, i, op, arg, *args, **kws): + arg1, arg2 = args + if arg1.type.kind == lc.TYPE_INTEGER: + ret_val = [self.builder.add(arg1, arg2)] + elif arg1.type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE): + ret_val = [self.builder.fadd(arg1, arg2)] + elif arg1.type.kind == lc.TYPE_POINTER: + ret_val = [self.builder.gep(arg1, [arg2])] + else: + raise NotImplementedError("LLVMTranslator.op_BINARY_ADD for %r" % + (args,)) + return ret_val + + def op_BINARY_AND (self, i, op, arg, *args, **kws): + return [self.builder.and_(args[0], args[1])] + + def op_BINARY_DIVIDE (self, i, op, arg, *args, **kws): + arg1, arg2 = args + if arg1.type.kind == lc.TYPE_INTEGER: + ret_val = [self.builder.sdiv(arg1, arg2)] + elif arg1.type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE): + ret_val = [self.builder.fdiv(arg1, arg2)] + else: + raise NotImplementedError("LLVMTranslator.op_BINARY_DIVIDE for %r" + % (args,)) + return ret_val + + def op_BINARY_FLOOR_DIVIDE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_BINARY_FLOOR_DIVIDE") + + def op_BINARY_LSHIFT (self, i, op, arg, *args, **kws): + return [self.builder.shl(args[0], args[1])] + + def op_BINARY_MODULO (self, i, op, arg, *args, **kws): + arg1, arg2 = args + if arg1.type.kind == lc.TYPE_INTEGER: + ret_val = [self.builder.srem(arg1, arg2)] + elif arg1.type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE): + ret_val = [self.builder.frem(arg1, arg2)] + else: + raise NotImplementedError("LLVMTranslator.op_BINARY_MODULO for %r" + % (args,)) + return ret_val + + def op_BINARY_MULTIPLY (self, i, op, arg, *args, **kws): + arg1, arg2 = args + if arg1.type.kind == lc.TYPE_INTEGER: + ret_val = [self.builder.mul(arg1, arg2)] + elif arg1.type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE): + ret_val = [self.builder.fmul(arg1, arg2)] + else: + raise NotImplementedError("LLVMTranslator.op_BINARY_MULTIPLY for " + "%r" % (args,)) + return ret_val + + def op_BINARY_OR (self, i, op, arg, *args, **kws): + return [self.builder.or_(args[0], args[1])] + + def op_BINARY_POWER (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_BINARY_POWER") + + def op_BINARY_RSHIFT (self, i, op, arg, *args, **kws): + return [self.builder.lshr(args[0], args[1])] + + def op_BINARY_SUBSCR (self, i, op, arg, *args, **kws): + arr_val = args[0] + index_vals = args[1:] + ret_val = gep_result = self.builder.gep(arr_val, index_vals) + if (gep_result.type.kind == lc.TYPE_POINTER and + gep_result.type.pointee.kind != lc.TYPE_POINTER): + ret_val = self.builder.load(gep_result) + return [ret_val] + + def op_BINARY_SUBTRACT (self, i, op, arg, *args, **kws): + arg1, arg2 = args + if arg1.type.kind == lc.TYPE_INTEGER: + ret_val = [self.builder.sub(arg1, arg2)] + elif arg1.type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE): + ret_val = [self.builder.fsub(arg1, arg2)] + else: + raise NotImplementedError("LLVMTranslator.op_BINARY_SUBTRACT for " + "%r" % (args,)) + return ret_val + + op_BINARY_TRUE_DIVIDE = op_BINARY_DIVIDE + + def op_BINARY_XOR (self, i, op, arg, *args, **kws): + return [self.builder.xor(args[0], args[1])] + + def op_BREAK_LOOP (self, i, op, arg, *args, **kws): + return [self.builder.branch(self.llvm_blocks[arg])] + + def op_BUILD_SLICE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_BUILD_SLICE") + + def op_BUILD_TUPLE (self, i, op, arg, *args, **kws): + return args + + def op_CALL_FUNCTION (self, i, op, arg, *args, **kws): + fn = args[0] + args = args[1:] + if isinstance(fn, lc.Type): + if isinstance(fn, lc.FunctionType): + ret_val = [self.builder.call( + self.llvm_module.get_or_insert_function(fn, fn.__name__), + args)] + else: + assert len(args) == 1 + ret_val = [LLVMCaster.build_cast(self.builder, args[0], fn)] + elif fn.__name__ in lc.Builder.__dict__: + ret_val = [fn(self.builder, *args)] + else: + raise NotImplementedError("Don't know how to call %r!" % (fn,)) + return ret_val + + def op_CALL_FUNCTION_KW (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_CALL_FUNCTION_KW") + + def op_CALL_FUNCTION_VAR (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_CALL_FUNCTION_VAR") + + def op_CALL_FUNCTION_VAR_KW (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_CALL_FUNCTION_VAR_KW") + + def op_COMPARE_OP (self, i, op, arg, *args, **kws): + arg1, arg2 = args + cmp_kind = opcode.cmp_op[arg] + if isinstance(arg1.type, lc.IntegerType): + ret_val = [self.builder.icmp(_compare_mapping_sint[cmp_kind], + arg1, arg2)] + elif arg1.type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE): + ret_val = [self.builder.fcmp(_compare_mapping_float[cmp_kind], + arg1, arg2)] + else: + raise NotImplementedError('Comparison of type %r' % (arg1.type,)) + return ret_val + + def op_CONTINUE_LOOP (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_CONTINUE_LOOP") + + def op_DELETE_ATTR (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_DELETE_ATTR") + + def op_DELETE_SLICE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_DELETE_SLICE") + + def op_FOR_ITER (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_FOR_ITER") + + def op_GET_ITER (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_GET_ITER") + + op_INPLACE_ADD = op_BINARY_ADD + op_INPLACE_AND = op_BINARY_AND + op_INPLACE_DIVIDE = op_BINARY_DIVIDE + op_INPLACE_FLOOR_DIVIDE = op_BINARY_FLOOR_DIVIDE + op_INPLACE_LSHIFT = op_BINARY_LSHIFT + op_INPLACE_MODULO = op_BINARY_MODULO + op_INPLACE_MULTIPLY = op_BINARY_MULTIPLY + op_INPLACE_OR = op_BINARY_OR + op_INPLACE_POWER = op_BINARY_POWER + op_INPLACE_RSHIFT = op_BINARY_RSHIFT + op_INPLACE_SUBTRACT = op_BINARY_SUBTRACT + op_INPLACE_TRUE_DIVIDE = op_BINARY_TRUE_DIVIDE + op_INPLACE_XOR = op_BINARY_XOR + + def op_JUMP_ABSOLUTE (self, i, op, arg, *args, **kws): + return [self.builder.branch(self.llvm_blocks[arg])] + + def op_JUMP_FORWARD (self, i, op, arg, *args, **kws): + return [self.builder.branch(self.llvm_blocks[i + arg + 3])] + + def op_JUMP_IF_FALSE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_JUMP_IF_FALSE") + + def op_JUMP_IF_FALSE_OR_POP (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_JUMP_IF_FALSE_OR_POP") + + def op_JUMP_IF_TRUE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_JUMP_IF_TRUE") + + def op_JUMP_IF_TRUE_OR_POP (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_JUMP_IF_TRUE_OR_POP") + + def op_LOAD_ATTR (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_LOAD_ATTR") + + def op_LOAD_CONST (self, i, op, arg, *args, **kws): + py_val = self.code_obj.co_consts[arg] + if isinstance(py_val, int): + ret_val = [lc.Constant.int(bytetype.lc_int, py_val)] + elif isinstance(py_val, float): + ret_val = [lc.Constant.double(py_val)] + elif py_val == None: + ret_val = [None] + else: + raise NotImplementedError('Constant converstion for %r' % + (py_val,)) + return ret_val + + def op_LOAD_GLOBAL (self, i, op, arg, *args, **kws): + ret_val = self.globals[self.code_obj.co_names[arg]] + if not hasattr(ret_val, '__name__'): + ret_val.__name__ = self.code_obj.co_names[arg] + return [ret_val] + + def op_POP_BLOCK (self, i, op, arg, *args, **kws): + self.loop_stack.pop() + return [self.builder.branch(self.llvm_blocks[i + 1])] + + def op_POP_JUMP_IF_FALSE (self, i, op, arg, *args, **kws): + return [self.builder.cbranch(args[0], self.llvm_blocks[i + 3], + self.llvm_blocks[arg])] + + def op_POP_JUMP_IF_TRUE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_POP_JUMP_IF_TRUE") + + def op_POP_TOP (self, i, op, arg, *args, **kws): + return args + + def op_RETURN_VALUE (self, i, op, arg, *args, **kws): + if args[0] is None: + ret_val = [self.builder.ret_void()] + else: + ret_val = [self.builder.ret(args[0])] + return ret_val + + def op_SETUP_LOOP (self, i, op, arg, *args, **kws): + self.loop_stack.append((i, arg)) + return [self.builder.branch(self.llvm_blocks[i + 3])] + + def op_SLICE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_SLICE") + + def op_STORE_ATTR (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_STORE_ATTR") + + def op_STORE_SLICE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_STORE_SLICE") + + def op_STORE_SUBSCR (self, i, op, arg, *args, **kws): + store_val, arr_val, index_val = args + dest_addr = self.builder.gep(arr_val, [index_val]) + return [self.builder.store(store_val, dest_addr)] + + def op_UNARY_CONVERT (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_UNARY_CONVERT") + + def op_UNARY_INVERT (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_UNARY_INVERT") + + def op_UNARY_NEGATIVE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_UNARY_NEGATIVE") + + def op_UNARY_NOT (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_UNARY_NOT") + + def op_UNARY_POSITIVE (self, i, op, arg, *args, **kws): + raise NotImplementedError("LLVMTranslator.op_UNARY_POSITIVE") + +# ______________________________________________________________________ + +def translate_function (func, lltype, llvm_module = None, **kws): + translator = LLVMTranslator(llvm_module) + translator.translate(func, lltype, kws) + return translator + +# ______________________________________________________________________ +# Main (self-test) routine + +def main (*args): + from tests import llfuncs, llfunctys + if not args: + args = ('doslice',) + elif 'all' in args: + args = [llfunc + for llfunc in dir(llfuncs) if not llfunc.startswith('_')] + llvm_module = lc.Module.new('test_module') + for arg in args: + translate_function(getattr(llfuncs, arg), getattr(llfunctys, arg), + llvm_module) + print(llvm_module) + +# ______________________________________________________________________ + +if __name__ == '__main__': + import sys + main(*sys.argv[1:]) + +# ______________________________________________________________________ +# End of byte_translator.py diff --git a/bytecode_visitor.py b/bytecode_visitor.py new file mode 100644 index 0000000..6048ba8 --- /dev/null +++ b/bytecode_visitor.py @@ -0,0 +1,566 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +import itertools + +import opcode +from opcode_util import itercode + +# ______________________________________________________________________ + +class BytecodeVisitor (object): + opnames = [name.split('+')[0] for name in opcode.opname] + + def visit_op (self, i, op, arg, *args, **kws): + if op < 0: + ret_val = self.visit_synthetic_op(i, op, arg, *args, **kws) + else: + method = getattr(self, 'op_' + self.opnames[op]) + ret_val = method(i, op, arg, *args, **kws) + return ret_val + + def visit_synthetic_op (self, i, op, arg, *args, **kws): + raise NotImplementedError( + 'BytecodeVisitor.visit_synthetic_op() must be overloaded if using ' + 'synthetic opcodes.') + + def op_BINARY_ADD (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_ADD") + + def op_BINARY_AND (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_AND") + + def op_BINARY_DIVIDE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_DIVIDE") + + def op_BINARY_FLOOR_DIVIDE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_FLOOR_DIVIDE") + + def op_BINARY_LSHIFT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_LSHIFT") + + def op_BINARY_MODULO (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_MODULO") + + def op_BINARY_MULTIPLY (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_MULTIPLY") + + def op_BINARY_OR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_OR") + + def op_BINARY_POWER (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_POWER") + + def op_BINARY_RSHIFT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_RSHIFT") + + def op_BINARY_SUBSCR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_SUBSCR") + + def op_BINARY_SUBTRACT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_SUBTRACT") + + def op_BINARY_TRUE_DIVIDE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_TRUE_DIVIDE") + + def op_BINARY_XOR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BINARY_XOR") + + def op_BREAK_LOOP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BREAK_LOOP") + + def op_BUILD_CLASS (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BUILD_CLASS") + + def op_BUILD_LIST (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BUILD_LIST") + + def op_BUILD_MAP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BUILD_MAP") + + def op_BUILD_SET (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BUILD_SET") + + def op_BUILD_SLICE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BUILD_SLICE") + + def op_BUILD_TUPLE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_BUILD_TUPLE") + + def op_CALL_FUNCTION (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_CALL_FUNCTION") + + def op_CALL_FUNCTION_KW (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_CALL_FUNCTION_KW") + + def op_CALL_FUNCTION_VAR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_CALL_FUNCTION_VAR") + + def op_CALL_FUNCTION_VAR_KW (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_CALL_FUNCTION_VAR_KW") + + def op_COMPARE_OP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_COMPARE_OP") + + def op_CONTINUE_LOOP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_CONTINUE_LOOP") + + def op_DELETE_ATTR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_DELETE_ATTR") + + def op_DELETE_DEREF (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_DELETE_DEREF") + + def op_DELETE_FAST (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_DELETE_FAST") + + def op_DELETE_GLOBAL (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_DELETE_GLOBAL") + + def op_DELETE_NAME (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_DELETE_NAME") + + def op_DELETE_SLICE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_DELETE_SLICE") + + def op_DELETE_SUBSCR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_DELETE_SUBSCR") + + def op_DUP_TOP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_DUP_TOP") + + def op_DUP_TOPX (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_DUP_TOPX") + + def op_DUP_TOP_TWO (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_DUP_TOP_TWO") + + def op_END_FINALLY (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_END_FINALLY") + + def op_EXEC_STMT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_EXEC_STMT") + + def op_EXTENDED_ARG (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_EXTENDED_ARG") + + def op_FOR_ITER (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_FOR_ITER") + + def op_GET_ITER (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_GET_ITER") + + def op_IMPORT_FROM (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_IMPORT_FROM") + + def op_IMPORT_NAME (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_IMPORT_NAME") + + def op_IMPORT_STAR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_IMPORT_STAR") + + def op_INPLACE_ADD (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_ADD") + + def op_INPLACE_AND (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_AND") + + def op_INPLACE_DIVIDE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_DIVIDE") + + def op_INPLACE_FLOOR_DIVIDE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_FLOOR_DIVIDE") + + def op_INPLACE_LSHIFT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_LSHIFT") + + def op_INPLACE_MODULO (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_MODULO") + + def op_INPLACE_MULTIPLY (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_MULTIPLY") + + def op_INPLACE_OR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_OR") + + def op_INPLACE_POWER (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_POWER") + + def op_INPLACE_RSHIFT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_RSHIFT") + + def op_INPLACE_SUBTRACT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_SUBTRACT") + + def op_INPLACE_TRUE_DIVIDE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_TRUE_DIVIDE") + + def op_INPLACE_XOR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_INPLACE_XOR") + + def op_JUMP_ABSOLUTE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_JUMP_ABSOLUTE") + + def op_JUMP_FORWARD (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_JUMP_FORWARD") + + def op_JUMP_IF_FALSE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_JUMP_IF_FALSE") + + def op_JUMP_IF_FALSE_OR_POP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_JUMP_IF_FALSE_OR_POP") + + def op_JUMP_IF_TRUE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_JUMP_IF_TRUE") + + def op_JUMP_IF_TRUE_OR_POP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_JUMP_IF_TRUE_OR_POP") + + def op_LIST_APPEND (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_LIST_APPEND") + + def op_LOAD_ATTR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_LOAD_ATTR") + + def op_LOAD_BUILD_CLASS (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_LOAD_BUILD_CLASS") + + def op_LOAD_CLOSURE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_LOAD_CLOSURE") + + def op_LOAD_CONST (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_LOAD_CONST") + + def op_LOAD_DEREF (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_LOAD_DEREF") + + def op_LOAD_FAST (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_LOAD_FAST") + + def op_LOAD_GLOBAL (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_LOAD_GLOBAL") + + def op_LOAD_LOCALS (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_LOAD_LOCALS") + + def op_LOAD_NAME (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_LOAD_NAME") + + def op_MAKE_CLOSURE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_MAKE_CLOSURE") + + def op_MAKE_FUNCTION (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_MAKE_FUNCTION") + + def op_MAP_ADD (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_MAP_ADD") + + def op_NOP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_NOP") + + def op_POP_BLOCK (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_POP_BLOCK") + + def op_POP_EXCEPT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_POP_EXCEPT") + + def op_POP_JUMP_IF_FALSE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_POP_JUMP_IF_FALSE") + + def op_POP_JUMP_IF_TRUE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_POP_JUMP_IF_TRUE") + + def op_POP_TOP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_POP_TOP") + + def op_PRINT_EXPR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_PRINT_EXPR") + + def op_PRINT_ITEM (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_PRINT_ITEM") + + def op_PRINT_ITEM_TO (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_PRINT_ITEM_TO") + + def op_PRINT_NEWLINE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_PRINT_NEWLINE") + + def op_PRINT_NEWLINE_TO (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_PRINT_NEWLINE_TO") + + def op_RAISE_VARARGS (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_RAISE_VARARGS") + + def op_RETURN_VALUE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_RETURN_VALUE") + + def op_ROT_FOUR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_ROT_FOUR") + + def op_ROT_THREE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_ROT_THREE") + + def op_ROT_TWO (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_ROT_TWO") + + def op_SETUP_EXCEPT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_SETUP_EXCEPT") + + def op_SETUP_FINALLY (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_SETUP_FINALLY") + + def op_SETUP_LOOP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_SETUP_LOOP") + + def op_SETUP_WITH (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_SETUP_WITH") + + def op_SET_ADD (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_SET_ADD") + + def op_SLICE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_SLICE") + + def op_STOP_CODE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_STOP_CODE") + + def op_STORE_ATTR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_STORE_ATTR") + + def op_STORE_DEREF (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_STORE_DEREF") + + def op_STORE_FAST (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_STORE_FAST") + + def op_STORE_GLOBAL (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_STORE_GLOBAL") + + def op_STORE_LOCALS (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_STORE_LOCALS") + + def op_STORE_MAP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_STORE_MAP") + + def op_STORE_NAME (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_STORE_NAME") + + def op_STORE_SLICE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_STORE_SLICE") + + def op_STORE_SUBSCR (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_STORE_SUBSCR") + + def op_UNARY_CONVERT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_UNARY_CONVERT") + + def op_UNARY_INVERT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_UNARY_INVERT") + + def op_UNARY_NEGATIVE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_UNARY_NEGATIVE") + + def op_UNARY_NOT (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_UNARY_NOT") + + def op_UNARY_POSITIVE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_UNARY_POSITIVE") + + def op_UNPACK_EX (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_UNPACK_EX") + + def op_UNPACK_SEQUENCE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_UNPACK_SEQUENCE") + + def op_WITH_CLEANUP (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_WITH_CLEANUP") + + def op_YIELD_VALUE (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_YIELD_VALUE") + +# ______________________________________________________________________ + +class BytecodeIterVisitor (BytecodeVisitor): + def visit (self, co_obj): + self.enter_code_object(co_obj) + for i, op, arg in itercode(co_obj.co_code): + self.visit_op(i, op, arg) + return self.exit_code_object(co_obj) + + def enter_code_object (self, co_obj): + pass + + def exit_code_object (self, co_obj): + pass + +# ______________________________________________________________________ + +class BytecodeFlowVisitor (BytecodeVisitor): + def visit (self, flow): + self.block_list = list(flow.keys()) + self.block_list.sort() + self.enter_flow_object(flow) + for block in self.block_list: + prelude = self.enter_block(block) + prelude_isa_list = isinstance(prelude, list) + if prelude or prelude_isa_list: + if not prelude_isa_list: + prelude = [] + new_stmts = list(self.visit_op(i, op, arg, *args) + for i, op, _, arg, args in flow[block]) + self.new_flow[block] = list(itertools.chain( + prelude, *new_stmts)) + self.exit_block(block) + del self.block_list + return self.exit_flow_object(flow) + + def visit_op (self, i, op, arg, *args, **kws): + new_args = [] + for child_i, child_op, _, child_arg, child_args in args: + new_args.extend(self.visit_op(child_i, child_op, child_arg, + *child_args)) + ret_val = super(BytecodeFlowVisitor, self).visit_op(i, op, arg, + *new_args) + return ret_val + + def enter_flow_object (self, flow): + self.new_flow = {} + + def exit_flow_object (self, flow): + ret_val = self.new_flow + del self.new_flow + return ret_val + + def enter_block (self, block): + pass + + def exit_block (self, block): + pass + +# ______________________________________________________________________ + +class BenignBytecodeVisitorMixin (object): + def _do_nothing (self, i, op, arg, *args, **kws): + return [(i, op, self.opnames[op], arg, args)] + + op_BINARY_ADD = _do_nothing + op_BINARY_AND = _do_nothing + op_BINARY_DIVIDE = _do_nothing + op_BINARY_FLOOR_DIVIDE = _do_nothing + op_BINARY_LSHIFT = _do_nothing + op_BINARY_MODULO = _do_nothing + op_BINARY_MULTIPLY = _do_nothing + op_BINARY_OR = _do_nothing + op_BINARY_POWER = _do_nothing + op_BINARY_RSHIFT = _do_nothing + op_BINARY_SUBSCR = _do_nothing + op_BINARY_SUBTRACT = _do_nothing + op_BINARY_TRUE_DIVIDE = _do_nothing + op_BINARY_XOR = _do_nothing + op_BREAK_LOOP = _do_nothing + op_BUILD_CLASS = _do_nothing + op_BUILD_LIST = _do_nothing + op_BUILD_MAP = _do_nothing + op_BUILD_SET = _do_nothing + op_BUILD_SLICE = _do_nothing + op_BUILD_TUPLE = _do_nothing + op_CALL_FUNCTION = _do_nothing + op_CALL_FUNCTION_KW = _do_nothing + op_CALL_FUNCTION_VAR = _do_nothing + op_CALL_FUNCTION_VAR_KW = _do_nothing + op_COMPARE_OP = _do_nothing + op_CONTINUE_LOOP = _do_nothing + op_DELETE_ATTR = _do_nothing + op_DELETE_DEREF = _do_nothing + op_DELETE_FAST = _do_nothing + op_DELETE_GLOBAL = _do_nothing + op_DELETE_NAME = _do_nothing + op_DELETE_SLICE = _do_nothing + op_DELETE_SUBSCR = _do_nothing + op_DUP_TOP = _do_nothing + op_DUP_TOPX = _do_nothing + op_DUP_TOP_TWO = _do_nothing + op_END_FINALLY = _do_nothing + op_EXEC_STMT = _do_nothing + op_EXTENDED_ARG = _do_nothing + op_FOR_ITER = _do_nothing + op_GET_ITER = _do_nothing + op_IMPORT_FROM = _do_nothing + op_IMPORT_NAME = _do_nothing + op_IMPORT_STAR = _do_nothing + op_INPLACE_ADD = _do_nothing + op_INPLACE_AND = _do_nothing + op_INPLACE_DIVIDE = _do_nothing + op_INPLACE_FLOOR_DIVIDE = _do_nothing + op_INPLACE_LSHIFT = _do_nothing + op_INPLACE_MODULO = _do_nothing + op_INPLACE_MULTIPLY = _do_nothing + op_INPLACE_OR = _do_nothing + op_INPLACE_POWER = _do_nothing + op_INPLACE_RSHIFT = _do_nothing + op_INPLACE_SUBTRACT = _do_nothing + op_INPLACE_TRUE_DIVIDE = _do_nothing + op_INPLACE_XOR = _do_nothing + op_JUMP_ABSOLUTE = _do_nothing + op_JUMP_FORWARD = _do_nothing + op_JUMP_IF_FALSE = _do_nothing + op_JUMP_IF_FALSE_OR_POP = _do_nothing + op_JUMP_IF_TRUE = _do_nothing + op_JUMP_IF_TRUE_OR_POP = _do_nothing + op_LIST_APPEND = _do_nothing + op_LOAD_ATTR = _do_nothing + op_LOAD_BUILD_CLASS = _do_nothing + op_LOAD_CLOSURE = _do_nothing + op_LOAD_CONST = _do_nothing + op_LOAD_DEREF = _do_nothing + op_LOAD_FAST = _do_nothing + op_LOAD_GLOBAL = _do_nothing + op_LOAD_LOCALS = _do_nothing + op_LOAD_NAME = _do_nothing + op_MAKE_CLOSURE = _do_nothing + op_MAKE_FUNCTION = _do_nothing + op_MAP_ADD = _do_nothing + op_NOP = _do_nothing + op_POP_BLOCK = _do_nothing + op_POP_EXCEPT = _do_nothing + op_POP_JUMP_IF_FALSE = _do_nothing + op_POP_JUMP_IF_TRUE = _do_nothing + op_POP_TOP = _do_nothing + op_PRINT_EXPR = _do_nothing + op_PRINT_ITEM = _do_nothing + op_PRINT_ITEM_TO = _do_nothing + op_PRINT_NEWLINE = _do_nothing + op_PRINT_NEWLINE_TO = _do_nothing + op_RAISE_VARARGS = _do_nothing + op_RETURN_VALUE = _do_nothing + op_ROT_FOUR = _do_nothing + op_ROT_THREE = _do_nothing + op_ROT_TWO = _do_nothing + op_SETUP_EXCEPT = _do_nothing + op_SETUP_FINALLY = _do_nothing + op_SETUP_LOOP = _do_nothing + op_SETUP_WITH = _do_nothing + op_SET_ADD = _do_nothing + op_SLICE = _do_nothing + op_STOP_CODE = _do_nothing + op_STORE_ATTR = _do_nothing + op_STORE_DEREF = _do_nothing + op_STORE_FAST = _do_nothing + op_STORE_GLOBAL = _do_nothing + op_STORE_LOCALS = _do_nothing + op_STORE_MAP = _do_nothing + op_STORE_NAME = _do_nothing + op_STORE_SLICE = _do_nothing + op_STORE_SUBSCR = _do_nothing + op_UNARY_CONVERT = _do_nothing + op_UNARY_INVERT = _do_nothing + op_UNARY_NEGATIVE = _do_nothing + op_UNARY_NOT = _do_nothing + op_UNARY_POSITIVE = _do_nothing + op_UNPACK_EX = _do_nothing + op_UNPACK_SEQUENCE = _do_nothing + op_WITH_CLEANUP = _do_nothing + op_YIELD_VALUE = _do_nothing + +# ______________________________________________________________________ +# End of bytecode_visitor.py diff --git a/bytetype.py b/bytetype.py new file mode 100644 index 0000000..25a0355 --- /dev/null +++ b/bytetype.py @@ -0,0 +1,41 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +import ctypes + +import llvm.core as lc + +# ______________________________________________________________________ + +lvoid = lc.Type.void() +li1 = lc.Type.int(1) +li8 = lc.Type.int(8) +li16 = lc.Type.int(16) +li32 = lc.Type.int(32) +li64 = lc.Type.int(64) +lc_size_t = lc.Type.int(ctypes.sizeof( + getattr(ctypes, 'c_ssize_t', getattr(ctypes, 'c_size_t'))) * 8) +lfloat = lc.Type.float() +ldouble = lc.Type.double() +li8_ptr = lc.Type.pointer(li8) + +lc_int = lc.Type.int(ctypes.sizeof(ctypes.c_int) * 8) +lc_long = lc.Type.int(ctypes.sizeof(ctypes.c_long) * 8) + +l_pyobject_head = [lc_size_t, lc.Type.pointer(li32)] +l_pyobject_head_struct = lc.Type.struct(l_pyobject_head) +l_pyobj_p = l_pyobject_head_struct_p = lc.Type.pointer(l_pyobject_head_struct) + +strlen = lc.Type.function(lc_size_t, (li8_ptr,)) +strncpy = lc.Type.function(li8_ptr, (li8_ptr, li8_ptr, lc_size_t)) +strndup = lc.Type.function(li8_ptr, (li8_ptr, lc_size_t)) +malloc = lc.Type.function(li8_ptr, (lc_size_t,)) +free = lc.Type.function(lvoid, (li8_ptr,)) + +Py_BuildValue = lc.Type.function(l_pyobj_p, [li8_ptr], True) +PyArg_ParseTuple = lc.Type.function(lc_int, [l_pyobj_p, li8_ptr], True) +PyEval_SaveThread = lc.Type.function(li8_ptr, []) +PyEval_RestoreThread = lc.Type.function(lc.Type.void(), [li8_ptr]) + +# ______________________________________________________________________ +# End of bytetype.py diff --git a/control_flow.py b/control_flow.py new file mode 100644 index 0000000..5ea030a --- /dev/null +++ b/control_flow.py @@ -0,0 +1,218 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +import pprint + +# ______________________________________________________________________ + +class ControlFlowGraph (object): + def __init__ (self): + self.blocks = {} + self.blocks_in = {} + self.blocks_out = {} + self.blocks_reads = {} + self.blocks_writes = {} + self.blocks_writer = {} + self.blocks_dom = {} + self.blocks_reaching = {} + + def add_block (self, key, value = None): + self.blocks[key] = value + if key not in self.blocks_in: + self.blocks_in[key] = set() + self.blocks_out[key] = set() + self.blocks_reads[key] = set() + self.blocks_writes[key] = set() + self.blocks_writer[key] = {} + + def add_edge (self, from_block, to_block): + self.blocks_out[from_block].add(to_block) + self.blocks_in[to_block].add(from_block) + + def unlink_unreachables (self): + changed = True + next_blocks = self.blocks.keys() + next_blocks.remove(0) + while changed: + changed = False + blocks = next_blocks + next_blocks = blocks[:] + for block in blocks: + if len(self.blocks_in[block]) == 0: + blocks_out = self.blocks_out[block] + for out_edge in blocks_out: + self.blocks_in[out_edge].discard(block) + blocks_out.clear() + next_blocks.remove(block) + changed = True + + def compute_dataflow (self): + '''Compute the dominator and reaching dataflow relationships + in the CFG.''' + blocks = set(self.blocks.keys()) + nonentry_blocks = blocks.copy() + for block in blocks: + self.blocks_dom[block] = blocks + self.blocks_reaching[block] = set((block,)) + if len(self.blocks_in[block]) == 0: + self.blocks_dom[block] = set((block,)) + nonentry_blocks.remove(block) + changed = True + while changed: + changed = False + for block in nonentry_blocks: + olddom = self.blocks_dom[block] + newdom = set.intersection(*[self.blocks_dom[pred] + for pred in self.blocks_in[block]]) + newdom.add(block) + if newdom != olddom: + changed = True + self.blocks_dom[block] = newdom + oldreaching = self.blocks_reaching[block] + newreaching = set.union( + *[self.blocks_reaching[pred] + for pred in self.blocks_in[block]]) + newreaching.add(block) + if newreaching != oldreaching: + changed = True + self.blocks_reaching[block] = newreaching + return self.blocks_dom, self.blocks_reaching + + def update_for_ssa (self): + '''Modify the blocks_writes map to reflect phi nodes inserted + for static single assignment representations.''' + joins = [block for block in self.blocks.keys() + if len(self.blocks_in[block]) > 1] + changed = True + while changed: + changed = False + for block in joins: + phis_needed = self.phi_needed(block) + for affected_local in phis_needed: + if affected_local not in self.blocks_writes[block]: + changed = True + # NOTE: For this to work, we assume that basic + # blocks are indexed by their instruction + # index in the VM bytecode. + self.writes_local(block, block, affected_local) + if changed: + # Any modifications have invalidated the reaching + # definitions, so delete any memoized results. + if hasattr(self, 'reaching_definitions'): + del self.reaching_definitions + + def idom (self, block): + '''Compute the immediate dominator (idom) of the given block + key. Returns None if the block has no in edges. + + Note that in the case where there are multiple immediate + dominators (a join after a non-loop branch), this returns one + of the predecessors, but is not guaranteed to reliably select + one over the others (depends on the ordering of the set type + iterator).''' + preds = self.blocks_in[block] + npreds = len(preds) + if npreds == 0: + ret_val = None + elif npreds == 1: + ret_val = tuple(preds)[0] + else: + ret_val = [pred for pred in preds + if block not in self.blocks_dom[pred]][0] + return ret_val + + def block_writes_to_writer_map (self, block): + ret_val = {} + for local in self.blocks_writes[block]: + ret_val[local] = block + return ret_val + + def get_reaching_definitions (self, block): + '''Return a nested map for the given block + s.t. ret_val[pred][local] equals the block key for the + definition of local that reaches the argument block via that + predecessor. + + Useful for actually populating phi nodes, once you know you + need them.''' + has_memoized = hasattr(self, 'reaching_definitions') + if has_memoized and block in self.reaching_definitions: + ret_val = self.reaching_definitions[block] + else: + preds = self.blocks_in[block] + ret_val = {} + for pred in preds: + ret_val[pred] = self.block_writes_to_writer_map(pred) + crnt = self.idom(pred) + while crnt != None: + crnt_writer_map = self.block_writes_to_writer_map(crnt) + # This order of update favors the first definitions + # encountered in the traversal since the traversal + # visits blocks in reverse execution order. + crnt_writer_map.update(ret_val[pred]) + ret_val[pred] = crnt_writer_map + crnt = self.idom(crnt) + if not has_memoized: + self.reaching_definitions = {} + self.reaching_definitions[block] = ret_val + return ret_val + + def nreaches (self, block): + '''For each local, find the number of unique reaching + definitions the current block has.''' + reaching_definitions = self.get_reaching_definitions(block) + definition_map = {} + for pred in self.blocks_in[block]: + reaching_from_pred = reaching_definitions[pred] + for local in reaching_from_pred.keys(): + if local not in definition_map: + definition_map[local] = set() + definition_map[local].add(reaching_from_pred[local]) + ret_val = {} + for local in definition_map.keys(): + ret_val[local] = len(definition_map[local]) + return ret_val + + def writes_local (self, block, write_instr_index, local_index): + self.blocks_writes[block].add(local_index) + block_writers = self.blocks_writer[block] + old_index = block_writers.get(local_index, -1) + # This checks for a corner case that would impact + # numba.translate.Translate.build_phi_nodes(). + assert old_index != write_instr_index, ( + "Found corner case for STORE_FAST at a CFG join!") + block_writers[local_index] = max(write_instr_index, old_index) + + def phi_needed (self, join): + '''Return the set of locals that will require a phi node to be + generated at the given join.''' + nreaches = self.nreaches(join) + return set([local for local in nreaches.keys() + if nreaches[local] > 1]) + + def pprint (self, *args, **kws): + pprint.pprint(self.__dict__, *args, **kws) + + def pformat (self, *args, **kws): + return pprint.pformat(self.__dict__, *args, **kws) + + def to_dot (self, graph_name = None): + '''Return a dot (digraph visualizer in Graphviz) graph + description as a string.''' + if graph_name is None: + graph_name = 'CFG_%d' % id(self) + lines_out = [] + for block_index in self.blocks: + lines_out.append( + 'BLOCK_%r [shape=box, label="BLOCK_%r\\nr: %r, w: %r"];' % + (block_index, block_index, + tuple(self.blocks_reads[block_index]), + tuple(self.blocks_writes[block_index]))) + for block_index in self.blocks: + for out_edge in self.blocks_out[block_index]: + lines_out.append('BLOCK_%r -> BLOCK_%r;' % + (block_index, out_edge)) + return 'digraph %s {\n%s\n}\n' % (graph_name, '\n'.join(lines_out)) + +# ______________________________________________________________________ +# End of control_flow.py diff --git a/gen_bytecode_visitor.py b/gen_bytecode_visitor.py new file mode 100644 index 0000000..7f922e2 --- /dev/null +++ b/gen_bytecode_visitor.py @@ -0,0 +1,27 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +import opcode_util + +# ______________________________________________________________________ + +def generate_bytecode_visitor (classname = 'BytecodeVisitor', + baseclass = 'object'): + opnames = list(set((opname.split('+')[0] + for opname in opcode_util.OPCODE_MAP.keys()))) + opnames.sort() + return 'class %s (%s):\n%s\n' % ( + classname, baseclass, + '\n\n'.join((' def op_%s (self, i, op, arg):\n' + ' raise NotImplementedError("%s.op_%s")' % + (opname, classname, opname) + for opname in opnames))) + +# ______________________________________________________________________ + +if __name__ == "__main__": + import sys + print(generate_bytecode_visitor(*sys.argv[1:])) + +# ______________________________________________________________________ +# End of gen_bytecode_visitor.py diff --git a/nobitey.py b/nobitey.py new file mode 100644 index 0000000..bca491e --- /dev/null +++ b/nobitey.py @@ -0,0 +1,366 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +import sys +import os.path +import imp +import io +import types + +import llvm.core as lc +import llvm.ee as le + +import bytetype + +from pyaddfunc import pyaddfunc + +LLVM_TO_INT_PARSE_STR_MAP = { + 8 : 'b', + 16 : 'h', + 32 : 'i', # Note that on 32-bit systems sizeof(int) == sizeof(long) + 64 : 'L', # Seeing sizeof(long long) == 8 on both 32 and 64-bit platforms +} + +LLVM_TO_PARSE_STR_MAP = { + lc.TYPE_FLOAT : 'f', + lc.TYPE_DOUBLE : 'd', +} + +# ______________________________________________________________________ + +# XXX Stolen from numba.translate + +def get_string_constant (module, const_str): + const_name = "__STR_%x" % (hash(const_str),) + try: + ret_val = module.get_global_variable_named(const_name) + except: + lconst_str = lc.Constant.stringz(const_str) + ret_val = module.add_global_variable(lconst_str.type, const_name) + ret_val.initializer = lconst_str + ret_val.linkage = lc.LINKAGE_INTERNAL + return ret_val + +# ______________________________________________________________________ + +class NoBitey (object): + def __init__ (self, target_module = None, type_annotations = None): + if target_module is None: + target_module = lc.Module.new('NoBitey_%d' % id(self)) + if type_annotations is None: + type_annotations = {} + self.target_module = target_module + self.type_aliases = type_annotations # Reserved for future use. + + def _build_parse_string (self, llvm_type): + kind = llvm_type.kind + if kind == lc.TYPE_INTEGER: + ret_val = LLVM_TO_INT_PARSE_STR_MAP[llvm_type.width] + elif kind in LLVM_TO_PARSE_STR_MAP: + ret_val = LLVM_TO_PARSE_STR_MAP[kind] + else: + raise TypeError('Unsupported LLVM type: %s' % str(llvm_type)) + return ret_val + + def build_parse_string (self, llvm_tys): + """Given a set of LLVM types, return a string for parsing + them via PyArg_ParseTuple.""" + return ''.join((self._build_parse_string(ty) + for ty in llvm_tys)) + + def handle_abi_casts (self, builder, result): + if result.type.kind == lc.TYPE_FLOAT: + # NOTE: The C ABI apparently casts floats to doubles when + # an argument must be pushed on the stack, as is the case + # when calling a variable argument function. + # XXX Is there documentation on this where I can find all + # coercion rules? Do we still need some libffi + # integration? + result = builder.fpext(result, bytetype.ldouble) + return result + + def build_wrapper_function (self, llvm_function): + _pyobj_p = bytetype.l_pyobject_head_struct_p + _void_p = _char_p = bytetype.li8_ptr + self.crnt_function = self.target_module.add_function( + lc.Type.function(_pyobj_p, (_pyobj_p, _pyobj_p)), + llvm_function.name + "_wrapper") + entry_block = self.crnt_function.append_basic_block('entry') + args_ok_block = self.crnt_function.append_basic_block('args_ok') + exit_block = self.crnt_function.append_basic_block('exit') + _int32_zero = lc.Constant.int(bytetype.li32, 0) + _Py_BuildValue = self.target_module.get_or_insert_function( + lc.Type.function(_pyobj_p, [_char_p], True), 'Py_BuildValue') + _PyArg_ParseTuple = self.target_module.get_or_insert_function( + lc.Type.function(bytetype.lc_int, [_pyobj_p, _char_p], True), + 'PyArg_ParseTuple') + _PyEval_SaveThread = self.target_module.get_or_insert_function( + lc.Type.function(_void_p, []), 'PyEval_SaveThread') + _PyEval_RestoreThread = self.target_module.get_or_insert_function( + lc.Type.function(lc.Type.void(), [_void_p]), + 'PyEval_RestoreThread') + # __________________________________________________ + # entry: + builder = lc.Builder.new(entry_block) + arg_types = llvm_function.type.pointee.args + parse_str = builder.gep( + get_string_constant( + self.target_module, + self.build_parse_string(arg_types)), + [_int32_zero, _int32_zero]) + parse_args = [builder.alloca(arg_ty) for arg_ty in arg_types] + parse_args.insert(0, parse_str) + parse_args.insert(0, self.crnt_function.args[1]) + parse_result = builder.call(_PyArg_ParseTuple, parse_args) + builder.cbranch(builder.icmp(lc.ICMP_NE, parse_result, _int32_zero), + args_ok_block, exit_block) + # __________________________________________________ + # args_ok: + builder = lc.Builder.new(args_ok_block) + thread_state = builder.call(_PyEval_SaveThread, ()) + target_args = [builder.load(parse_arg) for parse_arg in parse_args[2:]] + result = builder.call(llvm_function, target_args) + result_cast = self.handle_abi_casts(builder, result) + builder.call(_PyEval_RestoreThread, (thread_state,)) + build_str = builder.gep( + get_string_constant( + self.target_module, + self._build_parse_string(result.type)), + [_int32_zero, _int32_zero]) + py_result = builder.call(_Py_BuildValue, [build_str, result_cast]) + builder.branch(exit_block) + # __________________________________________________ + # exit: + builder = lc.Builder.new(exit_block) + rval = builder.phi(bytetype.l_pyobject_head_struct_p) + rval.add_incoming(lc.Constant.null(bytetype.l_pyobject_head_struct_p), + entry_block) + rval.add_incoming(py_result, args_ok_block) + builder.ret(rval) + return self.crnt_function + + def wrap_llvm_module (self, llvm_module, engine = None, py_module = None): + ''' + Shamefully adapted from bitey.bind.wrap_llvm_module(). + ''' + functions = [func for func in llvm_module.functions + if not func.name.startswith("_") + and not func.is_declaration + and func.linkage == lc.LINKAGE_EXTERNAL] + wrappers = [self.build_wrapper_function(func) for func in functions] + if engine is None: + engine = le.ExecutionEngine.new(llvm_module) + if self.target_module != llvm_module: + engine.add_module(self.target_module) + py_wrappers = [pyaddfunc(wrapper.name, + engine.get_pointer_to_function(wrapper)) + for wrapper in wrappers] + if py_module: + for py_wrapper in py_wrappers: + setattr(py_module, py_wrapper.__name__[:-8], py_wrapper) + setattr(py_module, '_llvm_module', llvm_module) + setattr(py_module, '_llvm_engine', engine) + if self.target_module != llvm_module: + setattr(py_module, '_llvm_wrappers', self.target_module) + return engine, py_wrappers + + def wrap_llvm_module_in_python (self, llvm_module, py_module = None): + ''' + Mildly reworked and abstracted bitey.bind.wrap_llvm_bitcode(). + Abstracted to accept any existing LLVM Module object, and + return a Python wrapper module (even if one wasn't originally + specified). + ''' + if py_module is None: + py_module = types.ModuleType(str(llvm_module.id)) + engine = le.ExecutionEngine.new(llvm_module) + self.wrap_llvm_module(llvm_module, engine, py_module) + return py_module + + def wrap_llvm_bitcode (self, bitcode, py_module = None): + ''' + Intended to be drop-in replacement of + bitey.bind.wrap_llvm_bitcode(). + ''' + return self.wrap_llvm_module_in_python( + lc.Module.from_bitcode(io.BytesIO(bitcode)), py_module) + + def wrap_llvm_assembly (self, llvm_asm, py_module = None): + return self.wrap_llvm_module_in_python( + lc.Module.from_assembly(io.BytesIO(llvm_asm)), py_module) + +# ______________________________________________________________________ + +class NoBiteyLoader(object): + """ + Load LLVM compiled bitcode and autogenerate a ctypes binding. + + Initially copied and adapted from bitey.loader module. + """ + def __init__(self, pkg, name, source, preload, postload): + self.package = pkg + self.name = name + self.fullname = '.'.join((pkg,name)) + self.source = source + self.preload = preload + self.postload = postload + + @classmethod + def _check_magic(cls, filename): + if os.path.exists(filename): + magic = open(filename,"rb").read(4) + if magic == b'\xde\xc0\x17\x0b': + return True + elif magic[:2] == b'\x42\x43': + return True + else: + return False + else: + return False + + @classmethod + def build_module(cls, fullname, source_path, source_data, preload=None, + postload=None): + name = fullname.split(".")[-1] + mod = imp.new_module(name) + if preload: + exec(preload, mod.__dict__, mod.__dict__) + type_annotations = getattr(mod, '_type_annotations', None) + nb = NoBitey(type_annotations = type_annotations) + if source_path.endswith(('.o', '.bc')): + nb.wrap_llvm_bitcode(source_data, mod) + elif source_path.endswith('.s'): + nb.wrap_llvm_assembly(source_data, mod) + if postload: + exec(postload, mod.__dict__, mod.__dict__) + return mod + + @classmethod + def find_module(cls, fullname, paths = None): + if paths is None: + paths = sys.path + names = fullname.split('.') + modname = names[-1] + source_paths = None + for f in paths: + path = os.path.join(os.path.realpath(f), modname) + source = path + '.o' + if cls._check_magic(source): + source_paths = path, source + break + source = path + '.bc' + if os.path.exists(source): + source_paths = path, source + break + source = path + '.s' + if os.path.exists(source): + source_paths = path, source + break + if source_paths: + path, source = source_paths + return cls('.'.join(names[:-1]), modname, source, + path + ".pre.py", path + ".post.py") + + def get_code(self, module): + pass + + def get_data(self, module): + pass + + def get_filename(self, name): + return self.source + + def get_source(self, name): + with open(self.source, 'rb') as f: + return f.read() + + def is_package(self, *args, **kw): + return False + + def load_module(self, fullname): + if fullname in sys.modules: + return sys.modules[fullname] + + preload = None + postload = None + + # Get the preload file (if any) + if os.path.exists(self.preload): + with open(self.preload) as f: + preload = f.read() + + # Get the source + with open(self.source, 'rb') as f: + source_data = f.read() + + # Get the postload file (if any) + if os.path.exists(self.postload): + with open(self.postload) as f: + postload = f.read() + + mod = self.build_module(fullname, self.get_filename(None), source_data, + preload, postload) + sys.modules[fullname] = mod + mod.__loader__ = self + mod.__file__ = self.source + return mod + + @classmethod + def install(cls): + if cls not in sys.meta_path: + sys.meta_path.append(cls) + + @classmethod + def remove(cls): + sys.meta_path.remove(cls) + +# ______________________________________________________________________ + +def _mk_add_42 (llvm_module, at_type = bytetype.lc_long): + f = llvm_module.add_function( + lc.Type.function(at_type, [at_type]), 'add_42_%s' % str(at_type)) + block = f.append_basic_block('entry') + builder = lc.Builder.new(block) + if at_type.kind == lc.TYPE_INTEGER: + const_42 = lc.Constant.int(at_type, 42) + add = builder.add + elif at_type.kind in (lc.TYPE_FLOAT, lc.TYPE_DOUBLE): + const_42 = lc.Constant.real(at_type, 42.) + add = builder.fadd + else: + raise TypeError('Unsupported type: %s' % str(at_type)) + builder.ret(add(f.args[0], const_42)) + return f + +# ______________________________________________________________________ + +def build_test_module (): + llvm_module = lc.Module.new('nobitey_test') + for ty in (bytetype.li32, bytetype.li64, bytetype.lfloat, + bytetype.ldouble): + fn = _mk_add_42(llvm_module, ty) + return llvm_module + +# ______________________________________________________________________ + +def main (*args): + # Build up a module. + m = build_test_module() + print(m) + wrap_module = NoBitey().wrap_llvm_module_in_python(m) + # Now try running the generated wrappers. + for py_wf_name in ('add_42_i32', 'add_42_i64', 'add_42_float', + 'add_42_double'): + py_wf = getattr(wrap_module, py_wf_name) + for i in range(42): + result = py_wf(i) + expected = i + 42 + assert result == expected, "%r != %r in %r" % ( + result, expected, py_wf) + return wrap_module + +if __name__ == "__main__": + main(*sys.argv[1:]) + +# ______________________________________________________________________ +# End of nobitey.py diff --git a/opcode_util.py b/opcode_util.py new file mode 100644 index 0000000..9bc8f25 --- /dev/null +++ b/opcode_util.py @@ -0,0 +1,215 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +import dis +import opcode + +# ______________________________________________________________________ +# Module data + +hasjump = opcode.hasjrel + opcode.hasjabs +hascbranch = [op for op in hasjump + if 'IF' in opcode.opname[op] + or opcode.opname[op] in ('FOR_ITER', 'SETUP_LOOP')] + +# Since the actual opcode value may change, manage opcode abstraction +# data by opcode name. + +OPCODE_MAP = { + 'BINARY_ADD': (2, 1, None), + 'BINARY_AND': (2, 1, None), + 'BINARY_DIVIDE': (2, 1, None), + 'BINARY_FLOOR_DIVIDE': (2, 1, None), + 'BINARY_LSHIFT': (2, 1, None), + 'BINARY_MODULO': (2, 1, None), + 'BINARY_MULTIPLY': (2, 1, None), + 'BINARY_OR': (2, 1, None), + 'BINARY_POWER': (2, 1, None), + 'BINARY_RSHIFT': (2, 1, None), + 'BINARY_SUBSCR': (2, 1, None), + 'BINARY_SUBTRACT': (2, 1, None), + 'BINARY_TRUE_DIVIDE': (2, 1, None), + 'BINARY_XOR': (2, 1, None), + 'BREAK_LOOP': (0, None, 1), + 'BUILD_CLASS': (None, None, None), + 'BUILD_LIST': (-1, 1, None), + 'BUILD_MAP': (None, None, None), + 'BUILD_SET': (None, None, None), + 'BUILD_SLICE': (None, None, None), + 'BUILD_TUPLE': (-1, 1, None), + 'CALL_FUNCTION': (-2, 1, None), + 'CALL_FUNCTION_KW': (-3, 1, None), + 'CALL_FUNCTION_VAR': (-3, 1, None), + 'CALL_FUNCTION_VAR_KW': (-4, 1, None), + 'COMPARE_OP': (2, 1, None), + 'CONTINUE_LOOP': (None, None, None), + 'DELETE_ATTR': (1, None, 1), + 'DELETE_DEREF': (None, None, None), + 'DELETE_FAST': (0, None, 1), + 'DELETE_GLOBAL': (0, None, 1), + 'DELETE_NAME': (0, None, 1), + 'DELETE_SLICE+0': (1, None, 1), + 'DELETE_SLICE+1': (2, None, 1), + 'DELETE_SLICE+2': (2, None, 1), + 'DELETE_SLICE+3': (3, None, 1), + 'DELETE_SUBSCR': (2, None, 1), + 'DUP_TOP': (None, None, None), + 'DUP_TOPX': (None, None, None), + 'DUP_TOP_TWO': (None, None, None), + 'END_FINALLY': (None, None, None), + 'EXEC_STMT': (None, None, None), + 'EXTENDED_ARG': (None, None, None), + 'FOR_ITER': (1, 1, 1), + 'GET_ITER': (1, 1, None), + 'IMPORT_FROM': (None, None, None), + 'IMPORT_NAME': (None, None, None), + 'IMPORT_STAR': (1, None, 1), + 'INPLACE_ADD': (2, 1, None), + 'INPLACE_AND': (2, 1, None), + 'INPLACE_DIVIDE': (2, 1, None), + 'INPLACE_FLOOR_DIVIDE': (2, 1, None), + 'INPLACE_LSHIFT': (2, 1, None), + 'INPLACE_MODULO': (2, 1, None), + 'INPLACE_MULTIPLY': (2, 1, None), + 'INPLACE_OR': (2, 1, None), + 'INPLACE_POWER': (2, 1, None), + 'INPLACE_RSHIFT': (2, 1, None), + 'INPLACE_SUBTRACT': (2, 1, None), + 'INPLACE_TRUE_DIVIDE': (2, 1, None), + 'INPLACE_XOR': (2, 1, None), + 'JUMP_ABSOLUTE': (0, None, 1), + 'JUMP_FORWARD': (0, None, 1), + 'JUMP_IF_FALSE': (1, None, 1), + 'JUMP_IF_FALSE_OR_POP': (None, None, None), + 'JUMP_IF_TRUE': (1, None, 1), + 'JUMP_IF_TRUE_OR_POP': (None, None, None), + 'LIST_APPEND': (2, 0, 1), + 'LOAD_ATTR': (1, 1, None), + 'LOAD_BUILD_CLASS': (None, None, None), + 'LOAD_CLOSURE': (None, None, None), + 'LOAD_CONST': (0, 1, None), + 'LOAD_DEREF': (0, 1, None), + 'LOAD_FAST': (0, 1, None), + 'LOAD_GLOBAL': (0, 1, None), + 'LOAD_LOCALS': (None, None, None), + 'LOAD_NAME': (0, 1, None), + 'MAKE_CLOSURE': (None, None, None), + 'MAKE_FUNCTION': (None, None, None), + 'MAP_ADD': (None, None, None), + 'NOP': (0, None, None), + 'POP_BLOCK': (0, None, 1), + 'POP_EXCEPT': (None, None, None), + 'POP_JUMP_IF_FALSE': (1, None, 1), + 'POP_JUMP_IF_TRUE': (1, None, 1), + 'POP_TOP': (1, None, 1), + 'PRINT_EXPR': (1, None, 1), + 'PRINT_ITEM': (1, None, 1), + 'PRINT_ITEM_TO': (2, None, 1), + 'PRINT_NEWLINE': (0, None, 1), + 'PRINT_NEWLINE_TO': (1, None, 1), + 'RAISE_VARARGS': (None, None, None), + 'RETURN_VALUE': (1, None, 1), + 'ROT_FOUR': (None, None, None), + 'ROT_THREE': (None, None, None), + 'ROT_TWO': (None, None, None), + 'SETUP_EXCEPT': (None, None, None), + 'SETUP_FINALLY': (None, None, None), + 'SETUP_LOOP': (None, None, None), + 'SETUP_WITH': (None, None, None), + 'SET_ADD': (None, None, None), + 'SLICE+0': (1, 1, None), + 'SLICE+1': (2, 1, None), + 'SLICE+2': (2, 1, None), + 'SLICE+3': (3, 1, None), + 'STOP_CODE': (None, None, None), + 'STORE_ATTR': (2, None, 1), + 'STORE_DEREF': (1, 0, 1), + 'STORE_FAST': (1, None, 1), + 'STORE_GLOBAL': (1, None, 1), + 'STORE_LOCALS': (None, None, None), + 'STORE_MAP': (1, None, 1), + 'STORE_NAME': (1, None, 1), + 'STORE_SLICE+0': (1, None, 1), + 'STORE_SLICE+1': (2, None, 1), + 'STORE_SLICE+2': (2, None, 1), + 'STORE_SLICE+3': (3, None, 1), + 'STORE_SUBSCR': (3, None, 1), + 'UNARY_CONVERT': (1, 1, None), + 'UNARY_INVERT': (1, 1, None), + 'UNARY_NEGATIVE': (1, 1, None), + 'UNARY_NOT': (1, 1, None), + 'UNARY_POSITIVE': (1, 1, None), + 'UNPACK_EX': (None, None, None), + 'UNPACK_SEQUENCE': (None, None, None), + 'WITH_CLEANUP': (None, None, None), + 'YIELD_VALUE': (1, None, 1), +} + +# ______________________________________________________________________ +# Module functions + +def itercode(code): + """Return a generator of byte-offset, opcode, and argument + from a byte-code-string + """ + i = 0 + extended_arg = 0 + if isinstance(code[0], str): + code = [ord(c) for c in code] + n = len(code) + while i < n: + op = code[i] + num = i + i = i + 1 + oparg = None + if op >= opcode.HAVE_ARGUMENT: + oparg = code[i] + (code[i + 1] * 256) + extended_arg + extended_arg = 0 + i = i + 2 + if op == opcode.EXTENDED_ARG: + extended_arg = oparg * 65536 + + delta = yield num, op, oparg + if delta is not None: + abs_rel, dst = delta + assert abs_rel == 'abs' or abs_rel == 'rel' + i = dst if abs_rel == 'abs' else i + dst + +# ______________________________________________________________________ + +def extendlabels(code, labels = None): + """Extend the set of jump target labels to account for the + passthrough targets of conditional branches. + + This allows us to create a control flow graph where there is at + most one branch per basic block. + """ + if labels is None: + labels = [] + if isinstance(code[0], str): + code = [ord(c) for c in code] + n = len(code) + i = 0 + while i < n: + op = code[i] + i += 1 + if op >= dis.HAVE_ARGUMENT: + i += 2 + label = -1 + if op in hasjump: + label = i + if label >= 0: + if label not in labels: + labels.append(label) + elif op == opcode.opmap['BREAK_LOOP']: + if i not in labels: + labels.append(i) + return labels + +# ______________________________________________________________________ + +def get_code_object (func): + return getattr(func, '__code__', getattr(func, 'func_code', None)) + +# ______________________________________________________________________ +# End of opcode_util.py diff --git a/phi_injector.py b/phi_injector.py new file mode 100644 index 0000000..c40abe3 --- /dev/null +++ b/phi_injector.py @@ -0,0 +1,131 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +from bytecode_visitor import BytecodeFlowVisitor, BenignBytecodeVisitorMixin + +# ______________________________________________________________________ + +synthetic_opname = [] +synthetic_opmap = {} + +def def_synth_op (opname): + global synthetic_opname, synthetic_opmap + ret_val = -(len(synthetic_opname) + 1) + synthetic_opname.insert(0, opname) + synthetic_opmap[opname] = ret_val + return ret_val + +REF_ARG = def_synth_op('REF_ARG') +BUILD_PHI = def_synth_op('BUILD_PHI') +DEFINITION = def_synth_op('DEFINITION') +REF_DEF = def_synth_op('REF_DEF') + +# ______________________________________________________________________ + +class PhiInjector (BenignBytecodeVisitorMixin, BytecodeFlowVisitor): + def visit_cfg (self, cfg, nargs = 0, *args, **kws): + self.cfg = cfg + ret_val = self.visit(cfg.blocks, nargs) + del self.cfg + return ret_val + + def visit (self, flow, nargs = 0, *args, **kws): + self.nargs = nargs + self.definitions = [] + self.phis = [] + self.prev_blocks = [] + self.blocks_locals = dict((block, {}) + for block in self.cfg.blocks.keys()) + ret_val = super(PhiInjector, self).visit(flow, *args, **kws) + for block, _, _, args, _ in self.phis: + local = args.pop() + reaching_definitions = self.cfg.reaching_definitions[block] + for prev in reaching_definitions.keys(): + if 0 in self.cfg.blocks_reaching[prev]: + args.append((prev, REF_DEF, 'REF_DEF', + self.blocks_locals[prev][local], ())) + args.sort() + del self.blocks_locals + del self.prev_blocks + del self.phis + del self.definitions + del self.nargs + return ret_val + + def add_definition (self, index, local, arg): + definition_index = len(self.definitions) + definition = (index, DEFINITION, 'DEFINITION', definition_index, + (arg,)) + self.definitions.append(definition) + self.blocks_locals[self.block][local] = definition_index + return definition + + def add_phi (self, index, local): + ret_val = (index, BUILD_PHI, 'BUILD_PHI', [local], ()) + self.phis.append(ret_val) + return ret_val + + def enter_block (self, block): + ret_val = False + if self.prev_blocks: + prev_block = self.prev_blocks[-1] + self.block = block + if block == 0: + if self.nargs > 0: + ret_val = [self.add_definition(-1, arg, + (-1, REF_ARG, 'REF_ARG', arg, + ())) + for arg in range(self.nargs)] + else: + ret_val = True + elif 0 in self.cfg.blocks_reaching[block]: + ret_val = True + prev_block_locals = self.blocks_locals[prev_block] + self.blocks_locals[block] = prev_block_locals.copy() + phis_needed = self.cfg.phi_needed(block) + if phis_needed: + ret_val = [self.add_definition(block, local, + self.add_phi(block, local)) + for local in phis_needed] + return ret_val + + def exit_block (self, block): + if 0 in self.cfg.blocks_reaching[block]: + self.prev_blocks.append(block) + del self.block + + def op_STORE_FAST (self, i, op, arg, *args, **kws): + assert len(args) == 1 + return [self.add_definition(i, arg, args[0])] + + def op_LOAD_FAST (self, i, op, arg, *args, **kws): + return [(i, REF_DEF, 'REF_DEF', self.blocks_locals[self.block][arg], + args)] + +# ______________________________________________________________________ + +def inject_phis (func): + import byte_control + argcount = byte_control.opcode_util.get_code_object(func).co_argcount + cfg = byte_control.build_cfg(func) + return PhiInjector().visit_cfg(cfg, argcount) + +# ______________________________________________________________________ +# Main (self-test) routine + +def main (*args): + import pprint + from tests import llfuncs + if not args: + args = ('doslice',) + for arg in args: + pprint.pprint(inject_phis(getattr(llfuncs, arg))) + +# ______________________________________________________________________ + +if __name__ == "__main__": + import sys + main(*sys.argv[1:]) + +# ______________________________________________________________________ +# End of phi_injector.py diff --git a/pyaddfunc.py b/pyaddfunc.py new file mode 100644 index 0000000..8e09839 --- /dev/null +++ b/pyaddfunc.py @@ -0,0 +1,41 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +import ctypes + +# ______________________________________________________________________ +class PyMethodDef (ctypes.Structure): + _fields_ = [ + ('ml_name', ctypes.c_char_p), + ('ml_meth', ctypes.c_void_p), + ('ml_flags', ctypes.c_int), + ('ml_doc', ctypes.c_char_p), + ] + +PyCFunction_NewEx = ctypes.pythonapi.PyCFunction_NewEx +PyCFunction_NewEx.argtypes = (ctypes.POINTER(PyMethodDef), + ctypes.c_void_p, + ctypes.c_void_p) +PyCFunction_NewEx.restype = ctypes.py_object + +cache = {} # Unsure if this is necessary to keep the PyMethodDef + # structures from being garbage collected. Assuming so... + +def pyaddfunc (func_name, func_ptr, func_doc = None): + global cache + if bytes != str: + func_name = bytes(ord(ch) for ch in func_name) + key = (func_name, func_ptr) + if key in cache: + _, ret_val = cache[key] + else: + mdef = PyMethodDef(bytes(func_name), + func_ptr, + 1, # == METH_VARARGS (hopefully remains so...) + func_doc) + ret_val = PyCFunction_NewEx(ctypes.byref(mdef), 0, 0) + cache[key] = (mdef, ret_val) + return ret_val + +# ______________________________________________________________________ +# End of pyaddfunc.py diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/llfuncs.py b/tests/llfuncs.py new file mode 100644 index 0000000..55e9000 --- /dev/null +++ b/tests/llfuncs.py @@ -0,0 +1,42 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +def doslice (in_string, lower, upper): + l = strlen(in_string) + if lower < 0: + lower += l + if upper < 0: + upper += l + temp_len = upper - lower + if temp_len < 0: + temp_len = 0 + ret_val = alloca_array(li8, temp_len + 1) + strncpy(ret_val, in_string + lower, temp_len) + ret_val[temp_len] = li8(0) + return ret_val + +def ipow (val, exp): + ret_val = 1 + temp = val + w = exp + while w > 0: + if (w & 1) != 0: + ret_val *= temp + # TODO: Overflow check on ret_val + w >>= 1 + if w == 0: break + temp *= temp + # TODO: Overflow check on temp + return ret_val + +def pymod (arg1, arg2): + ret_val = arg1 % arg2 + if ret_val < 0: + if arg2 > 0: + ret_val += arg2 + elif arg2 < 0: + ret_val += arg2 + return ret_val + +# ______________________________________________________________________ +# End of llfuncs.py diff --git a/tests/llfunctys.py b/tests/llfunctys.py new file mode 100644 index 0000000..107b5a3 --- /dev/null +++ b/tests/llfunctys.py @@ -0,0 +1,23 @@ +#! /usr/bin/env python +# ______________________________________________________________________ + +import llvm.core as lc + +try: + from llnumba import bytetype +except ImportError: + from numba.llnumba import bytetype + +# ______________________________________________________________________ + +doslice = lc.Type.function(bytetype.li8_ptr, ( + bytetype.li8_ptr, bytetype.lc_size_t, bytetype.lc_size_t)) + +ipow = lc.Type.function(bytetype.li32, (bytetype.li32, + bytetype.li32)) + +pymod = lc.Type.function(bytetype.li32, (bytetype.li32, + bytetype.li32)) + +# ______________________________________________________________________ +# End of llfunctys.py From fe1ba066983fce48c5242f9e9578b9dd388d35f7 Mon Sep 17 00:00:00 2001 From: Jon Riehl Date: Mon, 15 Oct 2012 15:21:53 -0500 Subject: [PATCH 068/516] Adding docstrings for some of llnumba. --- byte_control.py | 12 ++++++++++++ byte_flow.py | 15 +++++++++++++++ byte_translator.py | 22 ++++++++++++++++++++++ phi_injector.py | 19 +++++++++++++++++++ 4 files changed, 68 insertions(+) diff --git a/byte_control.py b/byte_control.py index 8180cf2..0ee4b67 100644 --- a/byte_control.py +++ b/byte_control.py @@ -11,7 +11,17 @@ from control_flow import ControlFlowGraph # ______________________________________________________________________ class ControlFlowBuilder (BenignBytecodeVisitorMixin, BytecodeFlowVisitor): + '''Visitor responsible for traversing a bytecode flow object and + building a control flow graph (CFG). + + The primary purpose of this transformation is to create a CFG, + which is used by later transformers for dataflow analysis. + ''' def visit (self, flow, nargs = 0, *args, **kws): + '''Given a bytecode flow, and an optional number of arguments, + return a :py:class:`numba.llnumba.control_flow.ControlFlowGraph` + instance describing the full control flow of the bytecode + flow.''' self.nargs = nargs ret_val = super(ControlFlowBuilder, self).visit(flow, *args, **kws) del self.nargs @@ -73,6 +83,8 @@ class ControlFlowBuilder (BenignBytecodeVisitorMixin, BytecodeFlowVisitor): # ______________________________________________________________________ def build_cfg (func): + '''Given a Python function, create a bytecode flow, visit the flow + object, and return a control flow graph.''' import byte_flow return ControlFlowBuilder().visit( byte_flow.build_flow(func), diff --git a/byte_flow.py b/byte_flow.py index 6951b26..f0df934 100644 --- a/byte_flow.py +++ b/byte_flow.py @@ -10,6 +10,19 @@ import opcode_util # ______________________________________________________________________ class BytecodeFlowBuilder (BytecodeIterVisitor): + '''Transforms a bytecode vector into a bytecode "flow tree". + + The flow tree is a Python dictionary, described loosely by the + following set of productions: + + * `flow_tree` ``:=`` ``{`` `blocks` ``*`` ``}`` + * `blocks` ``:=`` `block_index` ``:`` ``[`` `bytecode_tree` ``*`` ``]`` + * `bytecode_tree` ``:=`` ``(`` `opcode_index` ``,`` `opcode` ``,`` + `opname` ``,`` `arg` ``,`` ``[`` `bytecode_tree` ``*`` ``]`` ``)`` + + The primary purpose of this transformation is to simulate the + value stack, removing it and any stack-specific opcodes.''' + def __init__ (self, *args, **kws): super(BytecodeFlowBuilder, self).__init__(*args, **kws) om_items = opcode_util.OPCODE_MAP.items() @@ -195,6 +208,8 @@ class BytecodeFlowBuilder (BytecodeIterVisitor): # ______________________________________________________________________ def build_flow (func): + '''Given a Python function, return a bytecode flow tree for that + function.''' return BytecodeFlowBuilder().visit(opcode_util.get_code_object(func)) # ______________________________________________________________________ diff --git a/byte_translator.py b/byte_translator.py index 7954970..62f3e21 100644 --- a/byte_translator.py +++ b/byte_translator.py @@ -1,5 +1,8 @@ #! /usr/bin/env python # ______________________________________________________________________ +'''Defines a bytecode based LLVM translator for llnumba code. +''' +# ______________________________________________________________________ # Module imports import opcode @@ -113,7 +116,17 @@ class LLVMCaster (object): # Class definitions class LLVMTranslator (BytecodeFlowVisitor): + '''Transformer responsible for visiting a set of bytecode flow + trees, emitting LLVM code. + + Unlike other translators in :py:mod:`numba.llnumba`, this + incorporates the full transformation chain, starting with + :py:class:`numba.llnumba.byte_flow.BytecodeFlowBuilder`, then + :py:class:`numba.llnumba.byte_control.ControlFlowBuilder`, and + then :py:class:`numba.llnumba.phi_injector.PhiInjector`.''' + def __init__ (self, llvm_module = None, *args, **kws): + '''Constructor for LLVMTranslator.''' super(LLVMTranslator, self).__init__(*args, **kws) if llvm_module is None: llvm_module = lc.Module.new('Translated_Module_%d' % (id(self),)) @@ -123,6 +136,13 @@ class LLVMTranslator (BytecodeFlowVisitor): self.phi_injector = PhiInjector() def translate (self, function, llvm_type = None, env = None): + '''Translate a function to the given LLVM function type. + + If no type is given, then assume the function is of LLVM type + "void ()". + + The optional env parameter allows extension of the global + environment.''' if llvm_type is None: llvm_type = lc.Type.function(lvoid, ()) if env is None: @@ -495,6 +515,8 @@ class LLVMTranslator (BytecodeFlowVisitor): # ______________________________________________________________________ def translate_function (func, lltype, llvm_module = None, **kws): + '''Given a function and an LLVM function type, emit LLVM code for + that function using a new LLVMTranslator instance.''' translator = LLVMTranslator(llvm_module) translator.translate(func, lltype, kws) return translator diff --git a/phi_injector.py b/phi_injector.py index c40abe3..b45be20 100644 --- a/phi_injector.py +++ b/phi_injector.py @@ -23,6 +23,23 @@ REF_DEF = def_synth_op('REF_DEF') # ______________________________________________________________________ class PhiInjector (BenignBytecodeVisitorMixin, BytecodeFlowVisitor): + '''Transformer responsible for modifying a bytecode flow, removing + LOAD_FAST and STORE_FAST opcodes, and replacing them with a static + single assignment (SSA) representation. + + In order to support SSA, PhiInjector adds the following synthetic + opcodes to transformed flows: + + * REF_ARG: Specifically reference an incomming argument value. + + * BUILD_PHI: Build a phi node to disambiguate between several + possible definitions at a control flow join. + + * DEFINITION: Unique value definition indexed by the "arg" field + in the tuple. + + * REF_DEF: Reference a specific value definition.''' + def visit_cfg (self, cfg, nargs = 0, *args, **kws): self.cfg = cfg ret_val = self.visit(cfg.blocks, nargs) @@ -105,6 +122,8 @@ class PhiInjector (BenignBytecodeVisitorMixin, BytecodeFlowVisitor): # ______________________________________________________________________ def inject_phis (func): + '''Given a Python function, return a bytecode flow object that has + been transformed by a fresh PhiInjector instance.''' import byte_control argcount = byte_control.opcode_util.get_code_object(func).co_argcount cfg = byte_control.build_cfg(func) From 40b84ffd7445d2ab8f2e5ca875a22bc88950d46e Mon Sep 17 00:00:00 2001 From: Jon Riehl Date: Tue, 16 Oct 2012 10:18:13 -0500 Subject: [PATCH 069/516] Added manual linkage to nobitey when target module isn't the same as the source module. --- byte_flow.py | 3 ++- byte_translator.py | 24 ++++++++++++++++++------ bytetype.py | 2 ++ nobitey.py | 25 +++++++++++++++++++++---- opcode_util.py | 2 +- 5 files changed, 44 insertions(+), 12 deletions(-) diff --git a/byte_flow.py b/byte_flow.py index f0df934..822e564 100644 --- a/byte_flow.py +++ b/byte_flow.py @@ -31,7 +31,8 @@ class BytecodeFlowBuilder (BytecodeIterVisitor): if opname in opcode.opmap) def _visit_op (self, i, op, arg, opname, pops, pushes, appends): - assert pops is not None + assert pops is not None, ('%s not well defined in opcode_util.' + 'OPCODE_MAP' % opname) if pops: if pops < 0: pops = arg - pops - 1 diff --git a/byte_translator.py b/byte_translator.py index 62f3e21..91753dd 100644 --- a/byte_translator.py +++ b/byte_translator.py @@ -10,7 +10,6 @@ import opcode import llvm.core as lc import opcode_util - import bytetype from bytecode_visitor import BytecodeFlowVisitor from byte_flow import BytecodeFlowBuilder @@ -353,25 +352,30 @@ class LLVMTranslator (BytecodeFlowVisitor): def op_CALL_FUNCTION (self, i, op, arg, *args, **kws): fn = args[0] args = args[1:] + fn_name = getattr(fn, '__name__', None) if isinstance(fn, lc.Type): if isinstance(fn, lc.FunctionType): ret_val = [self.builder.call( - self.llvm_module.get_or_insert_function(fn, fn.__name__), + self.llvm_module.get_or_insert_function(fn, fn_name), args)] else: assert len(args) == 1 ret_val = [LLVMCaster.build_cast(self.builder, args[0], fn)] - elif fn.__name__ in lc.Builder.__dict__: + elif fn_name in lc.Builder.__dict__: ret_val = [fn(self.builder, *args)] else: - raise NotImplementedError("Don't know how to call %r!" % (fn,)) + raise NotImplementedError("Don't know how to call %s() (%r)!" % + (fn_name, fn)) return ret_val def op_CALL_FUNCTION_KW (self, i, op, arg, *args, **kws): raise NotImplementedError("LLVMTranslator.op_CALL_FUNCTION_KW") def op_CALL_FUNCTION_VAR (self, i, op, arg, *args, **kws): - raise NotImplementedError("LLVMTranslator.op_CALL_FUNCTION_VAR") + args = list(args) + var_args = list(args.pop()) + args.extend(var_args) + return self.op_CALL_FUNCTION(i, op, arg, *args, **kws) def op_CALL_FUNCTION_VAR_KW (self, i, op, arg, *args, **kws): raise NotImplementedError("LLVMTranslator.op_CALL_FUNCTION_VAR_KW") @@ -454,7 +458,7 @@ class LLVMTranslator (BytecodeFlowVisitor): def op_LOAD_GLOBAL (self, i, op, arg, *args, **kws): ret_val = self.globals[self.code_obj.co_names[arg]] - if not hasattr(ret_val, '__name__'): + if isinstance(fn, lc.Type) and not hasattr(ret_val, '__name__'): ret_val.__name__ = self.code_obj.co_names[arg] return [ret_val] @@ -521,6 +525,14 @@ def translate_function (func, lltype, llvm_module = None, **kws): translator.translate(func, lltype, kws) return translator +# ______________________________________________________________________ + +def llnumba (lltype, llvm_module = None, **kws): + '''Decorator version of translate_function().''' + def _llnumba (func): + return translate_function(func, lltype, llvm_module, **kws) + return _llnumba + # ______________________________________________________________________ # Main (self-test) routine diff --git a/bytetype.py b/bytetype.py index 25a0355..211f3f8 100644 --- a/bytetype.py +++ b/bytetype.py @@ -13,6 +13,7 @@ li8 = lc.Type.int(8) li16 = lc.Type.int(16) li32 = lc.Type.int(32) li64 = lc.Type.int(64) +liptr = lc.Type.int(ctypes.sizeof(ctypes.c_void_p) * 8) lc_size_t = lc.Type.int(ctypes.sizeof( getattr(ctypes, 'c_ssize_t', getattr(ctypes, 'c_size_t'))) * 8) lfloat = lc.Type.float() @@ -25,6 +26,7 @@ lc_long = lc.Type.int(ctypes.sizeof(ctypes.c_long) * 8) l_pyobject_head = [lc_size_t, lc.Type.pointer(li32)] l_pyobject_head_struct = lc.Type.struct(l_pyobject_head) l_pyobj_p = l_pyobject_head_struct_p = lc.Type.pointer(l_pyobject_head_struct) +l_pyfunc = lc.Type.function(l_pyobj_p, (l_pyobj_p, l_pyobj_p)) strlen = lc.Type.function(lc_size_t, (li8_ptr,)) strncpy = lc.Type.function(li8_ptr, (li8_ptr, li8_ptr, lc_size_t)) diff --git a/nobitey.py b/nobitey.py index bca491e..5ae133f 100644 --- a/nobitey.py +++ b/nobitey.py @@ -79,7 +79,20 @@ class NoBitey (object): result = builder.fpext(result, bytetype.ldouble) return result - def build_wrapper_function (self, llvm_function): + def build_wrapper_function (self, llvm_function, engine = None): + manual_linkage = False + if self.target_module != llvm_function.module: + manual_linkage = True + assert engine, ("Execution engine argument currently required for " + "linkage to separate LLVM module.") + llvm_function_ptr = self.target_module.add_global_variable( + llvm_function.type, llvm_function.name) + llvm_function_ptr.initializer = lc.Constant.inttoptr( + lc.Constant.int(bytetype.liptr, + engine.get_pointer_to_function(llvm_function)), + llvm_function.type) + llvm_function_ptr.linkage = lc.LINKAGE_INTERNAL + # __________________________________________________ _pyobj_p = bytetype.l_pyobject_head_struct_p _void_p = _char_p = bytetype.li8_ptr self.crnt_function = self.target_module.add_function( @@ -119,7 +132,10 @@ class NoBitey (object): builder = lc.Builder.new(args_ok_block) thread_state = builder.call(_PyEval_SaveThread, ()) target_args = [builder.load(parse_arg) for parse_arg in parse_args[2:]] - result = builder.call(llvm_function, target_args) + if manual_linkage: + result = builder.call(builder.load(llvm_function_ptr), target_args) + else: + result = builder.call(llvm_function, target_args) result_cast = self.handle_abi_casts(builder, result) builder.call(_PyEval_RestoreThread, (thread_state,)) build_str = builder.gep( @@ -147,9 +163,10 @@ class NoBitey (object): if not func.name.startswith("_") and not func.is_declaration and func.linkage == lc.LINKAGE_EXTERNAL] - wrappers = [self.build_wrapper_function(func) for func in functions] if engine is None: engine = le.ExecutionEngine.new(llvm_module) + wrappers = [self.build_wrapper_function(func, engine) + for func in functions] if self.target_module != llvm_module: engine.add_module(self.target_module) py_wrappers = [pyaddfunc(wrapper.name, @@ -346,8 +363,8 @@ def build_test_module (): def main (*args): # Build up a module. m = build_test_module() - print(m) wrap_module = NoBitey().wrap_llvm_module_in_python(m) + print(m) # Now try running the generated wrappers. for py_wf_name in ('add_42_i32', 'add_42_i64', 'add_42_float', 'add_42_double'): diff --git a/opcode_util.py b/opcode_util.py index 9bc8f25..5c0cff9 100644 --- a/opcode_util.py +++ b/opcode_util.py @@ -94,7 +94,7 @@ OPCODE_MAP = { 'LOAD_LOCALS': (None, None, None), 'LOAD_NAME': (0, 1, None), 'MAKE_CLOSURE': (None, None, None), - 'MAKE_FUNCTION': (None, None, None), + 'MAKE_FUNCTION': (-2, 1, None), 'MAP_ADD': (None, None, None), 'NOP': (0, None, None), 'POP_BLOCK': (0, None, 1), From ba309ea6c5b796ce66a1b2dcc26942c3bd673894 Mon Sep 17 00:00:00 2001 From: Jon Riehl Date: Tue, 16 Oct 2012 12:36:47 -0500 Subject: [PATCH 070/516] Got nobitey unit test working using llnumba for wrapper generation. --- byte_translator.py | 39 +++- bytecode_visitor.py | 475 ++++++++++++-------------------------------- nobitey.py | 136 ++++++------- 3 files changed, 211 insertions(+), 439 deletions(-) diff --git a/byte_translator.py b/byte_translator.py index 91753dd..b7149cf 100644 --- a/byte_translator.py +++ b/byte_translator.py @@ -6,6 +6,7 @@ # Module imports import opcode +import types import llvm.core as lc @@ -68,6 +69,9 @@ class LLVMCaster (object): ret_val = builder.sitofp(lval1, lty2) return ret_val + def build_int_to_ptr_cast(_, builder, lval1, lty2): + return builder.inttoptr(lval1, lty2) + def build_float_to_int_cast(_, builder, lval1, lty2, unsigned = False): ret_val = None if unsigned: @@ -83,6 +87,7 @@ class LLVMCaster (object): (lc.TYPE_DOUBLE, lc.TYPE_FLOAT) : build_float_trunc, (lc.TYPE_INTEGER, lc.TYPE_FLOAT) : build_int_to_float_cast, (lc.TYPE_INTEGER, lc.TYPE_DOUBLE) : build_int_to_float_cast, + (lc.TYPE_INTEGER, lc.TYPE_POINTER) : build_int_to_ptr_cast, (lc.TYPE_FLOAT, lc.TYPE_INTEGER) : build_float_to_int_cast, (lc.TYPE_DOUBLE, lc.TYPE_INTEGER) : build_float_to_int_cast, @@ -156,6 +161,8 @@ class LLVMTranslator (BytecodeFlowVisitor): if not name.startswith('_')) self.loop_stack = [] self.llvm_type = llvm_type + self.target_function_name = env.get('target_function_name', + function.__name__) self.function = function self.code_obj = opcode_util.get_code_object(function) func_globals = getattr(function, 'func_globals', @@ -170,6 +177,7 @@ class LLVMTranslator (BytecodeFlowVisitor): del self.cfg del self.globals del self.code_obj + del self.target_function_name del self.function del self.llvm_type del self.loop_stack @@ -178,7 +186,7 @@ class LLVMTranslator (BytecodeFlowVisitor): def enter_flow_object (self, flow): super(LLVMTranslator, self).enter_flow_object(flow) self.llvm_function = self.llvm_module.add_function( - self.llvm_type, self.function.__name__) + self.llvm_type, self.target_function_name) self.llvm_blocks = {} self.llvm_definitions = {} self.pending_phis = {} @@ -195,6 +203,7 @@ class LLVMTranslator (BytecodeFlowVisitor): del self.llvm_definitions del self.llvm_blocks del self.llvm_function + if __debug__: print(ret_val) return ret_val def enter_block (self, block): @@ -353,19 +362,21 @@ class LLVMTranslator (BytecodeFlowVisitor): fn = args[0] args = args[1:] fn_name = getattr(fn, '__name__', None) - if isinstance(fn, lc.Type): + if isinstance(fn, (types.FunctionType, types.MethodType)): + ret_val = [fn(self.builder, *args)] + elif isinstance(fn, lc.Value): + ret_val = [self.builder.call(fn, args)] + elif isinstance(fn, lc.Type): if isinstance(fn, lc.FunctionType): ret_val = [self.builder.call( - self.llvm_module.get_or_insert_function(fn, fn_name), - args)] + self.llvm_module.get_or_insert_function(fn, fn_name), + args)] else: assert len(args) == 1 ret_val = [LLVMCaster.build_cast(self.builder, args[0], fn)] - elif fn_name in lc.Builder.__dict__: - ret_val = [fn(self.builder, *args)] else: - raise NotImplementedError("Don't know how to call %s() (%r)!" % - (fn_name, fn)) + raise NotImplementedError("Don't know how to call %s() (%r @ %d)!" + % (fn_name, fn, i)) return ret_val def op_CALL_FUNCTION_KW (self, i, op, arg, *args, **kws): @@ -456,9 +467,15 @@ class LLVMTranslator (BytecodeFlowVisitor): (py_val,)) return ret_val + def op_LOAD_DEREF (self, i, op, arg, *args, **kws): + ret_val = self.globals[self.code_obj.co_freevars[arg]] + if isinstance(ret_val, lc.Type) and not hasattr(ret_val, '__name__'): + ret_val.__name__ = self.code_obj.co_names[arg] + return [ret_val] + def op_LOAD_GLOBAL (self, i, op, arg, *args, **kws): ret_val = self.globals[self.code_obj.co_names[arg]] - if isinstance(fn, lc.Type) and not hasattr(ret_val, '__name__'): + if isinstance(ret_val, lc.Type) and not hasattr(ret_val, '__name__'): ret_val.__name__ = self.code_obj.co_names[arg] return [ret_val] @@ -522,8 +539,8 @@ def translate_function (func, lltype, llvm_module = None, **kws): '''Given a function and an LLVM function type, emit LLVM code for that function using a new LLVMTranslator instance.''' translator = LLVMTranslator(llvm_module) - translator.translate(func, lltype, kws) - return translator + ret_val = translator.translate(func, lltype, kws) + return ret_val # ______________________________________________________________________ diff --git a/bytecode_visitor.py b/bytecode_visitor.py index 6048ba8..091e138 100644 --- a/bytecode_visitor.py +++ b/bytecode_visitor.py @@ -24,359 +24,128 @@ class BytecodeVisitor (object): 'BytecodeVisitor.visit_synthetic_op() must be overloaded if using ' 'synthetic opcodes.') - def op_BINARY_ADD (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_ADD") - - def op_BINARY_AND (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_AND") - - def op_BINARY_DIVIDE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_DIVIDE") - - def op_BINARY_FLOOR_DIVIDE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_FLOOR_DIVIDE") - - def op_BINARY_LSHIFT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_LSHIFT") - - def op_BINARY_MODULO (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_MODULO") - - def op_BINARY_MULTIPLY (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_MULTIPLY") - - def op_BINARY_OR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_OR") - - def op_BINARY_POWER (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_POWER") - - def op_BINARY_RSHIFT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_RSHIFT") - - def op_BINARY_SUBSCR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_SUBSCR") - - def op_BINARY_SUBTRACT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_SUBTRACT") - - def op_BINARY_TRUE_DIVIDE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_TRUE_DIVIDE") - - def op_BINARY_XOR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_XOR") - - def op_BREAK_LOOP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BREAK_LOOP") - - def op_BUILD_CLASS (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BUILD_CLASS") - - def op_BUILD_LIST (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BUILD_LIST") - - def op_BUILD_MAP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BUILD_MAP") - - def op_BUILD_SET (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BUILD_SET") - - def op_BUILD_SLICE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BUILD_SLICE") - - def op_BUILD_TUPLE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BUILD_TUPLE") - - def op_CALL_FUNCTION (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_CALL_FUNCTION") - - def op_CALL_FUNCTION_KW (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_CALL_FUNCTION_KW") - - def op_CALL_FUNCTION_VAR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_CALL_FUNCTION_VAR") - - def op_CALL_FUNCTION_VAR_KW (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_CALL_FUNCTION_VAR_KW") - - def op_COMPARE_OP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_COMPARE_OP") - - def op_CONTINUE_LOOP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_CONTINUE_LOOP") - - def op_DELETE_ATTR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_DELETE_ATTR") - - def op_DELETE_DEREF (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_DELETE_DEREF") - - def op_DELETE_FAST (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_DELETE_FAST") - - def op_DELETE_GLOBAL (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_DELETE_GLOBAL") - - def op_DELETE_NAME (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_DELETE_NAME") - - def op_DELETE_SLICE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_DELETE_SLICE") - - def op_DELETE_SUBSCR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_DELETE_SUBSCR") - - def op_DUP_TOP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_DUP_TOP") - - def op_DUP_TOPX (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_DUP_TOPX") - - def op_DUP_TOP_TWO (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_DUP_TOP_TWO") - - def op_END_FINALLY (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_END_FINALLY") - - def op_EXEC_STMT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_EXEC_STMT") - - def op_EXTENDED_ARG (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_EXTENDED_ARG") - - def op_FOR_ITER (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_FOR_ITER") - - def op_GET_ITER (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_GET_ITER") - - def op_IMPORT_FROM (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_IMPORT_FROM") - - def op_IMPORT_NAME (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_IMPORT_NAME") - - def op_IMPORT_STAR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_IMPORT_STAR") - - def op_INPLACE_ADD (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_ADD") - - def op_INPLACE_AND (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_AND") - - def op_INPLACE_DIVIDE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_DIVIDE") - - def op_INPLACE_FLOOR_DIVIDE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_FLOOR_DIVIDE") - - def op_INPLACE_LSHIFT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_LSHIFT") - - def op_INPLACE_MODULO (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_MODULO") - - def op_INPLACE_MULTIPLY (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_MULTIPLY") - - def op_INPLACE_OR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_OR") - - def op_INPLACE_POWER (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_POWER") - - def op_INPLACE_RSHIFT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_RSHIFT") - - def op_INPLACE_SUBTRACT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_SUBTRACT") - - def op_INPLACE_TRUE_DIVIDE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_TRUE_DIVIDE") - - def op_INPLACE_XOR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_XOR") - - def op_JUMP_ABSOLUTE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_JUMP_ABSOLUTE") - - def op_JUMP_FORWARD (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_JUMP_FORWARD") - - def op_JUMP_IF_FALSE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_JUMP_IF_FALSE") - - def op_JUMP_IF_FALSE_OR_POP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_JUMP_IF_FALSE_OR_POP") - - def op_JUMP_IF_TRUE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_JUMP_IF_TRUE") - - def op_JUMP_IF_TRUE_OR_POP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_JUMP_IF_TRUE_OR_POP") - - def op_LIST_APPEND (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_LIST_APPEND") - - def op_LOAD_ATTR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_LOAD_ATTR") - - def op_LOAD_BUILD_CLASS (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_LOAD_BUILD_CLASS") - - def op_LOAD_CLOSURE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_LOAD_CLOSURE") - - def op_LOAD_CONST (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_LOAD_CONST") - - def op_LOAD_DEREF (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_LOAD_DEREF") - - def op_LOAD_FAST (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_LOAD_FAST") - - def op_LOAD_GLOBAL (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_LOAD_GLOBAL") - - def op_LOAD_LOCALS (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_LOAD_LOCALS") - - def op_LOAD_NAME (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_LOAD_NAME") - - def op_MAKE_CLOSURE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_MAKE_CLOSURE") - - def op_MAKE_FUNCTION (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_MAKE_FUNCTION") - - def op_MAP_ADD (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_MAP_ADD") - - def op_NOP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_NOP") - - def op_POP_BLOCK (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_POP_BLOCK") - - def op_POP_EXCEPT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_POP_EXCEPT") - - def op_POP_JUMP_IF_FALSE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_POP_JUMP_IF_FALSE") - - def op_POP_JUMP_IF_TRUE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_POP_JUMP_IF_TRUE") - - def op_POP_TOP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_POP_TOP") - - def op_PRINT_EXPR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_PRINT_EXPR") - - def op_PRINT_ITEM (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_PRINT_ITEM") - - def op_PRINT_ITEM_TO (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_PRINT_ITEM_TO") - - def op_PRINT_NEWLINE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_PRINT_NEWLINE") - - def op_PRINT_NEWLINE_TO (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_PRINT_NEWLINE_TO") - - def op_RAISE_VARARGS (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_RAISE_VARARGS") - - def op_RETURN_VALUE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_RETURN_VALUE") - - def op_ROT_FOUR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_ROT_FOUR") - - def op_ROT_THREE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_ROT_THREE") - - def op_ROT_TWO (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_ROT_TWO") - - def op_SETUP_EXCEPT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_SETUP_EXCEPT") - - def op_SETUP_FINALLY (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_SETUP_FINALLY") - - def op_SETUP_LOOP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_SETUP_LOOP") - - def op_SETUP_WITH (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_SETUP_WITH") - - def op_SET_ADD (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_SET_ADD") - - def op_SLICE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_SLICE") - - def op_STOP_CODE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_STOP_CODE") - - def op_STORE_ATTR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_STORE_ATTR") - - def op_STORE_DEREF (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_STORE_DEREF") - - def op_STORE_FAST (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_STORE_FAST") - - def op_STORE_GLOBAL (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_STORE_GLOBAL") - - def op_STORE_LOCALS (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_STORE_LOCALS") - - def op_STORE_MAP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_STORE_MAP") - - def op_STORE_NAME (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_STORE_NAME") - - def op_STORE_SLICE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_STORE_SLICE") - - def op_STORE_SUBSCR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_STORE_SUBSCR") - - def op_UNARY_CONVERT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_UNARY_CONVERT") - - def op_UNARY_INVERT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_UNARY_INVERT") - - def op_UNARY_NEGATIVE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_UNARY_NEGATIVE") - - def op_UNARY_NOT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_UNARY_NOT") - - def op_UNARY_POSITIVE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_UNARY_POSITIVE") - - def op_UNPACK_EX (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_UNPACK_EX") - - def op_UNPACK_SEQUENCE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_UNPACK_SEQUENCE") - - def op_WITH_CLEANUP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_WITH_CLEANUP") - - def op_YIELD_VALUE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_YIELD_VALUE") + def _not_implemented (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_%s (@ bytecode index %d)" + % (self.opnames[op], i)) + + op_BINARY_ADD = _not_implemented + op_BINARY_AND = _not_implemented + op_BINARY_DIVIDE = _not_implemented + op_BINARY_FLOOR_DIVIDE = _not_implemented + op_BINARY_LSHIFT = _not_implemented + op_BINARY_MODULO = _not_implemented + op_BINARY_MULTIPLY = _not_implemented + op_BINARY_OR = _not_implemented + op_BINARY_POWER = _not_implemented + op_BINARY_RSHIFT = _not_implemented + op_BINARY_SUBSCR = _not_implemented + op_BINARY_SUBTRACT = _not_implemented + op_BINARY_TRUE_DIVIDE = _not_implemented + op_BINARY_XOR = _not_implemented + op_BREAK_LOOP = _not_implemented + op_BUILD_CLASS = _not_implemented + op_BUILD_LIST = _not_implemented + op_BUILD_MAP = _not_implemented + op_BUILD_SET = _not_implemented + op_BUILD_SLICE = _not_implemented + op_BUILD_TUPLE = _not_implemented + op_CALL_FUNCTION = _not_implemented + op_CALL_FUNCTION_KW = _not_implemented + op_CALL_FUNCTION_VAR = _not_implemented + op_CALL_FUNCTION_VAR_KW = _not_implemented + op_COMPARE_OP = _not_implemented + op_CONTINUE_LOOP = _not_implemented + op_DELETE_ATTR = _not_implemented + op_DELETE_DEREF = _not_implemented + op_DELETE_FAST = _not_implemented + op_DELETE_GLOBAL = _not_implemented + op_DELETE_NAME = _not_implemented + op_DELETE_SLICE = _not_implemented + op_DELETE_SUBSCR = _not_implemented + op_DUP_TOP = _not_implemented + op_DUP_TOPX = _not_implemented + op_DUP_TOP_TWO = _not_implemented + op_END_FINALLY = _not_implemented + op_EXEC_STMT = _not_implemented + op_EXTENDED_ARG = _not_implemented + op_FOR_ITER = _not_implemented + op_GET_ITER = _not_implemented + op_IMPORT_FROM = _not_implemented + op_IMPORT_NAME = _not_implemented + op_IMPORT_STAR = _not_implemented + op_INPLACE_ADD = _not_implemented + op_INPLACE_AND = _not_implemented + op_INPLACE_DIVIDE = _not_implemented + op_INPLACE_FLOOR_DIVIDE = _not_implemented + op_INPLACE_LSHIFT = _not_implemented + op_INPLACE_MODULO = _not_implemented + op_INPLACE_MULTIPLY = _not_implemented + op_INPLACE_OR = _not_implemented + op_INPLACE_POWER = _not_implemented + op_INPLACE_RSHIFT = _not_implemented + op_INPLACE_SUBTRACT = _not_implemented + op_INPLACE_TRUE_DIVIDE = _not_implemented + op_INPLACE_XOR = _not_implemented + op_JUMP_ABSOLUTE = _not_implemented + op_JUMP_FORWARD = _not_implemented + op_JUMP_IF_FALSE = _not_implemented + op_JUMP_IF_FALSE_OR_POP = _not_implemented + op_JUMP_IF_TRUE = _not_implemented + op_JUMP_IF_TRUE_OR_POP = _not_implemented + op_LIST_APPEND = _not_implemented + op_LOAD_ATTR = _not_implemented + op_LOAD_BUILD_CLASS = _not_implemented + op_LOAD_CLOSURE = _not_implemented + op_LOAD_CONST = _not_implemented + op_LOAD_DEREF = _not_implemented + op_LOAD_FAST = _not_implemented + op_LOAD_GLOBAL = _not_implemented + op_LOAD_LOCALS = _not_implemented + op_LOAD_NAME = _not_implemented + op_MAKE_CLOSURE = _not_implemented + op_MAKE_FUNCTION = _not_implemented + op_MAP_ADD = _not_implemented + op_NOP = _not_implemented + op_POP_BLOCK = _not_implemented + op_POP_EXCEPT = _not_implemented + op_POP_JUMP_IF_FALSE = _not_implemented + op_POP_JUMP_IF_TRUE = _not_implemented + op_POP_TOP = _not_implemented + op_PRINT_EXPR = _not_implemented + op_PRINT_ITEM = _not_implemented + op_PRINT_ITEM_TO = _not_implemented + op_PRINT_NEWLINE = _not_implemented + op_PRINT_NEWLINE_TO = _not_implemented + op_RAISE_VARARGS = _not_implemented + op_RETURN_VALUE = _not_implemented + op_ROT_FOUR = _not_implemented + op_ROT_THREE = _not_implemented + op_ROT_TWO = _not_implemented + op_SETUP_EXCEPT = _not_implemented + op_SETUP_FINALLY = _not_implemented + op_SETUP_LOOP = _not_implemented + op_SETUP_WITH = _not_implemented + op_SET_ADD = _not_implemented + op_SLICE = _not_implemented + op_STOP_CODE = _not_implemented + op_STORE_ATTR = _not_implemented + op_STORE_DEREF = _not_implemented + op_STORE_FAST = _not_implemented + op_STORE_GLOBAL = _not_implemented + op_STORE_LOCALS = _not_implemented + op_STORE_MAP = _not_implemented + op_STORE_NAME = _not_implemented + op_STORE_SLICE = _not_implemented + op_STORE_SUBSCR = _not_implemented + op_UNARY_CONVERT = _not_implemented + op_UNARY_INVERT = _not_implemented + op_UNARY_NEGATIVE = _not_implemented + op_UNARY_NOT = _not_implemented + op_UNARY_POSITIVE = _not_implemented + op_UNPACK_EX = _not_implemented + op_UNPACK_SEQUENCE = _not_implemented + op_WITH_CLEANUP = _not_implemented + op_YIELD_VALUE = _not_implemented # ______________________________________________________________________ diff --git a/nobitey.py b/nobitey.py index 5ae133f..67d134e 100644 --- a/nobitey.py +++ b/nobitey.py @@ -11,7 +11,7 @@ import llvm.core as lc import llvm.ee as le import bytetype - +import byte_translator from pyaddfunc import pyaddfunc LLVM_TO_INT_PARSE_STR_MAP = { @@ -80,80 +80,54 @@ class NoBitey (object): return result def build_wrapper_function (self, llvm_function, engine = None): - manual_linkage = False - if self.target_module != llvm_function.module: - manual_linkage = True - assert engine, ("Execution engine argument currently required for " - "linkage to separate LLVM module.") - llvm_function_ptr = self.target_module.add_global_variable( - llvm_function.type, llvm_function.name) - llvm_function_ptr.initializer = lc.Constant.inttoptr( - lc.Constant.int(bytetype.liptr, - engine.get_pointer_to_function(llvm_function)), - llvm_function.type) - llvm_function_ptr.linkage = lc.LINKAGE_INTERNAL - # __________________________________________________ - _pyobj_p = bytetype.l_pyobject_head_struct_p - _void_p = _char_p = bytetype.li8_ptr - self.crnt_function = self.target_module.add_function( - lc.Type.function(_pyobj_p, (_pyobj_p, _pyobj_p)), - llvm_function.name + "_wrapper") - entry_block = self.crnt_function.append_basic_block('entry') - args_ok_block = self.crnt_function.append_basic_block('args_ok') - exit_block = self.crnt_function.append_basic_block('exit') - _int32_zero = lc.Constant.int(bytetype.li32, 0) - _Py_BuildValue = self.target_module.get_or_insert_function( - lc.Type.function(_pyobj_p, [_char_p], True), 'Py_BuildValue') - _PyArg_ParseTuple = self.target_module.get_or_insert_function( - lc.Type.function(bytetype.lc_int, [_pyobj_p, _char_p], True), - 'PyArg_ParseTuple') - _PyEval_SaveThread = self.target_module.get_or_insert_function( - lc.Type.function(_void_p, []), 'PyEval_SaveThread') - _PyEval_RestoreThread = self.target_module.get_or_insert_function( - lc.Type.function(lc.Type.void(), [_void_p]), - 'PyEval_RestoreThread') - # __________________________________________________ - # entry: - builder = lc.Builder.new(entry_block) arg_types = llvm_function.type.pointee.args - parse_str = builder.gep( - get_string_constant( - self.target_module, - self.build_parse_string(arg_types)), - [_int32_zero, _int32_zero]) - parse_args = [builder.alloca(arg_ty) for arg_ty in arg_types] - parse_args.insert(0, parse_str) - parse_args.insert(0, self.crnt_function.args[1]) - parse_result = builder.call(_PyArg_ParseTuple, parse_args) - builder.cbranch(builder.icmp(lc.ICMP_NE, parse_result, _int32_zero), - args_ok_block, exit_block) + return_type = llvm_function.type.pointee.return_type + li32_0 = lc.Constant.int(bytetype.li32, 0) + def get_llvm_function (builder): + if self.target_module != llvm_function.module: + llvm_function_ptr = self.target_module.add_global_variable( + llvm_function.type, llvm_function.name) + llvm_function_ptr.initializer = lc.Constant.inttoptr( + lc.Constant.int( + bytetype.liptr, + engine.get_pointer_to_function(llvm_function)), + llvm_function.type) + llvm_function_ptr.linkage = lc.LINKAGE_INTERNAL + ret_val = builder.load(llvm_function_ptr) + else: + ret_val = llvm_function + return ret_val + def build_parse_args (builder): + return [builder.alloca(arg_type) for arg_type in arg_types] + def build_parse_string (builder): + parse_str = get_string_constant( + self.target_module, self.build_parse_string(arg_types)) + return builder.gep(parse_str, (li32_0, li32_0)) + def load_target_args (builder, args): + return [builder.load(arg) for arg in args] + def build_build_string (builder): + build_str = get_string_constant( + self.target_module, self._build_parse_string(return_type)) + return builder.gep(build_str, (li32_0, li32_0)) + handle_abi_casts = self.handle_abi_casts + target_function_name = llvm_function.name + "_wrapper" # __________________________________________________ - # args_ok: - builder = lc.Builder.new(args_ok_block) - thread_state = builder.call(_PyEval_SaveThread, ()) - target_args = [builder.load(parse_arg) for parse_arg in parse_args[2:]] - if manual_linkage: - result = builder.call(builder.load(llvm_function_ptr), target_args) - else: - result = builder.call(llvm_function, target_args) - result_cast = self.handle_abi_casts(builder, result) - builder.call(_PyEval_RestoreThread, (thread_state,)) - build_str = builder.gep( - get_string_constant( - self.target_module, - self._build_parse_string(result.type)), - [_int32_zero, _int32_zero]) - py_result = builder.call(_Py_BuildValue, [build_str, result_cast]) - builder.branch(exit_block) + @byte_translator.llnumba(bytetype.l_pyfunc, self.target_module, + **locals()) + def _wrapper (self, args): + ret_val = l_pyobj_p(0) + parse_args = build_parse_args() + parse_result = PyArg_ParseTuple(args, build_parse_string(), + *parse_args) + if parse_result != li32(0): + thread_state = PyEval_SaveThread() + target_args = load_target_args(parse_args) + llresult = handle_abi_casts(get_llvm_function()(*target_args)) + PyEval_RestoreThread(thread_state) + ret_val = Py_BuildValue(build_build_string(), llresult) + return ret_val # __________________________________________________ - # exit: - builder = lc.Builder.new(exit_block) - rval = builder.phi(bytetype.l_pyobject_head_struct_p) - rval.add_incoming(lc.Constant.null(bytetype.l_pyobject_head_struct_p), - entry_block) - rval.add_incoming(py_result, args_ok_block) - builder.ret(rval) - return self.crnt_function + return _wrapper def wrap_llvm_module (self, llvm_module, engine = None, py_module = None): ''' @@ -167,6 +141,7 @@ class NoBitey (object): engine = le.ExecutionEngine.new(llvm_module) wrappers = [self.build_wrapper_function(func, engine) for func in functions] + if __debug__: print(self.target_module) if self.target_module != llvm_module: engine.add_module(self.target_module) py_wrappers = [pyaddfunc(wrapper.name, @@ -360,11 +335,13 @@ def build_test_module (): # ______________________________________________________________________ -def main (*args): +def test_wrap_module (arg = None): # Build up a module. m = build_test_module() - wrap_module = NoBitey().wrap_llvm_module_in_python(m) - print(m) + if arg and arg.lower() == 'separated': + wrap_module = NoBitey().wrap_llvm_module_in_python(m) + else: + wrap_module = NoBitey(m).wrap_llvm_module_in_python(m) # Now try running the generated wrappers. for py_wf_name in ('add_42_i32', 'add_42_i64', 'add_42_float', 'add_42_double'): @@ -376,6 +353,15 @@ def main (*args): result, expected, py_wf) return wrap_module +# ______________________________________________________________________ + +def main (*args): + if args: + for arg in args: + test_wrap_module(arg) + else: + test_wrap_module() + if __name__ == "__main__": main(*sys.argv[1:]) From e0d1b94053517bccb30f88b53d541cd4b986dfbb Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 16 Oct 2012 16:35:20 -0500 Subject: [PATCH 071/516] Add NamedMetaData --- llvm/_core.cpp | 19 +++++++++++++++++++ llvm/core.py | 33 +++++++++++++++++++++++++++++++++ llvm/extra.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ llvm/extra.h | 31 +++++++++++++++++++++++++++++++ llvm/llvm_c_extra.h | 1 + llvm/test_llvmpy.py | 14 ++++++++++++++ 6 files changed, 138 insertions(+) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 1ec86aa..19dadec 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -295,6 +295,9 @@ _wLLVMLinkModules(PyObject *self, PyObject *args) LLVMPY_CATCH_ALL } +_wrap_objstr2obj(LLVMModuleGetOrInsertNamedMetaData, LLVMModuleRef, LLVMNamedMDRef) +_wrap_objstr2obj(LLVMModuleGetNamedMetaData, LLVMModuleRef, LLVMNamedMDRef) + /*===----------------------------------------------------------------------===*/ /* Types */ /*===----------------------------------------------------------------------===*/ @@ -703,6 +706,14 @@ _wLLVMGetNamedMetadataOperands(PyObject *self, PyObject *args) LLVMPY_CATCH_ALL } + +/*===-- NamedMetaData -----------------------------------------------------===*/ + +_wrap_obj2str( LLVMNamedMetaDataGetName, LLVMNamedMDRef ) +_wrap_objobj2none( LLVMNamedMetaDataAddOperand, LLVMNamedMDRef, LLVMValueRef ) +_wrap_obj2none( LLVMEraseNamedMetaData, LLVMNamedMDRef ) +_wrap_dumper(LLVMDumpNamedMDToString, LLVMNamedMDRef) + /*===-- Instructions -----------------------------------------------------===*/ _wrap_obj2obj(LLVMGetInstructionParent, LLVMValueRef, LLVMBasicBlockRef) @@ -1564,6 +1575,8 @@ static PyMethodDef core_methods[] = { _method( LLVMModuleGetPointerSize ) _method( LLVMModuleGetOrInsertFunction ) _method( LLVMLinkModules ) + _method( LLVMModuleGetOrInsertNamedMetaData ) + _method( LLVMModuleGetNamedMetaData ) /* Types */ @@ -1788,6 +1801,12 @@ static PyMethodDef core_methods[] = { _method( LLVMMetaDataGetNumOperands ) _method( LLVMMetaDataStringGet ) + /* NamedMetaData */ + _method( LLVMNamedMetaDataGetName ) + _method( LLVMNamedMetaDataAddOperand ) + _method( LLVMEraseNamedMetaData ) + _method( LLVMDumpNamedMDToString ) + /* Instructions */ _method( LLVMGetInstructionParent ) _method( LLVMGetFirstInstruction ) diff --git a/llvm/core.py b/llvm/core.py index 2de3615..8b9a7ae 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -574,6 +574,14 @@ class Module(llvm.Ownable, llvm.Cacheable): else: return data + def get_or_insert_named_metadata(self, name): + ptr = _core.LLVMModuleGetOrInsertNamedMetaData(self.ptr, name) + return NamedMetaData(ptr) + + def get_named_metadata(self, name): + ptr = _core.LLVMModuleGetNamedMetaData(self.ptr, name) + return NamedMetaData(ptr) + #===----------------------------------------------------------------------=== # Types #===----------------------------------------------------------------------=== @@ -1542,6 +1550,31 @@ class MetaDataString(Value): '''Same as MDString::getString''' return self.name +class NamedMetaData(llvm.Cacheable): + @staticmethod + def get_or_insert(mod, name): + return mod.get_or_insert_named_metadata(name) + + @staticmethod + def get(mod, name): + return mod.get_named_metadata(name) + + def __init__(self, ptr): + self.ptr = ptr + + def delete(self): + _core.LLVMEraseNamedMetaData(self.ptr) + + @property + def name(self): + return _core.LLVMNamedMetaDataGetName(self.ptr) + + def __str__(self): + return _core.LLVMDumpNamedMDToString(self.ptr) + + def add(self, operand): + _core.LLVMNamedMetaDataAddOperand(self.ptr, operand.ptr) + #===----------------------------------------------------------------------=== # Instruction #===----------------------------------------------------------------------=== diff --git a/llvm/extra.cpp b/llvm/extra.cpp index 537eae2..198fbb9 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -75,6 +75,7 @@ #include "llvm/Linker.h" #include "llvm/Support/SourceMgr.h" + // LLVM-C includes #include "llvm-c/Core.h" #include "llvm-c/ExecutionEngine.h" @@ -86,6 +87,7 @@ namespace llvm{ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(EngineBuilder, LLVMEngineBuilderRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(NamedMDNode, LLVMNamedMDRef) template inline T **unwrap(LLVMTypeRef *Tys, unsigned Length) { @@ -133,6 +135,44 @@ const CodeGenOpt::Level OptLevelMap[] = { }; } // end anony namespace +const char * LLVMDumpNamedMDToString(LLVMNamedMDRef nmd) +{ + using namespace llvm; + std::string s; + llvm::raw_string_ostream buf(s); + unwrap(nmd)->print(buf, NULL); + return strdup(buf.str().c_str()); +} + +const char * LLVMNamedMetaDataGetName(LLVMNamedMDRef nmd) +{ + using namespace llvm; + return unwrap(nmd)->getName().data(); +} + +void LLVMNamedMetaDataAddOperand(LLVMNamedMDRef nmd, LLVMValueRef md) +{ + using namespace llvm; + unwrap(nmd)->addOperand(unwrap(md)); +} + +void LLVMEraseNamedMetaData(LLVMNamedMDRef nmd) +{ + using namespace llvm; + unwrap(nmd)->eraseFromParent(); +} + +LLVMNamedMDRef LLVMModuleGetOrInsertNamedMetaData(LLVMModuleRef mod, const char *name) +{ + using namespace llvm; + return wrap(unwrap(mod)->getOrInsertNamedMetadata(name)); +} + +LLVMNamedMDRef LLVMModuleGetNamedMetaData(LLVMModuleRef mod, const char *name) +{ + using namespace llvm; + return wrap(unwrap(mod)->getNamedMetadata(name)); +} void LLVMInstSetMetaData(LLVMValueRef instref, const char* mdkind, LLVMValueRef metaref) diff --git a/llvm/extra.h b/llvm/extra.h index 1772878..32ca193 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -47,12 +47,43 @@ #include "llvm-c/Transforms/PassManagerBuilder.h" + #include "llvm_c_extra.h" #ifdef __cplusplus extern "C" { #endif +/* + * Wraps NamedMDNode::print() + */ +const char * LLVMDumpNamedMDToString(LLVMNamedMDRef nmd); + +/* + * Wraps NamedMDNode::getName() + */ +const char * LLVMNamedMetaDataGetName(LLVMNamedMDRef nmd); + +/* + * Wraps NamedMDNode::addOperand() + */ +void LLVMNamedMetaDataAddOperand(LLVMNamedMDRef nmd, LLVMValueRef md); + +/* + * Wraps NamedMDNode::eraseFromParent() + */ +void LLVMEraseNamedMetaData(LLVMNamedMDRef nmd); + +/* + * Wraps Module::getOrInsertNamedMetadata + */ +LLVMNamedMDRef LLVMModuleGetOrInsertNamedMetaData(LLVMModuleRef mod, const char *name); + +/* + * Wraps Module::getNamedMetadata + */ +LLVMNamedMDRef LLVMModuleGetNamedMetaData(LLVMModuleRef mod, const char *name); + /* * Wraps Instruction::setMetadata() */ diff --git a/llvm/llvm_c_extra.h b/llvm/llvm_c_extra.h index 53fe71c..9eb77dc 100644 --- a/llvm/llvm_c_extra.h +++ b/llvm/llvm_c_extra.h @@ -20,6 +20,7 @@ inline ref wrap(const ty *P) { \ typedef struct LLVMOpaqueEngineBuilder *LLVMEngineBuilderRef; typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef; +typedef struct LLVMOpaqueNamedMD *LLVMNamedMDRef; #ifdef __cplusplus diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 985df2b..7757cd1 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -952,6 +952,20 @@ tests.append(TestVolatile) # --------------------------------------------------------------------------- +class TestNamedMetaData(unittest.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) + +# --------------------------------------------------------------------------- + def run(verbosity=1): print('llvmpy is installed in: ' + os.path.dirname(__file__)) print('llvmpy version: ' + llvm.__version__) From 01d0ff4ebafdb685a61d7e06beaaed8c077aff16 Mon Sep 17 00:00:00 2001 From: Jon Riehl Date: Tue, 16 Oct 2012 10:18:13 -0500 Subject: [PATCH 072/516] Added manual linkage to nobitey when target module isn't the same as the source module. --- byte_flow.py | 3 ++- byte_translator.py | 24 ++++++++++++++++++------ bytetype.py | 2 ++ nobitey.py | 25 +++++++++++++++++++++---- opcode_util.py | 2 +- 5 files changed, 44 insertions(+), 12 deletions(-) diff --git a/byte_flow.py b/byte_flow.py index f0df934..822e564 100644 --- a/byte_flow.py +++ b/byte_flow.py @@ -31,7 +31,8 @@ class BytecodeFlowBuilder (BytecodeIterVisitor): if opname in opcode.opmap) def _visit_op (self, i, op, arg, opname, pops, pushes, appends): - assert pops is not None + assert pops is not None, ('%s not well defined in opcode_util.' + 'OPCODE_MAP' % opname) if pops: if pops < 0: pops = arg - pops - 1 diff --git a/byte_translator.py b/byte_translator.py index 62f3e21..91753dd 100644 --- a/byte_translator.py +++ b/byte_translator.py @@ -10,7 +10,6 @@ import opcode import llvm.core as lc import opcode_util - import bytetype from bytecode_visitor import BytecodeFlowVisitor from byte_flow import BytecodeFlowBuilder @@ -353,25 +352,30 @@ class LLVMTranslator (BytecodeFlowVisitor): def op_CALL_FUNCTION (self, i, op, arg, *args, **kws): fn = args[0] args = args[1:] + fn_name = getattr(fn, '__name__', None) if isinstance(fn, lc.Type): if isinstance(fn, lc.FunctionType): ret_val = [self.builder.call( - self.llvm_module.get_or_insert_function(fn, fn.__name__), + self.llvm_module.get_or_insert_function(fn, fn_name), args)] else: assert len(args) == 1 ret_val = [LLVMCaster.build_cast(self.builder, args[0], fn)] - elif fn.__name__ in lc.Builder.__dict__: + elif fn_name in lc.Builder.__dict__: ret_val = [fn(self.builder, *args)] else: - raise NotImplementedError("Don't know how to call %r!" % (fn,)) + raise NotImplementedError("Don't know how to call %s() (%r)!" % + (fn_name, fn)) return ret_val def op_CALL_FUNCTION_KW (self, i, op, arg, *args, **kws): raise NotImplementedError("LLVMTranslator.op_CALL_FUNCTION_KW") def op_CALL_FUNCTION_VAR (self, i, op, arg, *args, **kws): - raise NotImplementedError("LLVMTranslator.op_CALL_FUNCTION_VAR") + args = list(args) + var_args = list(args.pop()) + args.extend(var_args) + return self.op_CALL_FUNCTION(i, op, arg, *args, **kws) def op_CALL_FUNCTION_VAR_KW (self, i, op, arg, *args, **kws): raise NotImplementedError("LLVMTranslator.op_CALL_FUNCTION_VAR_KW") @@ -454,7 +458,7 @@ class LLVMTranslator (BytecodeFlowVisitor): def op_LOAD_GLOBAL (self, i, op, arg, *args, **kws): ret_val = self.globals[self.code_obj.co_names[arg]] - if not hasattr(ret_val, '__name__'): + if isinstance(fn, lc.Type) and not hasattr(ret_val, '__name__'): ret_val.__name__ = self.code_obj.co_names[arg] return [ret_val] @@ -521,6 +525,14 @@ def translate_function (func, lltype, llvm_module = None, **kws): translator.translate(func, lltype, kws) return translator +# ______________________________________________________________________ + +def llnumba (lltype, llvm_module = None, **kws): + '''Decorator version of translate_function().''' + def _llnumba (func): + return translate_function(func, lltype, llvm_module, **kws) + return _llnumba + # ______________________________________________________________________ # Main (self-test) routine diff --git a/bytetype.py b/bytetype.py index 25a0355..211f3f8 100644 --- a/bytetype.py +++ b/bytetype.py @@ -13,6 +13,7 @@ li8 = lc.Type.int(8) li16 = lc.Type.int(16) li32 = lc.Type.int(32) li64 = lc.Type.int(64) +liptr = lc.Type.int(ctypes.sizeof(ctypes.c_void_p) * 8) lc_size_t = lc.Type.int(ctypes.sizeof( getattr(ctypes, 'c_ssize_t', getattr(ctypes, 'c_size_t'))) * 8) lfloat = lc.Type.float() @@ -25,6 +26,7 @@ lc_long = lc.Type.int(ctypes.sizeof(ctypes.c_long) * 8) l_pyobject_head = [lc_size_t, lc.Type.pointer(li32)] l_pyobject_head_struct = lc.Type.struct(l_pyobject_head) l_pyobj_p = l_pyobject_head_struct_p = lc.Type.pointer(l_pyobject_head_struct) +l_pyfunc = lc.Type.function(l_pyobj_p, (l_pyobj_p, l_pyobj_p)) strlen = lc.Type.function(lc_size_t, (li8_ptr,)) strncpy = lc.Type.function(li8_ptr, (li8_ptr, li8_ptr, lc_size_t)) diff --git a/nobitey.py b/nobitey.py index bca491e..5ae133f 100644 --- a/nobitey.py +++ b/nobitey.py @@ -79,7 +79,20 @@ class NoBitey (object): result = builder.fpext(result, bytetype.ldouble) return result - def build_wrapper_function (self, llvm_function): + def build_wrapper_function (self, llvm_function, engine = None): + manual_linkage = False + if self.target_module != llvm_function.module: + manual_linkage = True + assert engine, ("Execution engine argument currently required for " + "linkage to separate LLVM module.") + llvm_function_ptr = self.target_module.add_global_variable( + llvm_function.type, llvm_function.name) + llvm_function_ptr.initializer = lc.Constant.inttoptr( + lc.Constant.int(bytetype.liptr, + engine.get_pointer_to_function(llvm_function)), + llvm_function.type) + llvm_function_ptr.linkage = lc.LINKAGE_INTERNAL + # __________________________________________________ _pyobj_p = bytetype.l_pyobject_head_struct_p _void_p = _char_p = bytetype.li8_ptr self.crnt_function = self.target_module.add_function( @@ -119,7 +132,10 @@ class NoBitey (object): builder = lc.Builder.new(args_ok_block) thread_state = builder.call(_PyEval_SaveThread, ()) target_args = [builder.load(parse_arg) for parse_arg in parse_args[2:]] - result = builder.call(llvm_function, target_args) + if manual_linkage: + result = builder.call(builder.load(llvm_function_ptr), target_args) + else: + result = builder.call(llvm_function, target_args) result_cast = self.handle_abi_casts(builder, result) builder.call(_PyEval_RestoreThread, (thread_state,)) build_str = builder.gep( @@ -147,9 +163,10 @@ class NoBitey (object): if not func.name.startswith("_") and not func.is_declaration and func.linkage == lc.LINKAGE_EXTERNAL] - wrappers = [self.build_wrapper_function(func) for func in functions] if engine is None: engine = le.ExecutionEngine.new(llvm_module) + wrappers = [self.build_wrapper_function(func, engine) + for func in functions] if self.target_module != llvm_module: engine.add_module(self.target_module) py_wrappers = [pyaddfunc(wrapper.name, @@ -346,8 +363,8 @@ def build_test_module (): def main (*args): # Build up a module. m = build_test_module() - print(m) wrap_module = NoBitey().wrap_llvm_module_in_python(m) + print(m) # Now try running the generated wrappers. for py_wf_name in ('add_42_i32', 'add_42_i64', 'add_42_float', 'add_42_double'): diff --git a/opcode_util.py b/opcode_util.py index 9bc8f25..5c0cff9 100644 --- a/opcode_util.py +++ b/opcode_util.py @@ -94,7 +94,7 @@ OPCODE_MAP = { 'LOAD_LOCALS': (None, None, None), 'LOAD_NAME': (0, 1, None), 'MAKE_CLOSURE': (None, None, None), - 'MAKE_FUNCTION': (None, None, None), + 'MAKE_FUNCTION': (-2, 1, None), 'MAP_ADD': (None, None, None), 'NOP': (0, None, None), 'POP_BLOCK': (0, None, 1), From 80437fc07723f9a93b96d9a942548bc1ffe5b4ce Mon Sep 17 00:00:00 2001 From: Jon Riehl Date: Tue, 16 Oct 2012 12:36:47 -0500 Subject: [PATCH 073/516] Got nobitey unit test working using llnumba for wrapper generation. --- byte_translator.py | 39 +++- bytecode_visitor.py | 475 ++++++++++++-------------------------------- nobitey.py | 136 ++++++------- 3 files changed, 211 insertions(+), 439 deletions(-) diff --git a/byte_translator.py b/byte_translator.py index 91753dd..b7149cf 100644 --- a/byte_translator.py +++ b/byte_translator.py @@ -6,6 +6,7 @@ # Module imports import opcode +import types import llvm.core as lc @@ -68,6 +69,9 @@ class LLVMCaster (object): ret_val = builder.sitofp(lval1, lty2) return ret_val + def build_int_to_ptr_cast(_, builder, lval1, lty2): + return builder.inttoptr(lval1, lty2) + def build_float_to_int_cast(_, builder, lval1, lty2, unsigned = False): ret_val = None if unsigned: @@ -83,6 +87,7 @@ class LLVMCaster (object): (lc.TYPE_DOUBLE, lc.TYPE_FLOAT) : build_float_trunc, (lc.TYPE_INTEGER, lc.TYPE_FLOAT) : build_int_to_float_cast, (lc.TYPE_INTEGER, lc.TYPE_DOUBLE) : build_int_to_float_cast, + (lc.TYPE_INTEGER, lc.TYPE_POINTER) : build_int_to_ptr_cast, (lc.TYPE_FLOAT, lc.TYPE_INTEGER) : build_float_to_int_cast, (lc.TYPE_DOUBLE, lc.TYPE_INTEGER) : build_float_to_int_cast, @@ -156,6 +161,8 @@ class LLVMTranslator (BytecodeFlowVisitor): if not name.startswith('_')) self.loop_stack = [] self.llvm_type = llvm_type + self.target_function_name = env.get('target_function_name', + function.__name__) self.function = function self.code_obj = opcode_util.get_code_object(function) func_globals = getattr(function, 'func_globals', @@ -170,6 +177,7 @@ class LLVMTranslator (BytecodeFlowVisitor): del self.cfg del self.globals del self.code_obj + del self.target_function_name del self.function del self.llvm_type del self.loop_stack @@ -178,7 +186,7 @@ class LLVMTranslator (BytecodeFlowVisitor): def enter_flow_object (self, flow): super(LLVMTranslator, self).enter_flow_object(flow) self.llvm_function = self.llvm_module.add_function( - self.llvm_type, self.function.__name__) + self.llvm_type, self.target_function_name) self.llvm_blocks = {} self.llvm_definitions = {} self.pending_phis = {} @@ -195,6 +203,7 @@ class LLVMTranslator (BytecodeFlowVisitor): del self.llvm_definitions del self.llvm_blocks del self.llvm_function + if __debug__: print(ret_val) return ret_val def enter_block (self, block): @@ -353,19 +362,21 @@ class LLVMTranslator (BytecodeFlowVisitor): fn = args[0] args = args[1:] fn_name = getattr(fn, '__name__', None) - if isinstance(fn, lc.Type): + if isinstance(fn, (types.FunctionType, types.MethodType)): + ret_val = [fn(self.builder, *args)] + elif isinstance(fn, lc.Value): + ret_val = [self.builder.call(fn, args)] + elif isinstance(fn, lc.Type): if isinstance(fn, lc.FunctionType): ret_val = [self.builder.call( - self.llvm_module.get_or_insert_function(fn, fn_name), - args)] + self.llvm_module.get_or_insert_function(fn, fn_name), + args)] else: assert len(args) == 1 ret_val = [LLVMCaster.build_cast(self.builder, args[0], fn)] - elif fn_name in lc.Builder.__dict__: - ret_val = [fn(self.builder, *args)] else: - raise NotImplementedError("Don't know how to call %s() (%r)!" % - (fn_name, fn)) + raise NotImplementedError("Don't know how to call %s() (%r @ %d)!" + % (fn_name, fn, i)) return ret_val def op_CALL_FUNCTION_KW (self, i, op, arg, *args, **kws): @@ -456,9 +467,15 @@ class LLVMTranslator (BytecodeFlowVisitor): (py_val,)) return ret_val + def op_LOAD_DEREF (self, i, op, arg, *args, **kws): + ret_val = self.globals[self.code_obj.co_freevars[arg]] + if isinstance(ret_val, lc.Type) and not hasattr(ret_val, '__name__'): + ret_val.__name__ = self.code_obj.co_names[arg] + return [ret_val] + def op_LOAD_GLOBAL (self, i, op, arg, *args, **kws): ret_val = self.globals[self.code_obj.co_names[arg]] - if isinstance(fn, lc.Type) and not hasattr(ret_val, '__name__'): + if isinstance(ret_val, lc.Type) and not hasattr(ret_val, '__name__'): ret_val.__name__ = self.code_obj.co_names[arg] return [ret_val] @@ -522,8 +539,8 @@ def translate_function (func, lltype, llvm_module = None, **kws): '''Given a function and an LLVM function type, emit LLVM code for that function using a new LLVMTranslator instance.''' translator = LLVMTranslator(llvm_module) - translator.translate(func, lltype, kws) - return translator + ret_val = translator.translate(func, lltype, kws) + return ret_val # ______________________________________________________________________ diff --git a/bytecode_visitor.py b/bytecode_visitor.py index 6048ba8..091e138 100644 --- a/bytecode_visitor.py +++ b/bytecode_visitor.py @@ -24,359 +24,128 @@ class BytecodeVisitor (object): 'BytecodeVisitor.visit_synthetic_op() must be overloaded if using ' 'synthetic opcodes.') - def op_BINARY_ADD (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_ADD") - - def op_BINARY_AND (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_AND") - - def op_BINARY_DIVIDE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_DIVIDE") - - def op_BINARY_FLOOR_DIVIDE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_FLOOR_DIVIDE") - - def op_BINARY_LSHIFT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_LSHIFT") - - def op_BINARY_MODULO (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_MODULO") - - def op_BINARY_MULTIPLY (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_MULTIPLY") - - def op_BINARY_OR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_OR") - - def op_BINARY_POWER (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_POWER") - - def op_BINARY_RSHIFT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_RSHIFT") - - def op_BINARY_SUBSCR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_SUBSCR") - - def op_BINARY_SUBTRACT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_SUBTRACT") - - def op_BINARY_TRUE_DIVIDE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_TRUE_DIVIDE") - - def op_BINARY_XOR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BINARY_XOR") - - def op_BREAK_LOOP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BREAK_LOOP") - - def op_BUILD_CLASS (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BUILD_CLASS") - - def op_BUILD_LIST (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BUILD_LIST") - - def op_BUILD_MAP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BUILD_MAP") - - def op_BUILD_SET (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BUILD_SET") - - def op_BUILD_SLICE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BUILD_SLICE") - - def op_BUILD_TUPLE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_BUILD_TUPLE") - - def op_CALL_FUNCTION (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_CALL_FUNCTION") - - def op_CALL_FUNCTION_KW (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_CALL_FUNCTION_KW") - - def op_CALL_FUNCTION_VAR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_CALL_FUNCTION_VAR") - - def op_CALL_FUNCTION_VAR_KW (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_CALL_FUNCTION_VAR_KW") - - def op_COMPARE_OP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_COMPARE_OP") - - def op_CONTINUE_LOOP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_CONTINUE_LOOP") - - def op_DELETE_ATTR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_DELETE_ATTR") - - def op_DELETE_DEREF (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_DELETE_DEREF") - - def op_DELETE_FAST (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_DELETE_FAST") - - def op_DELETE_GLOBAL (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_DELETE_GLOBAL") - - def op_DELETE_NAME (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_DELETE_NAME") - - def op_DELETE_SLICE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_DELETE_SLICE") - - def op_DELETE_SUBSCR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_DELETE_SUBSCR") - - def op_DUP_TOP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_DUP_TOP") - - def op_DUP_TOPX (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_DUP_TOPX") - - def op_DUP_TOP_TWO (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_DUP_TOP_TWO") - - def op_END_FINALLY (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_END_FINALLY") - - def op_EXEC_STMT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_EXEC_STMT") - - def op_EXTENDED_ARG (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_EXTENDED_ARG") - - def op_FOR_ITER (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_FOR_ITER") - - def op_GET_ITER (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_GET_ITER") - - def op_IMPORT_FROM (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_IMPORT_FROM") - - def op_IMPORT_NAME (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_IMPORT_NAME") - - def op_IMPORT_STAR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_IMPORT_STAR") - - def op_INPLACE_ADD (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_ADD") - - def op_INPLACE_AND (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_AND") - - def op_INPLACE_DIVIDE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_DIVIDE") - - def op_INPLACE_FLOOR_DIVIDE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_FLOOR_DIVIDE") - - def op_INPLACE_LSHIFT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_LSHIFT") - - def op_INPLACE_MODULO (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_MODULO") - - def op_INPLACE_MULTIPLY (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_MULTIPLY") - - def op_INPLACE_OR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_OR") - - def op_INPLACE_POWER (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_POWER") - - def op_INPLACE_RSHIFT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_RSHIFT") - - def op_INPLACE_SUBTRACT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_SUBTRACT") - - def op_INPLACE_TRUE_DIVIDE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_TRUE_DIVIDE") - - def op_INPLACE_XOR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_INPLACE_XOR") - - def op_JUMP_ABSOLUTE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_JUMP_ABSOLUTE") - - def op_JUMP_FORWARD (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_JUMP_FORWARD") - - def op_JUMP_IF_FALSE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_JUMP_IF_FALSE") - - def op_JUMP_IF_FALSE_OR_POP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_JUMP_IF_FALSE_OR_POP") - - def op_JUMP_IF_TRUE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_JUMP_IF_TRUE") - - def op_JUMP_IF_TRUE_OR_POP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_JUMP_IF_TRUE_OR_POP") - - def op_LIST_APPEND (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_LIST_APPEND") - - def op_LOAD_ATTR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_LOAD_ATTR") - - def op_LOAD_BUILD_CLASS (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_LOAD_BUILD_CLASS") - - def op_LOAD_CLOSURE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_LOAD_CLOSURE") - - def op_LOAD_CONST (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_LOAD_CONST") - - def op_LOAD_DEREF (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_LOAD_DEREF") - - def op_LOAD_FAST (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_LOAD_FAST") - - def op_LOAD_GLOBAL (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_LOAD_GLOBAL") - - def op_LOAD_LOCALS (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_LOAD_LOCALS") - - def op_LOAD_NAME (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_LOAD_NAME") - - def op_MAKE_CLOSURE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_MAKE_CLOSURE") - - def op_MAKE_FUNCTION (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_MAKE_FUNCTION") - - def op_MAP_ADD (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_MAP_ADD") - - def op_NOP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_NOP") - - def op_POP_BLOCK (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_POP_BLOCK") - - def op_POP_EXCEPT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_POP_EXCEPT") - - def op_POP_JUMP_IF_FALSE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_POP_JUMP_IF_FALSE") - - def op_POP_JUMP_IF_TRUE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_POP_JUMP_IF_TRUE") - - def op_POP_TOP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_POP_TOP") - - def op_PRINT_EXPR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_PRINT_EXPR") - - def op_PRINT_ITEM (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_PRINT_ITEM") - - def op_PRINT_ITEM_TO (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_PRINT_ITEM_TO") - - def op_PRINT_NEWLINE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_PRINT_NEWLINE") - - def op_PRINT_NEWLINE_TO (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_PRINT_NEWLINE_TO") - - def op_RAISE_VARARGS (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_RAISE_VARARGS") - - def op_RETURN_VALUE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_RETURN_VALUE") - - def op_ROT_FOUR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_ROT_FOUR") - - def op_ROT_THREE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_ROT_THREE") - - def op_ROT_TWO (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_ROT_TWO") - - def op_SETUP_EXCEPT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_SETUP_EXCEPT") - - def op_SETUP_FINALLY (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_SETUP_FINALLY") - - def op_SETUP_LOOP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_SETUP_LOOP") - - def op_SETUP_WITH (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_SETUP_WITH") - - def op_SET_ADD (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_SET_ADD") - - def op_SLICE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_SLICE") - - def op_STOP_CODE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_STOP_CODE") - - def op_STORE_ATTR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_STORE_ATTR") - - def op_STORE_DEREF (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_STORE_DEREF") - - def op_STORE_FAST (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_STORE_FAST") - - def op_STORE_GLOBAL (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_STORE_GLOBAL") - - def op_STORE_LOCALS (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_STORE_LOCALS") - - def op_STORE_MAP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_STORE_MAP") - - def op_STORE_NAME (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_STORE_NAME") - - def op_STORE_SLICE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_STORE_SLICE") - - def op_STORE_SUBSCR (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_STORE_SUBSCR") - - def op_UNARY_CONVERT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_UNARY_CONVERT") - - def op_UNARY_INVERT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_UNARY_INVERT") - - def op_UNARY_NEGATIVE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_UNARY_NEGATIVE") - - def op_UNARY_NOT (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_UNARY_NOT") - - def op_UNARY_POSITIVE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_UNARY_POSITIVE") - - def op_UNPACK_EX (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_UNPACK_EX") - - def op_UNPACK_SEQUENCE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_UNPACK_SEQUENCE") - - def op_WITH_CLEANUP (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_WITH_CLEANUP") - - def op_YIELD_VALUE (self, i, op, arg, *args, **kws): - raise NotImplementedError("BytecodeVisitor.op_YIELD_VALUE") + def _not_implemented (self, i, op, arg, *args, **kws): + raise NotImplementedError("BytecodeVisitor.op_%s (@ bytecode index %d)" + % (self.opnames[op], i)) + + op_BINARY_ADD = _not_implemented + op_BINARY_AND = _not_implemented + op_BINARY_DIVIDE = _not_implemented + op_BINARY_FLOOR_DIVIDE = _not_implemented + op_BINARY_LSHIFT = _not_implemented + op_BINARY_MODULO = _not_implemented + op_BINARY_MULTIPLY = _not_implemented + op_BINARY_OR = _not_implemented + op_BINARY_POWER = _not_implemented + op_BINARY_RSHIFT = _not_implemented + op_BINARY_SUBSCR = _not_implemented + op_BINARY_SUBTRACT = _not_implemented + op_BINARY_TRUE_DIVIDE = _not_implemented + op_BINARY_XOR = _not_implemented + op_BREAK_LOOP = _not_implemented + op_BUILD_CLASS = _not_implemented + op_BUILD_LIST = _not_implemented + op_BUILD_MAP = _not_implemented + op_BUILD_SET = _not_implemented + op_BUILD_SLICE = _not_implemented + op_BUILD_TUPLE = _not_implemented + op_CALL_FUNCTION = _not_implemented + op_CALL_FUNCTION_KW = _not_implemented + op_CALL_FUNCTION_VAR = _not_implemented + op_CALL_FUNCTION_VAR_KW = _not_implemented + op_COMPARE_OP = _not_implemented + op_CONTINUE_LOOP = _not_implemented + op_DELETE_ATTR = _not_implemented + op_DELETE_DEREF = _not_implemented + op_DELETE_FAST = _not_implemented + op_DELETE_GLOBAL = _not_implemented + op_DELETE_NAME = _not_implemented + op_DELETE_SLICE = _not_implemented + op_DELETE_SUBSCR = _not_implemented + op_DUP_TOP = _not_implemented + op_DUP_TOPX = _not_implemented + op_DUP_TOP_TWO = _not_implemented + op_END_FINALLY = _not_implemented + op_EXEC_STMT = _not_implemented + op_EXTENDED_ARG = _not_implemented + op_FOR_ITER = _not_implemented + op_GET_ITER = _not_implemented + op_IMPORT_FROM = _not_implemented + op_IMPORT_NAME = _not_implemented + op_IMPORT_STAR = _not_implemented + op_INPLACE_ADD = _not_implemented + op_INPLACE_AND = _not_implemented + op_INPLACE_DIVIDE = _not_implemented + op_INPLACE_FLOOR_DIVIDE = _not_implemented + op_INPLACE_LSHIFT = _not_implemented + op_INPLACE_MODULO = _not_implemented + op_INPLACE_MULTIPLY = _not_implemented + op_INPLACE_OR = _not_implemented + op_INPLACE_POWER = _not_implemented + op_INPLACE_RSHIFT = _not_implemented + op_INPLACE_SUBTRACT = _not_implemented + op_INPLACE_TRUE_DIVIDE = _not_implemented + op_INPLACE_XOR = _not_implemented + op_JUMP_ABSOLUTE = _not_implemented + op_JUMP_FORWARD = _not_implemented + op_JUMP_IF_FALSE = _not_implemented + op_JUMP_IF_FALSE_OR_POP = _not_implemented + op_JUMP_IF_TRUE = _not_implemented + op_JUMP_IF_TRUE_OR_POP = _not_implemented + op_LIST_APPEND = _not_implemented + op_LOAD_ATTR = _not_implemented + op_LOAD_BUILD_CLASS = _not_implemented + op_LOAD_CLOSURE = _not_implemented + op_LOAD_CONST = _not_implemented + op_LOAD_DEREF = _not_implemented + op_LOAD_FAST = _not_implemented + op_LOAD_GLOBAL = _not_implemented + op_LOAD_LOCALS = _not_implemented + op_LOAD_NAME = _not_implemented + op_MAKE_CLOSURE = _not_implemented + op_MAKE_FUNCTION = _not_implemented + op_MAP_ADD = _not_implemented + op_NOP = _not_implemented + op_POP_BLOCK = _not_implemented + op_POP_EXCEPT = _not_implemented + op_POP_JUMP_IF_FALSE = _not_implemented + op_POP_JUMP_IF_TRUE = _not_implemented + op_POP_TOP = _not_implemented + op_PRINT_EXPR = _not_implemented + op_PRINT_ITEM = _not_implemented + op_PRINT_ITEM_TO = _not_implemented + op_PRINT_NEWLINE = _not_implemented + op_PRINT_NEWLINE_TO = _not_implemented + op_RAISE_VARARGS = _not_implemented + op_RETURN_VALUE = _not_implemented + op_ROT_FOUR = _not_implemented + op_ROT_THREE = _not_implemented + op_ROT_TWO = _not_implemented + op_SETUP_EXCEPT = _not_implemented + op_SETUP_FINALLY = _not_implemented + op_SETUP_LOOP = _not_implemented + op_SETUP_WITH = _not_implemented + op_SET_ADD = _not_implemented + op_SLICE = _not_implemented + op_STOP_CODE = _not_implemented + op_STORE_ATTR = _not_implemented + op_STORE_DEREF = _not_implemented + op_STORE_FAST = _not_implemented + op_STORE_GLOBAL = _not_implemented + op_STORE_LOCALS = _not_implemented + op_STORE_MAP = _not_implemented + op_STORE_NAME = _not_implemented + op_STORE_SLICE = _not_implemented + op_STORE_SUBSCR = _not_implemented + op_UNARY_CONVERT = _not_implemented + op_UNARY_INVERT = _not_implemented + op_UNARY_NEGATIVE = _not_implemented + op_UNARY_NOT = _not_implemented + op_UNARY_POSITIVE = _not_implemented + op_UNPACK_EX = _not_implemented + op_UNPACK_SEQUENCE = _not_implemented + op_WITH_CLEANUP = _not_implemented + op_YIELD_VALUE = _not_implemented # ______________________________________________________________________ diff --git a/nobitey.py b/nobitey.py index 5ae133f..67d134e 100644 --- a/nobitey.py +++ b/nobitey.py @@ -11,7 +11,7 @@ import llvm.core as lc import llvm.ee as le import bytetype - +import byte_translator from pyaddfunc import pyaddfunc LLVM_TO_INT_PARSE_STR_MAP = { @@ -80,80 +80,54 @@ class NoBitey (object): return result def build_wrapper_function (self, llvm_function, engine = None): - manual_linkage = False - if self.target_module != llvm_function.module: - manual_linkage = True - assert engine, ("Execution engine argument currently required for " - "linkage to separate LLVM module.") - llvm_function_ptr = self.target_module.add_global_variable( - llvm_function.type, llvm_function.name) - llvm_function_ptr.initializer = lc.Constant.inttoptr( - lc.Constant.int(bytetype.liptr, - engine.get_pointer_to_function(llvm_function)), - llvm_function.type) - llvm_function_ptr.linkage = lc.LINKAGE_INTERNAL - # __________________________________________________ - _pyobj_p = bytetype.l_pyobject_head_struct_p - _void_p = _char_p = bytetype.li8_ptr - self.crnt_function = self.target_module.add_function( - lc.Type.function(_pyobj_p, (_pyobj_p, _pyobj_p)), - llvm_function.name + "_wrapper") - entry_block = self.crnt_function.append_basic_block('entry') - args_ok_block = self.crnt_function.append_basic_block('args_ok') - exit_block = self.crnt_function.append_basic_block('exit') - _int32_zero = lc.Constant.int(bytetype.li32, 0) - _Py_BuildValue = self.target_module.get_or_insert_function( - lc.Type.function(_pyobj_p, [_char_p], True), 'Py_BuildValue') - _PyArg_ParseTuple = self.target_module.get_or_insert_function( - lc.Type.function(bytetype.lc_int, [_pyobj_p, _char_p], True), - 'PyArg_ParseTuple') - _PyEval_SaveThread = self.target_module.get_or_insert_function( - lc.Type.function(_void_p, []), 'PyEval_SaveThread') - _PyEval_RestoreThread = self.target_module.get_or_insert_function( - lc.Type.function(lc.Type.void(), [_void_p]), - 'PyEval_RestoreThread') - # __________________________________________________ - # entry: - builder = lc.Builder.new(entry_block) arg_types = llvm_function.type.pointee.args - parse_str = builder.gep( - get_string_constant( - self.target_module, - self.build_parse_string(arg_types)), - [_int32_zero, _int32_zero]) - parse_args = [builder.alloca(arg_ty) for arg_ty in arg_types] - parse_args.insert(0, parse_str) - parse_args.insert(0, self.crnt_function.args[1]) - parse_result = builder.call(_PyArg_ParseTuple, parse_args) - builder.cbranch(builder.icmp(lc.ICMP_NE, parse_result, _int32_zero), - args_ok_block, exit_block) + return_type = llvm_function.type.pointee.return_type + li32_0 = lc.Constant.int(bytetype.li32, 0) + def get_llvm_function (builder): + if self.target_module != llvm_function.module: + llvm_function_ptr = self.target_module.add_global_variable( + llvm_function.type, llvm_function.name) + llvm_function_ptr.initializer = lc.Constant.inttoptr( + lc.Constant.int( + bytetype.liptr, + engine.get_pointer_to_function(llvm_function)), + llvm_function.type) + llvm_function_ptr.linkage = lc.LINKAGE_INTERNAL + ret_val = builder.load(llvm_function_ptr) + else: + ret_val = llvm_function + return ret_val + def build_parse_args (builder): + return [builder.alloca(arg_type) for arg_type in arg_types] + def build_parse_string (builder): + parse_str = get_string_constant( + self.target_module, self.build_parse_string(arg_types)) + return builder.gep(parse_str, (li32_0, li32_0)) + def load_target_args (builder, args): + return [builder.load(arg) for arg in args] + def build_build_string (builder): + build_str = get_string_constant( + self.target_module, self._build_parse_string(return_type)) + return builder.gep(build_str, (li32_0, li32_0)) + handle_abi_casts = self.handle_abi_casts + target_function_name = llvm_function.name + "_wrapper" # __________________________________________________ - # args_ok: - builder = lc.Builder.new(args_ok_block) - thread_state = builder.call(_PyEval_SaveThread, ()) - target_args = [builder.load(parse_arg) for parse_arg in parse_args[2:]] - if manual_linkage: - result = builder.call(builder.load(llvm_function_ptr), target_args) - else: - result = builder.call(llvm_function, target_args) - result_cast = self.handle_abi_casts(builder, result) - builder.call(_PyEval_RestoreThread, (thread_state,)) - build_str = builder.gep( - get_string_constant( - self.target_module, - self._build_parse_string(result.type)), - [_int32_zero, _int32_zero]) - py_result = builder.call(_Py_BuildValue, [build_str, result_cast]) - builder.branch(exit_block) + @byte_translator.llnumba(bytetype.l_pyfunc, self.target_module, + **locals()) + def _wrapper (self, args): + ret_val = l_pyobj_p(0) + parse_args = build_parse_args() + parse_result = PyArg_ParseTuple(args, build_parse_string(), + *parse_args) + if parse_result != li32(0): + thread_state = PyEval_SaveThread() + target_args = load_target_args(parse_args) + llresult = handle_abi_casts(get_llvm_function()(*target_args)) + PyEval_RestoreThread(thread_state) + ret_val = Py_BuildValue(build_build_string(), llresult) + return ret_val # __________________________________________________ - # exit: - builder = lc.Builder.new(exit_block) - rval = builder.phi(bytetype.l_pyobject_head_struct_p) - rval.add_incoming(lc.Constant.null(bytetype.l_pyobject_head_struct_p), - entry_block) - rval.add_incoming(py_result, args_ok_block) - builder.ret(rval) - return self.crnt_function + return _wrapper def wrap_llvm_module (self, llvm_module, engine = None, py_module = None): ''' @@ -167,6 +141,7 @@ class NoBitey (object): engine = le.ExecutionEngine.new(llvm_module) wrappers = [self.build_wrapper_function(func, engine) for func in functions] + if __debug__: print(self.target_module) if self.target_module != llvm_module: engine.add_module(self.target_module) py_wrappers = [pyaddfunc(wrapper.name, @@ -360,11 +335,13 @@ def build_test_module (): # ______________________________________________________________________ -def main (*args): +def test_wrap_module (arg = None): # Build up a module. m = build_test_module() - wrap_module = NoBitey().wrap_llvm_module_in_python(m) - print(m) + if arg and arg.lower() == 'separated': + wrap_module = NoBitey().wrap_llvm_module_in_python(m) + else: + wrap_module = NoBitey(m).wrap_llvm_module_in_python(m) # Now try running the generated wrappers. for py_wf_name in ('add_42_i32', 'add_42_i64', 'add_42_float', 'add_42_double'): @@ -376,6 +353,15 @@ def main (*args): result, expected, py_wf) return wrap_module +# ______________________________________________________________________ + +def main (*args): + if args: + for arg in args: + test_wrap_module(arg) + else: + test_wrap_module() + if __name__ == "__main__": main(*sys.argv[1:]) From 9b1b444000588add435539347c0c62aae10a5f68 Mon Sep 17 00:00:00 2001 From: Jon Riehl Date: Thu, 18 Oct 2012 16:01:32 -0500 Subject: [PATCH 074/516] Working on using InternalFunction instances from ast_translate. Fixed bug in AST modulo implementation. --- byte_translator.py | 42 ++++++++++++++++++++++++++++++++---------- phi_injector.py | 9 ++++++--- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/byte_translator.py b/byte_translator.py index b7149cf..06df156 100644 --- a/byte_translator.py +++ b/byte_translator.py @@ -139,7 +139,8 @@ class LLVMTranslator (BytecodeFlowVisitor): self.control_flow_builder = ControlFlowBuilder() self.phi_injector = PhiInjector() - def translate (self, function, llvm_type = None, env = None): + def translate (self, function, llvm_type = None, llvm_function = None, + env = None): '''Translate a function to the given LLVM function type. If no type is given, then assume the function is of LLVM type @@ -148,7 +149,10 @@ class LLVMTranslator (BytecodeFlowVisitor): The optional env parameter allows extension of the global environment.''' if llvm_type is None: - llvm_type = lc.Type.function(lvoid, ()) + if llvm_function is None: + llvm_type = lc.Type.function(lvoid, ()) + else: + llvm_type = llvm_function.type.pointee if env is None: env = {} else: @@ -172,6 +176,7 @@ class LLVMTranslator (BytecodeFlowVisitor): nargs = self.code_obj.co_argcount self.cfg = self.control_flow_builder.visit( self.bytecode_flow_builder.visit(self.code_obj), nargs) + self.llvm_function = llvm_function flow = self.phi_injector.visit_cfg(self.cfg, nargs) ret_val = self.visit(flow) del self.cfg @@ -185,8 +190,9 @@ class LLVMTranslator (BytecodeFlowVisitor): def enter_flow_object (self, flow): super(LLVMTranslator, self).enter_flow_object(flow) - self.llvm_function = self.llvm_module.add_function( - self.llvm_type, self.target_function_name) + if self.llvm_function is None: + self.llvm_function = self.llvm_module.add_function( + self.llvm_type, self.target_function_name) self.llvm_blocks = {} self.llvm_definitions = {} self.pending_phis = {} @@ -202,7 +208,6 @@ class LLVMTranslator (BytecodeFlowVisitor): del self.pending_phis del self.llvm_definitions del self.llvm_blocks - del self.llvm_function if __debug__: print(ret_val) return ret_val @@ -468,15 +473,17 @@ class LLVMTranslator (BytecodeFlowVisitor): return ret_val def op_LOAD_DEREF (self, i, op, arg, *args, **kws): - ret_val = self.globals[self.code_obj.co_freevars[arg]] + name = self.code_obj.co_freevars[arg] + ret_val = self.globals[name] if isinstance(ret_val, lc.Type) and not hasattr(ret_val, '__name__'): - ret_val.__name__ = self.code_obj.co_names[arg] + ret_val.__name__ = name return [ret_val] def op_LOAD_GLOBAL (self, i, op, arg, *args, **kws): - ret_val = self.globals[self.code_obj.co_names[arg]] + name = self.code_obj.co_names[arg] + ret_val = self.globals[name] if isinstance(ret_val, lc.Type) and not hasattr(ret_val, '__name__'): - ret_val.__name__ = self.code_obj.co_names[arg] + ret_val.__name__ = name return [ret_val] def op_POP_BLOCK (self, i, op, arg, *args, **kws): @@ -539,7 +546,15 @@ def translate_function (func, lltype, llvm_module = None, **kws): '''Given a function and an LLVM function type, emit LLVM code for that function using a new LLVMTranslator instance.''' translator = LLVMTranslator(llvm_module) - ret_val = translator.translate(func, lltype, kws) + ret_val = translator.translate(func, lltype, env = kws) + return ret_val + +# ______________________________________________________________________ + +def translate_into_function (py_function, llvm_function, **kws): + translator = LLVMTranslator(llvm_function.module) + ret_val = translator.translate(py_function, llvm_function = llvm_function, + env = kws) return ret_val # ______________________________________________________________________ @@ -550,6 +565,13 @@ def llnumba (lltype, llvm_module = None, **kws): return translate_function(func, lltype, llvm_module, **kws) return _llnumba +# ______________________________________________________________________ + +def llnumba_into (llvm_function, **kws): + def _llnumba_into (func): + return translate_into_function(llvm_function, func, **kws) + return _llnumba_into + # ______________________________________________________________________ # Main (self-test) routine diff --git a/phi_injector.py b/phi_injector.py index b45be20..2618e97 100644 --- a/phi_injector.py +++ b/phi_injector.py @@ -84,8 +84,6 @@ class PhiInjector (BenignBytecodeVisitorMixin, BytecodeFlowVisitor): def enter_block (self, block): ret_val = False - if self.prev_blocks: - prev_block = self.prev_blocks[-1] self.block = block if block == 0: if self.nargs > 0: @@ -97,7 +95,12 @@ class PhiInjector (BenignBytecodeVisitorMixin, BytecodeFlowVisitor): ret_val = True elif 0 in self.cfg.blocks_reaching[block]: ret_val = True - prev_block_locals = self.blocks_locals[prev_block] + prev_block_locals = None + for pred_block in self.cfg.blocks_in[block]: + if pred_block in self.prev_blocks: + prev_block_locals = self.blocks_locals[pred_block] + break + assert prev_block_locals is not None, "Internal translation error" self.blocks_locals[block] = prev_block_locals.copy() phis_needed = self.cfg.phi_needed(block) if phis_needed: From aab2c39fc98aadb54343829f6552598eabe6b84c Mon Sep 17 00:00:00 2001 From: Jon Riehl Date: Thu, 18 Oct 2012 16:01:32 -0500 Subject: [PATCH 075/516] Working on using InternalFunction instances from ast_translate. Fixed bug in AST modulo implementation. --- byte_translator.py | 42 ++++++++++++++++++++++++++++++++---------- phi_injector.py | 9 ++++++--- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/byte_translator.py b/byte_translator.py index b7149cf..06df156 100644 --- a/byte_translator.py +++ b/byte_translator.py @@ -139,7 +139,8 @@ class LLVMTranslator (BytecodeFlowVisitor): self.control_flow_builder = ControlFlowBuilder() self.phi_injector = PhiInjector() - def translate (self, function, llvm_type = None, env = None): + def translate (self, function, llvm_type = None, llvm_function = None, + env = None): '''Translate a function to the given LLVM function type. If no type is given, then assume the function is of LLVM type @@ -148,7 +149,10 @@ class LLVMTranslator (BytecodeFlowVisitor): The optional env parameter allows extension of the global environment.''' if llvm_type is None: - llvm_type = lc.Type.function(lvoid, ()) + if llvm_function is None: + llvm_type = lc.Type.function(lvoid, ()) + else: + llvm_type = llvm_function.type.pointee if env is None: env = {} else: @@ -172,6 +176,7 @@ class LLVMTranslator (BytecodeFlowVisitor): nargs = self.code_obj.co_argcount self.cfg = self.control_flow_builder.visit( self.bytecode_flow_builder.visit(self.code_obj), nargs) + self.llvm_function = llvm_function flow = self.phi_injector.visit_cfg(self.cfg, nargs) ret_val = self.visit(flow) del self.cfg @@ -185,8 +190,9 @@ class LLVMTranslator (BytecodeFlowVisitor): def enter_flow_object (self, flow): super(LLVMTranslator, self).enter_flow_object(flow) - self.llvm_function = self.llvm_module.add_function( - self.llvm_type, self.target_function_name) + if self.llvm_function is None: + self.llvm_function = self.llvm_module.add_function( + self.llvm_type, self.target_function_name) self.llvm_blocks = {} self.llvm_definitions = {} self.pending_phis = {} @@ -202,7 +208,6 @@ class LLVMTranslator (BytecodeFlowVisitor): del self.pending_phis del self.llvm_definitions del self.llvm_blocks - del self.llvm_function if __debug__: print(ret_val) return ret_val @@ -468,15 +473,17 @@ class LLVMTranslator (BytecodeFlowVisitor): return ret_val def op_LOAD_DEREF (self, i, op, arg, *args, **kws): - ret_val = self.globals[self.code_obj.co_freevars[arg]] + name = self.code_obj.co_freevars[arg] + ret_val = self.globals[name] if isinstance(ret_val, lc.Type) and not hasattr(ret_val, '__name__'): - ret_val.__name__ = self.code_obj.co_names[arg] + ret_val.__name__ = name return [ret_val] def op_LOAD_GLOBAL (self, i, op, arg, *args, **kws): - ret_val = self.globals[self.code_obj.co_names[arg]] + name = self.code_obj.co_names[arg] + ret_val = self.globals[name] if isinstance(ret_val, lc.Type) and not hasattr(ret_val, '__name__'): - ret_val.__name__ = self.code_obj.co_names[arg] + ret_val.__name__ = name return [ret_val] def op_POP_BLOCK (self, i, op, arg, *args, **kws): @@ -539,7 +546,15 @@ def translate_function (func, lltype, llvm_module = None, **kws): '''Given a function and an LLVM function type, emit LLVM code for that function using a new LLVMTranslator instance.''' translator = LLVMTranslator(llvm_module) - ret_val = translator.translate(func, lltype, kws) + ret_val = translator.translate(func, lltype, env = kws) + return ret_val + +# ______________________________________________________________________ + +def translate_into_function (py_function, llvm_function, **kws): + translator = LLVMTranslator(llvm_function.module) + ret_val = translator.translate(py_function, llvm_function = llvm_function, + env = kws) return ret_val # ______________________________________________________________________ @@ -550,6 +565,13 @@ def llnumba (lltype, llvm_module = None, **kws): return translate_function(func, lltype, llvm_module, **kws) return _llnumba +# ______________________________________________________________________ + +def llnumba_into (llvm_function, **kws): + def _llnumba_into (func): + return translate_into_function(llvm_function, func, **kws) + return _llnumba_into + # ______________________________________________________________________ # Main (self-test) routine diff --git a/phi_injector.py b/phi_injector.py index b45be20..2618e97 100644 --- a/phi_injector.py +++ b/phi_injector.py @@ -84,8 +84,6 @@ class PhiInjector (BenignBytecodeVisitorMixin, BytecodeFlowVisitor): def enter_block (self, block): ret_val = False - if self.prev_blocks: - prev_block = self.prev_blocks[-1] self.block = block if block == 0: if self.nargs > 0: @@ -97,7 +95,12 @@ class PhiInjector (BenignBytecodeVisitorMixin, BytecodeFlowVisitor): ret_val = True elif 0 in self.cfg.blocks_reaching[block]: ret_val = True - prev_block_locals = self.blocks_locals[prev_block] + prev_block_locals = None + for pred_block in self.cfg.blocks_in[block]: + if pred_block in self.prev_blocks: + prev_block_locals = self.blocks_locals[pred_block] + break + assert prev_block_locals is not None, "Internal translation error" self.blocks_locals[block] = prev_block_locals.copy() phis_needed = self.cfg.phi_needed(block) if phis_needed: From d781e83bd11f801276afc4adb8fef5d9e862dbd3 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 19 Oct 2012 16:18:24 -0500 Subject: [PATCH 076/516] can now clone modules --- llvm/_core.cpp | 2 ++ llvm/core.py | 3 +++ llvm/extra.cpp | 6 ++++++ llvm/extra.h | 7 +++++++ test/clonemodule.py | 46 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 64 insertions(+) create mode 100644 test/clonemodule.py diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 19dadec..73d6099 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -297,6 +297,7 @@ _wLLVMLinkModules(PyObject *self, PyObject *args) _wrap_objstr2obj(LLVMModuleGetOrInsertNamedMetaData, LLVMModuleRef, LLVMNamedMDRef) _wrap_objstr2obj(LLVMModuleGetNamedMetaData, LLVMModuleRef, LLVMNamedMDRef) +_wrap_obj2obj(LLVMCloneModule, LLVMModuleRef, LLVMModuleRef) /*===----------------------------------------------------------------------===*/ /* Types */ @@ -1577,6 +1578,7 @@ static PyMethodDef core_methods[] = { _method( LLVMLinkModules ) _method( LLVMModuleGetOrInsertNamedMetaData ) _method( LLVMModuleGetNamedMetaData ) + _method( LLVMCloneModule ) /* Types */ diff --git a/llvm/core.py b/llvm/core.py index 8b9a7ae..b9e156c 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -582,6 +582,9 @@ class Module(llvm.Ownable, llvm.Cacheable): ptr = _core.LLVMModuleGetNamedMetaData(self.ptr, name) return NamedMetaData(ptr) + def clone(self): + return Module(_core.LLVMCloneModule(self.ptr)) + #===----------------------------------------------------------------------=== # Types #===----------------------------------------------------------------------=== diff --git a/llvm/extra.cpp b/llvm/extra.cpp index 198fbb9..3c636b6 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -135,6 +135,12 @@ const CodeGenOpt::Level OptLevelMap[] = { }; } // end anony namespace +LLVMModuleRef LLVMCloneModule(LLVMModuleRef mod) +{ + using namespace llvm; + return wrap(CloneModule(unwrap(mod))); +} + const char * LLVMDumpNamedMDToString(LLVMNamedMDRef nmd) { using namespace llvm; diff --git a/llvm/extra.h b/llvm/extra.h index 32ca193..007f6c0 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -54,6 +54,13 @@ extern "C" { #endif + +/* + * Wraps llvm::CloneModule + */ +LLVMModuleRef LLVMCloneModule(LLVMModuleRef mod); + + /* * Wraps NamedMDNode::print() */ diff --git a/test/clonemodule.py b/test/clonemodule.py new file mode 100644 index 0000000..d762faa --- /dev/null +++ b/test/clonemodule.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python + +# Import the llvm-py modules. +from llvm import * +from llvm.core import * + +import logging +import unittest + + +class TestCloneModule(unittest.TestCase): + def test_example(self): + my_module = Module.new('my_module') + + ty_int = Type.int() # by default 32 bits + + ty_func = Type.function(ty_int, [ty_int, ty_int]) + + f_sum = my_module.add_function(ty_func, "sum") + + self.assertEqual(str(f_sum).strip(), 'declare i32 @sum(i32, i32)') + + f_sum.args[0].name = "a" + f_sum.args[1].name = "b" + + bb = f_sum.append_basic_block("entry") + + builder = Builder.new(bb) + + tmp = builder.add(f_sum.args[0], f_sum.args[1], "tmp") + + self.assertEqual(str(tmp).strip(), '%tmp = add i32 %a, %b') + + builder.ret(tmp) + + cloned = my_module.clone() + + self.assertTrue(id(cloned) != id(my_module)) + self.assertTrue(str(cloned) == str(my_module)) + self.assertTrue(cloned == my_module) + + + +if __name__ == '__main__': + unittest.main() + From 47cd581ca53d468e5ad84ad7ab147101e3faa7d1 Mon Sep 17 00:00:00 2001 From: Jon Riehl Date: Thu, 18 Oct 2012 16:01:32 -0500 Subject: [PATCH 077/516] Working on using InternalFunction instances from ast_translate. Fixed bug in AST modulo implementation. --- byte_translator.py | 42 ++++++++++++++++++++++++++++++++---------- phi_injector.py | 9 ++++++--- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/byte_translator.py b/byte_translator.py index b7149cf..06df156 100644 --- a/byte_translator.py +++ b/byte_translator.py @@ -139,7 +139,8 @@ class LLVMTranslator (BytecodeFlowVisitor): self.control_flow_builder = ControlFlowBuilder() self.phi_injector = PhiInjector() - def translate (self, function, llvm_type = None, env = None): + def translate (self, function, llvm_type = None, llvm_function = None, + env = None): '''Translate a function to the given LLVM function type. If no type is given, then assume the function is of LLVM type @@ -148,7 +149,10 @@ class LLVMTranslator (BytecodeFlowVisitor): The optional env parameter allows extension of the global environment.''' if llvm_type is None: - llvm_type = lc.Type.function(lvoid, ()) + if llvm_function is None: + llvm_type = lc.Type.function(lvoid, ()) + else: + llvm_type = llvm_function.type.pointee if env is None: env = {} else: @@ -172,6 +176,7 @@ class LLVMTranslator (BytecodeFlowVisitor): nargs = self.code_obj.co_argcount self.cfg = self.control_flow_builder.visit( self.bytecode_flow_builder.visit(self.code_obj), nargs) + self.llvm_function = llvm_function flow = self.phi_injector.visit_cfg(self.cfg, nargs) ret_val = self.visit(flow) del self.cfg @@ -185,8 +190,9 @@ class LLVMTranslator (BytecodeFlowVisitor): def enter_flow_object (self, flow): super(LLVMTranslator, self).enter_flow_object(flow) - self.llvm_function = self.llvm_module.add_function( - self.llvm_type, self.target_function_name) + if self.llvm_function is None: + self.llvm_function = self.llvm_module.add_function( + self.llvm_type, self.target_function_name) self.llvm_blocks = {} self.llvm_definitions = {} self.pending_phis = {} @@ -202,7 +208,6 @@ class LLVMTranslator (BytecodeFlowVisitor): del self.pending_phis del self.llvm_definitions del self.llvm_blocks - del self.llvm_function if __debug__: print(ret_val) return ret_val @@ -468,15 +473,17 @@ class LLVMTranslator (BytecodeFlowVisitor): return ret_val def op_LOAD_DEREF (self, i, op, arg, *args, **kws): - ret_val = self.globals[self.code_obj.co_freevars[arg]] + name = self.code_obj.co_freevars[arg] + ret_val = self.globals[name] if isinstance(ret_val, lc.Type) and not hasattr(ret_val, '__name__'): - ret_val.__name__ = self.code_obj.co_names[arg] + ret_val.__name__ = name return [ret_val] def op_LOAD_GLOBAL (self, i, op, arg, *args, **kws): - ret_val = self.globals[self.code_obj.co_names[arg]] + name = self.code_obj.co_names[arg] + ret_val = self.globals[name] if isinstance(ret_val, lc.Type) and not hasattr(ret_val, '__name__'): - ret_val.__name__ = self.code_obj.co_names[arg] + ret_val.__name__ = name return [ret_val] def op_POP_BLOCK (self, i, op, arg, *args, **kws): @@ -539,7 +546,15 @@ def translate_function (func, lltype, llvm_module = None, **kws): '''Given a function and an LLVM function type, emit LLVM code for that function using a new LLVMTranslator instance.''' translator = LLVMTranslator(llvm_module) - ret_val = translator.translate(func, lltype, kws) + ret_val = translator.translate(func, lltype, env = kws) + return ret_val + +# ______________________________________________________________________ + +def translate_into_function (py_function, llvm_function, **kws): + translator = LLVMTranslator(llvm_function.module) + ret_val = translator.translate(py_function, llvm_function = llvm_function, + env = kws) return ret_val # ______________________________________________________________________ @@ -550,6 +565,13 @@ def llnumba (lltype, llvm_module = None, **kws): return translate_function(func, lltype, llvm_module, **kws) return _llnumba +# ______________________________________________________________________ + +def llnumba_into (llvm_function, **kws): + def _llnumba_into (func): + return translate_into_function(llvm_function, func, **kws) + return _llnumba_into + # ______________________________________________________________________ # Main (self-test) routine diff --git a/phi_injector.py b/phi_injector.py index b45be20..2618e97 100644 --- a/phi_injector.py +++ b/phi_injector.py @@ -84,8 +84,6 @@ class PhiInjector (BenignBytecodeVisitorMixin, BytecodeFlowVisitor): def enter_block (self, block): ret_val = False - if self.prev_blocks: - prev_block = self.prev_blocks[-1] self.block = block if block == 0: if self.nargs > 0: @@ -97,7 +95,12 @@ class PhiInjector (BenignBytecodeVisitorMixin, BytecodeFlowVisitor): ret_val = True elif 0 in self.cfg.blocks_reaching[block]: ret_val = True - prev_block_locals = self.blocks_locals[prev_block] + prev_block_locals = None + for pred_block in self.cfg.blocks_in[block]: + if pred_block in self.prev_blocks: + prev_block_locals = self.blocks_locals[pred_block] + break + assert prev_block_locals is not None, "Internal translation error" self.blocks_locals[block] = prev_block_locals.copy() phis_needed = self.cfg.phi_needed(block) if phis_needed: From c8e44702cb4f1a3ec88acf503c144630d81222e9 Mon Sep 17 00:00:00 2001 From: Jon Riehl Date: Tue, 23 Oct 2012 14:35:07 -0500 Subject: [PATCH 078/516] Got AST translation working for numba.tests.test_cstring. Modified AST type inference to use Python API for string to number conversion (was using atol/atof, which suppress Python errors). Tweaked numba.functions.CStringSlice2, and added numba.functions.CStringSlice2Len (currently unused). Added support for PyInt_FromString and PyFloat_FromString in numba.functions. Modified llnumba slicing code to type properly on 64-bit systems. Changed string slice support in numba.transforms to use Python slicing by default. --- tests/llfuncs.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/llfuncs.py b/tests/llfuncs.py index 55e9000..2a8614f 100644 --- a/tests/llfuncs.py +++ b/tests/llfuncs.py @@ -3,14 +3,14 @@ def doslice (in_string, lower, upper): l = strlen(in_string) - if lower < 0: + if lower < lc_size_t(0): lower += l - if upper < 0: + if upper < lc_size_t(0): upper += l temp_len = upper - lower - if temp_len < 0: - temp_len = 0 - ret_val = alloca_array(li8, temp_len + 1) + if temp_len < lc_size_t(0): + temp_len = lc_size_t(0) + ret_val = alloca_array(li8, temp_len + lc_size_t(1)) strncpy(ret_val, in_string + lower, temp_len) ret_val[temp_len] = li8(0) return ret_val From 6d190964385707d65480678762d4fe2c8e792f4f Mon Sep 17 00:00:00 2001 From: Jon Riehl Date: Wed, 24 Oct 2012 17:14:32 -0500 Subject: [PATCH 079/516] Prototyped non-Python string slicing implementation. --- byte_translator.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/byte_translator.py b/byte_translator.py index 06df156..bcbe06c 100644 --- a/byte_translator.py +++ b/byte_translator.py @@ -7,6 +7,7 @@ import opcode import types +import logging import llvm.core as lc @@ -20,6 +21,8 @@ from phi_injector import PhiInjector, synthetic_opname # ______________________________________________________________________ # Module data +logger = logging.getLogger(__name__) + # XXX Stolen from numba.translate: _compare_mapping_float = {'>':lc.FCMP_OGT, @@ -208,7 +211,8 @@ class LLVMTranslator (BytecodeFlowVisitor): del self.pending_phis del self.llvm_definitions del self.llvm_blocks - if __debug__: print(ret_val) + if __debug__ and logger.getEffectiveLevel() < logging.DEBUG: + logger.debug(str(ret_val)) return ret_val def enter_block (self, block): From daa62d9f78caabb062db57ffa9acd58223331981 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 26 Oct 2012 14:08:33 -0500 Subject: [PATCH 080/516] Add address-space control to global-variable --- llvm/_core.cpp | 4 +++- llvm/core.py | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 73d6099..51b595c 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -607,8 +607,9 @@ _wrap_obj2obj(LLVMGetAlignment, LLVMValueRef, int) _wrap_objint2none(LLVMSetAlignment, LLVMValueRef) /*===-- Global Variables -------------------------------------------------===*/ - + _wrap_objobjstr2obj(LLVMAddGlobal, LLVMModuleRef, LLVMTypeRef, LLVMValueRef) +_wrap_objobjstrint2obj(LLVMAddGlobalInAddressSpace, LLVMModuleRef, LLVMTypeRef, LLVMValueRef) _wrap_objstr2obj(LLVMGetNamedGlobal, LLVMModuleRef, LLVMValueRef) _wrap_obj2obj(LLVMGetFirstGlobal, LLVMModuleRef, LLVMValueRef) _wrap_obj2obj(LLVMGetNextGlobal, LLVMValueRef, LLVMValueRef) @@ -1744,6 +1745,7 @@ static PyMethodDef core_methods[] = { /* Global Variables */ _method( LLVMAddGlobal ) + _method( LLVMAddGlobalInAddressSpace ) _method( LLVMGetNamedGlobal ) _method( LLVMGetFirstGlobal ) _method( LLVMGetNextGlobal ) diff --git a/llvm/core.py b/llvm/core.py index b9e156c..cc47662 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -478,9 +478,9 @@ class Module(llvm.Ownable, llvm.Cacheable): return _make_type(ptr, kind) return None - def add_global_variable(self, ty, name): + def add_global_variable(self, ty, name, addrspace=0): """Add a global variable of given type with given name.""" - return GlobalVariable.new(self, ty, name) + return GlobalVariable.new(self, ty, name, addrspace) def get_global_variable_named(self, name): """Return a GlobalVariable object for the given name.""" @@ -1337,10 +1337,10 @@ class GlobalValue(Constant): class GlobalVariable(GlobalValue): @staticmethod - def new(module, ty, name): + def new(module, ty, name, addrspace=0): check_is_module(module) check_is_type(ty) - return _make_value(_core.LLVMAddGlobal(module.ptr, ty.ptr, name)) + return _make_value(_core.LLVMAddGlobalInAddressSpace(module.ptr, ty.ptr, name, addrspace)) @staticmethod def get(module, name): From 87a44e3117fd3b781eab21a628d86532a22a9c84 Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Fri, 26 Oct 2012 20:40:06 +0100 Subject: [PATCH 081/516] Get array slicing and expressions compiling --- builder.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/builder.py b/builder.py index 4a6f23b..cce1ba2 100644 --- a/builder.py +++ b/builder.py @@ -1040,6 +1040,9 @@ class IntegerValue(OperatorMixin): else: return self._temp(self.parent.builder.icmp(lc.ICMP_SGE, self.value, rhs.value)) + def __neg__(self): + return self._temp(self.parent.builder.neg(self.value)) + def cast(self, ty, unsigned=False): if ty == self.type: return self._temp(self.value) From 6133b643d8c8d414584d09e6daf9a93896f5142a Mon Sep 17 00:00:00 2001 From: Mark Wiebe Date: Fri, 26 Oct 2012 15:33:42 -0700 Subject: [PATCH 082/516] Fix PTX lib detection logic on windows --- llvm-config-win32.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/llvm-config-win32.py b/llvm-config-win32.py index 0e70231..2370625 100644 --- a/llvm-config-win32.py +++ b/llvm-config-win32.py @@ -50,12 +50,12 @@ Advapi32 Shell32 """.split(): print('-l%s' % lib) - # Look for the PTX .lib in %LIBPATH% - if find_path_of('LLVMPTXCodeGen.lib', 'LIBPATH') != None: - print('-lLLVMPTXAsmPrinter') - print('-lLLVMPTXCodeGen') - print('-lLLVMPTXDesc') - print('-lLLVMPTXInfo') + llvmbin = find_path_of('llvm-tblgen.exe') + if os.path.exists(os.path.join(llvmbin, '../lib/LLVMPTXCodeGen.lib')): + print('-lLLVMPTXAsmPrinter') + print('-lLLVMPTXCodeGen') + print('-lLLVMPTXDesc') + print('-lLLVMPTXInfo') elif sys.argv[1] == '--includedir': llvmbin = find_path_of('llvm-tblgen.exe') if llvmbin is None: From bd377de19831f3ac21f4adfa162795690d82788b Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Mon, 29 Oct 2012 14:16:13 +0000 Subject: [PATCH 083/516] Fix cbuilder CDefinition specialization design and magic --- builder.py | 80 ++++++++++++++++++++++++++---------------------------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/builder.py b/builder.py index cce1ba2..b05a368 100644 --- a/builder.py +++ b/builder.py @@ -709,24 +709,6 @@ class CBuilder(object): md = lc.MetaData.get(self.function.module, [const_one]) ldst.set_metadata('nontemporal', md) -class _DeclareCDef(object): - '''create a function a CDefinition to use with `CBuilder.depends` - - An instance of this class is created by the constructor of CDefinition. - Do not use directly. - ''' - def __init__(self, cdef): - self.cdef = cdef - - def __str__(self): - return self.cdef._name_ - - def __call__(self, module): - try: - func = self.cdef.define(module) - except FunctionAlreadyExists as e: - (func,) = e - return func class CFuncRef(object): '''create a function reference to use with `CBuilder.depends` @@ -766,7 +748,8 @@ class CFuncRef(object): def __str__(self): return self._name -class CDefinition(CBuilder): + +class CDefinition(object): '''represents function definition Inherit from this class to create a new function definition. @@ -782,31 +765,33 @@ class CDefinition(CBuilder): _retty_ = types.void # return type; can overide in subclass _argtys_ = [] # a list of tuple(name, type, [attributes]); can overide in subclass - def __new__(cls, *args, **kws): - if cls.is_generic(): - # Call specialize if it is defined. - cls = type('%s_Specialized' % cls.__name__, (cls,), {}) - cls.specialize(*args, **kws) + def __init__(self, *args, **kwargs): + self.specialize(*args, **kwargs) + self.cbuilder = None - obj = object.__new__(_DeclareCDef) - obj.__init__(cls) - return obj + def specialize(self, *args, **kwargs): + """ + Override in subclasses + """ - @classmethod - def is_generic(cls): - '''Is this a generic definition? - ''' - return hasattr(cls, 'specialize') + def specialize_name(self): + """ + Specialize the class name to enable multiple function definitions + """ + cls = type(self) - @classmethod - def define(cls, module): + counter = getattr(cls, 'counter', 0) + cls._name_ = "%s_%d" % (cls._name_, counter) + cls.counter = counter + 1 + + def define(self, module): '''define the function in the module. Raises NameError if a function of the same name has already been defined. ''' - functype = lc.Type.function(cls._retty_, [arg[1] for arg in cls._argtys_]) - name = cls._name_ + functype = lc.Type.function(self._retty_, [arg[1] for arg in self._argtys_]) + name = self._name_ if not name: raise AttributeError("Function name cannot be empty.") @@ -816,17 +801,17 @@ class CDefinition(CBuilder): raise FunctionAlreadyExists(func) # Name all arguments - for i, arginfo in enumerate(cls._argtys_): + for i, arginfo in enumerate(self._argtys_): name = arginfo[0] func.args[i].name = name if len(arginfo) > 2: for attr in arginfo[2]: func.args[i].add_attribute(attr) + # Create builder and populate body - cbuilder = object.__new__(cls) - cbuilder.__init__(func) - cbuilder.body(*cbuilder.args) - cbuilder.close() + self.cbuilder = CBuilder(func) + self.body(*self.cbuilder.args) + self.cbuilder.close() # optimize fpm = lp.FunctionPassManager.new(module) @@ -837,11 +822,24 @@ class CDefinition(CBuilder): fpm.run(func) return func + def __call__(self, module): + # We don't really have to overload __call__ to do things like + # defining functions... + try: + func = self.define(module) + except FunctionAlreadyExists as e: + (func,) = e + return func + + def __getattr__(self, attr): + return getattr(self.cbuilder, attr) + def body(self): '''overide this function to define the body. ''' raise NotImplementedError + class CValue(object): def __init__(self, parent, handle): self.__parent = parent From 507ff7306157331443f7176696b3711bee658bff Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 31 Oct 2012 16:41:10 -0500 Subject: [PATCH 084/516] Add InlineAsm --- llvm/_core.cpp | 30 +++++++++++++++++++++++++++++- llvm/core.py | 16 ++++++++++++++++ llvm/extra.cpp | 17 +++++++++++++++++ llvm/extra.h | 9 +++++++++ 4 files changed, 71 insertions(+), 1 deletion(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 51b595c..1a64f88 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -642,7 +642,6 @@ _wrap_obj2none(LLVMViewFunctionCFGOnly, LLVMValueRef) _wrap_objenum2none(LLVMAddFunctionAttr, LLVMValueRef, LLVMAttribute) _wrap_objenum2none(LLVMRemoveFunctionAttr, LLVMValueRef, LLVMAttribute) - static PyObject * _wLLVMVerifyFunction(PyObject *self, PyObject *args) { @@ -654,6 +653,33 @@ _wLLVMVerifyFunction(PyObject *self, PyObject *args) LLVMPY_CATCH_ALL } +static PyObject * +_wLLVMGetFunctionFromInlineAsm(PyObject *self, PyObject *args) +{ + LLVMPY_TRY + PyObject *pycapFuncType; + const char *inlineAsm = NULL; + const char *constrains = NULL; + int hasSideEffect; + int isAlignStack; + int asmDialect; + + if (!PyArg_ParseTuple(args, "Ossiii", &pycapFuncType, &inlineAsm, + &constrains, &hasSideEffect, + &isAlignStack, &asmDialect)) + return NULL; + + + LLVMTypeRef funcType = pycap_get(pycapFuncType); + LLVMValueRef inlineAsmRef; + inlineAsmRef = LLVMGetFunctionFromInlineAsm(funcType, inlineAsm, constrains, + hasSideEffect, isAlignStack, + asmDialect); + + return pycap_new(inlineAsmRef); + LLVMPY_CATCH_ALL +} + /*===-- Arguments --------------------------------------------------------===*/ @@ -747,6 +773,7 @@ _wrap_obj2obj(LLVMIsTailCall, LLVMValueRef, int) _wrap_objint2none(LLVMSetTailCall, LLVMValueRef) _wrap_obj2obj(LLVMInstGetCalledFunction, LLVMValueRef, LLVMValueRef) + /*===-- PHI Nodes --------------------------------------------------------===*/ static void LLVMAddIncoming1(LLVMValueRef PhiNode, LLVMValueRef IncomingValue, LLVMBasicBlockRef IncomingBlock) @@ -1776,6 +1803,7 @@ static PyMethodDef core_methods[] = { _method( LLVMViewFunctionCFGOnly ) _method( LLVMAddFunctionAttr ) _method( LLVMRemoveFunctionAttr ) + _method( LLVMGetFunctionFromInlineAsm ) /* Arguments */ _method( LLVMCountParams ) diff --git a/llvm/core.py b/llvm/core.py index cc47662..7c9b1e1 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -1505,6 +1505,21 @@ class Function(GlobalValue): # failure, it appears to print result to stderr and abort. return _core.LLVMVerifyFunction(self.ptr) != 0 +#===----------------------------------------------------------------------=== +# InlineAsm +#===----------------------------------------------------------------------=== + +class InlineAsm(Value): + @staticmethod + def get(functype, asm, constrains, side_effect=False, + align_stack=False, dialect=0): + assert dialect == 0, "LLVM 3.1 does not implement dialect selection" + check_is_type(functype) + pycap = _core.LLVMGetFunctionFromInlineAsm(functype.ptr, asm, + constrains, int(side_effect), + int(align_stack), dialect) + return _make_value(pycap) + #===----------------------------------------------------------------------=== # MetaData #===----------------------------------------------------------------------=== @@ -1750,6 +1765,7 @@ __class_for_valueid = { VALUE_CONSTANT_POINTER_NULL : ConstantPointerNull, VALUE_MD_NODE : MetaData, VALUE_MD_STRING : MetaDataString, + VALUE_INLINE_ASM : InlineAsm, VALUE_INSTRUCTION + OPCODE_PHI : PHINode, VALUE_INSTRUCTION + OPCODE_CALL : CallOrInvokeInstruction, VALUE_INSTRUCTION + OPCODE_INVOKE : CallOrInvokeInstruction, diff --git a/llvm/extra.cpp b/llvm/extra.cpp index 3c636b6..b9f4ac2 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -74,6 +74,7 @@ #include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Linker.h" #include "llvm/Support/SourceMgr.h" +#include // LLVM-C includes @@ -135,6 +136,22 @@ const CodeGenOpt::Level OptLevelMap[] = { }; } // end anony namespace + +LLVMValueRef LLVMGetFunctionFromInlineAsm(LLVMTypeRef funcType, + const char inlineAsm[], + const char constrains[], + bool hasSideEffect, + bool isAlignStack, + int asmDialect) +{ + using namespace llvm; + FunctionType *fnty = unwrap(funcType); + // asmDialect does not exist for LLVM 3.1 + InlineAsm *inlineasmobj = InlineAsm::get(fnty, inlineAsm, constrains, + hasSideEffect, isAlignStack); + return wrap(inlineasmobj); +} + LLVMModuleRef LLVMCloneModule(LLVMModuleRef mod) { using namespace llvm; diff --git a/llvm/extra.h b/llvm/extra.h index 007f6c0..dae90ec 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -54,6 +54,15 @@ extern "C" { #endif +/* + * Wraps llvm:InlineAsm::get + */ +LLVMValueRef LLVMGetFunctionFromInlineAsm(LLVMTypeRef funcType, + const char inlineAsm[], + const char constrains[], + bool hasSideEffect, + bool isAlignStack, + int asmDialect); /* * Wraps llvm::CloneModule From b9d05bb6fe4b385896877731019d0c25c0c0a17e Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 1 Nov 2012 11:41:28 -0500 Subject: [PATCH 085/516] Can now modify called_function of CallOrInvokeInstruction --- llvm/_core.cpp | 3 ++- llvm/core.py | 8 ++++++-- llvm/extra.cpp | 7 +++++++ llvm/extra.h | 4 ++++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 1a64f88..1b7ec09 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -772,7 +772,7 @@ _wrap_objintint2none(LLVMSetInstrParamAlignment, LLVMValueRef) _wrap_obj2obj(LLVMIsTailCall, LLVMValueRef, int) _wrap_objint2none(LLVMSetTailCall, LLVMValueRef) _wrap_obj2obj(LLVMInstGetCalledFunction, LLVMValueRef, LLVMValueRef) - +_wrap_objobj2none(LLVMInstSetCalledFunction, LLVMValueRef, LLVMValueRef) /*===-- PHI Nodes --------------------------------------------------------===*/ @@ -1867,6 +1867,7 @@ static PyMethodDef core_methods[] = { _method( LLVMRemoveInstrAttribute ) _method( LLVMSetInstrParamAlignment ) _method( LLVMInstGetCalledFunction ) + _method( LLVMInstSetCalledFunction ) /* PHI Nodes */ _method( LLVMAddIncoming1 ) diff --git a/llvm/core.py b/llvm/core.py index 7c9b1e1..b264b50 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -1670,12 +1670,16 @@ class CallOrInvokeInstruction(Instruction): def set_parameter_alignment(self, idx, align): _core.LLVMSetInstrParamAlignment(self.ptr, idx, align) - @property - def called_function(self): + def _get_called_function(self): function = _core.LLVMInstGetCalledFunction(self.ptr) if function: # Return value can be None on indirect call/invoke return _make_value(function) + def _set_called_function(self, function): + _core.LLVMInstSetCalledFunction(self.ptr, function.ptr) + + called_function = property(_get_called_function, _set_called_function) + # tail call is valid only for 'call', not 'invoke' # disabled for now #def _get_tc(self): return _core.LLVMIsTailCall(self.ptr) diff --git a/llvm/extra.cpp b/llvm/extra.cpp index b9f4ac2..b8545ea 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -855,6 +855,13 @@ LLVMValueRef LLVMInstGetCalledFunction(LLVMValueRef inst) return llvm::wrap(CallSite(instp).getCalledFunction()); } +void LLVMInstSetCalledFunction(LLVMValueRef inst, LLVMValueRef fn) +{ + using namespace llvm; + Instruction *instp = unwrap(inst); + CallSite(instp).setCalledFunction(unwrap(fn)); +} + ///* llvm::unwrap a set of `n' wrapped objects starting at `values', // * into a vector of pointers to llvm::unwrapped objects `out'. */ //template diff --git a/llvm/extra.h b/llvm/extra.h index dae90ec..26235e1 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -488,6 +488,10 @@ unsigned LLVMCmpInstGetPredicate(LLVMValueRef cmpinst); */ LLVMValueRef LLVMInstGetCalledFunction(LLVMValueRef inst); +/* Wraps llvm::CallSite::setCalledFunction. + */ +void LLVMInstSetCalledFunction(LLVMValueRef inst, LLVMValueRef fn); + /* Wraps llvm::ParseAssemblyString(). Returns a module reference or NULL (with * `out' pointing to an error message). Dispose error message after use, via * LLVMDisposeMessage(). */ From 2799e9f4525126737a7ddccbdd42556ae18f5760 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 1 Nov 2012 11:42:30 -0500 Subject: [PATCH 086/516] Test for InlineAsm --- test/inlineasm.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 test/inlineasm.py diff --git a/test/inlineasm.py b/test/inlineasm.py new file mode 100644 index 0000000..635e6bf --- /dev/null +++ b/test/inlineasm.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python + +# Import the llvm-py modules. +from llvm import * +from llvm.core import * + +import logging +import unittest + + +class TestInlineAsm(unittest.TestCase): + def test_inline_asm(self): + mod = Module.new(__name__) + fnty = Type.function(Type.int(), [Type.int()]) + fn = mod.add_function(fnty, name='test_inline_asm') + builder = Builder.new(fn.append_basic_block('entry')) + + iaty = Type.function(Type.int(), [Type.int()]) + inlineasm = InlineAsm.get(iaty, "bswap $0", "=r,r") + self.assertIn('asm "bswap $0", "=r,r"', str(inlineasm)) + builder.ret(builder.call(inlineasm, [fn.args[0]])) + print fn + +if __name__ == '__main__': + unittest.main() + From 2685d60e38020b6962760ac6c268e1b187906232 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 5 Nov 2012 14:59:43 -0600 Subject: [PATCH 087/516] Fix CDefinition. Note: This fixes a horrible undeterminisitic bug for parallel vectorize. --- builder.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/builder.py b/builder.py index b05a368..67644db 100644 --- a/builder.py +++ b/builder.py @@ -812,6 +812,7 @@ class CDefinition(object): self.cbuilder = CBuilder(func) self.body(*self.cbuilder.args) self.cbuilder.close() + self.cbuilder = None # optimize fpm = lp.FunctionPassManager.new(module) @@ -839,6 +840,8 @@ class CDefinition(object): ''' raise NotImplementedError + def __str__(self): + return self._name_ class CValue(object): def __init__(self, parent, handle): From 004313fcbdcdc9932ac06a696fc657f848efd6e8 Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Wed, 7 Nov 2012 11:01:40 -0600 Subject: [PATCH 088/516] Collected the data to move llvm_cbuilder --- __init__.py => llvm_cbuilder/__init__.py | 0 builder.py => llvm_cbuilder/builder.py | 0 executor.py => llvm_cbuilder/executor.py | 0 libc.py => llvm_cbuilder/libc.py | 0 shortnames.py => llvm_cbuilder/shortnames.py | 0 translator.py => llvm_cbuilder/translator.py | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename __init__.py => llvm_cbuilder/__init__.py (100%) rename builder.py => llvm_cbuilder/builder.py (100%) rename executor.py => llvm_cbuilder/executor.py (100%) rename libc.py => llvm_cbuilder/libc.py (100%) rename shortnames.py => llvm_cbuilder/shortnames.py (100%) rename translator.py => llvm_cbuilder/translator.py (100%) diff --git a/__init__.py b/llvm_cbuilder/__init__.py similarity index 100% rename from __init__.py rename to llvm_cbuilder/__init__.py diff --git a/builder.py b/llvm_cbuilder/builder.py similarity index 100% rename from builder.py rename to llvm_cbuilder/builder.py diff --git a/executor.py b/llvm_cbuilder/executor.py similarity index 100% rename from executor.py rename to llvm_cbuilder/executor.py diff --git a/libc.py b/llvm_cbuilder/libc.py similarity index 100% rename from libc.py rename to llvm_cbuilder/libc.py diff --git a/shortnames.py b/llvm_cbuilder/shortnames.py similarity index 100% rename from shortnames.py rename to llvm_cbuilder/shortnames.py diff --git a/translator.py b/llvm_cbuilder/translator.py similarity index 100% rename from translator.py rename to llvm_cbuilder/translator.py From 119ef506896dd3914e0609bb93ea226158805d44 Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Wed, 7 Nov 2012 11:03:50 -0600 Subject: [PATCH 089/516] Add llvm_cbuilder to list of packages. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 89c9df6..3fb3e00 100644 --- a/setup.py +++ b/setup.py @@ -129,7 +129,7 @@ setup( author = 'Mahadevan R', author_email = 'mdevan@mdevan.org', url = 'http://www.llvmpy.org/', - packages = ['llvm'], + packages = ['llvm', 'llvm_cbuilder'], py_modules = ['llvm.core'], license = "BSD", classifiers = [ From bbc7a4ddf019d4841d5f104192adeee1c1bc65cd Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Wed, 7 Nov 2012 12:08:32 -0600 Subject: [PATCH 090/516] Ready for numba/llnumba -> llvmpy/llpython --- __init__.py => llpython/__init__.py | 0 byte_control.py => llpython/byte_control.py | 0 byte_flow.py => llpython/byte_flow.py | 0 byte_translator.py => llpython/byte_translator.py | 0 bytecode_visitor.py => llpython/bytecode_visitor.py | 0 bytetype.py => llpython/bytetype.py | 0 control_flow.py => llpython/control_flow.py | 0 gen_bytecode_visitor.py => llpython/gen_bytecode_visitor.py | 0 nobitey.py => llpython/nobitey.py | 0 opcode_util.py => llpython/opcode_util.py | 0 phi_injector.py => llpython/phi_injector.py | 0 pyaddfunc.py => llpython/pyaddfunc.py | 0 {tests => llpython/tests}/__init__.py | 0 {tests => llpython/tests}/llfuncs.py | 0 {tests => llpython/tests}/llfunctys.py | 0 15 files changed, 0 insertions(+), 0 deletions(-) rename __init__.py => llpython/__init__.py (100%) rename byte_control.py => llpython/byte_control.py (100%) rename byte_flow.py => llpython/byte_flow.py (100%) rename byte_translator.py => llpython/byte_translator.py (100%) rename bytecode_visitor.py => llpython/bytecode_visitor.py (100%) rename bytetype.py => llpython/bytetype.py (100%) rename control_flow.py => llpython/control_flow.py (100%) rename gen_bytecode_visitor.py => llpython/gen_bytecode_visitor.py (100%) rename nobitey.py => llpython/nobitey.py (100%) rename opcode_util.py => llpython/opcode_util.py (100%) rename phi_injector.py => llpython/phi_injector.py (100%) rename pyaddfunc.py => llpython/pyaddfunc.py (100%) rename {tests => llpython/tests}/__init__.py (100%) rename {tests => llpython/tests}/llfuncs.py (100%) rename {tests => llpython/tests}/llfunctys.py (100%) diff --git a/__init__.py b/llpython/__init__.py similarity index 100% rename from __init__.py rename to llpython/__init__.py diff --git a/byte_control.py b/llpython/byte_control.py similarity index 100% rename from byte_control.py rename to llpython/byte_control.py diff --git a/byte_flow.py b/llpython/byte_flow.py similarity index 100% rename from byte_flow.py rename to llpython/byte_flow.py diff --git a/byte_translator.py b/llpython/byte_translator.py similarity index 100% rename from byte_translator.py rename to llpython/byte_translator.py diff --git a/bytecode_visitor.py b/llpython/bytecode_visitor.py similarity index 100% rename from bytecode_visitor.py rename to llpython/bytecode_visitor.py diff --git a/bytetype.py b/llpython/bytetype.py similarity index 100% rename from bytetype.py rename to llpython/bytetype.py diff --git a/control_flow.py b/llpython/control_flow.py similarity index 100% rename from control_flow.py rename to llpython/control_flow.py diff --git a/gen_bytecode_visitor.py b/llpython/gen_bytecode_visitor.py similarity index 100% rename from gen_bytecode_visitor.py rename to llpython/gen_bytecode_visitor.py diff --git a/nobitey.py b/llpython/nobitey.py similarity index 100% rename from nobitey.py rename to llpython/nobitey.py diff --git a/opcode_util.py b/llpython/opcode_util.py similarity index 100% rename from opcode_util.py rename to llpython/opcode_util.py diff --git a/phi_injector.py b/llpython/phi_injector.py similarity index 100% rename from phi_injector.py rename to llpython/phi_injector.py diff --git a/pyaddfunc.py b/llpython/pyaddfunc.py similarity index 100% rename from pyaddfunc.py rename to llpython/pyaddfunc.py diff --git a/tests/__init__.py b/llpython/tests/__init__.py similarity index 100% rename from tests/__init__.py rename to llpython/tests/__init__.py diff --git a/tests/llfuncs.py b/llpython/tests/llfuncs.py similarity index 100% rename from tests/llfuncs.py rename to llpython/tests/llfuncs.py diff --git a/tests/llfunctys.py b/llpython/tests/llfunctys.py similarity index 100% rename from tests/llfunctys.py rename to llpython/tests/llfunctys.py From ac791e5c38e6489a324854a8bd00c1ab31971573 Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Wed, 7 Nov 2012 12:14:01 -0600 Subject: [PATCH 091/516] Change name to llpython and remove llnumba references. --- llpython/byte_control.py | 2 +- llpython/byte_translator.py | 22 +++++++++++----------- llpython/nobitey.py | 4 ++-- llpython/tests/llfunctys.py | 5 +---- setup.py | 2 +- 5 files changed, 16 insertions(+), 19 deletions(-) diff --git a/llpython/byte_control.py b/llpython/byte_control.py index 0ee4b67..34ebae4 100644 --- a/llpython/byte_control.py +++ b/llpython/byte_control.py @@ -19,7 +19,7 @@ class ControlFlowBuilder (BenignBytecodeVisitorMixin, BytecodeFlowVisitor): ''' def visit (self, flow, nargs = 0, *args, **kws): '''Given a bytecode flow, and an optional number of arguments, - return a :py:class:`numba.llnumba.control_flow.ControlFlowGraph` + return a :py:class:`llpython.control_flow.ControlFlowGraph` instance describing the full control flow of the bytecode flow.''' self.nargs = nargs diff --git a/llpython/byte_translator.py b/llpython/byte_translator.py index bcbe06c..08b4560 100644 --- a/llpython/byte_translator.py +++ b/llpython/byte_translator.py @@ -1,6 +1,6 @@ #! /usr/bin/env python # ______________________________________________________________________ -'''Defines a bytecode based LLVM translator for llnumba code. +'''Defines a bytecode based LLVM translator for llpython code. ''' # ______________________________________________________________________ # Module imports @@ -126,11 +126,11 @@ class LLVMTranslator (BytecodeFlowVisitor): '''Transformer responsible for visiting a set of bytecode flow trees, emitting LLVM code. - Unlike other translators in :py:mod:`numba.llnumba`, this + Unlike other translators in :py:mod:`llpython`, this incorporates the full transformation chain, starting with - :py:class:`numba.llnumba.byte_flow.BytecodeFlowBuilder`, then - :py:class:`numba.llnumba.byte_control.ControlFlowBuilder`, and - then :py:class:`numba.llnumba.phi_injector.PhiInjector`.''' + :py:class:`llpython.byte_flow.BytecodeFlowBuilder`, then + :py:class:`llpython.byte_control.ControlFlowBuilder`, and + then :py:class:`llpython.phi_injector.PhiInjector`.''' def __init__ (self, llvm_module = None, *args, **kws): '''Constructor for LLVMTranslator.''' @@ -563,18 +563,18 @@ def translate_into_function (py_function, llvm_function, **kws): # ______________________________________________________________________ -def llnumba (lltype, llvm_module = None, **kws): +def llpython (lltype, llvm_module = None, **kws): '''Decorator version of translate_function().''' - def _llnumba (func): + def _llpython (func): return translate_function(func, lltype, llvm_module, **kws) - return _llnumba + return _llpython # ______________________________________________________________________ -def llnumba_into (llvm_function, **kws): - def _llnumba_into (func): +def llpython_into (llvm_function, **kws): + def _llpython_into (func): return translate_into_function(llvm_function, func, **kws) - return _llnumba_into + return _llpython_into # ______________________________________________________________________ # Main (self-test) routine diff --git a/llpython/nobitey.py b/llpython/nobitey.py index 67d134e..b756fc8 100644 --- a/llpython/nobitey.py +++ b/llpython/nobitey.py @@ -112,8 +112,8 @@ class NoBitey (object): handle_abi_casts = self.handle_abi_casts target_function_name = llvm_function.name + "_wrapper" # __________________________________________________ - @byte_translator.llnumba(bytetype.l_pyfunc, self.target_module, - **locals()) + @byte_translator.llpython(bytetype.l_pyfunc, self.target_module, + **locals()) def _wrapper (self, args): ret_val = l_pyobj_p(0) parse_args = build_parse_args() diff --git a/llpython/tests/llfunctys.py b/llpython/tests/llfunctys.py index 107b5a3..b552cf4 100644 --- a/llpython/tests/llfunctys.py +++ b/llpython/tests/llfunctys.py @@ -3,10 +3,7 @@ import llvm.core as lc -try: - from llnumba import bytetype -except ImportError: - from numba.llnumba import bytetype +from llpython import bytetype # ______________________________________________________________________ diff --git a/setup.py b/setup.py index 3fb3e00..88281dc 100644 --- a/setup.py +++ b/setup.py @@ -129,7 +129,7 @@ setup( author = 'Mahadevan R', author_email = 'mdevan@mdevan.org', url = 'http://www.llvmpy.org/', - packages = ['llvm', 'llvm_cbuilder'], + packages = ['llvm', 'llvm_cbuilder', 'llpython'], py_modules = ['llvm.core'], license = "BSD", classifiers = [ From 5b9885fc40382cdfe43b521af40047b9623bf0f2 Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Thu, 8 Nov 2012 12:15:00 +0000 Subject: [PATCH 092/516] Allow creating a cbuilder struct from a minitype struct type --- llvm_cbuilder/builder.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 67644db..628ed85 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -1328,10 +1328,6 @@ class CStruct(CValue): Can define new methods which gets inlined to the parent CBuilder. ''' - @classmethod - def llvm_type(cls): - return lc.Type.struct([v for k, v in cls._fields_]) - def __init__(self, parent, ptr): super(CStruct, self).__init__(parent, ptr) makeind = lambda x: self.parent.constant(types.int, x).value @@ -1348,6 +1344,17 @@ class CStruct(CValue): def reference(self): return self._temp(self.handle) + @classmethod + def llvm_type(cls): + return lc.Type.struct([v for k, v in cls._fields_]) + + @classmethod + def from_numba_struct(cls, context, struct_type): + class Struct(cls): + _fields_ = [(name, type.to_llvm(context)) + for name, type in struct_type.fields] + return Struct + class CExternal(object): '''subclass to define external interface From 22d8e0048b7e2d140224ed6e4becf26a568fc80c Mon Sep 17 00:00:00 2001 From: Jon Riehl Date: Thu, 8 Nov 2012 15:51:14 -0600 Subject: [PATCH 093/516] Moved and updated LLPython (formerly LLNumba) documentation from Numba repository. --- docs/source/conf.py | 2 +- docs/source/doc/llpython/articles.rst | 10 ++++ docs/source/doc/llpython/ctmp_in_llpython.rst | 5 ++ docs/source/doc/llpython/index.rst | 9 ++++ docs/source/doc/llpython/intro_llpython.rst | 46 +++++++++++++++++++ .../doc/llpython/llpython.byte_control.rst | 6 +++ .../doc/llpython/llpython.byte_flow.rst | 6 +++ .../doc/llpython/llpython.byte_translator.rst | 6 +++ .../llpython/llpython.bytecode_visitor.rst | 6 +++ .../source/doc/llpython/llpython.bytetype.rst | 6 +++ .../doc/llpython/llpython.control_flow.rst | 6 +++ .../llpython.gen_bytecode_visitor.rst | 6 +++ docs/source/doc/llpython/llpython.nobitey.rst | 6 +++ .../doc/llpython/llpython.opcode_util.rst | 6 +++ .../doc/llpython/llpython.phi_injector.rst | 6 +++ .../doc/llpython/llpython.pyaddfunc.rst | 6 +++ docs/source/doc/llpython/llpython.rst | 6 +++ docs/source/doc/llpython/nobitey_dev.rst | 5 ++ docs/source/doc/llpython/reference.rst | 21 +++++++++ 19 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 docs/source/doc/llpython/articles.rst create mode 100644 docs/source/doc/llpython/ctmp_in_llpython.rst create mode 100644 docs/source/doc/llpython/index.rst create mode 100644 docs/source/doc/llpython/intro_llpython.rst create mode 100644 docs/source/doc/llpython/llpython.byte_control.rst create mode 100644 docs/source/doc/llpython/llpython.byte_flow.rst create mode 100644 docs/source/doc/llpython/llpython.byte_translator.rst create mode 100644 docs/source/doc/llpython/llpython.bytecode_visitor.rst create mode 100644 docs/source/doc/llpython/llpython.bytetype.rst create mode 100644 docs/source/doc/llpython/llpython.control_flow.rst create mode 100644 docs/source/doc/llpython/llpython.gen_bytecode_visitor.rst create mode 100644 docs/source/doc/llpython/llpython.nobitey.rst create mode 100644 docs/source/doc/llpython/llpython.opcode_util.rst create mode 100644 docs/source/doc/llpython/llpython.phi_injector.rst create mode 100644 docs/source/doc/llpython/llpython.pyaddfunc.rst create mode 100644 docs/source/doc/llpython/llpython.rst create mode 100644 docs/source/doc/llpython/nobitey_dev.rst create mode 100644 docs/source/doc/llpython/reference.rst diff --git a/docs/source/conf.py b/docs/source/conf.py index b7a7342..758adf6 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -25,7 +25,7 @@ import sys, os # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.mathjax'] +extensions = ['sphinx.ext.mathjax', 'sphinx.ext.autodoc'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/source/doc/llpython/articles.rst b/docs/source/doc/llpython/articles.rst new file mode 100644 index 0000000..ff7669c --- /dev/null +++ b/docs/source/doc/llpython/articles.rst @@ -0,0 +1,10 @@ +LLPython Articles +================= + +.. toctree:: + :titlesonly: + :maxdepth: 1 + + intro_llpython.rst + nobitey_dev.rst + ctmp_in_llpython.rst diff --git a/docs/source/doc/llpython/ctmp_in_llpython.rst b/docs/source/doc/llpython/ctmp_in_llpython.rst new file mode 100644 index 0000000..53f63bf --- /dev/null +++ b/docs/source/doc/llpython/ctmp_in_llpython.rst @@ -0,0 +1,5 @@ +Compile-time Metaprogramming in LLPython +======================================== + +In this article, we discuss how LLPython supports compile-time +metaprogramming. diff --git a/docs/source/doc/llpython/index.rst b/docs/source/doc/llpython/index.rst new file mode 100644 index 0000000..43ea17a --- /dev/null +++ b/docs/source/doc/llpython/index.rst @@ -0,0 +1,9 @@ +LLPython Documentation +====================== + +.. toctree:: + :titlesonly: + :maxdepth: 2 + + articles.rst + reference.rst diff --git a/docs/source/doc/llpython/intro_llpython.rst b/docs/source/doc/llpython/intro_llpython.rst new file mode 100644 index 0000000..47c0c2a --- /dev/null +++ b/docs/source/doc/llpython/intro_llpython.rst @@ -0,0 +1,46 @@ +==================== +Introducing LLPython +==================== + +In this article, we introduce the llpython package. The primary goal +of the llpython package is to provide a Python dialect/subset that +maps directly to LLVM code. LLPython differs from its originating +LLVM translator, Numba, in the following aspects: + + * LLPython code is not intended to work in Python if not translated + and wrapped. + * The LLPython translator only uses LLVM types. + * LLPython is explicitly typed, and does not support type inference. + LLPython does not support implicit casts, all casts must be explicit. + * LLPython supports code that directly calls the C API, the Python C + API, and the llvm.core.Builder methods. + +Additionally, we designed the sub-package to have the following +engineering properties: + + * Usable from Python 2.7, and 3.X. At the time of writing, we plan + to support Python 2.6. + * Clean from Numba dependencies (other than llvmpy), and can be used + as a standalone code generator without a full Numba installation. + * Provides a series of Python bytecode passes that can be easily + used by other projects. + + +LLPython Origins +================ + +We developed LLPython with the initial goal of simplifying writing +LLVM code. + + +LLPython Internals +================== + +In this section, we describe the various passes performed by the +LLPython translator. + + +Conclusions +=========== + +LLPython is neat. diff --git a/docs/source/doc/llpython/llpython.byte_control.rst b/docs/source/doc/llpython/llpython.byte_control.rst new file mode 100644 index 0000000..e851dac --- /dev/null +++ b/docs/source/doc/llpython/llpython.byte_control.rst @@ -0,0 +1,6 @@ +===================== +llpython.byte_control +===================== + +.. automodule:: llpython.byte_control + :members: diff --git a/docs/source/doc/llpython/llpython.byte_flow.rst b/docs/source/doc/llpython/llpython.byte_flow.rst new file mode 100644 index 0000000..783a54b --- /dev/null +++ b/docs/source/doc/llpython/llpython.byte_flow.rst @@ -0,0 +1,6 @@ +================== +llpython.byte_flow +================== + +.. automodule:: llpython.byte_flow + :members: diff --git a/docs/source/doc/llpython/llpython.byte_translator.rst b/docs/source/doc/llpython/llpython.byte_translator.rst new file mode 100644 index 0000000..2a5993c --- /dev/null +++ b/docs/source/doc/llpython/llpython.byte_translator.rst @@ -0,0 +1,6 @@ +======================== +llpython.byte_translator +======================== + +.. automodule:: llpython.byte_translator + :members: diff --git a/docs/source/doc/llpython/llpython.bytecode_visitor.rst b/docs/source/doc/llpython/llpython.bytecode_visitor.rst new file mode 100644 index 0000000..3479ff7 --- /dev/null +++ b/docs/source/doc/llpython/llpython.bytecode_visitor.rst @@ -0,0 +1,6 @@ +========================= +llpython.bytecode_visitor +========================= + +.. automodule:: llpython.bytecode_visitor + :members: diff --git a/docs/source/doc/llpython/llpython.bytetype.rst b/docs/source/doc/llpython/llpython.bytetype.rst new file mode 100644 index 0000000..81efe83 --- /dev/null +++ b/docs/source/doc/llpython/llpython.bytetype.rst @@ -0,0 +1,6 @@ +================= +llpython.bytetype +================= + +.. automodule:: llpython.bytetype + :members: diff --git a/docs/source/doc/llpython/llpython.control_flow.rst b/docs/source/doc/llpython/llpython.control_flow.rst new file mode 100644 index 0000000..c9aee7d --- /dev/null +++ b/docs/source/doc/llpython/llpython.control_flow.rst @@ -0,0 +1,6 @@ +===================== +llpython.control_flow +===================== + +.. automodule:: llpython.control_flow + :members: diff --git a/docs/source/doc/llpython/llpython.gen_bytecode_visitor.rst b/docs/source/doc/llpython/llpython.gen_bytecode_visitor.rst new file mode 100644 index 0000000..2bc19db --- /dev/null +++ b/docs/source/doc/llpython/llpython.gen_bytecode_visitor.rst @@ -0,0 +1,6 @@ +============================= +llpython.gen_bytecode_visitor +============================= + +.. automodule:: llpython.gen_bytecode_visitor + :members: diff --git a/docs/source/doc/llpython/llpython.nobitey.rst b/docs/source/doc/llpython/llpython.nobitey.rst new file mode 100644 index 0000000..59e052d --- /dev/null +++ b/docs/source/doc/llpython/llpython.nobitey.rst @@ -0,0 +1,6 @@ +================ +llpython.nobitey +================ + +.. automodule:: llpython.nobitey + :members: diff --git a/docs/source/doc/llpython/llpython.opcode_util.rst b/docs/source/doc/llpython/llpython.opcode_util.rst new file mode 100644 index 0000000..0fa5387 --- /dev/null +++ b/docs/source/doc/llpython/llpython.opcode_util.rst @@ -0,0 +1,6 @@ +==================== +llpython.opcode_util +==================== + +.. automodule:: llpython.opcode_util + :members: diff --git a/docs/source/doc/llpython/llpython.phi_injector.rst b/docs/source/doc/llpython/llpython.phi_injector.rst new file mode 100644 index 0000000..3db3863 --- /dev/null +++ b/docs/source/doc/llpython/llpython.phi_injector.rst @@ -0,0 +1,6 @@ +===================== +llpython.phi_injector +===================== + +.. automodule:: llpython.phi_injector + :members: diff --git a/docs/source/doc/llpython/llpython.pyaddfunc.rst b/docs/source/doc/llpython/llpython.pyaddfunc.rst new file mode 100644 index 0000000..39e0de7 --- /dev/null +++ b/docs/source/doc/llpython/llpython.pyaddfunc.rst @@ -0,0 +1,6 @@ +================== +llpython.pyaddfunc +================== + +.. automodule:: llpython.pyaddfunc + :members: diff --git a/docs/source/doc/llpython/llpython.rst b/docs/source/doc/llpython/llpython.rst new file mode 100644 index 0000000..87fd3d5 --- /dev/null +++ b/docs/source/doc/llpython/llpython.rst @@ -0,0 +1,6 @@ +======== +llpython +======== + +.. automodule:: llpython + :members: diff --git a/docs/source/doc/llpython/nobitey_dev.rst b/docs/source/doc/llpython/nobitey_dev.rst new file mode 100644 index 0000000..be7b4d8 --- /dev/null +++ b/docs/source/doc/llpython/nobitey_dev.rst @@ -0,0 +1,5 @@ +nobitey: Using ctypes and llvmpy to Bypass ctypes +================================================= + +In this article, we show how nobitey uses llvmpy to eliminate the +ctypes call overhead. diff --git a/docs/source/doc/llpython/reference.rst b/docs/source/doc/llpython/reference.rst new file mode 100644 index 0000000..7818100 --- /dev/null +++ b/docs/source/doc/llpython/reference.rst @@ -0,0 +1,21 @@ +LLPython Module Reference +========================= + +Contents: + +.. toctree:: + :titlesonly: + :maxdepth: 2 + + llpython.rst + llpython.bytecode_visitor.rst + llpython.byte_control.rst + llpython.byte_flow.rst + llpython.byte_translator.rst + llpython.bytetype.rst + llpython.control_flow.rst + llpython.gen_bytecode_visitor.rst + llpython.nobitey.rst + llpython.opcode_util.rst + llpython.phi_injector.rst + llpython.pyaddfunc.rst From 23a2d3a446cf8f6ac71a6419944db6401eb10845 Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Sat, 10 Nov 2012 18:43:10 -0600 Subject: [PATCH 094/516] Collect the directory to move --- __init__.py | 0 test_atomic_add.py | 117 ------------------------------- test_atomic_cmpxchg.py | 124 -------------------------------- test_cstr_collide.py | 17 ----- test_isprime.py | 125 --------------------------------- test_loopcontrol.py | 135 ----------------------------------- test_nestedloops.py | 128 --------------------------------- test_print.py | 68 ------------------ test_pthread.py | 92 ------------------------ test_struct.py | 52 -------------- test_translate.py | 94 ------------------------- test_vectorarith.py | 156 ----------------------------------------- 12 files changed, 1108 deletions(-) delete mode 100644 __init__.py delete mode 100644 test_atomic_add.py delete mode 100644 test_atomic_cmpxchg.py delete mode 100644 test_cstr_collide.py delete mode 100644 test_isprime.py delete mode 100644 test_loopcontrol.py delete mode 100644 test_nestedloops.py delete mode 100644 test_print.py delete mode 100644 test_pthread.py delete mode 100644 test_struct.py delete mode 100644 test_translate.py delete mode 100644 test_vectorarith.py diff --git a/__init__.py b/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/test_atomic_add.py b/test_atomic_add.py deleted file mode 100644 index 70faa0c..0000000 --- a/test_atomic_add.py +++ /dev/null @@ -1,117 +0,0 @@ -''' -Base on the test_pthread.py and extend to use atomic instructions -''' - -from llvm.core import * -from llvm.passes import * -from llvm.ee import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import unittest, logging -import sys - -# logging.basicConfig(level=logging.DEBUG) - -NUM_OF_THREAD = 4 -REPEAT = 10000 - -def gen_test_worker(mod): - cb = CBuilder.new_function(mod, 'worker', C.void, [C.pointer(C.int)]) - pval = cb.args[0] - one = cb.constant(pval.type.pointee, 1) - - ct = cb.var(C.int, 0) - limit = cb.constant(C.int, REPEAT) - with cb.loop() as loop: - with loop.condition() as setcond: - setcond( ct < limit ) - - with loop.body(): - cb.atomic_add(pval, one, 'acq_rel') - ct += one - - cb.ret() - cb.close() - return cb.function - -def gen_test_pthread(mod): - cb = CBuilder.new_function(mod, 'manager', C.int, [C.int]) - arg = cb.args[0] - - worker_func = cb.get_function_named('worker') - pthread_create = cb.get_function_named('pthread_create') - pthread_join = cb.get_function_named('pthread_join') - - - NULL = cb.constant_null(C.void_p) - cast_to_null = lambda x: x.cast(C.void_p) - - threads = cb.array(C.void_p, NUM_OF_THREAD) - - for tid in range(NUM_OF_THREAD): - pthread_create_args = [threads[tid].reference(), - NULL, - worker_func, - arg.reference()] - pthread_create(*map(cast_to_null, pthread_create_args)) - - worker_func(arg.reference()) - - for tid in range(NUM_OF_THREAD): - pthread_join_args = threads[tid], NULL - pthread_join(*map(cast_to_null, pthread_join_args)) - - - cb.ret(arg) - cb.close() - return cb.function - -class TestAtomicAdd(unittest.TestCase): - @unittest.skipIf(sys.platform == 'win32', "test uses pthreads, not supported on Windows") - def test_atomic_add(self): - mod = Module.new(__name__) - # add pthread functions - - mod.add_function(Type.function(C.int, - [C.void_p, C.void_p, C.void_p, C.void_p]), - 'pthread_create') - - mod.add_function(Type.function(C.int, - [C.void_p, C.void_p]), - 'pthread_join') - - lf_test_worker = gen_test_worker(mod) - lf_test_pthread = gen_test_pthread(mod) - logging.debug(mod) - mod.verify() - - # optimize - fpm = FunctionPassManager.new(mod) - mpm = PassManager.new() - pmb = PassManagerBuilder.new() - pmb.vectorize = True - pmb.opt_level = 3 - pmb.populate(fpm) - pmb.populate(mpm) - - fpm.run(lf_test_worker) - fpm.run(lf_test_pthread) - mpm.run(mod) - logging.debug(mod) - mod.verify() - - # run - exe = CExecutor(mod) - exe.engine.get_pointer_to_function(mod.get_function_named('worker')) - func = exe.get_ctype_function(lf_test_pthread, 'int, int') - - inarg = 1234 - gold = inarg + (NUM_OF_THREAD + 1) * REPEAT - - for _ in range(1000): # run many many times to catch race condition - self.assertEqual(func(inarg), gold, "Unexpected race condition") - - -if __name__ == '__main__': - unittest.main() - diff --git a/test_atomic_cmpxchg.py b/test_atomic_cmpxchg.py deleted file mode 100644 index 9058e42..0000000 --- a/test_atomic_cmpxchg.py +++ /dev/null @@ -1,124 +0,0 @@ -''' -Base on the test_pthread.py and extend to use atomic instructions -''' - -from llvm.core import * -from llvm.passes import * -from llvm.ee import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import unittest, logging -import sys - -# logging.basicConfig(level=logging.DEBUG) - -NUM_OF_THREAD = 4 -REPEAT = 10000 - -def gen_test_worker(mod): - cb = CBuilder.new_function(mod, 'worker', C.void, [C.pointer(C.int)]) - pval = cb.args[0] - one = cb.constant(pval.type.pointee, 1) - - ct = cb.var(C.int, 0) - limit = cb.constant(C.int, REPEAT) - with cb.loop() as loop: - with loop.condition() as setcond: - setcond( ct < limit ) - - with loop.body(): - oldval = pval.atomic_load('acquire') - updated = oldval + one - castmp = pval.atomic_cmpxchg(oldval, updated, 'release') - - with cb.ifelse( castmp == oldval ) as ifelse: - with ifelse.then(): - ct += one - - cb.ret() - cb.close() - return cb.function - -def gen_test_pthread(mod): - cb = CBuilder.new_function(mod, 'manager', C.int, [C.int]) - arg = cb.args[0] - - worker_func = cb.get_function_named('worker') - pthread_create = cb.get_function_named('pthread_create') - pthread_join = cb.get_function_named('pthread_join') - - - NULL = cb.constant_null(C.void_p) - cast_to_null = lambda x: x.cast(C.void_p) - - threads = cb.array(C.void_p, NUM_OF_THREAD) - - for tid in range(NUM_OF_THREAD): - pthread_create_args = [threads[tid].reference(), - NULL, - worker_func, - arg.reference()] - pthread_create(*map(cast_to_null, pthread_create_args)) - - worker_func(arg.reference()) - - for tid in range(NUM_OF_THREAD): - pthread_join_args = threads[tid], NULL - pthread_join(*map(cast_to_null, pthread_join_args)) - - - cb.ret(arg) - cb.close() - return cb.function - -class TestAtomicCmpXchg(unittest.TestCase): - @unittest.skipIf(sys.platform == 'win32', "test uses pthreads, not supported on Windows") - def test_atomic_cmpxchg(self): - mod = Module.new(__name__) - # add pthread functions - - mod.add_function(Type.function(C.int, - [C.void_p, C.void_p, C.void_p, C.void_p]), - 'pthread_create') - - mod.add_function(Type.function(C.int, - [C.void_p, C.void_p]), - 'pthread_join') - - lf_test_worker = gen_test_worker(mod) - lf_test_pthread = gen_test_pthread(mod) - logging.debug(mod) - mod.verify() - - # optimize - fpm = FunctionPassManager.new(mod) - mpm = PassManager.new() - pmb = PassManagerBuilder.new() - pmb.vectorize = True - pmb.opt_level = 3 - pmb.populate(fpm) - pmb.populate(mpm) - - fpm.run(lf_test_worker) - fpm.run(lf_test_pthread) - mpm.run(mod) - logging.debug(mod) - mod.verify() - - # run - exe = CExecutor(mod) - exe.engine.get_pointer_to_function(mod.get_function_named('worker')) - func = exe.get_ctype_function(lf_test_pthread, 'int, int') - - inarg = 1234 - gold = inarg + (NUM_OF_THREAD + 1) * REPEAT - - for _ in range(1000): # run many many times to catch race condition - res = func(inarg) - self.assertEqual(res, gold, - "Unexpected race condition: res = %d" % res) - - -if __name__ == '__main__': - unittest.main() - diff --git a/test_cstr_collide.py b/test_cstr_collide.py deleted file mode 100644 index 4a427c6..0000000 --- a/test_cstr_collide.py +++ /dev/null @@ -1,17 +0,0 @@ -from llvm.core import * -from llvm_cbuilder import * -from llvm_cbuilder import shortnames as C - -import unittest - -class TestCstrCollide(unittest.TestCase): - def test_same_string(self): - mod = Module.new(__name__) - cb = CBuilder.new_function(mod, 'test_cstr_collide', C.void, []) - - a = cb.constant_string("hello") - b = cb.constant_string("hello") - self.assertEqual(a.value, b.value) - -if __name__ == '__main__': - unittest.main() diff --git a/test_isprime.py b/test_isprime.py deleted file mode 100644 index bcc0b9c..0000000 --- a/test_isprime.py +++ /dev/null @@ -1,125 +0,0 @@ -from llvm.core import * -from llvm.passes import * -from llvm.ee import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import unittest, logging - -def is_prime(x): - if x <= 2: - return True - if (x % 2) == 0: - return False - for y in range(2, int(1 + x**0.5)): - if (x % y) == 0: - return False - return True - -def gen_is_prime(mod): - functype = Type.function(C.int, [C.int]) - func = mod.add_function(functype, 'isprime') - - cb = CBuilder(func) - - arg = cb.args[0] - - two = cb.constant(C.int, 2) - true = one = cb.constant(C.int, 1) - false = zero = cb.constant(C.int, 0) - - with cb.ifelse( arg <= two ) as ifelse: - with ifelse.then(): - cb.ret(true) - - with cb.ifelse( (arg % two) == zero ) as ifelse: - with ifelse.then(): - cb.ret(false) - - idx = cb.var(C.int, 3, name='idx') - with cb.loop() as loop: - with loop.condition() as setcond: - setcond( idx < arg ) - - with loop.body(): - with cb.ifelse( (arg % idx) == zero ) as ifelse: - with ifelse.then(): - cb.ret(false) - # increment - idx += two - - cb.ret(true) - cb.close() - return func - - -def gen_is_prime_fast(mod): - functype = Type.function(C.int, [C.int]) - func = mod.add_function(functype, 'isprime_fast') - - cb = CBuilder(func) - - arg = cb.args[0] - - two = cb.constant(C.int, 2) - true = one = cb.constant(C.int, 1) - false = zero = cb.constant(C.int, 0) - - with cb.ifelse( arg <= two ) as ifelse: - with ifelse.then(): - cb.ret(true) - - with cb.ifelse( (arg % two) == zero ) as ifelse: - with ifelse.then(): - cb.ret(false) - - idx = cb.var(C.int, 3, name='idx') - - sqrt = cb.get_intrinsic(INTR_SQRT, [C.float]) - - looplimit = one + sqrt(arg.cast(C.float)).cast(C.int) - - - with cb.loop() as loop: - with loop.condition() as setcond: - setcond( idx < looplimit ) - - with loop.body(): - with cb.ifelse( (arg % idx) == zero ) as ifelse: - with ifelse.then(): - cb.ret(false) - # increment - idx += two - - - cb.ret(true) - cb.close() - return func - -class TestIsPrime(unittest.TestCase): - def test_isprime(self): - mod = Module.new(__name__) - lf_isprime = gen_is_prime(mod) - logging.debug(mod) - mod.verify() - - exe = CExecutor(mod) - func = exe.get_ctype_function(lf_isprime, 'bool, int') - for x in range(2, 1000): - msg = "Failed at x = %d" % x - self.assertEqual(func(x), is_prime(x), msg) - - def test_isprime_fast(self): - mod = Module.new(__name__) - lf_isprime = gen_is_prime_fast(mod) - logging.debug(mod) - mod.verify() - - exe = CExecutor(mod) - func = exe.get_ctype_function(lf_isprime, 'bool, int') - for x in range(2, 1000): - msg = "Failed at x = %d" % x - self.assertEqual(func(x), is_prime(x), msg) - -if __name__ == '__main__': - unittest.main() - diff --git a/test_loopcontrol.py b/test_loopcontrol.py deleted file mode 100644 index 7e252bf..0000000 --- a/test_loopcontrol.py +++ /dev/null @@ -1,135 +0,0 @@ -from llvm.core import * -from llvm.passes import * -from llvm.ee import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import unittest, logging - -def loopbreak(d): - z = 0 - for x in range(100): - for y in range(100): - z += x + y - if z > 50: - break - z -= d - return z - -def gen_loopbreak(mod): - functype = Type.function(C.int, [C.int]) - func = mod.add_function(functype, 'loopbreak') - - cb = CBuilder(func) - - d = cb.args[0] - x = cb.var(C.int) - y = cb.var(C.int) - z = cb.var(C.int) - - one = cb.constant(C.int, 1) - zero = cb.constant(C.int, 0) - limit = cb.constant(C.int, 100) - fifty = cb.constant(C.int, 50) - - z.assign(zero) - x.assign(zero) - with cb.loop() as outer: - with outer.condition() as setcond: - setcond( x < limit ) - - with outer.body(): - y.assign(zero) - with cb.loop() as inner: - with inner.condition() as setcond: - setcond( y < limit ) - - with inner.body(): - z += x + y - with cb.ifelse( z > fifty ) as ifelse: - with ifelse.then(): - inner.break_loop() - y += one - z -= d - x += one - - cb.ret(z) - cb.close() - return func - -def loopcontinue(d): - z = 0 - for x in range(100): - for y in range(100): - z += x + y - if z > 50: - continue - z += d - return z - -def gen_loopcontinue(mod): - functype = Type.function(C.int, [C.int]) - func = mod.add_function(functype, 'loopcontinue') - - cb = CBuilder(func) - - d = cb.args[0] - x = cb.var(C.int) - y = cb.var(C.int) - z = cb.var(C.int) - - one = cb.constant(C.int, 1) - zero = cb.constant(C.int, 0) - limit = cb.constant(C.int, 100) - fifty = cb.constant(C.int, 50) - - z.assign(zero) - x.assign(zero) - with cb.loop() as outer: - with outer.condition() as setcond: - setcond( x < limit ) - - with outer.body(): - y.assign(zero) - with cb.loop() as inner: - with inner.condition() as setcond: - setcond( y < limit ) - - with inner.body(): - z += x + y - y += one - with cb.ifelse( z > fifty ) as ifelse: - with ifelse.then(): - inner.continue_loop() - z += d - x += one - - cb.ret(z) - cb.close() - return func - -class TestLoopControl(unittest.TestCase): - def test_loopbreak(self): - mod = Module.new(__name__) - lfunc = gen_loopbreak(mod) - logging.debug(mod) - mod.verify() - - exe = CExecutor(mod) - func = exe.get_ctype_function(lfunc, 'int, int') - for x in range(100): - self.assertEqual(func(x), loopbreak(x)) - - def test_loopcontinue(self): - mod = Module.new(__name__) - lfunc = gen_loopcontinue(mod) - logging.debug(mod) - mod.verify() - - exe = CExecutor(mod) - func = exe.get_ctype_function(lfunc, 'int, int') - for x in range(100): - self.assertEqual(func(x), loopcontinue(x)) - -if __name__ == '__main__': - unittest.main() - diff --git a/test_nestedloops.py b/test_nestedloops.py deleted file mode 100644 index 0876bb2..0000000 --- a/test_nestedloops.py +++ /dev/null @@ -1,128 +0,0 @@ -from llvm.core import * -from llvm.passes import * -from llvm.ee import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import unittest, logging - -def nestedloop1(d): - z = 0 - for x in range(100): - for y in range(100): - z += x * d + int(y / d) - return z - -def gen_nestedloop1(mod): - functype = Type.function(C.int, [C.int]) - func = mod.add_function(functype, 'nestedloop1') - - cb = CBuilder(func) - - d = cb.args[0] - x = cb.var(C.int) - y = cb.var(C.int) - z = cb.var(C.int) - - one = cb.constant(C.int, 1) - zero = cb.constant(C.int, 0) - limit = cb.constant(C.int, 100) - - z.assign(zero) - x.assign(zero) - with cb.loop() as outer: - with outer.condition() as setcond: - setcond( x < limit ) - - with outer.body(): - y.assign(zero) - with cb.loop() as inner: - with inner.condition() as setcond: - setcond( y < limit ) - - with inner.body(): - z += x * d + y / d - y += one - x += one - - cb.ret(z) - cb.close() - return func - - -def nestedloop2(d): - z = 0 - for x in range(1, 100): - for y in range(1, 100): - if x > y: - z += int(x / y) * d - else: - z += int(y / x) * d - return z - -def gen_nestedloop2(mod): - functype = Type.function(C.int, [C.int]) - func = mod.add_function(functype, 'nestedloop2') - - cb = CBuilder(func) - - d = cb.args[0] - x = cb.var(C.int) - y = cb.var(C.int) - z = cb.var(C.int) - - one = cb.constant(C.int, 1) - zero = cb.constant(C.int, 0) - limit = cb.constant(C.int, 100) - - z.assign(zero) - x.assign(one) - with cb.loop() as outer: - with outer.condition() as setcond: - setcond( x < limit ) - - with outer.body(): - y.assign(one) - with cb.loop() as inner: - with inner.condition() as setcond: - setcond( y < limit ) - - with inner.body(): - with cb.ifelse(x > y) as ifelse: - with ifelse.then(): - z += x / y * d - with ifelse.otherwise(): - z += y / x * d - y += one - x += one - - cb.ret(z) - cb.close() - return func - - -class TestNestedLoop(unittest.TestCase): - def test_nestedloop1(self): - mod = Module.new(__name__) - lfunc = gen_nestedloop1(mod) - logging.debug(mod) - mod.verify() - - exe = CExecutor(mod) - func = exe.get_ctype_function(lfunc, 'int, int') - for x in range(1, 100): - self.assertEqual(func(x), int(nestedloop1(x))) - - def test_nestedloop2(self): - mod = Module.new(__name__) - lfunc = gen_nestedloop2(mod) - logging.debug(mod) - mod.verify() - - exe = CExecutor(mod) - func = exe.get_ctype_function(lfunc, 'int, int') - for x in range(1, 100): - self.assertEqual(func(x), int(nestedloop2(x))) - -if __name__ == '__main__': - unittest.main() - diff --git a/test_print.py b/test_print.py deleted file mode 100644 index 510161a..0000000 --- a/test_print.py +++ /dev/null @@ -1,68 +0,0 @@ -from llvm.core import * -from llvm.passes import * -from llvm.ee import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import sys, unittest, logging -from subprocess import Popen, PIPE - -def gen_debugprint(mod): - functype = Type.function(C.void, []) - func = mod.add_function(functype, 'debugprint') - - cb = CBuilder(func) - fmt = cb.constant_string("Show %d %.3f %.3e\n") - - an_int = cb.constant(C.int, 123) - a_float = cb.constant(C.double, 1.234) - a_double = cb.constant(C.double, 1e-31) - cb.printf(fmt, an_int, a_float, a_double) - - cb.debug('an_int =', an_int, 'a_float =', a_float, 'a_double =', a_double) - - cb.ret() - cb.close() - return func - -def main_debugprint(): - # generate code - mod = Module.new(__name__) - lfunc = gen_debugprint(mod) - logging.debug(mod) - mod.verify() - # run - exe = CExecutor(mod) - func = exe.get_ctype_function(lfunc, 'void') - func() - -class TestPrint(unittest.TestCase): - def test_debugprint(self): - p = Popen([sys.executable, __file__, "-child"], stdout=PIPE) - p.wait() - - # The encode(utf-8) is for Python 3 compatibility - lines = p.stdout.read().encode('utf-8').splitlines(False) - - # Try to account for variations in the system printf - if lines[0].find('e-031') >= 0: - expect = [ - 'Show 123 1.234 1.000e-031', - 'an_int = 123 a_float = 1.234000e+000 a_double = 1.000000e-031', - ] - else: - expect = [ - 'Show 123 1.234 1.000e-31', - 'an_int = 123 a_float = 1.234000e+00 a_double = 1.000000e-31', - ] - self.assertEqual(expect, lines) - - p.stdout.close() - -if __name__ == '__main__': - try: - if sys.argv[1] == '-child': - main_debugprint() - except IndexError: - unittest.main() - - diff --git a/test_pthread.py b/test_pthread.py deleted file mode 100644 index 23a2083..0000000 --- a/test_pthread.py +++ /dev/null @@ -1,92 +0,0 @@ -from llvm.core import * -from llvm.passes import * -from llvm.ee import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import unittest, logging -import sys - -# logging.basicConfig(level=logging.DEBUG) - -NUM_OF_THREAD = 4 - -def gen_test_worker(mod): - cb = CBuilder.new_function(mod, 'worker', C.void, [C.pointer(C.int)]) - pval = cb.args[0] - val = pval.load() - one = cb.constant(val.type, 1) - pval.store(val + one) - cb.ret() - cb.close() - -def gen_test_pthread(mod): - cb = CBuilder.new_function(mod, 'manager', C.int, [C.int]) - arg = cb.args[0] - - worker_func = cb.get_function_named('worker') - pthread_create = cb.get_function_named('pthread_create') - pthread_join = cb.get_function_named('pthread_join') - - - NULL = cb.constant_null(C.void_p) - cast_to_null = lambda x: x.cast(C.void_p) - - threads = cb.array(C.void_p, NUM_OF_THREAD) - - for tid in range(NUM_OF_THREAD): - pthread_create_args = [threads[tid].reference(), - NULL, - worker_func, - arg.reference()] - pthread_create(*map(cast_to_null, pthread_create_args)) - - worker_func(arg.reference()) - - for tid in range(NUM_OF_THREAD): - pthread_join_args = threads[tid], NULL - pthread_join(*map(cast_to_null, pthread_join_args)) - - cb.ret(arg) - cb.close() - return cb.function - -class TestPThread(unittest.TestCase): - @unittest.skipIf(sys.platform == 'win32', "pthreads not supported on Windows") - def test_pthread(self): - mod = Module.new(__name__) - # add pthread functions - - mod.add_function(Type.function(C.int, - [C.void_p, C.void_p, C.void_p, C.void_p]), - 'pthread_create') - - mod.add_function(Type.function(C.int, - [C.void_p, C.void_p]), - 'pthread_join') - - gen_test_worker(mod) - lf_test_pthread = gen_test_pthread(mod) - logging.debug(mod) - mod.verify() - - exe = CExecutor(mod) - exe.engine.get_pointer_to_function(mod.get_function_named('worker')) - func = exe.get_ctype_function(lf_test_pthread, 'int, int') - - inarg = 1234 - gold = inarg + NUM_OF_THREAD + 1 - self.assertLessEqual(func(inarg), gold) - # Cannot determine the exact return value due to untamed race condition - - count_race = 0 - for _ in range(2**12): - if func(inarg) != gold: - count_race += 1 - - if count_race > 0: - logging.info("Race condition occured %d times.", count_race) - logging.info("Race condition is expected.") - -if __name__ == '__main__': - unittest.main() - diff --git a/test_struct.py b/test_struct.py deleted file mode 100644 index 35048e6..0000000 --- a/test_struct.py +++ /dev/null @@ -1,52 +0,0 @@ -from llvm.core import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import unittest, ctypes - -class Vector2D(CStruct): - _fields_ = [ - ('x', C.float), - ('y', C.float), - ] - -class Vector2DCtype(ctypes.Structure): - _fields_ = [ - ('x', ctypes.c_float), - ('y', ctypes.c_float), - ] - -def gen_vector2d_dist(mod): - functype = Type.function(C.float, [C.pointer(Vector2D.llvm_type())]) - func = mod.add_function(functype, 'vector2d_dist') - - cb = CBuilder(func) - vec = cb.var(Vector2D, cb.args[0].load()) - dist = vec.x * vec.x + vec.y * vec.y - - cb.ret(dist) - cb.close() - return func - - -class TestStruct(unittest.TestCase): - def test_vector2d_dist(self): - # prepare module - mod = Module.new('mod') - lfunc = gen_vector2d_dist(mod) - mod.verify() - # run - exe = CExecutor(mod) - func = exe.get_ctype_function(lfunc, ctypes.c_float, ctypes.POINTER(Vector2DCtype)) - - from random import random - pydist = lambda x, y: x * x + y * y - for _ in range(100): - x, y = random(), random() - vec = Vector2DCtype(x=x, y=y) - ans = func(ctypes.pointer(vec)) - gold = pydist(x, y) - - self.assertLess(abs(ans-gold)/gold, 1e-6) - -if __name__ == '__main__': - unittest.main() diff --git a/test_translate.py b/test_translate.py deleted file mode 100644 index b9e39ea..0000000 --- a/test_translate.py +++ /dev/null @@ -1,94 +0,0 @@ - -from llvm.core import Module -from llvm_cbuilder import * -from llvm_cbuilder.translator import translate -import llvm_cbuilder.shortnames as C -import unittest, logging - -#logging.basicConfig(level=logging.DEBUG) - -class FooIf(CDefinition): - _name_ = 'foo_if' - _retty_ = C.int - _argtys_ = [('x', C.int), - ('y', C.int),] - - def body(self, x, y): - @translate - def _(): - if x > y: - return x - y - else: - return y - x - - -class FooWhile(CDefinition): - _name_ = 'foo_while' - _retty_ = C.int - _argtys_ = [('x', C.int)] - - def body(self, x): - y = self.var_copy(x) - - @translate - def _(): - while x > 0: - x -= 1 - y += x - return y - -class FooForRange(CDefinition): - _name_ = 'foo_for_range' - _retty_ = C.int - _argtys_ = [('x', C.int)] - - def body(self, x): - y = self.var(x.type, 0) - - @translate - def _(): - for i in range(x + 1): - y += i - return y - - -class TestTranslate(unittest.TestCase): - def test_if(self): - mod = Module.new(__name__) - lfoo = FooIf()(mod) - - print(mod) - mod.verify() - - exe = CExecutor(mod) - foo = exe.get_ctype_function(lfoo, 'int, int') - self.assertEqual(foo(10, 20), 20 - 10) - self.assertEqual(foo(23, 17), 23 - 17) - - def test_whileloop(self): - mod = Module.new(__name__) - lfoo = FooWhile()(mod) - - print(mod) - mod.verify() - - exe = CExecutor(mod) - foo = exe.get_ctype_function(lfoo, 'int') - self.assertEqual(foo(10), sum(range(10+1))) - self.assertEqual(foo(1324), sum(range(1324+1))) - - def test_forloop(self): - mod = Module.new(__name__) - lfoo = FooForRange()(mod) - - print(mod) - mod.verify() - - exe = CExecutor(mod) - foo = exe.get_ctype_function(lfoo, 'int') - self.assertEqual(foo(10), sum(range(10+1))) - self.assertEqual(foo(1324), sum(range(1324+1))) - -if __name__ == '__main__': - unittest.main() - diff --git a/test_vectorarith.py b/test_vectorarith.py deleted file mode 100644 index dad9262..0000000 --- a/test_vectorarith.py +++ /dev/null @@ -1,156 +0,0 @@ -from llvm_cbuilder import * -from llvm_cbuilder import shortnames as C -from llvm_cbuilder.translator import translate -from ctypes import * -from llvm.core import * -from llvm.passes import * -import numpy as np -import unittest -import logging -floatv4 = C.vector(C.float, 4) - -class VectorArith(CDefinition): - _name_ = 'vector_arith' - _argtys_ = [('a', floatv4), - ('b', floatv4), - ('c', floatv4),] - _retty_ = floatv4 - - def body(self, a, b, c): - ''' - Arguments - --------- - a, b, c -- must be vectors - ''' - @translate - def _(): # write like python in here - return a * b + c - -class VectorArithDriver1(CDefinition): - _name_ = 'vector_arith_driver_1' - _argtys_ = [('A', C.pointer(C.float)), - ('B', C.pointer(C.float)), - ('C', C.pointer(C.float)), - ('D', C.pointer(C.float)), - ('n', C.int),] - - def body(self, Aary, Bary, Cary, Dary, n): - ''' - This version uses vector load to fetch array elements as vectors. - - ''' - vecarith = self.depends(VectorArith()) - elem_per_vec = self.constant(C.int, floatv4.count) - with self.for_range(0, n, elem_per_vec) as (loop, i): - # Aary[i:] offset the array at i - a = Aary[i:].vector_load(4, align=1) # unaligned vector load - b = Bary[i:].vector_load(4, align=1) - c = Cary[i:].vector_load(4, align=1) - r = vecarith(a, b, c) - Dary[i:].vector_store(r, align=1) - # self.debug(r[0], r[1], r[2], r[3]) - self.ret() - - -class VectorArithDriver2(CDefinition): - _name_ = 'vector_arith_driver_2' - _argtys_ = [('A', C.pointer(C.float)), - ('B', C.pointer(C.float)), - ('C', C.pointer(C.float)), - ('D', C.pointer(C.float)), - ('n', C.int),] - - def body(self, Aary, Bary, Cary, Dary, n): - ''' - This version loads element of vector individually. - This style generates scalar ld/st instead of vector ld/st. - ''' - vecarith = self.depends(VectorArith()) - a = self.var(floatv4) - b = self.var(floatv4) - c = self.var(floatv4) - elem_per_vec = self.constant(C.int, floatv4.count) - with self.for_range(0, n, elem_per_vec) as (outer, i): - with self.for_range(elem_per_vec) as (inner, j): - a[j] = Aary[i + j] - b[j] = Bary[i + j] - c[j] = Cary[i + j] - r = vecarith(a, b, c) - Dary[i:].vector_store(r, align=1) - # self.debug(r[0], r[1], r[2], r[3]) - self.ret() - - - -def aligned_zeros(shape, boundary=16, dtype=float, order='C'): - ''' - Is there a better way to allocate aligned memory? - ''' - N = np.prod(shape) - d = np.dtype(dtype) - tmp = np.zeros(N * d.itemsize + boundary, dtype=np.uint8) - address = tmp.__array_interface__['data'][0] - offset = (boundary - address % boundary) % boundary - viewed = tmp[offset:offset + N * d.itemsize].view(dtype=d) - return viewed.reshape(shape, order=order) - -class TestVectorArith(unittest.TestCase): - def test_vector_arith_1(self): - self.run_and_test_udt(VectorArithDriver1(), 16) # aligned for SSE - self.run_and_test_udt(VectorArithDriver1(), 20) # misaligned for SSE - - def test_vector_arith_2(self): - self.run_and_test_udt(VectorArithDriver2(), 16) # aligned for SSE - self.run_and_test_udt(VectorArithDriver2(), 20) # misaligned for SSE - - def run_and_test_udt(self, udt, align): - module = Module.new('mod.test.vectoriarith') - - ldriver = udt(module) - - pm = PassManager.new() - pmb = PassManagerBuilder.new() - pmb.opt = 3 - pmb.vectorize = True - pmb.populate(pm) - pm.run(module) - - print(module.to_native_assembly()) - - exe = CExecutor(module) - - float_p = POINTER(c_float) - - driver = exe.get_ctype_function(ldriver, - None, - float_p, float_p, float_p, - float_p, - c_int) - - # prepare for execution - - n = 4*10 - - Aary = aligned_zeros(n, boundary=align, dtype=np.float32) - Bary = aligned_zeros(n, boundary=align, dtype=np.float32) - Cary = aligned_zeros(n, boundary=align, dtype=np.float32) - Dary = aligned_zeros(n, boundary=align, dtype=np.float32) - - Aary[:] = range(n) - Bary[:] = range(n, 2 * n) - Cary[:] = range(2 * n, 3 * n) - - golden = Aary * Bary + Cary - - getptr = lambda ary: ary.ctypes.data_as(float_p) - - driver(getptr(Aary), getptr(Bary), getptr(Cary), getptr(Dary), n) - - for x, y in zip(golden, Dary): - self.assertEqual(x, y) - - -if __name__ == '__main__': - unittest.main() - - From 4bc9f00d95f00fec58cebf20bcde343ed164b0a7 Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Sat, 10 Nov 2012 18:43:19 -0600 Subject: [PATCH 095/516] Collect the directory to move --- llvm_cbuilder_tests/__init__.py | 0 llvm_cbuilder_tests/test_atomic_add.py | 117 ++++++++++++++++ llvm_cbuilder_tests/test_atomic_cmpxchg.py | 124 ++++++++++++++++ llvm_cbuilder_tests/test_cstr_collide.py | 17 +++ llvm_cbuilder_tests/test_isprime.py | 125 +++++++++++++++++ llvm_cbuilder_tests/test_loopcontrol.py | 135 ++++++++++++++++++ llvm_cbuilder_tests/test_nestedloops.py | 128 +++++++++++++++++ llvm_cbuilder_tests/test_print.py | 68 +++++++++ llvm_cbuilder_tests/test_pthread.py | 92 ++++++++++++ llvm_cbuilder_tests/test_struct.py | 52 +++++++ llvm_cbuilder_tests/test_translate.py | 94 +++++++++++++ llvm_cbuilder_tests/test_vectorarith.py | 156 +++++++++++++++++++++ 12 files changed, 1108 insertions(+) create mode 100644 llvm_cbuilder_tests/__init__.py create mode 100644 llvm_cbuilder_tests/test_atomic_add.py create mode 100644 llvm_cbuilder_tests/test_atomic_cmpxchg.py create mode 100644 llvm_cbuilder_tests/test_cstr_collide.py create mode 100644 llvm_cbuilder_tests/test_isprime.py create mode 100644 llvm_cbuilder_tests/test_loopcontrol.py create mode 100644 llvm_cbuilder_tests/test_nestedloops.py create mode 100644 llvm_cbuilder_tests/test_print.py create mode 100644 llvm_cbuilder_tests/test_pthread.py create mode 100644 llvm_cbuilder_tests/test_struct.py create mode 100644 llvm_cbuilder_tests/test_translate.py create mode 100644 llvm_cbuilder_tests/test_vectorarith.py diff --git a/llvm_cbuilder_tests/__init__.py b/llvm_cbuilder_tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/llvm_cbuilder_tests/test_atomic_add.py b/llvm_cbuilder_tests/test_atomic_add.py new file mode 100644 index 0000000..70faa0c --- /dev/null +++ b/llvm_cbuilder_tests/test_atomic_add.py @@ -0,0 +1,117 @@ +''' +Base on the test_pthread.py and extend to use atomic instructions +''' + +from llvm.core import * +from llvm.passes import * +from llvm.ee import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import unittest, logging +import sys + +# logging.basicConfig(level=logging.DEBUG) + +NUM_OF_THREAD = 4 +REPEAT = 10000 + +def gen_test_worker(mod): + cb = CBuilder.new_function(mod, 'worker', C.void, [C.pointer(C.int)]) + pval = cb.args[0] + one = cb.constant(pval.type.pointee, 1) + + ct = cb.var(C.int, 0) + limit = cb.constant(C.int, REPEAT) + with cb.loop() as loop: + with loop.condition() as setcond: + setcond( ct < limit ) + + with loop.body(): + cb.atomic_add(pval, one, 'acq_rel') + ct += one + + cb.ret() + cb.close() + return cb.function + +def gen_test_pthread(mod): + cb = CBuilder.new_function(mod, 'manager', C.int, [C.int]) + arg = cb.args[0] + + worker_func = cb.get_function_named('worker') + pthread_create = cb.get_function_named('pthread_create') + pthread_join = cb.get_function_named('pthread_join') + + + NULL = cb.constant_null(C.void_p) + cast_to_null = lambda x: x.cast(C.void_p) + + threads = cb.array(C.void_p, NUM_OF_THREAD) + + for tid in range(NUM_OF_THREAD): + pthread_create_args = [threads[tid].reference(), + NULL, + worker_func, + arg.reference()] + pthread_create(*map(cast_to_null, pthread_create_args)) + + worker_func(arg.reference()) + + for tid in range(NUM_OF_THREAD): + pthread_join_args = threads[tid], NULL + pthread_join(*map(cast_to_null, pthread_join_args)) + + + cb.ret(arg) + cb.close() + return cb.function + +class TestAtomicAdd(unittest.TestCase): + @unittest.skipIf(sys.platform == 'win32', "test uses pthreads, not supported on Windows") + def test_atomic_add(self): + mod = Module.new(__name__) + # add pthread functions + + mod.add_function(Type.function(C.int, + [C.void_p, C.void_p, C.void_p, C.void_p]), + 'pthread_create') + + mod.add_function(Type.function(C.int, + [C.void_p, C.void_p]), + 'pthread_join') + + lf_test_worker = gen_test_worker(mod) + lf_test_pthread = gen_test_pthread(mod) + logging.debug(mod) + mod.verify() + + # optimize + fpm = FunctionPassManager.new(mod) + mpm = PassManager.new() + pmb = PassManagerBuilder.new() + pmb.vectorize = True + pmb.opt_level = 3 + pmb.populate(fpm) + pmb.populate(mpm) + + fpm.run(lf_test_worker) + fpm.run(lf_test_pthread) + mpm.run(mod) + logging.debug(mod) + mod.verify() + + # run + exe = CExecutor(mod) + exe.engine.get_pointer_to_function(mod.get_function_named('worker')) + func = exe.get_ctype_function(lf_test_pthread, 'int, int') + + inarg = 1234 + gold = inarg + (NUM_OF_THREAD + 1) * REPEAT + + for _ in range(1000): # run many many times to catch race condition + self.assertEqual(func(inarg), gold, "Unexpected race condition") + + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm_cbuilder_tests/test_atomic_cmpxchg.py b/llvm_cbuilder_tests/test_atomic_cmpxchg.py new file mode 100644 index 0000000..9058e42 --- /dev/null +++ b/llvm_cbuilder_tests/test_atomic_cmpxchg.py @@ -0,0 +1,124 @@ +''' +Base on the test_pthread.py and extend to use atomic instructions +''' + +from llvm.core import * +from llvm.passes import * +from llvm.ee import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import unittest, logging +import sys + +# logging.basicConfig(level=logging.DEBUG) + +NUM_OF_THREAD = 4 +REPEAT = 10000 + +def gen_test_worker(mod): + cb = CBuilder.new_function(mod, 'worker', C.void, [C.pointer(C.int)]) + pval = cb.args[0] + one = cb.constant(pval.type.pointee, 1) + + ct = cb.var(C.int, 0) + limit = cb.constant(C.int, REPEAT) + with cb.loop() as loop: + with loop.condition() as setcond: + setcond( ct < limit ) + + with loop.body(): + oldval = pval.atomic_load('acquire') + updated = oldval + one + castmp = pval.atomic_cmpxchg(oldval, updated, 'release') + + with cb.ifelse( castmp == oldval ) as ifelse: + with ifelse.then(): + ct += one + + cb.ret() + cb.close() + return cb.function + +def gen_test_pthread(mod): + cb = CBuilder.new_function(mod, 'manager', C.int, [C.int]) + arg = cb.args[0] + + worker_func = cb.get_function_named('worker') + pthread_create = cb.get_function_named('pthread_create') + pthread_join = cb.get_function_named('pthread_join') + + + NULL = cb.constant_null(C.void_p) + cast_to_null = lambda x: x.cast(C.void_p) + + threads = cb.array(C.void_p, NUM_OF_THREAD) + + for tid in range(NUM_OF_THREAD): + pthread_create_args = [threads[tid].reference(), + NULL, + worker_func, + arg.reference()] + pthread_create(*map(cast_to_null, pthread_create_args)) + + worker_func(arg.reference()) + + for tid in range(NUM_OF_THREAD): + pthread_join_args = threads[tid], NULL + pthread_join(*map(cast_to_null, pthread_join_args)) + + + cb.ret(arg) + cb.close() + return cb.function + +class TestAtomicCmpXchg(unittest.TestCase): + @unittest.skipIf(sys.platform == 'win32', "test uses pthreads, not supported on Windows") + def test_atomic_cmpxchg(self): + mod = Module.new(__name__) + # add pthread functions + + mod.add_function(Type.function(C.int, + [C.void_p, C.void_p, C.void_p, C.void_p]), + 'pthread_create') + + mod.add_function(Type.function(C.int, + [C.void_p, C.void_p]), + 'pthread_join') + + lf_test_worker = gen_test_worker(mod) + lf_test_pthread = gen_test_pthread(mod) + logging.debug(mod) + mod.verify() + + # optimize + fpm = FunctionPassManager.new(mod) + mpm = PassManager.new() + pmb = PassManagerBuilder.new() + pmb.vectorize = True + pmb.opt_level = 3 + pmb.populate(fpm) + pmb.populate(mpm) + + fpm.run(lf_test_worker) + fpm.run(lf_test_pthread) + mpm.run(mod) + logging.debug(mod) + mod.verify() + + # run + exe = CExecutor(mod) + exe.engine.get_pointer_to_function(mod.get_function_named('worker')) + func = exe.get_ctype_function(lf_test_pthread, 'int, int') + + inarg = 1234 + gold = inarg + (NUM_OF_THREAD + 1) * REPEAT + + for _ in range(1000): # run many many times to catch race condition + res = func(inarg) + self.assertEqual(res, gold, + "Unexpected race condition: res = %d" % res) + + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm_cbuilder_tests/test_cstr_collide.py b/llvm_cbuilder_tests/test_cstr_collide.py new file mode 100644 index 0000000..4a427c6 --- /dev/null +++ b/llvm_cbuilder_tests/test_cstr_collide.py @@ -0,0 +1,17 @@ +from llvm.core import * +from llvm_cbuilder import * +from llvm_cbuilder import shortnames as C + +import unittest + +class TestCstrCollide(unittest.TestCase): + def test_same_string(self): + mod = Module.new(__name__) + cb = CBuilder.new_function(mod, 'test_cstr_collide', C.void, []) + + a = cb.constant_string("hello") + b = cb.constant_string("hello") + self.assertEqual(a.value, b.value) + +if __name__ == '__main__': + unittest.main() diff --git a/llvm_cbuilder_tests/test_isprime.py b/llvm_cbuilder_tests/test_isprime.py new file mode 100644 index 0000000..bcc0b9c --- /dev/null +++ b/llvm_cbuilder_tests/test_isprime.py @@ -0,0 +1,125 @@ +from llvm.core import * +from llvm.passes import * +from llvm.ee import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import unittest, logging + +def is_prime(x): + if x <= 2: + return True + if (x % 2) == 0: + return False + for y in range(2, int(1 + x**0.5)): + if (x % y) == 0: + return False + return True + +def gen_is_prime(mod): + functype = Type.function(C.int, [C.int]) + func = mod.add_function(functype, 'isprime') + + cb = CBuilder(func) + + arg = cb.args[0] + + two = cb.constant(C.int, 2) + true = one = cb.constant(C.int, 1) + false = zero = cb.constant(C.int, 0) + + with cb.ifelse( arg <= two ) as ifelse: + with ifelse.then(): + cb.ret(true) + + with cb.ifelse( (arg % two) == zero ) as ifelse: + with ifelse.then(): + cb.ret(false) + + idx = cb.var(C.int, 3, name='idx') + with cb.loop() as loop: + with loop.condition() as setcond: + setcond( idx < arg ) + + with loop.body(): + with cb.ifelse( (arg % idx) == zero ) as ifelse: + with ifelse.then(): + cb.ret(false) + # increment + idx += two + + cb.ret(true) + cb.close() + return func + + +def gen_is_prime_fast(mod): + functype = Type.function(C.int, [C.int]) + func = mod.add_function(functype, 'isprime_fast') + + cb = CBuilder(func) + + arg = cb.args[0] + + two = cb.constant(C.int, 2) + true = one = cb.constant(C.int, 1) + false = zero = cb.constant(C.int, 0) + + with cb.ifelse( arg <= two ) as ifelse: + with ifelse.then(): + cb.ret(true) + + with cb.ifelse( (arg % two) == zero ) as ifelse: + with ifelse.then(): + cb.ret(false) + + idx = cb.var(C.int, 3, name='idx') + + sqrt = cb.get_intrinsic(INTR_SQRT, [C.float]) + + looplimit = one + sqrt(arg.cast(C.float)).cast(C.int) + + + with cb.loop() as loop: + with loop.condition() as setcond: + setcond( idx < looplimit ) + + with loop.body(): + with cb.ifelse( (arg % idx) == zero ) as ifelse: + with ifelse.then(): + cb.ret(false) + # increment + idx += two + + + cb.ret(true) + cb.close() + return func + +class TestIsPrime(unittest.TestCase): + def test_isprime(self): + mod = Module.new(__name__) + lf_isprime = gen_is_prime(mod) + logging.debug(mod) + mod.verify() + + exe = CExecutor(mod) + func = exe.get_ctype_function(lf_isprime, 'bool, int') + for x in range(2, 1000): + msg = "Failed at x = %d" % x + self.assertEqual(func(x), is_prime(x), msg) + + def test_isprime_fast(self): + mod = Module.new(__name__) + lf_isprime = gen_is_prime_fast(mod) + logging.debug(mod) + mod.verify() + + exe = CExecutor(mod) + func = exe.get_ctype_function(lf_isprime, 'bool, int') + for x in range(2, 1000): + msg = "Failed at x = %d" % x + self.assertEqual(func(x), is_prime(x), msg) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm_cbuilder_tests/test_loopcontrol.py b/llvm_cbuilder_tests/test_loopcontrol.py new file mode 100644 index 0000000..7e252bf --- /dev/null +++ b/llvm_cbuilder_tests/test_loopcontrol.py @@ -0,0 +1,135 @@ +from llvm.core import * +from llvm.passes import * +from llvm.ee import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import unittest, logging + +def loopbreak(d): + z = 0 + for x in range(100): + for y in range(100): + z += x + y + if z > 50: + break + z -= d + return z + +def gen_loopbreak(mod): + functype = Type.function(C.int, [C.int]) + func = mod.add_function(functype, 'loopbreak') + + cb = CBuilder(func) + + d = cb.args[0] + x = cb.var(C.int) + y = cb.var(C.int) + z = cb.var(C.int) + + one = cb.constant(C.int, 1) + zero = cb.constant(C.int, 0) + limit = cb.constant(C.int, 100) + fifty = cb.constant(C.int, 50) + + z.assign(zero) + x.assign(zero) + with cb.loop() as outer: + with outer.condition() as setcond: + setcond( x < limit ) + + with outer.body(): + y.assign(zero) + with cb.loop() as inner: + with inner.condition() as setcond: + setcond( y < limit ) + + with inner.body(): + z += x + y + with cb.ifelse( z > fifty ) as ifelse: + with ifelse.then(): + inner.break_loop() + y += one + z -= d + x += one + + cb.ret(z) + cb.close() + return func + +def loopcontinue(d): + z = 0 + for x in range(100): + for y in range(100): + z += x + y + if z > 50: + continue + z += d + return z + +def gen_loopcontinue(mod): + functype = Type.function(C.int, [C.int]) + func = mod.add_function(functype, 'loopcontinue') + + cb = CBuilder(func) + + d = cb.args[0] + x = cb.var(C.int) + y = cb.var(C.int) + z = cb.var(C.int) + + one = cb.constant(C.int, 1) + zero = cb.constant(C.int, 0) + limit = cb.constant(C.int, 100) + fifty = cb.constant(C.int, 50) + + z.assign(zero) + x.assign(zero) + with cb.loop() as outer: + with outer.condition() as setcond: + setcond( x < limit ) + + with outer.body(): + y.assign(zero) + with cb.loop() as inner: + with inner.condition() as setcond: + setcond( y < limit ) + + with inner.body(): + z += x + y + y += one + with cb.ifelse( z > fifty ) as ifelse: + with ifelse.then(): + inner.continue_loop() + z += d + x += one + + cb.ret(z) + cb.close() + return func + +class TestLoopControl(unittest.TestCase): + def test_loopbreak(self): + mod = Module.new(__name__) + lfunc = gen_loopbreak(mod) + logging.debug(mod) + mod.verify() + + exe = CExecutor(mod) + func = exe.get_ctype_function(lfunc, 'int, int') + for x in range(100): + self.assertEqual(func(x), loopbreak(x)) + + def test_loopcontinue(self): + mod = Module.new(__name__) + lfunc = gen_loopcontinue(mod) + logging.debug(mod) + mod.verify() + + exe = CExecutor(mod) + func = exe.get_ctype_function(lfunc, 'int, int') + for x in range(100): + self.assertEqual(func(x), loopcontinue(x)) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm_cbuilder_tests/test_nestedloops.py b/llvm_cbuilder_tests/test_nestedloops.py new file mode 100644 index 0000000..0876bb2 --- /dev/null +++ b/llvm_cbuilder_tests/test_nestedloops.py @@ -0,0 +1,128 @@ +from llvm.core import * +from llvm.passes import * +from llvm.ee import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import unittest, logging + +def nestedloop1(d): + z = 0 + for x in range(100): + for y in range(100): + z += x * d + int(y / d) + return z + +def gen_nestedloop1(mod): + functype = Type.function(C.int, [C.int]) + func = mod.add_function(functype, 'nestedloop1') + + cb = CBuilder(func) + + d = cb.args[0] + x = cb.var(C.int) + y = cb.var(C.int) + z = cb.var(C.int) + + one = cb.constant(C.int, 1) + zero = cb.constant(C.int, 0) + limit = cb.constant(C.int, 100) + + z.assign(zero) + x.assign(zero) + with cb.loop() as outer: + with outer.condition() as setcond: + setcond( x < limit ) + + with outer.body(): + y.assign(zero) + with cb.loop() as inner: + with inner.condition() as setcond: + setcond( y < limit ) + + with inner.body(): + z += x * d + y / d + y += one + x += one + + cb.ret(z) + cb.close() + return func + + +def nestedloop2(d): + z = 0 + for x in range(1, 100): + for y in range(1, 100): + if x > y: + z += int(x / y) * d + else: + z += int(y / x) * d + return z + +def gen_nestedloop2(mod): + functype = Type.function(C.int, [C.int]) + func = mod.add_function(functype, 'nestedloop2') + + cb = CBuilder(func) + + d = cb.args[0] + x = cb.var(C.int) + y = cb.var(C.int) + z = cb.var(C.int) + + one = cb.constant(C.int, 1) + zero = cb.constant(C.int, 0) + limit = cb.constant(C.int, 100) + + z.assign(zero) + x.assign(one) + with cb.loop() as outer: + with outer.condition() as setcond: + setcond( x < limit ) + + with outer.body(): + y.assign(one) + with cb.loop() as inner: + with inner.condition() as setcond: + setcond( y < limit ) + + with inner.body(): + with cb.ifelse(x > y) as ifelse: + with ifelse.then(): + z += x / y * d + with ifelse.otherwise(): + z += y / x * d + y += one + x += one + + cb.ret(z) + cb.close() + return func + + +class TestNestedLoop(unittest.TestCase): + def test_nestedloop1(self): + mod = Module.new(__name__) + lfunc = gen_nestedloop1(mod) + logging.debug(mod) + mod.verify() + + exe = CExecutor(mod) + func = exe.get_ctype_function(lfunc, 'int, int') + for x in range(1, 100): + self.assertEqual(func(x), int(nestedloop1(x))) + + def test_nestedloop2(self): + mod = Module.new(__name__) + lfunc = gen_nestedloop2(mod) + logging.debug(mod) + mod.verify() + + exe = CExecutor(mod) + func = exe.get_ctype_function(lfunc, 'int, int') + for x in range(1, 100): + self.assertEqual(func(x), int(nestedloop2(x))) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm_cbuilder_tests/test_print.py b/llvm_cbuilder_tests/test_print.py new file mode 100644 index 0000000..510161a --- /dev/null +++ b/llvm_cbuilder_tests/test_print.py @@ -0,0 +1,68 @@ +from llvm.core import * +from llvm.passes import * +from llvm.ee import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import sys, unittest, logging +from subprocess import Popen, PIPE + +def gen_debugprint(mod): + functype = Type.function(C.void, []) + func = mod.add_function(functype, 'debugprint') + + cb = CBuilder(func) + fmt = cb.constant_string("Show %d %.3f %.3e\n") + + an_int = cb.constant(C.int, 123) + a_float = cb.constant(C.double, 1.234) + a_double = cb.constant(C.double, 1e-31) + cb.printf(fmt, an_int, a_float, a_double) + + cb.debug('an_int =', an_int, 'a_float =', a_float, 'a_double =', a_double) + + cb.ret() + cb.close() + return func + +def main_debugprint(): + # generate code + mod = Module.new(__name__) + lfunc = gen_debugprint(mod) + logging.debug(mod) + mod.verify() + # run + exe = CExecutor(mod) + func = exe.get_ctype_function(lfunc, 'void') + func() + +class TestPrint(unittest.TestCase): + def test_debugprint(self): + p = Popen([sys.executable, __file__, "-child"], stdout=PIPE) + p.wait() + + # The encode(utf-8) is for Python 3 compatibility + lines = p.stdout.read().encode('utf-8').splitlines(False) + + # Try to account for variations in the system printf + if lines[0].find('e-031') >= 0: + expect = [ + 'Show 123 1.234 1.000e-031', + 'an_int = 123 a_float = 1.234000e+000 a_double = 1.000000e-031', + ] + else: + expect = [ + 'Show 123 1.234 1.000e-31', + 'an_int = 123 a_float = 1.234000e+00 a_double = 1.000000e-31', + ] + self.assertEqual(expect, lines) + + p.stdout.close() + +if __name__ == '__main__': + try: + if sys.argv[1] == '-child': + main_debugprint() + except IndexError: + unittest.main() + + diff --git a/llvm_cbuilder_tests/test_pthread.py b/llvm_cbuilder_tests/test_pthread.py new file mode 100644 index 0000000..23a2083 --- /dev/null +++ b/llvm_cbuilder_tests/test_pthread.py @@ -0,0 +1,92 @@ +from llvm.core import * +from llvm.passes import * +from llvm.ee import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import unittest, logging +import sys + +# logging.basicConfig(level=logging.DEBUG) + +NUM_OF_THREAD = 4 + +def gen_test_worker(mod): + cb = CBuilder.new_function(mod, 'worker', C.void, [C.pointer(C.int)]) + pval = cb.args[0] + val = pval.load() + one = cb.constant(val.type, 1) + pval.store(val + one) + cb.ret() + cb.close() + +def gen_test_pthread(mod): + cb = CBuilder.new_function(mod, 'manager', C.int, [C.int]) + arg = cb.args[0] + + worker_func = cb.get_function_named('worker') + pthread_create = cb.get_function_named('pthread_create') + pthread_join = cb.get_function_named('pthread_join') + + + NULL = cb.constant_null(C.void_p) + cast_to_null = lambda x: x.cast(C.void_p) + + threads = cb.array(C.void_p, NUM_OF_THREAD) + + for tid in range(NUM_OF_THREAD): + pthread_create_args = [threads[tid].reference(), + NULL, + worker_func, + arg.reference()] + pthread_create(*map(cast_to_null, pthread_create_args)) + + worker_func(arg.reference()) + + for tid in range(NUM_OF_THREAD): + pthread_join_args = threads[tid], NULL + pthread_join(*map(cast_to_null, pthread_join_args)) + + cb.ret(arg) + cb.close() + return cb.function + +class TestPThread(unittest.TestCase): + @unittest.skipIf(sys.platform == 'win32', "pthreads not supported on Windows") + def test_pthread(self): + mod = Module.new(__name__) + # add pthread functions + + mod.add_function(Type.function(C.int, + [C.void_p, C.void_p, C.void_p, C.void_p]), + 'pthread_create') + + mod.add_function(Type.function(C.int, + [C.void_p, C.void_p]), + 'pthread_join') + + gen_test_worker(mod) + lf_test_pthread = gen_test_pthread(mod) + logging.debug(mod) + mod.verify() + + exe = CExecutor(mod) + exe.engine.get_pointer_to_function(mod.get_function_named('worker')) + func = exe.get_ctype_function(lf_test_pthread, 'int, int') + + inarg = 1234 + gold = inarg + NUM_OF_THREAD + 1 + self.assertLessEqual(func(inarg), gold) + # Cannot determine the exact return value due to untamed race condition + + count_race = 0 + for _ in range(2**12): + if func(inarg) != gold: + count_race += 1 + + if count_race > 0: + logging.info("Race condition occured %d times.", count_race) + logging.info("Race condition is expected.") + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm_cbuilder_tests/test_struct.py b/llvm_cbuilder_tests/test_struct.py new file mode 100644 index 0000000..35048e6 --- /dev/null +++ b/llvm_cbuilder_tests/test_struct.py @@ -0,0 +1,52 @@ +from llvm.core import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import unittest, ctypes + +class Vector2D(CStruct): + _fields_ = [ + ('x', C.float), + ('y', C.float), + ] + +class Vector2DCtype(ctypes.Structure): + _fields_ = [ + ('x', ctypes.c_float), + ('y', ctypes.c_float), + ] + +def gen_vector2d_dist(mod): + functype = Type.function(C.float, [C.pointer(Vector2D.llvm_type())]) + func = mod.add_function(functype, 'vector2d_dist') + + cb = CBuilder(func) + vec = cb.var(Vector2D, cb.args[0].load()) + dist = vec.x * vec.x + vec.y * vec.y + + cb.ret(dist) + cb.close() + return func + + +class TestStruct(unittest.TestCase): + def test_vector2d_dist(self): + # prepare module + mod = Module.new('mod') + lfunc = gen_vector2d_dist(mod) + mod.verify() + # run + exe = CExecutor(mod) + func = exe.get_ctype_function(lfunc, ctypes.c_float, ctypes.POINTER(Vector2DCtype)) + + from random import random + pydist = lambda x, y: x * x + y * y + for _ in range(100): + x, y = random(), random() + vec = Vector2DCtype(x=x, y=y) + ans = func(ctypes.pointer(vec)) + gold = pydist(x, y) + + self.assertLess(abs(ans-gold)/gold, 1e-6) + +if __name__ == '__main__': + unittest.main() diff --git a/llvm_cbuilder_tests/test_translate.py b/llvm_cbuilder_tests/test_translate.py new file mode 100644 index 0000000..b9e39ea --- /dev/null +++ b/llvm_cbuilder_tests/test_translate.py @@ -0,0 +1,94 @@ + +from llvm.core import Module +from llvm_cbuilder import * +from llvm_cbuilder.translator import translate +import llvm_cbuilder.shortnames as C +import unittest, logging + +#logging.basicConfig(level=logging.DEBUG) + +class FooIf(CDefinition): + _name_ = 'foo_if' + _retty_ = C.int + _argtys_ = [('x', C.int), + ('y', C.int),] + + def body(self, x, y): + @translate + def _(): + if x > y: + return x - y + else: + return y - x + + +class FooWhile(CDefinition): + _name_ = 'foo_while' + _retty_ = C.int + _argtys_ = [('x', C.int)] + + def body(self, x): + y = self.var_copy(x) + + @translate + def _(): + while x > 0: + x -= 1 + y += x + return y + +class FooForRange(CDefinition): + _name_ = 'foo_for_range' + _retty_ = C.int + _argtys_ = [('x', C.int)] + + def body(self, x): + y = self.var(x.type, 0) + + @translate + def _(): + for i in range(x + 1): + y += i + return y + + +class TestTranslate(unittest.TestCase): + def test_if(self): + mod = Module.new(__name__) + lfoo = FooIf()(mod) + + print(mod) + mod.verify() + + exe = CExecutor(mod) + foo = exe.get_ctype_function(lfoo, 'int, int') + self.assertEqual(foo(10, 20), 20 - 10) + self.assertEqual(foo(23, 17), 23 - 17) + + def test_whileloop(self): + mod = Module.new(__name__) + lfoo = FooWhile()(mod) + + print(mod) + mod.verify() + + exe = CExecutor(mod) + foo = exe.get_ctype_function(lfoo, 'int') + self.assertEqual(foo(10), sum(range(10+1))) + self.assertEqual(foo(1324), sum(range(1324+1))) + + def test_forloop(self): + mod = Module.new(__name__) + lfoo = FooForRange()(mod) + + print(mod) + mod.verify() + + exe = CExecutor(mod) + foo = exe.get_ctype_function(lfoo, 'int') + self.assertEqual(foo(10), sum(range(10+1))) + self.assertEqual(foo(1324), sum(range(1324+1))) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm_cbuilder_tests/test_vectorarith.py b/llvm_cbuilder_tests/test_vectorarith.py new file mode 100644 index 0000000..dad9262 --- /dev/null +++ b/llvm_cbuilder_tests/test_vectorarith.py @@ -0,0 +1,156 @@ +from llvm_cbuilder import * +from llvm_cbuilder import shortnames as C +from llvm_cbuilder.translator import translate +from ctypes import * +from llvm.core import * +from llvm.passes import * +import numpy as np +import unittest +import logging +floatv4 = C.vector(C.float, 4) + +class VectorArith(CDefinition): + _name_ = 'vector_arith' + _argtys_ = [('a', floatv4), + ('b', floatv4), + ('c', floatv4),] + _retty_ = floatv4 + + def body(self, a, b, c): + ''' + Arguments + --------- + a, b, c -- must be vectors + ''' + @translate + def _(): # write like python in here + return a * b + c + +class VectorArithDriver1(CDefinition): + _name_ = 'vector_arith_driver_1' + _argtys_ = [('A', C.pointer(C.float)), + ('B', C.pointer(C.float)), + ('C', C.pointer(C.float)), + ('D', C.pointer(C.float)), + ('n', C.int),] + + def body(self, Aary, Bary, Cary, Dary, n): + ''' + This version uses vector load to fetch array elements as vectors. + + ''' + vecarith = self.depends(VectorArith()) + elem_per_vec = self.constant(C.int, floatv4.count) + with self.for_range(0, n, elem_per_vec) as (loop, i): + # Aary[i:] offset the array at i + a = Aary[i:].vector_load(4, align=1) # unaligned vector load + b = Bary[i:].vector_load(4, align=1) + c = Cary[i:].vector_load(4, align=1) + r = vecarith(a, b, c) + Dary[i:].vector_store(r, align=1) + # self.debug(r[0], r[1], r[2], r[3]) + self.ret() + + +class VectorArithDriver2(CDefinition): + _name_ = 'vector_arith_driver_2' + _argtys_ = [('A', C.pointer(C.float)), + ('B', C.pointer(C.float)), + ('C', C.pointer(C.float)), + ('D', C.pointer(C.float)), + ('n', C.int),] + + def body(self, Aary, Bary, Cary, Dary, n): + ''' + This version loads element of vector individually. + This style generates scalar ld/st instead of vector ld/st. + ''' + vecarith = self.depends(VectorArith()) + a = self.var(floatv4) + b = self.var(floatv4) + c = self.var(floatv4) + elem_per_vec = self.constant(C.int, floatv4.count) + with self.for_range(0, n, elem_per_vec) as (outer, i): + with self.for_range(elem_per_vec) as (inner, j): + a[j] = Aary[i + j] + b[j] = Bary[i + j] + c[j] = Cary[i + j] + r = vecarith(a, b, c) + Dary[i:].vector_store(r, align=1) + # self.debug(r[0], r[1], r[2], r[3]) + self.ret() + + + +def aligned_zeros(shape, boundary=16, dtype=float, order='C'): + ''' + Is there a better way to allocate aligned memory? + ''' + N = np.prod(shape) + d = np.dtype(dtype) + tmp = np.zeros(N * d.itemsize + boundary, dtype=np.uint8) + address = tmp.__array_interface__['data'][0] + offset = (boundary - address % boundary) % boundary + viewed = tmp[offset:offset + N * d.itemsize].view(dtype=d) + return viewed.reshape(shape, order=order) + +class TestVectorArith(unittest.TestCase): + def test_vector_arith_1(self): + self.run_and_test_udt(VectorArithDriver1(), 16) # aligned for SSE + self.run_and_test_udt(VectorArithDriver1(), 20) # misaligned for SSE + + def test_vector_arith_2(self): + self.run_and_test_udt(VectorArithDriver2(), 16) # aligned for SSE + self.run_and_test_udt(VectorArithDriver2(), 20) # misaligned for SSE + + def run_and_test_udt(self, udt, align): + module = Module.new('mod.test.vectoriarith') + + ldriver = udt(module) + + pm = PassManager.new() + pmb = PassManagerBuilder.new() + pmb.opt = 3 + pmb.vectorize = True + pmb.populate(pm) + pm.run(module) + + print(module.to_native_assembly()) + + exe = CExecutor(module) + + float_p = POINTER(c_float) + + driver = exe.get_ctype_function(ldriver, + None, + float_p, float_p, float_p, + float_p, + c_int) + + # prepare for execution + + n = 4*10 + + Aary = aligned_zeros(n, boundary=align, dtype=np.float32) + Bary = aligned_zeros(n, boundary=align, dtype=np.float32) + Cary = aligned_zeros(n, boundary=align, dtype=np.float32) + Dary = aligned_zeros(n, boundary=align, dtype=np.float32) + + Aary[:] = range(n) + Bary[:] = range(n, 2 * n) + Cary[:] = range(2 * n, 3 * n) + + golden = Aary * Bary + Cary + + getptr = lambda ary: ary.ctypes.data_as(float_p) + + driver(getptr(Aary), getptr(Bary), getptr(Cary), getptr(Dary), n) + + for x, y in zip(golden, Dary): + self.assertEqual(x, y) + + +if __name__ == '__main__': + unittest.main() + + From a52db30af81c6df98927f35f6d8a8010638c8341 Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Sat, 10 Nov 2012 18:56:02 -0600 Subject: [PATCH 096/516] Add llvm_cbuilder tests --- README.rst | 4 +++- docs/source/index.rst | 2 ++ {llvm_cbuilder_tests => llvm_cbuilder/tests}/__init__.py | 0 .../tests}/test_atomic_add.py | 0 .../tests}/test_atomic_cmpxchg.py | 0 .../tests}/test_cstr_collide.py | 0 {llvm_cbuilder_tests => llvm_cbuilder/tests}/test_isprime.py | 0 .../tests}/test_loopcontrol.py | 0 .../tests}/test_nestedloops.py | 0 {llvm_cbuilder_tests => llvm_cbuilder/tests}/test_print.py | 0 {llvm_cbuilder_tests => llvm_cbuilder/tests}/test_pthread.py | 0 {llvm_cbuilder_tests => llvm_cbuilder/tests}/test_struct.py | 0 .../tests}/test_translate.py | 0 .../tests}/test_vectorarith.py | 0 14 files changed, 5 insertions(+), 1 deletion(-) rename {llvm_cbuilder_tests => llvm_cbuilder/tests}/__init__.py (100%) rename {llvm_cbuilder_tests => llvm_cbuilder/tests}/test_atomic_add.py (100%) rename {llvm_cbuilder_tests => llvm_cbuilder/tests}/test_atomic_cmpxchg.py (100%) rename {llvm_cbuilder_tests => llvm_cbuilder/tests}/test_cstr_collide.py (100%) rename {llvm_cbuilder_tests => llvm_cbuilder/tests}/test_isprime.py (100%) rename {llvm_cbuilder_tests => llvm_cbuilder/tests}/test_loopcontrol.py (100%) rename {llvm_cbuilder_tests => llvm_cbuilder/tests}/test_nestedloops.py (100%) rename {llvm_cbuilder_tests => llvm_cbuilder/tests}/test_print.py (100%) rename {llvm_cbuilder_tests => llvm_cbuilder/tests}/test_pthread.py (100%) rename {llvm_cbuilder_tests => llvm_cbuilder/tests}/test_struct.py (100%) rename {llvm_cbuilder_tests => llvm_cbuilder/tests}/test_translate.py (100%) rename {llvm_cbuilder_tests => llvm_cbuilder/tests}/test_vectorarith.py (100%) diff --git a/README.rst b/README.rst index 4bda151..3f9d23d 100644 --- a/README.rst +++ b/README.rst @@ -10,7 +10,9 @@ http://www.llvmpy.org Versions -------- -This package has only been tested with LLVM 3.1, and Python 2.7 and Python 3.2. +This package has been tested with LLVM 3.1, Python 2.7 and Python 3.2. +Other Python versions should work, but some modifications may be +needed for the upcoming LLVM 3.2 Quickstart ---------- diff --git a/docs/source/index.rst b/docs/source/index.rst index fbca2ec..f8b8a31 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -13,6 +13,8 @@ Contents: :maxdepth: 2 doc/userguide.rst + doc/llvm_cbuilder.rst + doc/llpython/index.rst doc/examples.rst diff --git a/llvm_cbuilder_tests/__init__.py b/llvm_cbuilder/tests/__init__.py similarity index 100% rename from llvm_cbuilder_tests/__init__.py rename to llvm_cbuilder/tests/__init__.py diff --git a/llvm_cbuilder_tests/test_atomic_add.py b/llvm_cbuilder/tests/test_atomic_add.py similarity index 100% rename from llvm_cbuilder_tests/test_atomic_add.py rename to llvm_cbuilder/tests/test_atomic_add.py diff --git a/llvm_cbuilder_tests/test_atomic_cmpxchg.py b/llvm_cbuilder/tests/test_atomic_cmpxchg.py similarity index 100% rename from llvm_cbuilder_tests/test_atomic_cmpxchg.py rename to llvm_cbuilder/tests/test_atomic_cmpxchg.py diff --git a/llvm_cbuilder_tests/test_cstr_collide.py b/llvm_cbuilder/tests/test_cstr_collide.py similarity index 100% rename from llvm_cbuilder_tests/test_cstr_collide.py rename to llvm_cbuilder/tests/test_cstr_collide.py diff --git a/llvm_cbuilder_tests/test_isprime.py b/llvm_cbuilder/tests/test_isprime.py similarity index 100% rename from llvm_cbuilder_tests/test_isprime.py rename to llvm_cbuilder/tests/test_isprime.py diff --git a/llvm_cbuilder_tests/test_loopcontrol.py b/llvm_cbuilder/tests/test_loopcontrol.py similarity index 100% rename from llvm_cbuilder_tests/test_loopcontrol.py rename to llvm_cbuilder/tests/test_loopcontrol.py diff --git a/llvm_cbuilder_tests/test_nestedloops.py b/llvm_cbuilder/tests/test_nestedloops.py similarity index 100% rename from llvm_cbuilder_tests/test_nestedloops.py rename to llvm_cbuilder/tests/test_nestedloops.py diff --git a/llvm_cbuilder_tests/test_print.py b/llvm_cbuilder/tests/test_print.py similarity index 100% rename from llvm_cbuilder_tests/test_print.py rename to llvm_cbuilder/tests/test_print.py diff --git a/llvm_cbuilder_tests/test_pthread.py b/llvm_cbuilder/tests/test_pthread.py similarity index 100% rename from llvm_cbuilder_tests/test_pthread.py rename to llvm_cbuilder/tests/test_pthread.py diff --git a/llvm_cbuilder_tests/test_struct.py b/llvm_cbuilder/tests/test_struct.py similarity index 100% rename from llvm_cbuilder_tests/test_struct.py rename to llvm_cbuilder/tests/test_struct.py diff --git a/llvm_cbuilder_tests/test_translate.py b/llvm_cbuilder/tests/test_translate.py similarity index 100% rename from llvm_cbuilder_tests/test_translate.py rename to llvm_cbuilder/tests/test_translate.py diff --git a/llvm_cbuilder_tests/test_vectorarith.py b/llvm_cbuilder/tests/test_vectorarith.py similarity index 100% rename from llvm_cbuilder_tests/test_vectorarith.py rename to llvm_cbuilder/tests/test_vectorarith.py From 994c1432a6015faad08d2a15e843354a73fdfa52 Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Sat, 10 Nov 2012 18:56:24 -0600 Subject: [PATCH 097/516] Add documentation for llvm_cbuilder --- docs/source/doc/llvm_cbuilder.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 docs/source/doc/llvm_cbuilder.rst diff --git a/docs/source/doc/llvm_cbuilder.rst b/docs/source/doc/llvm_cbuilder.rst new file mode 100644 index 0000000..990bfb0 --- /dev/null +++ b/docs/source/doc/llvm_cbuilder.rst @@ -0,0 +1,12 @@ +llvm_cbuilder +========= + +llvm_cbuilder is a set of Python-contexts you can use to write C-like +constructs in Python which generates llvmpy code directly. + +Similar to llpython it allows you to build llvm IR without using the +llvmpy interface directly. + +Look in the llvm_cbuilder tests directory for examples of use. + + From a2c5e861c44693b46c1b5b66ecede3c5ef2f23bb Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Sat, 10 Nov 2012 19:01:32 -0600 Subject: [PATCH 098/516] Change author and email and version --- llvm/__init__.py | 2 +- setup.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/llvm/__init__.py b/llvm/__init__.py index 15720f3..1145d74 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -2,7 +2,7 @@ Common classes related to LLVM. """ -__version__ = '0.8.4' +__version__ = '0.9' from weakref import WeakValueDictionary diff --git a/setup.py b/setup.py index 88281dc..8249671 100644 --- a/setup.py +++ b/setup.py @@ -126,8 +126,8 @@ kwds['long_description'] = open('README.rst').read() setup( name = 'llvmpy', description = 'Python bindings for LLVM', - author = 'Mahadevan R', - author_email = 'mdevan@mdevan.org', + author = 'Continuum Analytics, Inc.', + author_email = 'llvmpy@continuum.io', url = 'http://www.llvmpy.org/', packages = ['llvm', 'llvm_cbuilder', 'llpython'], py_modules = ['llvm.core'], From f6a974a76778305fa076c53d97231eba53ca1a95 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Sat, 10 Nov 2012 19:39:23 -0600 Subject: [PATCH 099/516] REL: master is now 0.9.1 --- llvm/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/__init__.py b/llvm/__init__.py index 1145d74..c800500 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -2,7 +2,7 @@ Common classes related to LLVM. """ -__version__ = '0.9' +__version__ = '0.9.1' from weakref import WeakValueDictionary From 469349be075218630bdddba72b4d2bf2239463a7 Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Sun, 11 Nov 2012 01:37:20 -0600 Subject: [PATCH 100/516] Fix author. --- docs/source/conf.py | 4 ++-- docs/source/doc/getting_started.rst | 2 +- setup.py | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 758adf6..5c5c38d 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -48,9 +48,9 @@ copyright = u'2012, Mahadevan R (2008-2010), Continuum Analytics (2012)' # built documents. # # The short X.Y version. -version = '0.8' +version = '0.9' # The full version, including alpha/beta/rc tags. -release = '0.8.2' +release = '0.9.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/source/doc/getting_started.rst b/docs/source/doc/getting_started.rst index 36a408a..f13c616 100644 --- a/docs/source/doc/getting_started.rst +++ b/docs/source/doc/getting_started.rst @@ -38,7 +38,7 @@ supported, for a variety of reasons. Versions -------- -llvmpy 0.8.2 requires version 3.1 of LLVM. It may not work with +llvmpy 0.9 requires version 3.1 of LLVM. It may not work with previous versions. llvmpy has been built and tested with Python 2.7 and 3.2. It should work with diff --git a/setup.py b/setup.py index 8249671..996c1cb 100644 --- a/setup.py +++ b/setup.py @@ -126,8 +126,9 @@ kwds['long_description'] = open('README.rst').read() setup( name = 'llvmpy', description = 'Python bindings for LLVM', - author = 'Continuum Analytics, Inc.', - author_email = 'llvmpy@continuum.io', + author = 'R Mahadevan' + maintainer = 'Continuum Analytics, Inc.', + maintainer_email = 'llvmpy@continuum.io', url = 'http://www.llvmpy.org/', packages = ['llvm', 'llvm_cbuilder', 'llpython'], py_modules = ['llvm.core'], From 0691800c84064a820adbc927f639ed5b2a86e0bc Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Sun, 11 Nov 2012 01:39:58 -0600 Subject: [PATCH 101/516] Add comma --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 996c1cb..1fba3db 100644 --- a/setup.py +++ b/setup.py @@ -126,7 +126,7 @@ kwds['long_description'] = open('README.rst').read() setup( name = 'llvmpy', description = 'Python bindings for LLVM', - author = 'R Mahadevan' + author = 'R Mahadevan', maintainer = 'Continuum Analytics, Inc.', maintainer_email = 'llvmpy@continuum.io', url = 'http://www.llvmpy.org/', From 6f234dbf2c96c6ea5ba792f643b754689d086dda Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Sun, 11 Nov 2012 01:42:21 -0600 Subject: [PATCH 102/516] Revert to 0.9 --- llvm/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/__init__.py b/llvm/__init__.py index c800500..1145d74 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -2,7 +2,7 @@ Common classes related to LLVM. """ -__version__ = '0.9.1' +__version__ = '0.9' from weakref import WeakValueDictionary From 7adecd8f5dc3861bd1c6f8b9d412b866fe8473db Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Sun, 11 Nov 2012 01:43:47 -0600 Subject: [PATCH 103/516] master is now 0.9.1 --- llvm/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/__init__.py b/llvm/__init__.py index 1145d74..c800500 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -2,7 +2,7 @@ Common classes related to LLVM. """ -__version__ = '0.9' +__version__ = '0.9.1' from weakref import WeakValueDictionary From 52d7b8b6f5857fa994d1bea61a65a0775c71f421 Mon Sep 17 00:00:00 2001 From: Maggie Mari Date: Fri, 24 Aug 2012 16:02:38 -0500 Subject: [PATCH 104/516] Adding reference pages to toctree. --- docs/source/doc/core.rst | 9 +++++++++ docs/source/doc/llvmcore.rst | 9 +++++++++ docs/source/doc/llvmee.rst | 9 +++++++++ docs/source/doc/llvmpasses.rst | 9 +++++++++ docs/source/index.rst | 3 +++ 5 files changed, 39 insertions(+) create mode 100644 docs/source/doc/core.rst create mode 100644 docs/source/doc/llvmcore.rst create mode 100644 docs/source/doc/llvmee.rst create mode 100644 docs/source/doc/llvmpasses.rst diff --git a/docs/source/doc/core.rst b/docs/source/doc/core.rst new file mode 100644 index 0000000..a3b94b6 --- /dev/null +++ b/docs/source/doc/core.rst @@ -0,0 +1,9 @@ +******************************** +llvm.core +******************************** + +.. toctree:: + :titlesonly: + :glob: + + llvm.core.* \ No newline at end of file diff --git a/docs/source/doc/llvmcore.rst b/docs/source/doc/llvmcore.rst new file mode 100644 index 0000000..a3b94b6 --- /dev/null +++ b/docs/source/doc/llvmcore.rst @@ -0,0 +1,9 @@ +******************************** +llvm.core +******************************** + +.. toctree:: + :titlesonly: + :glob: + + llvm.core.* \ No newline at end of file diff --git a/docs/source/doc/llvmee.rst b/docs/source/doc/llvmee.rst new file mode 100644 index 0000000..2145502 --- /dev/null +++ b/docs/source/doc/llvmee.rst @@ -0,0 +1,9 @@ +******************************** +llvm.ee +******************************** + +.. toctree:: + :titlesonly: + :glob: + + llvm.ee.* \ No newline at end of file diff --git a/docs/source/doc/llvmpasses.rst b/docs/source/doc/llvmpasses.rst new file mode 100644 index 0000000..0931467 --- /dev/null +++ b/docs/source/doc/llvmpasses.rst @@ -0,0 +1,9 @@ +******************************** +llvm.passes +******************************** + +.. toctree:: + :titlesonly: + :glob: + + llvm.passes.* \ No newline at end of file diff --git a/docs/source/index.rst b/docs/source/index.rst index f8b8a31..9f86b32 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -16,6 +16,9 @@ Contents: doc/llvm_cbuilder.rst doc/llpython/index.rst doc/examples.rst + doc/llvmcore.rst + doc/llvmee.rst + doc/llvmpasses.rst Indices and tables From 425e382368a1aef491a7ea192b800058460a22e2 Mon Sep 17 00:00:00 2001 From: Maggie Mari Date: Mon, 12 Nov 2012 10:51:30 -0600 Subject: [PATCH 105/516] Fixed broken link in llvmpy docs. --- docs/source/doc/getting_started.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/doc/getting_started.rst b/docs/source/doc/getting_started.rst index f13c616..f9b9c56 100644 --- a/docs/source/doc/getting_started.rst +++ b/docs/source/doc/getting_started.rst @@ -26,7 +26,7 @@ Both LLVM and llvmpy are distributed under (different) permissive open source licenses. llvmpy uses the `new BSD license `_. More information is available -`here `_. +`here `_. Platforms --------- From d491d91dd27849eac3bd070f2069fe25fa98e398 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 29 Nov 2012 12:36:54 -0600 Subject: [PATCH 106/516] Add TBAA Builder --- llvm/tbaa.py | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ test/tbaa.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 llvm/tbaa.py create mode 100644 test/tbaa.py diff --git a/llvm/tbaa.py b/llvm/tbaa.py new file mode 100644 index 0000000..d8e0074 --- /dev/null +++ b/llvm/tbaa.py @@ -0,0 +1,51 @@ +from llvm.core import * + +class TBAABuilder(object): + '''Simplify creation of TBAA metadata. + + Each TBAABuidler object operates on a module. + User can create multiple TBAABuilder on a module + ''' + + def __init__(self, module, rootid): + ''' + module --- the module to use. + root --- string name to identify the TBAA root. + ''' + self.__module = module + self.__rootid = rootid + self.__rootmd = self.__new_md(rootid) + + @classmethod + def new(cls, module, rootid): + return cls(module, rootid) + + def get_node(self, name, parent=None, const=False): + '''Returns a MetaData object representing a TBAA node. + + Use loadstore_instruction.set_metadata('tbaa', node) to + bind a type to a memory. + ''' + parent = parent or self.root + const = Constant.int(Type.int(), int(bool(const))) + return self.__new_md(name, parent, const) + + @property + def module(self): + return self.__module + + @property + def root(self): + return self.__rootmd + + @property + def root_name(self): + return self.__rootid + + def __new_md(self, *args): + contents = list(args) + for i, v in enumerate(contents): + if isinstance(v, str): + contents[i] = MetaDataString.get(self.module, v) + return MetaData.get(self.module, contents) + diff --git a/test/tbaa.py b/test/tbaa.py new file mode 100644 index 0000000..d775a53 --- /dev/null +++ b/test/tbaa.py @@ -0,0 +1,34 @@ +from llvm.core import * +from llvm.tbaa import * +import unittest + +class TestTBAABuilder(unittest.TestCase): + def test_tbaa_builder(self): + mod = Module.new('test_tbaa_builder') + fty = Type.function(Type.void(), [Type.pointer(Type.float())]) + foo = mod.add_function(fty, 'foo') + bb = foo.append_basic_block('entry') + bldr = Builder.new(bb) + + tbaa = TBAABuilder.new(mod, "tbaa.root") + float = tbaa.get_node('float', const=False) + const_float = tbaa.get_node('const float', float, const=True) + + + tbaa = TBAABuilder.new(mod, "tbaa.root") + old_const_float = const_float + del const_float + + const_float = tbaa.get_node('const float', float, const=True) + + self.assertIs(old_const_float, const_float) + + ptr = bldr.load(foo.args[0]) + ptr.set_metadata('tbaa', const_float) + + + bldr.ret_void() + print mod + +if __name__ == '__main__': + unittest.main() From f9376bf2d0d8c969eed58cec68b7b782b2642827 Mon Sep 17 00:00:00 2001 From: John Szakmeister Date: Fri, 30 Nov 2012 03:29:40 -0500 Subject: [PATCH 107/516] Fix an error in the full listing for the kaleidoscope lexer. --- docs/source/doc/kaleidoscope/PythonLangImpl2.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl2.rst b/docs/source/doc/kaleidoscope/PythonLangImpl2.rst index 8c915db..d5d6efc 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl2.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl2.rst @@ -811,7 +811,7 @@ Lexer yield CharacterToken(string[0]) string = string[1:] - yield EOFToken() + yield EOFToken() From 7c7c198953b851711a99928303acd5165f2f6f30 Mon Sep 17 00:00:00 2001 From: John Szakmeister Date: Fri, 30 Nov 2012 04:01:04 -0500 Subject: [PATCH 108/516] Mark a block of code as text, and remove the python-isms. The kaleidoscope language being implemented looks similar to Python, but is not the same. --- docs/source/doc/kaleidoscope/PythonLangImpl1.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl1.rst b/docs/source/doc/kaleidoscope/PythonLangImpl1.rst index 7b1c3a6..90943c1 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl1.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl1.rst @@ -115,13 +115,13 @@ following simple example computes `Fibonacci numbers `_: -.. code-block:: python +.. code-block:: text # Compute the x'th fibonacci number. - def fib(x): - if x < 3: + def fib(x) + if x < 3 return 1 - else: + else return fib(x-1)+fib(x-2) # This expression will compute the 40th number. From 78f81fec73f69ec14cf894ebdb9c32b2b5aa2631 Mon Sep 17 00:00:00 2001 From: John Szakmeister Date: Fri, 30 Nov 2012 04:04:14 -0500 Subject: [PATCH 109/516] Fix the id matching in the kaleidoscope tutorial. --- docs/source/doc/kaleidoscope/PythonLangImpl1.rst | 2 +- docs/source/doc/kaleidoscope/PythonLangImpl2.rst | 2 +- docs/source/doc/kaleidoscope/PythonLangImpl6.rst | 2 +- docs/source/doc/kaleidoscope/PythonLangImpl7.rst | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl1.rst b/docs/source/doc/kaleidoscope/PythonLangImpl1.rst index 90943c1..00b16fb 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl1.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl1.rst @@ -226,7 +226,7 @@ the line. # Regular expressions that tokens and comments of our language. REGEX_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') - REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]\ *') + REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') REGEX_COMMENT = re.compile('#.*') diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl2.rst b/docs/source/doc/kaleidoscope/PythonLangImpl2.rst index d5d6efc..a375512 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl2.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl2.rst @@ -772,7 +772,7 @@ Lexer # Regular expressions that tokens and comments of our language. REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') - REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9] *') + REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') REGEX_COMMENT = re.compile('#.*') def Tokenize(string): diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl6.rst b/docs/source/doc/kaleidoscope/PythonLangImpl6.rst index 2e98cef..8ff31d4 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl6.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl6.rst @@ -847,7 +847,7 @@ Lexer # Regular expressions that tokens and comments of our language. REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') - REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9] *') + REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') REGEX_COMMENT = re.compile('#.*') def Tokenize(string): diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl7.rst b/docs/source/doc/kaleidoscope/PythonLangImpl7.rst index d3dfb74..629608c 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl7.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl7.rst @@ -1000,7 +1000,7 @@ Lexer # Regular expressions that tokens and comments of our language. REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') - REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9] *') + REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9] *') REGEX_COMMENT = re.compile('#.*') def Tokenize(string): From b3a04c4a34213e29b27245c91ab2998a4bed407d Mon Sep 17 00:00:00 2001 From: John Szakmeister Date: Fri, 30 Nov 2012 04:45:30 -0500 Subject: [PATCH 110/516] Move the closing curly branch to line up with the rest of the code. --- docs/source/doc/kaleidoscope/PythonLangImpl3.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl3.rst b/docs/source/doc/kaleidoscope/PythonLangImpl3.rst index 5719bb2..15ec212 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl3.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl3.rst @@ -1058,7 +1058,7 @@ Main driver code. '+': 20, '-': 20, '*': 40 - } + } # Run the main "interpreter loop". while True: From 03e54f2c123a9618bdd4b9dc89478f047b952562 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 4 Dec 2012 13:50:16 -0600 Subject: [PATCH 111/516] Expose preserve flag for Module.link_in --- llvm/core.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index b264b50..bfbab1c 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -450,7 +450,7 @@ class Module(llvm.Ownable, llvm.Cacheable): llvm::Module::AnyPointerSize.""" return _core.LLVMModuleGetPointerSize(self.ptr) - def link_in(self, other): + def link_in(self, other, preserve=False): """Link the `other' module into this one. The `other' module is linked into this one such that types, @@ -463,12 +463,12 @@ class Module(llvm.Ownable, llvm.Cacheable): Linker class. """ check_is_module(other) - other.forget() # remove it from object cache - ret = _core.LLVMLinkModules(self.ptr, other.ptr) - if isinstance(ret, str): - raise llvm.LLVMException(ret) - # Do not try to destroy the other module's llvm::Module*. - other._own(llvm.DummyOwner()) + if not preserve: + other.forget() # remove it from object cache + _core.LLVMLinkModules(self.ptr, other.ptr, int(bool(preserve))) + if not preserve: + # Do not try to destroy the other module's llvm::Module*. + other._own(llvm.DummyOwner()) def get_type_named(self, name): """Return a Type object with the given name.""" From 5c5f3015f729c339f7097784caae9cba0f7c2033 Mon Sep 17 00:00:00 2001 From: Alberto Valverde Date: Fri, 14 Dec 2012 23:54:49 +0100 Subject: [PATCH 112/516] exposed LLVMInstructionEraseFromParent --- llvm/_core.cpp | 2 ++ llvm/core.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 1b7ec09..75b50ed 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -761,6 +761,7 @@ _wrap_obj2obj(LLVMInstGetOpcode, LLVMValueRef, int) _wrap_obj2str(LLVMInstGetOpcodeName, LLVMValueRef) _wrap_objstrobj2none(LLVMInstSetMetaData, LLVMValueRef, LLVMValueRef) +_wrap_obj2none(LLVMInstructionEraseFromParent, LLVMValueRef) /*===-- Call Sites (Call or Invoke) --------------------------------------===*/ @@ -1857,6 +1858,7 @@ static PyMethodDef core_methods[] = { _method( LLVMInstGetOpcodeName ) _method( LLVMInstSetMetaData ) + _method( LLVMInstructionEraseFromParent ) /* Call Sites (Call or Invoke) */ _method( LLVMSetInstructionCallConv ) diff --git a/llvm/core.py b/llvm/core.py index bfbab1c..6a7cc1d 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -1654,6 +1654,8 @@ class Instruction(User): def opcode_name(self): return _core.LLVMInstGetOpcodeName(self.ptr) + def erase_from_parent(self): + return _core.LLVMInstructionEraseFromParent(self.ptr) class CallOrInvokeInstruction(Instruction): From 436a12db03f1bbd196fd70383202b4d05fb135dc Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 13 Dec 2012 12:03:28 -0600 Subject: [PATCH 113/516] Add Stephen's llvm-cbuilder examples. --- README_LLVM_CBUILDER.md | 144 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 README_LLVM_CBUILDER.md diff --git a/README_LLVM_CBUILDER.md b/README_LLVM_CBUILDER.md new file mode 100644 index 0000000..da180c4 --- /dev/null +++ b/README_LLVM_CBUILDER.md @@ -0,0 +1,144 @@ +LLVM CBuilder +============= + +A few short examples: +(TODO: add more later) + +```python +from llvm.core import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +``` + +```python +class Square(CDefinition): + _name_ = 'square' + _retty_ = C.double + _argtys_ = [ ('x', C.double) ] + + def body(self, x): + y = x * x + self.ret(y) +``` + +```python +m = Module.new('my_module') +llvm_square = Square()(m) +print(m) +``` + +``` +; ModuleID = 'my_module' + +define double @square(double %x) { +decl: + %0 = fmul double %x, %x + ret double %0 +} +``` + + +```python +class IsPrime(CDefinition): + _name_ = 'isprime' + _retty_ = C.int + _argtys_ = [('x', C.int)] + + def body(self, x): + false = zero = self.constant(C.int, 0) + true = one = self.constant(C.int, 1) + + two = self.constant(C.int, 2) + + with self.ifelse( x <= two ) as ifelse: + with ifelse.then(): + self.ret(true) + + with self.ifelse( (x % two) == zero ) as ifelse: + with ifelse.then(): + self.ret(false) + + idx = self.var(C.int, 3, name='idx') + + with self.loop() as loop: + with loop.condition() as setcond: + setcond( idx < x ) + + with loop.body(): + with self.ifelse( (x % idx ) == zero ) as ifelse: + with ifelse.then(): + self.ret(false) + idx += two + + self.ret(true) +``` + + + +``` +define i32 @isprime(i32 %x) { +decl: + %0 = icmp sle i32 %x, 2 + br i1 %0, label %if.then, label %if.end + +if.then: ; preds = %loop.body, %loop.cond, %if.end, %decl + %merge = phi i32 [ 1, %decl ], [ 0, %if.end ], [ 1, %loop.cond ], [ 0, %loop.body ] + ret i32 %merge + +if.end: ; preds = %decl + %1 = srem i32 %x, 2 + %2 = icmp eq i32 %1, 0 + br i1 %2, label %if.then, label %if.end4 + +if.end4: ; preds = %if.end + br label %loop.cond + +loop.cond: ; preds = %if.end7, %if.end4 + %idx.0 = phi i32 [ 3, %if.end4 ], [ %6, %if.end7 ] + %3 = icmp slt i32 %idx.0, %x + br i1 %3, label %loop.body, label %if.then + +loop.body: ; preds = %loop.cond + %4 = srem i32 %x, %idx.0 + %5 = icmp eq i32 %4, 0 + br i1 %5, label %if.then, label %if.end7 + +if.end7: ; preds = %loop.body + %6 = add i32 %idx.0, 2 + br label %loop.cond +} + +; ModuleID = 'my_module' + +define i32 @isprime(i32 %x) { +decl: + %0 = icmp sle i32 %x, 2 + br i1 %0, label %if.then, label %if.end + +if.then: ; preds = %loop.body, %loop.cond, %if.end, %decl + %merge = phi i32 [ 1, %decl ], [ 0, %if.end ], [ 1, %loop.cond ], [ 0, %loop.body ] + ret i32 %merge + +if.end: ; preds = %decl + %1 = srem i32 %x, 2 + %2 = icmp eq i32 %1, 0 + br i1 %2, label %if.then, label %if.end4 + +if.end4: ; preds = %if.end + br label %loop.cond + +loop.cond: ; preds = %if.end7, %if.end4 + %idx.0 = phi i32 [ 3, %if.end4 ], [ %6, %if.end7 ] + %3 = icmp slt i32 %idx.0, %x + br i1 %3, label %loop.body, label %if.then + +loop.body: ; preds = %loop.cond + %4 = srem i32 %x, %idx.0 + %5 = icmp eq i32 %4, 0 + br i1 %5, label %if.then, label %if.end7 + +if.end7: ; preds = %loop.body + %6 = add i32 %idx.0, 2 + br label %loop.cond +} +``` From f2e65c6c54debf2fa107ab7809e2523574c9926e Mon Sep 17 00:00:00 2001 From: Jon Riehl Date: Thu, 15 Nov 2012 12:13:50 -0600 Subject: [PATCH 114/516] Proposed fix for issue #31. --- llvm_cbuilder/shortnames.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/llvm_cbuilder/shortnames.py b/llvm_cbuilder/shortnames.py index 2acd69d..2d966d4 100644 --- a/llvm_cbuilder/shortnames.py +++ b/llvm_cbuilder/shortnames.py @@ -1,5 +1,3 @@ -from numba.minivect import minitypes -import numba.decorators from llvm.core import Type void = Type.void() @@ -13,8 +11,21 @@ int64 = Type.int(64) float = Type.float() double = Type.double() -npy_intp = minitypes.npy_intp.to_llvm(numba.decorators.context) -py_ssize_t = minitypes.Py_ssize_t.to_llvm(numba.decorators.context) +# platform dependent + +def _determine_sizes(): + import ctypes + # Makes following assumption: + # sizeof(py_ssize_t) == sizeof(ssize_t) == sizeof(size_t) + any_size_t = getattr(ctypes, 'c_ssize_t', ctypes.c_size_t) + return ctypes.sizeof(ctypes.c_void_p) * 8, ctypes.sizeof(any_ssize_t) * 8 + +pointer_size, _py_ssize_t_bits = _determine_pointer_size() + +intp = {32: int32, 64: int64}[pointer_size] + +npy_intp = Type.int(pointer_size) +py_ssize_t = Type.int(_py_ssize_t_bits) # pointers @@ -24,17 +35,6 @@ void_p = pointer(char) char_p = pointer(char) npy_intp_p = pointer(npy_intp) -# platform dependent - -def _determine_pointer_size(): - from ctypes import sizeof, c_void_p - return sizeof(c_void_p) * 8 - -pointer_size = _determine_pointer_size() - -intp = {32: int32, 64: int64}[pointer_size] - - # vector def vector(ty, ct): return Type.vector(ty, 4) From e2e6221f258a80890cd0a2f7ba57a12d7347b7b8 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 17 Dec 2012 14:24:05 -0600 Subject: [PATCH 115/516] Fix last commit --- llvm_cbuilder/shortnames.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm_cbuilder/shortnames.py b/llvm_cbuilder/shortnames.py index 2d966d4..44bb1ad 100644 --- a/llvm_cbuilder/shortnames.py +++ b/llvm_cbuilder/shortnames.py @@ -18,9 +18,9 @@ def _determine_sizes(): # Makes following assumption: # sizeof(py_ssize_t) == sizeof(ssize_t) == sizeof(size_t) any_size_t = getattr(ctypes, 'c_ssize_t', ctypes.c_size_t) - return ctypes.sizeof(ctypes.c_void_p) * 8, ctypes.sizeof(any_ssize_t) * 8 + return ctypes.sizeof(ctypes.c_void_p) * 8, ctypes.sizeof(any_size_t) * 8 -pointer_size, _py_ssize_t_bits = _determine_pointer_size() +pointer_size, _py_ssize_t_bits = _determine_sizes() intp = {32: int32, 64: int64}[pointer_size] From f3e9eb0b05d2db2ba28274a75e638945c27df2c8 Mon Sep 17 00:00:00 2001 From: xol Date: Mon, 24 Dec 2012 13:27:04 +0100 Subject: [PATCH 116/516] Fix for llvm 3.2 - TargetData -> DataLayout --- llvm/extra.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/llvm/extra.cpp b/llvm/extra.cpp index b8545ea..04215ee 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -53,7 +53,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/CallSite.h" #include "llvm/Support/FormattedStream.h" -#include "llvm/Target/TargetData.h" +//#include "llvm/Target/TargetData.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/Host.h" @@ -356,12 +356,12 @@ unsigned char* LLVMTargetMachineEmitFile(LLVMTargetMachineRef tmref, PassManager pm; - if (!tm->getTargetData()){ + if (!tm->getDataLayout()){ error = "No target data in target machine"; return NULL; } - pm.add(new TargetData(*tm->getTargetData())); + pm.add(new DataLayout(*tm->getDataLayout())); bool failed; if( assembly ) { @@ -427,7 +427,7 @@ void LLVMPrintRegisteredTargetsForVersion(){ LLVMTargetDataRef LLVMTargetMachineGetTargetData(LLVMTargetMachineRef tm) { using namespace llvm; - return wrap(new TargetData(*unwrap(tm)->getTargetData())); + return wrap(new DataLayout(*unwrap(tm)->getDataLayout())); } unsigned char* LLVMGetNativeCodeFromModule(LLVMModuleRef module, int assembly, @@ -992,7 +992,8 @@ void LLVMSetDoesNotThrow(LLVMValueRef fn, int DoesNotThrow) llvm::Function *fnp = llvm::unwrap(fn); assert(fnp); - return fnp->setDoesNotThrow((bool)DoesNotThrow); + if ((bool)DoesNotThrow) + fnp->setDoesNotThrow(); } From 5da98dac495df40e2712726b03564afeb10e99d1 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 27 Dec 2012 17:10:12 -0600 Subject: [PATCH 117/516] Add macros to enable support for llvm3.1. --- llvm/extra.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/llvm/extra.cpp b/llvm/extra.cpp index 04215ee..1b6d9fc 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -53,7 +53,6 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/CallSite.h" #include "llvm/Support/FormattedStream.h" -//#include "llvm/Target/TargetData.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/Host.h" @@ -75,8 +74,15 @@ #include "llvm/Linker.h" #include "llvm/Support/SourceMgr.h" #include +#include +#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 2 + #include "llvm/DataLayout.h" +#else + #include "llvm/Target/TargetData.h" +#endif + // LLVM-C includes #include "llvm-c/Core.h" #include "llvm-c/ExecutionEngine.h" @@ -105,7 +111,7 @@ class PassRegistryPrinter : public llvm::PassRegistrationListener{ public: std::ostringstream stringstream; - void passEnumerate(const llvm::PassInfo * pass_info){ + inline virtual void passEnumerate(const llvm::PassInfo * pass_info){ stringstream << pass_info->getPassArgument() << "\t" << pass_info->getPassName() @@ -355,13 +361,21 @@ unsigned char* LLVMTargetMachineEmitFile(LLVMTargetMachineRef tmref, TargetMachine * tm = unwrap(tmref); PassManager pm; - +#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 2 if (!tm->getDataLayout()){ error = "No target data in target machine"; return NULL; } - pm.add(new DataLayout(*tm->getDataLayout())); +#else + if (!tm->getTargetData()){ + error = "No target data in target machine"; + return NULL; + } + pm.add(new TargetData(*tm->getTargetData())); +#endif + + bool failed; if( assembly ) { @@ -427,7 +441,11 @@ void LLVMPrintRegisteredTargetsForVersion(){ LLVMTargetDataRef LLVMTargetMachineGetTargetData(LLVMTargetMachineRef tm) { using namespace llvm; +#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 2 return wrap(new DataLayout(*unwrap(tm)->getDataLayout())); +#else + return wrap(new TargetData(*unwrap(tm)->getTargetData())); +#endif } unsigned char* LLVMGetNativeCodeFromModule(LLVMModuleRef module, int assembly, From d397f4c49757ec0e5c420418a0d9731b8bc46400 Mon Sep 17 00:00:00 2001 From: Ewan Higgs Date: Sun, 30 Dec 2012 21:08:38 +0000 Subject: [PATCH 118/516] Issue #34 - Add tools to MANIFEST.in --- MANIFEST.in | 1 + 1 file changed, 1 insertion(+) diff --git a/MANIFEST.in b/MANIFEST.in index ec22b21..295794c 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,3 +2,4 @@ include CHANGELOG LICENSE README setup.py MANIFEST.in recursive-include llvm * recursive-include www * recursive-include test * +recursive-include tools * From 10e83f306fef2e9294df08e1c2e0819a898f8dd2 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 27 Dec 2012 17:58:15 -0600 Subject: [PATCH 119/516] Add PassManagerBuilder.loop_vectorize property --- llvm/_core.cpp | 10 +++++++++- llvm/extra.cpp | 13 +++++++++++++ llvm/extra.h | 13 +++++++++++++ llvm/passes.py | 16 ++++++++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 75b50ed..fa6087a 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -988,6 +988,11 @@ _wrap_obj2obj(LLVMPassManagerBuilderGetSizeLevel, LLVMPassManagerBuilderRef, int _wrap_objint2none(LLVMPassManagerBuilderSetVectorize, LLVMPassManagerBuilderRef) _wrap_obj2obj(LLVMPassManagerBuilderGetVectorize, LLVMPassManagerBuilderRef, int) +#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 2 +_wrap_objint2none(LLVMPassManagerBuilderSetLoopVectorize, LLVMPassManagerBuilderRef) +_wrap_obj2obj(LLVMPassManagerBuilderGetLoopVectorize, LLVMPassManagerBuilderRef, int) +#endif //llvm-3.2 + _wrap_objint2none(LLVMPassManagerBuilderSetDisableUnitAtATime, LLVMPassManagerBuilderRef) _wrap_obj2obj(LLVMPassManagerBuilderGetDisableUnitAtATime, @@ -1989,7 +1994,10 @@ static PyMethodDef core_methods[] = { _method( LLVMPassManagerBuilderSetVectorize ) _method( LLVMPassManagerBuilderGetVectorize ) - +#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 2 + _method( LLVMPassManagerBuilderSetLoopVectorize ) + _method( LLVMPassManagerBuilderGetLoopVectorize ) +#endif // llvm-3.2 _method( LLVMPassManagerBuilderSetDisableUnitAtATime ) _method( LLVMPassManagerBuilderGetDisableUnitAtATime ) diff --git a/llvm/extra.cpp b/llvm/extra.cpp index 1b6d9fc..484f9ac 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -669,6 +669,19 @@ int LLVMPassManagerBuilderGetVectorize(LLVMPassManagerBuilderRef pmb){ return llvm::unwrap(pmb)->Vectorize; } +#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 2 +void LLVMPassManagerBuilderSetLoopVectorize(LLVMPassManagerBuilderRef pmb, + int flag) +{ + llvm::unwrap(pmb)->LoopVectorize = flag; +} + +int LLVMPassManagerBuilderGetLoopVectorize(LLVMPassManagerBuilderRef pmb){ + return llvm::unwrap(pmb)->LoopVectorize; +} +#endif // llvm-3.2 + + int LLVMPassManagerBuilderGetDisableUnitAtATime(LLVMPassManagerBuilderRef pmb) { return llvm::unwrap(pmb)->DisableUnitAtATime; diff --git a/llvm/extra.h b/llvm/extra.h index 26235e1..97cc31b 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -312,6 +312,19 @@ void LLVMPassManagerBuilderSetVectorize(LLVMPassManagerBuilderRef pmb, int flag) */ int LLVMPassManagerBuilderGetVectorize(LLVMPassManagerBuilderRef pmb); +#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 2 +/* + * Wraps PassManagerBuilder::LoopVectorize + */ +void LLVMPassManagerBuilderSetLoopVectorize(LLVMPassManagerBuilderRef pmb, + int flag); + +/* + * Wraps PassManagerBuilder::LoopVectorize + */ +int LLVMPassManagerBuilderGetLoopVectorize(LLVMPassManagerBuilderRef pmb); +#endif // llvm-3.2 + /* * Wraps PassManagerBuilder::DisableUnitAtATime */ diff --git a/llvm/passes.py b/llvm/passes.py index fb5dc7c..d06fa59 100644 --- a/llvm/passes.py +++ b/llvm/passes.py @@ -41,6 +41,7 @@ import llvm.core as core # module, function etc. import llvm._core as _core # C wrappers import llvm._util as _util # Utility functions +import warnings #===----------------------------------------------------------------------=== # Pass manager builder #===----------------------------------------------------------------------=== @@ -89,6 +90,21 @@ class PassManagerBuilder(object): vectorize = property(_get_vectorize, _set_vectorize) + def _set_loop_vectorize(self, enable): + try: + _core.LLVMPassManagerBuilderSetLoopVectorize(self.ptr, + int(bool(enable))) + except AttributeError: + warnings.warn("Ignored. LLVM-3.1 & prior do not support loop vectorizer.") + + def _get_loop_vectorize(self): + try: + return bool(_core.LLVMPassManagerBuilderGetLoopVectorize(self.ptr)) + except AttributeError: + return False + + loop_vectorize = property(_get_loop_vectorize, _set_loop_vectorize) + def _set_disable_unit_at_a_time(self, disable): return _core.LLVMPassManagerBuilderSetDisableUnitAtATime( self.ptr, disable) From ff515528383aefad97ceb5d755d21138bd2d0b53 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 31 Dec 2012 10:43:37 -0600 Subject: [PATCH 120/516] Update README for LLVM 3.2. --- README.rst | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index 3f9d23d..973dfdb 100644 --- a/README.rst +++ b/README.rst @@ -10,15 +10,19 @@ http://www.llvmpy.org Versions -------- -This package has been tested with LLVM 3.1, Python 2.7 and Python 3.2. -Other Python versions should work, but some modifications may be -needed for the upcoming LLVM 3.2 +This package has been tested with LLVM 3.1 and 3.2, Python 2.7 and Python 3.2. +Other Python versions should work. Quickstart ---------- -1. Get 3.1 version of LLVM, build it. Make sure ``--enable-pic`` is passed to - LLVM's ``configure``. +1. Get 3.1 or 3.2 version of LLVM, build it. Make sure ``--enable-pic`` is + passed to LLVM's ``configure``. + + For LLVM 3.2, make sure that environment variable ``REQUIRES_RTTI=1`` is + defined when running ``make``. Otherwise, you may see "undefined symbol: + _ZTIN4llvm24PassRegistrationListenerE". Please refer to + http://llvm.org/docs/Packaging.html#c-features for details. 2. Get llvm-py and install it:: From b22c0233011e039061ceb4839643b63ebfa16181 Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Wed, 2 Jan 2013 19:17:12 +0000 Subject: [PATCH 121/516] Make cbuilder optimizations optional --- llvm_cbuilder/builder.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 628ed85..45e58d1 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -784,7 +784,7 @@ class CDefinition(object): cls._name_ = "%s_%d" % (cls._name_, counter) cls.counter = counter + 1 - def define(self, module): + def define(self, module, optimize=True): '''define the function in the module. Raises NameError if a function of the same name has already been @@ -814,13 +814,14 @@ class CDefinition(object): self.cbuilder.close() self.cbuilder = None - # optimize - fpm = lp.FunctionPassManager.new(module) - pmb = lp.PassManagerBuilder.new() - pmb.opt_level = 3 - pmb.vectorize = True - pmb.populate(fpm) - fpm.run(func) + if optimize: + fpm = lp.FunctionPassManager.new(module) + pmb = lp.PassManagerBuilder.new() + pmb.opt_level = 3 + pmb.vectorize = True + pmb.populate(fpm) + fpm.run(func) + return func def __call__(self, module): From ff92a05858364cb1ae5441445e8e33a51928b730 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 31 Dec 2012 18:46:57 -0600 Subject: [PATCH 122/516] Begin to expose Pass class. --- llvm/_core.cpp | 188 +++----------------------------------------- llvm/ee.py | 75 ++---------------- llvm/extra.cpp | 26 ++++++ llvm/extra.h | 20 +++++ llvm/llvm_c_extra.h | 2 +- llvm/passes.py | 130 +++++++++++++++++++++++++++--- 6 files changed, 182 insertions(+), 259 deletions(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index fa6087a..0b53138 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -1057,97 +1057,11 @@ _wrap_none2none(LLVMInitializePTXAsmPrinter) /*===----------------------------------------------------------------------===*/ /* Passes */ /*===----------------------------------------------------------------------===*/ -/* - -#define _wrap_pass(P) \ -_wrap_obj2none( LLVMAdd ## P ## Pass, LLVMPassManagerRef) - -_wrap_pass( AAEval ) -_wrap_pass( AggressiveDCE ) -_wrap_pass( AliasAnalysisCounter ) -_wrap_pass( AlwaysInliner ) -_wrap_pass( ArgumentPromotion ) -_wrap_pass( BasicAliasAnalysis ) -_wrap_pass( BlockPlacement ) -_wrap_pass( BreakCriticalEdges ) -_wrap_pass( CFGSimplification ) -_wrap_pass( CodeGenPrepare ) -_wrap_pass( ConstantMerge ) -_wrap_pass( ConstantPropagation ) -_wrap_pass( DbgInfoPrinter ) -_wrap_pass( DeadArgElimination ) -_wrap_pass( DeadCodeElimination ) -_wrap_pass( DeadInstElimination ) -_wrap_pass( DeadStoreElimination ) -_wrap_pass( DemoteRegisterToMemory ) -_wrap_pass( DomOnlyPrinter ) -_wrap_pass( DomOnlyViewer ) -_wrap_pass( DomPrinter ) -_wrap_pass( DomViewer ) -_wrap_pass( EdgeProfiler ) -_wrap_pass( FunctionAttrs ) -_wrap_pass( FunctionInlining ) -//_wrap_pass( GEPSplitter ) -_wrap_pass( GlobalDCE ) -_wrap_pass( GlobalOptimizer ) -_wrap_pass( GlobalsModRef ) -_wrap_pass( GVN ) -_wrap_pass( IndVarSimplify ) -_wrap_pass( InstCount ) -_wrap_pass( InstructionCombining ) -_wrap_pass( InstructionNamer ) -_wrap_pass( IPConstantPropagation ) -_wrap_pass( IPSCCP ) -_wrap_pass( JumpThreading ) -_wrap_pass( LazyValueInfo ) -_wrap_pass( LCSSA ) -_wrap_pass( LICM ) -//_wrap_pass( LiveValues ) -_wrap_pass( LoopDeletion ) -_wrap_pass( LoopDependenceAnalysis ) -_wrap_pass( LoopExtractor ) -//_wrap_pass( LoopIndexSplit ) -_wrap_pass( LoopRotate ) -_wrap_pass( LoopSimplify ) -_wrap_pass( LoopStrengthReduce ) -_wrap_pass( LoopUnroll ) -_wrap_pass( LoopUnswitch ) -_wrap_pass( LowerInvoke ) -_wrap_pass( LowerSwitch ) -_wrap_pass( MemCpyOpt ) -_wrap_pass( MergeFunctions ) -_wrap_pass( NoAA ) -_wrap_pass( NoProfileInfo ) -_wrap_pass( OptimalEdgeProfiler ) -_wrap_pass( PartialInlining ) -//_wrap_pass( PartialSpecialization ) -_wrap_pass( PostDomOnlyPrinter ) -_wrap_pass( PostDomOnlyViewer ) -_wrap_pass( PostDomPrinter ) -_wrap_pass( PostDomViewer ) -_wrap_pass( ProfileEstimator ) -_wrap_pass( ProfileLoader ) -_wrap_pass( ProfileVerifier ) -_wrap_pass( PromoteMemoryToRegister ) -_wrap_pass( PruneEH ) -_wrap_pass( Reassociate ) -_wrap_pass( ScalarEvolutionAliasAnalysis ) -_wrap_pass( ScalarReplAggregates ) -_wrap_pass( SCCP ) -//_wrap_pass( SimplifyHalfPowrLibCalls ) -_wrap_pass( SimplifyLibCalls ) -_wrap_pass( SingleLoopExtractor ) -_wrap_pass( StripDeadPrototypes ) -_wrap_pass( StripNonDebugSymbols ) -_wrap_pass( StripSymbols ) -//_wrap_pass( StructRetPromotion ) -_wrap_pass( TailCallElimination ) -//_wrap_pass( TailDuplication ) -_wrap_pass( UnifyFunctionExitNodes ) - -_wrap_pass( Internalize2 ) -*/ +_wrap_str2obj(LLVMCreatePassByName, LLVMPassRef) +_wrap_obj2none(LLVMDisposePass, LLVMPassRef) +_wrap_obj2str(LLVMGetPassName, LLVMPassRef) +_wrap_objobj2none(LLVMAddPass, LLVMPassManagerRef, LLVMPassRef) /*===----------------------------------------------------------------------===*/ /* Target Machine */ @@ -2040,94 +1954,6 @@ static PyMethodDef core_methods[] = { _method( LLVMInitializePTXAsmPrinter ) # endif #endif - /* Passes */ - - /* - _pass( AAEval ) - _pass( AggressiveDCE ) - _pass( AliasAnalysisCounter ) - _pass( AlwaysInliner ) - _pass( ArgumentPromotion ) - _pass( BasicAliasAnalysis ) - _pass( BlockPlacement ) - _pass( BreakCriticalEdges ) - _pass( CFGSimplification ) - _pass( CodeGenPrepare ) - _pass( ConstantMerge ) - _pass( ConstantPropagation ) - _pass( DbgInfoPrinter ) - _pass( DeadArgElimination ) - _pass( DeadCodeElimination ) - _pass( DeadInstElimination ) - _pass( DeadStoreElimination ) - _pass( DemoteRegisterToMemory ) - _pass( DomOnlyPrinter ) - _pass( DomOnlyViewer ) - _pass( DomPrinter ) - _pass( DomViewer ) - _pass( EdgeProfiler ) - _pass( FunctionAttrs ) - _pass( FunctionInlining ) - //_pass( GEPSplitter ) - _pass( GlobalDCE ) - _pass( GlobalOptimizer ) - _pass( GlobalsModRef ) - _pass( GVN ) - _pass( IndVarSimplify ) - _pass( InstCount ) - _pass( InstructionCombining ) - _pass( InstructionNamer ) - _pass( IPConstantPropagation ) - _pass( IPSCCP ) - _pass( JumpThreading ) - _pass( LazyValueInfo ) - _pass( LCSSA ) - _pass( LICM ) - //_pass( LiveValues ) - _pass( LoopDeletion ) - _pass( LoopDependenceAnalysis ) - _pass( LoopExtractor ) - //_pass( LoopIndexSplit ) - _pass( LoopRotate ) - _pass( LoopSimplify ) - _pass( LoopStrengthReduce ) - _pass( LoopUnroll ) - _pass( LoopUnswitch ) - _pass( LowerInvoke ) - _pass( LowerSwitch ) - _pass( MemCpyOpt ) - _pass( MergeFunctions ) - _pass( NoAA ) - _pass( NoProfileInfo ) - _pass( OptimalEdgeProfiler ) - _pass( PartialInlining ) - //_pass( PartialSpecialization ) - _pass( PostDomOnlyPrinter ) - _pass( PostDomOnlyViewer ) - _pass( PostDomPrinter ) - _pass( PostDomViewer ) - _pass( ProfileEstimator ) - _pass( ProfileLoader ) - _pass( ProfileVerifier ) - _pass( PromoteMemoryToRegister ) - _pass( PruneEH ) - _pass( Reassociate ) - _pass( ScalarEvolutionAliasAnalysis ) - _pass( ScalarReplAggregates ) - _pass( SCCP ) - //_pass( SimplifyHalfPowrLibCalls ) - _pass( SimplifyLibCalls ) - _pass( SingleLoopExtractor ) - _pass( StripDeadPrototypes ) - _pass( StripNonDebugSymbols ) - _pass( StripSymbols ) - //_pass( StructRetPromotion ) - _pass( TailCallElimination ) - //_pass( TailDuplication ) - _pass( UnifyFunctionExitNodes ) - - _pass( Internalize2 ) - */ /* Target Machine */ _method( LLVMTargetMachineFromEngineBuilder ) @@ -2194,6 +2020,12 @@ static PyMethodDef core_methods[] = { _method( LLVMGenericValueToPointer ) _method( LLVMDisposeGenericValue ) + /* Passes */ + _method( LLVMCreatePassByName ) + _method( LLVMDisposePass ) + _method( LLVMGetPassName ) + _method( LLVMAddPass ) + /* Misc */ _method( LLVMGetIntrinsic ) _method( LLVMLoadLibraryPermanently ) diff --git a/llvm/ee.py b/llvm/ee.py index a23aaf4..ebe5e87 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -40,6 +40,10 @@ import logging logger = logging.getLogger(__name__) + +# re-export TargetData for backward compatibility. +from llvm.passes import TargetData + #===----------------------------------------------------------------------=== # Enumerations #===----------------------------------------------------------------------=== @@ -48,76 +52,6 @@ BO_BIG_ENDIAN = 0 BO_LITTLE_ENDIAN = 1 -#===----------------------------------------------------------------------=== -# Target data -#===----------------------------------------------------------------------=== - -class TargetData(llvm.Ownable): - - @staticmethod - def new(strrep): - return TargetData(_core.LLVMCreateTargetData(strrep)) - - def __init__(self, ptr): - llvm.Ownable.__init__(self, ptr, _core.LLVMDisposeTargetData) - - def __str__(self): - return _core.LLVMTargetDataAsString(self.ptr) - - @property - def byte_order(self): - return _core.LLVMByteOrder(self.ptr) - - @property - def pointer_size(self): - return _core.LLVMPointerSize(self.ptr) - - @property - def target_integer_type(self): - ptr = _core.LLVMIntPtrType(self.ptr); - return core.IntegerType(ptr, core.TYPE_INTEGER) - - def size(self, ty): - core.check_is_type(ty) - return _core.LLVMSizeOfTypeInBits(self.ptr, ty.ptr) - - def store_size(self, ty): - core.check_is_type(ty) - return _core.LLVMStoreSizeOfType(self.ptr, ty.ptr) - - def abi_size(self, ty): - core.check_is_type(ty) - return _core.LLVMABISizeOfType(self.ptr, ty.ptr) - - def abi_alignment(self, ty): - core.check_is_type(ty) - return _core.LLVMABIAlignmentOfType(self.ptr, ty.ptr) - - def callframe_alignment(self, ty): - core.check_is_type(ty) - return _core.LLVMCallFrameAlignmentOfType(self.ptr, ty.ptr) - - def preferred_alignment(self, ty_or_gv): - if isinstance(ty_or_gv, core.Type): - return _core.LLVMPreferredAlignmentOfType(self.ptr, - ty_or_gv.ptr) - elif isinstance(ty_or_gv, core.GlobalVariable): - return _core.LLVMPreferredAlignmentOfGlobal(self.ptr, - ty_or_gv.ptr) - else: - raise core.LLVMException("argument is neither a type nor a global variable") - - def element_at_offset(self, ty, ofs): - core.check_is_type_struct(ty) - ofs = int(ofs) # ofs is unsigned long long - return _core.LLVMElementAtOffset(self.ptr, ty.ptr, ofs) - - def offset_of_element(self, ty, el): - core.check_is_type_struct(ty) - el = int(el) # el should be an int - return _core.LLVMOffsetOfElement(self.ptr, ty.ptr, el) - - #===----------------------------------------------------------------------=== # Generic value #===----------------------------------------------------------------------=== @@ -383,3 +317,4 @@ class TargetMachine(object): @property def feature_string(self): return _core.LLVMTargetMachineGetFS(self.ptr) + diff --git a/llvm/extra.cpp b/llvm/extra.cpp index 484f9ac..e58220d 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -95,6 +95,7 @@ namespace llvm{ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(EngineBuilder, LLVMEngineBuilderRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(NamedMDNode, LLVMNamedMDRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(Pass, LLVMPassRef) template inline T **unwrap(LLVMTypeRef *Tys, unsigned Length) { @@ -143,6 +144,31 @@ const CodeGenOpt::Level OptLevelMap[] = { } // end anony namespace +LLVMPassRef LLVMCreatePassByName(const char *name){ + using namespace llvm; + const PassInfo * pi = Pass::lookupPassInfo(StringRef(name)); + if (pi) { + return wrap(pi->createPass()); + } else { // cannot find pass + return NULL; + } +} + +void LLVMDisposePass(LLVMPassRef passref){ + using namespace llvm; + delete unwrap(passref); +} + +const char * LLVMGetPassName(LLVMPassRef passref){ + using namespace llvm; + return unwrap(passref)->getPassName(); +} + +void LLVMAddPass(LLVMPassManagerRef pmref, LLVMPassRef passref){ + using namespace llvm; + unwrap(pmref)->add(unwrap(passref)); +} + LLVMValueRef LLVMGetFunctionFromInlineAsm(LLVMTypeRef funcType, const char inlineAsm[], const char constrains[], diff --git a/llvm/extra.h b/llvm/extra.h index 97cc31b..49a75d1 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -54,6 +54,26 @@ extern "C" { #endif +/* + * Wraps Pass::lookupPassInfo and PassInfo::createPass + */ +LLVMPassRef LLVMCreatePassByName(const char *name); + +/* + * Wraps operator delete (Pass*) + */ +void LLVMDisposePass(LLVMPassRef passref); + +/* + * Wraps Pass::getPassName + */ +const char * LLVMGetPassName(LLVMPassRef passref); + +/* + * Wraps PassManager::add + */ +void LLVMAddPass(LLVMPassManagerRef pmref, LLVMPassRef passref); + /* * Wraps llvm:InlineAsm::get */ diff --git a/llvm/llvm_c_extra.h b/llvm/llvm_c_extra.h index 9eb77dc..5728875 100644 --- a/llvm/llvm_c_extra.h +++ b/llvm/llvm_c_extra.h @@ -21,7 +21,7 @@ inline ref wrap(const ty *P) { \ typedef struct LLVMOpaqueEngineBuilder *LLVMEngineBuilderRef; typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef; typedef struct LLVMOpaqueNamedMD *LLVMNamedMDRef; - +typedef struct LLVMOpaquePass *LLVMPassRef; #ifdef __cplusplus } diff --git a/llvm/passes.py b/llvm/passes.py index d06fa59..71de28d 100644 --- a/llvm/passes.py +++ b/llvm/passes.py @@ -36,7 +36,6 @@ are available. """ import llvm # top-level, for common stuff -import llvm.ee as ee # target data import llvm.core as core # module, function etc. import llvm._core as _core # C wrappers import llvm._util as _util # Utility functions @@ -155,16 +154,18 @@ class PassManager(object): def __del__(self): _core.LLVMDisposePassManager(self.ptr) - def add(self, tgt_data_or_pass_name): - if isinstance(tgt_data_or_pass_name, ee.TargetData): - self._add_target_data(tgt_data_or_pass_name) - elif _util.isstring(tgt_data_or_pass_name): - self._add_pass(tgt_data_or_pass_name) + def add(self, pass_obj): + '''Add a pass to the pass manager. + + pass_obj --- Either a Pass instance, a string name of a pass + ''' + if isinstance(pass_obj, Pass): + _core.LLVMAddPass(self.ptr, pass_obj.ptr) + pass_obj._own(self) # PassManager owns the pass + elif _util.isstring(pass_obj): + self._add_pass(pass_obj) else: - raise llvm.LLVMException("invalid pass_id (%s)" % tgt_data_or_pass_name) - - def _add_target_data(self, tgt): - _core.LLVMAddTargetData(tgt.ptr, self.ptr) + raise llvm.LLVMException("invalid pass_id (%s)" % pass_obj) def _add_pass(self, pass_name): status = _core.LLVMAddPassByName(self.ptr, pass_name) @@ -197,6 +198,115 @@ class FunctionPassManager(PassManager): def finalize(self): _core.LLVMFinalizeFunctionPassManager(self.ptr) + + +#===----------------------------------------------------------------------=== +# Passes +#===----------------------------------------------------------------------=== + +class Pass(llvm.Ownable): + '''Pass Inferface + ''' + def __init__(self, ptr): + llvm.Ownable.__init__(self, ptr, _core.LLVMDisposePass) + + @staticmethod + def new(name): + '''Create a new pass by name. + + Note: Not all pass has a default constructor. LLVM will kill + the process if an the pass requires arguments to construct. + The error cannot be caught. + ''' + ptr = _core.LLVMCreatePassByName(name) + p = Pass(ptr) + p.__name = name + return p + + @property + def name(self): + return self.__name + + @property + def description(self): + return _core.LLVMGetPassName(self.ptr) + + def dump(self): + return _core.LLVMPassDump(self.ptr) + + +#===----------------------------------------------------------------------=== +# Target data +#===----------------------------------------------------------------------=== + +class TargetData(Pass): + + @staticmethod + def new(strrep): + return TargetData(_core.LLVMCreateTargetData(strrep)) + + def __str__(self): + return _core.LLVMTargetDataAsString(self.ptr) + + @property + def byte_order(self): + return _core.LLVMByteOrder(self.ptr) + + @property + def pointer_size(self): + return _core.LLVMPointerSize(self.ptr) + + @property + def target_integer_type(self): + ptr = _core.LLVMIntPtrType(self.ptr); + return core.IntegerType(ptr, core.TYPE_INTEGER) + + def size(self, ty): + core.check_is_type(ty) + return _core.LLVMSizeOfTypeInBits(self.ptr, ty.ptr) + + def store_size(self, ty): + core.check_is_type(ty) + return _core.LLVMStoreSizeOfType(self.ptr, ty.ptr) + + def abi_size(self, ty): + core.check_is_type(ty) + return _core.LLVMABISizeOfType(self.ptr, ty.ptr) + + def abi_alignment(self, ty): + core.check_is_type(ty) + return _core.LLVMABIAlignmentOfType(self.ptr, ty.ptr) + + def callframe_alignment(self, ty): + core.check_is_type(ty) + return _core.LLVMCallFrameAlignmentOfType(self.ptr, ty.ptr) + + def preferred_alignment(self, ty_or_gv): + if isinstance(ty_or_gv, core.Type): + return _core.LLVMPreferredAlignmentOfType(self.ptr, + ty_or_gv.ptr) + elif isinstance(ty_or_gv, core.GlobalVariable): + return _core.LLVMPreferredAlignmentOfGlobal(self.ptr, + ty_or_gv.ptr) + else: + raise core.LLVMException("argument is neither a type nor a global variable") + + def element_at_offset(self, ty, ofs): + core.check_is_type_struct(ty) + ofs = int(ofs) # ofs is unsigned long long + return _core.LLVMElementAtOffset(self.ptr, ty.ptr, ofs) + + def offset_of_element(self, ty, el): + core.check_is_type_struct(ty) + el = int(el) # el should be an int + return _core.LLVMOffsetOfElement(self.ptr, ty.ptr, el) + + + +#===----------------------------------------------------------------------=== +# Misc. +#===----------------------------------------------------------------------=== + # Intialize passes PASSES = None From bcc467b2b53a16713eec4517376fcd9d16d666e0 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 2 Jan 2013 12:20:10 -0600 Subject: [PATCH 123/516] Add auto detect PTX/NVPTX support and disable them in the C-extension. --- setup.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 1fba3db..94c9f95 100644 --- a/setup.py +++ b/setup.py @@ -64,6 +64,8 @@ print('LLVM version = %d.%d' % llvm_version) auto_intrinsic_gen(incdir) +macros = [('__STDC_CONSTANT_MACROS', None), + ('__STDC_LIMIT_MACROS', None)] if dynlink: libs_core = ['LLVM-%d.%d' % llvm_version] objs_core = [] @@ -89,6 +91,7 @@ else: extra_components.extend(ptx_components) else: print("No CUDA support") + macros.append(('LLVM_DISABLE_PTX', None)) libs_core, objs_core = get_libs_and_objs( ['core', 'analysis', 'scalaropts', 'executionengine', @@ -97,12 +100,10 @@ else: 'asmparser', 'linker', 'support', 'vectorize'] + extra_components) -macros = [('__STDC_CONSTANT_MACROS', None), - ('__STDC_LIMIT_MACROS', None)] if sys.platform == 'win32': # If no PTX lib got added, disable PTX in the build if 'LLVMPTXCodeGen' not in libs_core: - macros.append(('LLVM_DISABLE_PTX', None)), + macros.append(('LLVM_DISABLE_PTX', None)) else: macros.append(('_GNU_SOURCE', None)) From 3b399f9d8bf7e272fb0d3f7822e30f01ddc74895 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 2 Jan 2013 17:00:59 -0600 Subject: [PATCH 124/516] Adding target specific passes. --- llvm/_core.cpp | 43 ++++++++++++++++++++++++++++++++++++++++--- llvm/ee.py | 13 +++++++++++++ llvm/extra.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++++++ llvm/extra.h | 26 ++++++++++++++++++++++++++ llvm/passes.py | 23 +++++++++++++++++++++++ 5 files changed, 149 insertions(+), 3 deletions(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 0b53138..b3fb298 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -1036,6 +1036,7 @@ _wrap_none2str(LLVMDumpPasses) _wrap_objstr2obj(LLVMAddPassByName, LLVMPassManagerRef, int) +_wrap_objobj2none(LLVMAddPass, LLVMPassManagerRef, LLVMPassRef) _wrap_none2none(LLVMInitializePasses) _wrap_none2obj(LLVMInitializeNativeTarget, int) @@ -1061,7 +1062,11 @@ _wrap_none2none(LLVMInitializePTXAsmPrinter) _wrap_str2obj(LLVMCreatePassByName, LLVMPassRef) _wrap_obj2none(LLVMDisposePass, LLVMPassRef) _wrap_obj2str(LLVMGetPassName, LLVMPassRef) -_wrap_objobj2none(LLVMAddPass, LLVMPassManagerRef, LLVMPassRef) +_wrap_obj2none(LLVMPassDump, LLVMPassRef) + +_wrap_str2obj(LLVMCreateTargetLibraryInfo, LLVMPassRef) +_wrap_obj2obj(LLVMCreateTargetTransformInfo, LLVMTargetMachineRef, LLVMPassRef) + /*===----------------------------------------------------------------------===*/ /* Target Machine */ @@ -1096,6 +1101,30 @@ _wLLVMTargetMachineLookup(PyObject * self, PyObject * args) LLVMPY_CATCH_ALL } + +static PyObject * +_wLLVMCreateTargetMachine(PyObject * self, PyObject * args) +{ + LLVMPY_TRY + const char *triple; + const char *cpu; + const char *features; + int opt; + + if (!PyArg_ParseTuple(args, "sssi", &triple, &cpu, &features, &opt)) + return NULL; + + std::string error; + LLVMTargetMachineRef tm = LLVMCreateTargetMachine(triple, cpu, features, opt, + error); + if(!error.empty()){ + PyErr_SetString(PyExc_RuntimeError, error.c_str()); + return NULL; + } + return pycap_new(tm); + LLVMPY_CATCH_ALL +} + static PyObject * _wLLVMTargetMachineEmitFile(PyObject * self, PyObject * args) { @@ -1482,6 +1511,9 @@ _wLLVMParseEnvOpts(PyObject *self, PyObject *args) _wrap_obj2obj(LLVMInlineFunction, LLVMValueRef, int) +_wrap_none2str(LLVMDefaultTargetTriple) + + /* Expose the void* inside a PyCObject as a PyLong. This allows us to * use it as a unique ID. */ static PyObject * @@ -1937,6 +1969,7 @@ static PyMethodDef core_methods[] = { _method( LLVMDisposePassManager ) _method( LLVMDumpPasses ) _method( LLVMAddPassByName ) + _method( LLVMAddPass ) _method( LLVMInitializePasses ) _method( LLVMInitializeNativeTarget ) @@ -1958,6 +1991,7 @@ static PyMethodDef core_methods[] = { /* Target Machine */ _method( LLVMTargetMachineFromEngineBuilder ) _method( LLVMDisposeTargetMachine ) + _method( LLVMCreateTargetMachine ) _method( LLVMTargetMachineLookup ) _method( LLVMTargetMachineEmitFile ) _method( LLVMTargetMachineGetTargetData ) @@ -2024,13 +2058,16 @@ static PyMethodDef core_methods[] = { _method( LLVMCreatePassByName ) _method( LLVMDisposePass ) _method( LLVMGetPassName ) - _method( LLVMAddPass ) + _method( LLVMPassDump ) + + _method( LLVMCreateTargetLibraryInfo ) + _method( LLVMCreateTargetTransformInfo ) /* Misc */ _method( LLVMGetIntrinsic ) _method( LLVMLoadLibraryPermanently ) _method( LLVMParseEnvOpts ) - + _method( LLVMDefaultTargetTriple ) _method( LLVMInlineFunction ) _method( PyCObjectVoidPtrToPyLong ) { NULL } diff --git a/llvm/ee.py b/llvm/ee.py index ebe5e87..8469138 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -257,8 +257,21 @@ def get_host_cpu_name(): ''' return _core.LLVMGetHostCPUName() +def get_default_triple(): + '''return the target triple of the host in str-rep + ''' + return _core.LLVMDefaultTargetTriple() + class TargetMachine(object): + @staticmethod + def new(triple='', cpu='', features='', opt=2): + if not triple and not cpu: + triple = get_default_triple() + cpu = get_host_cpu_name() + ptr = _core.LLVMCreateTargetMachine(triple, cpu, features, opt) + return TargetMachine(ptr) + @staticmethod def lookup(arch, cpu='', features='', opt=2): '''create a targetmachine given an architecture name diff --git a/llvm/extra.cpp b/llvm/extra.cpp index e58220d..10d090a 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -75,6 +75,7 @@ #include "llvm/Support/SourceMgr.h" #include #include +#include #if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 2 @@ -143,6 +144,23 @@ const CodeGenOpt::Level OptLevelMap[] = { }; } // end anony namespace +LLVMPassRef LLVMCreateTargetTransformInfo(LLVMTargetMachineRef tmref){ + using namespace llvm; + TargetMachine * tm = unwrap(tmref); + Pass * tti = new TargetTransformInfo(tm->getScalarTargetTransformInfo(), + tm->getVectorTargetTransformInfo()); + return wrap(tti); +} + +LLVMPassRef LLVMCreateTargetLibraryInfo(const char * triple){ + using namespace llvm; + Pass * tli = new TargetLibraryInfo(Triple(triple)); + return wrap(tli); +} + +const char * LLVMDefaultTargetTriple(){ + return strdup(llvm::sys::getDefaultTargetTriple().c_str()); +} LLVMPassRef LLVMCreatePassByName(const char *name){ using namespace llvm; @@ -164,6 +182,11 @@ const char * LLVMGetPassName(LLVMPassRef passref){ return unwrap(passref)->getPassName(); } +void LLVMPassDump(LLVMPassRef passref){ + using namespace llvm; + return unwrap(passref)->dump(); +} + void LLVMAddPass(LLVMPassManagerRef pmref, LLVMPassRef passref){ using namespace llvm; unwrap(pmref)->add(unwrap(passref)); @@ -354,6 +377,30 @@ LLVMTargetMachineRef LLVMTargetMachineLookup(const char *arch, const char *cpu, return wrap(tm); } +LLVMTargetMachineRef LLVMCreateTargetMachine(const char *triple, + const char *cpu, + const char *features, + int opt, + std::string &error) +{ + using namespace llvm; + + std::string TheTriple = triple; + const Target * TheTarget = TargetRegistry::lookupTarget(TheTriple, error); + if (!TheTarget) return NULL; + + TargetOptions no_target_options; + TargetMachine * tm = TheTarget->createTargetMachine(TheTriple, cpu, features, + no_target_options, + Reloc::Default, + CodeModel::Default, + OptLevelMap[opt]); + if (!tm) { + error = "Cannot create target machine"; + return NULL; + } + return wrap(tm); +} LLVMTargetMachineRef LLVMTargetMachineFromEngineBuilder(LLVMEngineBuilderRef eb) { diff --git a/llvm/extra.h b/llvm/extra.h index 49a75d1..3f2a413 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -54,6 +54,23 @@ extern "C" { #endif +/* + * Wraps new TargetTransformInfo( + * TargetMachine::getScalarTargetTransformInfo, + * TargetMachine::getVectorTargetTransformInfo) + */ +LLVMPassRef LLVMCreateTargetTransformInfo(LLVMTargetMachineRef tmref); + +/* + * Wraps new TargetLibraryInfo + */ +LLVMPassRef LLVMCreateTargetLibraryInfo(const char * triple); + +/* + * Wraps llvm::getDefaultTargetTriple + */ +const char * LLVMDefaultTargetTriple(); + /* * Wraps Pass::lookupPassInfo and PassInfo::createPass */ @@ -74,6 +91,11 @@ const char * LLVMGetPassName(LLVMPassRef passref); */ void LLVMAddPass(LLVMPassManagerRef pmref, LLVMPassRef passref); +/* + * Wraps Pass::dump + */ +void LLVMPassDump(LLVMPassRef passref); + /* * Wraps llvm:InlineAsm::get */ @@ -176,6 +198,10 @@ LLVMTargetMachineRef LLVMTargetMachineLookup(const char *arch, const char *cpu, const char *features, int opt, std::string &error); +LLVMTargetMachineRef LLVMCreateTargetMachine(const char *arch, const char *cpu, + const char *features, int opt, + std::string &error); + /* * Wraps EngineBuilder::selectTarget */ diff --git a/llvm/passes.py b/llvm/passes.py index 71de28d..106b86d 100644 --- a/llvm/passes.py +++ b/llvm/passes.py @@ -209,6 +209,7 @@ class Pass(llvm.Ownable): ''' def __init__(self, ptr): llvm.Ownable.__init__(self, ptr, _core.LLVMDisposePass) + self.__name = '' @staticmethod def new(name): @@ -225,6 +226,8 @@ class Pass(llvm.Ownable): @property def name(self): + '''The name used in PassRegistry. + ''' return self.__name @property @@ -302,6 +305,26 @@ class TargetData(Pass): return _core.LLVMOffsetOfElement(self.ptr, ty.ptr, el) +#===----------------------------------------------------------------------=== +# Target Library Info +#===----------------------------------------------------------------------=== + +class TargetLibraryInfo(Pass): + @staticmethod + def new(triple): + ptr = _core.LLVMCreateTargetLibraryInfo(triple) + return TargetLibraryInfo(ptr) + + +#===----------------------------------------------------------------------=== +# Target Transform Info +#===----------------------------------------------------------------------=== + +class TargetTransformInfo(Pass): + @staticmethod + def new(targetmachine): + ptr = _core.LLVMCreateTargetTransformInfo(targetmachine.ptr) + return TargetTransformInfo(ptr) #===----------------------------------------------------------------------=== # Misc. From 7f9c91e2aa9811c33553023ea6fce28e54ea5f33 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 2 Jan 2013 17:37:14 -0600 Subject: [PATCH 125/516] Add simpler API for building pass-managers given a TargetMachine. --- llvm/passes.py | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/llvm/passes.py b/llvm/passes.py index 106b86d..5660a24 100644 --- a/llvm/passes.py +++ b/llvm/passes.py @@ -326,6 +326,56 @@ class TargetTransformInfo(Pass): ptr = _core.LLVMCreateTargetTransformInfo(targetmachine.ptr) return TargetTransformInfo(ptr) +#===----------------------------------------------------------------------=== +# Helpers +#===----------------------------------------------------------------------=== + +def build_pass_managers(tm, opt=2, loop_vectorize=False, vectorize=False, + inline_threshold=2000, pm=True, fpm=True, mod=None): + ''' + tm --- The TargetMachine for which the passes are optimizing for. + The TargetMachine must stay alive until the pass managers + are removed. + opt --- [0-3] Optimization level. Default to 2. + loop_vectorize --- [boolean] Whether to use loop-vectorizer. + vectorize --- [boolean] Whether to use basic-block vectorizer. + inline_threshold --- [int] Threshold for the inliner. + features --- [str] CPU feature string. + pm --- [boolean] Whether to build a module-level pass-manager. + fpm --- [boolean] Whether to build a function-level pass-manager. + mod --- [Module] The module object for the FunctionPassManager. + ''' + if pm: + pm = PassManager.new() + if fpm: + if not mod: + raise TypeError("Keyword 'mod' must be defined") + fpm = FunctionPassManager.new(mod) + + # Populate PassManagers with target specific passes + pmb = PassManagerBuilder.new() + pmb.opt_level = opt + pmb.vectorize = vectorize + pmb.loop_vectorize = loop_vectorize + if inline_threshold: + pmb.use_inliner_with_threshold(inline_threshold) + if pm: + pm.add(tm.target_data) + pm.add(TargetLibraryInfo.new(tm.triple)) + pm.add(TargetTransformInfo.new(tm)) + pmb.populate(pm) + + if fpm: + fpm.add(tm.target_data) + fpm.add(TargetLibraryInfo.new(tm.triple)) + fpm.add(TargetTransformInfo.new(tm)) + pmb.populate(fpm) + fpm.initialize() + + from collections import namedtuple + return namedtuple('passmanagers', ['pm', 'fpm'])(pm=pm, fpm=fpm) + + #===----------------------------------------------------------------------=== # Misc. #===----------------------------------------------------------------------=== From e2ec14bbb9fada32a4d18674a8ecc5d614ab28d9 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 2 Jan 2013 17:42:16 -0600 Subject: [PATCH 126/516] Add test to verify new pass APIs and loop-vectorizer. --- test/loopvectorize.c | 44 +++++ test/loopvectorize.ll | 369 ++++++++++++++++++++++++++++++++++++++++++ test/loopvectorize.py | 38 +++++ test/pass.py | 45 ++++++ 4 files changed, 496 insertions(+) create mode 100644 test/loopvectorize.c create mode 100644 test/loopvectorize.ll create mode 100644 test/loopvectorize.py create mode 100644 test/pass.py diff --git a/test/loopvectorize.c b/test/loopvectorize.c new file mode 100644 index 0000000..a46b633 --- /dev/null +++ b/test/loopvectorize.c @@ -0,0 +1,44 @@ +void ex1(float *A, float* B, float K, int start, int end) { + for (int i = start; i < end; ++i) + A[i] *= B[i] + K; +} + +void ex2(float *A, float* B, float K, int n) { + for (int i = 0; i < n; ++i) + A[i] *= B[i] + K; +} + +int ex3(int *A, int *B, int n) { + unsigned sum = 0; + for (int i = 0; i < n; ++i) + sum += A[i] + 5; + return sum; +} + +void ex4(float *A, float* B, float K, int n) { + for (int i = 0; i < n; ++i) + A[i] = i; +} + +int ex5(int *A, int *B, int n) { + unsigned sum = 0; + for (int i = 0; i < n; ++i) + if (A[i] > B[i]) + sum += A[i] + 5; + return sum; +} + +void ex6(int *A, int *B, int n) { + for (int i = n; i > 0; --i) + A[i] +=1; +} + +void ex7(int *A, int *B, int n, int k) { + for (int i = 0; i < n; ++i) + A[i*7] += B[i*k]; +} + +void ex8(int *A, char *B, int n, int k) { + for (int i = 0; i < n; ++i) + A[i] += 4 * B[i]; +} \ No newline at end of file diff --git a/test/loopvectorize.ll b/test/loopvectorize.ll new file mode 100644 index 0000000..8d651ca --- /dev/null +++ b/test/loopvectorize.ll @@ -0,0 +1,369 @@ +; ModuleID = 'loopvectorize.c' +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" +;target triple = "x86_64-apple-macosx10.8.0" +target triple = "x86-64-unknown-linux-gnu" + +define void @ex1(float* %A, float* %B, float %K, i32 %start, i32 %end) nounwind uwtable ssp { + %1 = alloca float*, align 8 + %2 = alloca float*, align 8 + %3 = alloca float, align 4 + %4 = alloca i32, align 4 + %5 = alloca i32, align 4 + %i = alloca i32, align 4 + store float* %A, float** %1, align 8 + store float* %B, float** %2, align 8 + store float %K, float* %3, align 4 + store i32 %start, i32* %4, align 4 + store i32 %end, i32* %5, align 4 + %6 = load i32* %4, align 4 + store i32 %6, i32* %i, align 4 + br label %7 + +;

-from llvm.passes import (PASS_PROMOTE_MEMORY_TO_REGISTER,
-                         PASS_INSTRUCTION_COMBINING,
+from llvm.passes import (PASS_MEM2REG,
+                         PASS_INSTCOMBINE,
                          PASS_REASSOCIATE,
                          PASS_GVN,
-                         PASS_CFG_SIMPLIFICATION)
+                         PASS_SIMPLIFYCFG)
 ...
 def main():
   # Set up the optimizer pipeline. Start with registering info about how the
   # target lays out data structures.
   g_llvm_pass_manager.add(g_llvm_executor.target_data)
   # Promote allocas to registers.
-  g_llvm_pass_manager.add(PASS_PROMOTE_MEMORY_TO_REGISTER)
+  g_llvm_pass_manager.add(PASS_MEM2REG)
   # Do simple "peephole" optimizations and bit-twiddling optzns.
-  g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING)
+  g_llvm_pass_manager.add(PASS_INSTCOMBINE)
   # Reassociate expressions.
   g_llvm_pass_manager.add(PASS_REASSOCIATE)
 
@@ -981,11 +981,11 @@ from llvm.ee import ExecutionEngine, TargetData from llvm.passes import FunctionPassManager from llvm.core import FCMP_ULT, FCMP_ONE -from llvm.passes import (PASS_PROMOTE_MEMORY_TO_REGISTER, - PASS_INSTRUCTION_COMBINING, +from llvm.passes import (PASS_MEM2REG, + PASS_INSTCOMBINE, PASS_REASSOCIATE, PASS_GVN, - PASS_CFG_SIMPLIFICATION) + PASS_SIMPLIFYCFG) ################################################################################ ## Globals @@ -1836,15 +1836,15 @@ def main(): # target lays out data structures. g_llvm_pass_manager.add(g_llvm_executor.target_data) # Promote allocas to registers. - g_llvm_pass_manager.add(PASS_PROMOTE_MEMORY_TO_REGISTER) + g_llvm_pass_manager.add(PASS_MEM2REG) # Do simple "peephole" optimizations and bit-twiddling optzns. - g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) + g_llvm_pass_manager.add(PASS_INSTCOMBINE) # Reassociate expressions. g_llvm_pass_manager.add(PASS_REASSOCIATE) # Eliminate Common SubExpressions. g_llvm_pass_manager.add(PASS_GVN) # Simplify the control flow graph (deleting unreachable blocks, etc). - g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) + g_llvm_pass_manager.add(PASS_SIMPLIFYCFG) g_llvm_pass_manager.initialize() From af6b0d7823a9bce8da9c70edf1080cdd0a993fb7 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 7 Jan 2013 14:00:11 -0600 Subject: [PATCH 137/516] Suppress warning for missing loop-vectorizer feature if user is not enabling it. --- llvm/passes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/passes.py b/llvm/passes.py index f7cf0fe..7cc2b31 100644 --- a/llvm/passes.py +++ b/llvm/passes.py @@ -92,7 +92,7 @@ class PassManagerBuilder(llvm.Handle): if llvm.version >= (3, 2): _core.LLVMPassManagerBuilderSetLoopVectorize(self.ptr, int(bool(enable))) - else: + elif enable: warnings.warn("Ignored. LLVM-3.1 & prior do not support loop vectorizer.") def _get_loop_vectorize(self): From 8ca0e79bd07e36d53c71340caf3a9adbe6a990ec Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 7 Jan 2013 15:14:46 -0600 Subject: [PATCH 138/516] Fix free/delete mismatch in LLVMGetBitcodeFromModule --- llvm/_core.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 5440960..e5c309c 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -226,12 +226,12 @@ _wLLVMGetBitcodeFromModule(PyObject *self, PyObject *args) if (!m ) return NULL; size_t len; - unsigned const char *ubytes = LLVMGetBitcodeFromModule(m, &len) ; + const unsigned char *ubytes = LLVMGetBitcodeFromModule(m, &len) ; if ( !ubytes ) Py_RETURN_NONE; const char *chars = reinterpret_cast(ubytes) ; PyObject *ret = PyBytes_FromStringAndSize(chars, len); - LLVMDisposeMessage(const_cast(chars)); + delete [] ubytes; return ret; LLVMPY_CATCH_ALL } From 5fc5ba2e6631608922fb4e008f7419704ae61af5 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 7 Jan 2013 16:31:09 -0600 Subject: [PATCH 139/516] Fix free/delete mismatch in LLVMGetNativeCodeFromModule --- llvm/_core.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index e5c309c..2c95a12 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -259,7 +259,7 @@ _wLLVMGetNativeCodeFromModule(PyObject * self, PyObject * args) const char *chars = reinterpret_cast(ubytes) ; PyObject * ret = PyBytes_FromStringAndSize(chars, len); - LLVMDisposeMessage(const_cast(chars)); + delete [] ubytes; return ret; LLVMPY_CATCH_ALL From 371e940c83cb1169a3329d6be32202bc2f8abf71 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 7 Jan 2013 14:25:58 -0600 Subject: [PATCH 140/516] Reverse finalizer --- llvm/__init__.py | 33 +++++++---------------- llvm/_utils/__init__.py | 0 llvm/_utils/finalizer.py | 58 ---------------------------------------- llvm/core.py | 18 ++++++------- llvm/ee.py | 25 ++++++++--------- llvm/passes.py | 16 +++++------ setup.py | 2 +- 7 files changed, 41 insertions(+), 111 deletions(-) delete mode 100644 llvm/_utils/__init__.py delete mode 100644 llvm/_utils/finalizer.py diff --git a/llvm/__init__.py b/llvm/__init__.py index 395e698..318ba9d 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -6,9 +6,7 @@ __version__ = '0.9.1' from weakref import WeakValueDictionary -from llvm._utils.finalizer import track as track_resource -from llvm._utils.finalizer import OwnerMixin as _OwnerMixin -from llvm import _core +import _core #===----------------------------------------------------------------------=== # LLVM Version @@ -33,26 +31,11 @@ class LLVMException(Exception): Exception.__init__(self, msg) -#===----------------------------------------------------------------------=== -# Resource Handle -#===----------------------------------------------------------------------=== - -class Handle(_OwnerMixin): - _finalizer = NotImplemented - - def __init__(self, ptr): - self.ptr = ptr - self._finalizer_track(self.ptr) - - @classmethod - def _finalize(cls, ptr): - cls._finalizer(ptr) - #===----------------------------------------------------------------------=== # Ownables #===----------------------------------------------------------------------=== -class Ownable(Handle): +class Ownable(object): """Objects that can be owned. Modules and Module Providers can be owned, i.e., the responsibility of @@ -61,21 +44,25 @@ class Ownable(Handle): is NOT intended for public use. """ - def __init__(self, ptr): - Handle.__init__(self, ptr) + def __init__(self, ptr, del_fn): + self.ptr = ptr self.owner = None + self.del_fn = del_fn def _own(self, owner): if self.owner: raise LLVMException("object already owned") self.owner = owner - self._finalizer_untrack(self.ptr) def _disown(self): if not self.owner: raise LLVMException("not owned") self.owner = None - self._finalizer_track(self.ptr) + + def __del__(self): + if not self.owner: + self.del_fn(self.ptr) + #===----------------------------------------------------------------------=== # Dummy owner, will not delete ownee. Be careful. diff --git a/llvm/_utils/__init__.py b/llvm/_utils/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/llvm/_utils/finalizer.py b/llvm/_utils/finalizer.py deleted file mode 100644 index 56df5b7..0000000 --- a/llvm/_utils/finalizer.py +++ /dev/null @@ -1,58 +0,0 @@ -''' -Modified C-level finalizer by Benjamin Peterson -Available at http://code.activestate.com/recipes/577242-calling-c-level-finalizers-without-__del__/ -''' -import sys -import traceback -import weakref - -class OwnerRef(weakref.ref): - """A simple weakref.ref subclass, so attributes can be added.""" - pass - -def _run_finalizer(ref): - """Internal weakref callback to run finalizers""" - del _finalize_refs[ref.owner] - for item, finalizer in ref.items: - try: - finalizer(item) - except Exception: - print>>sys.stderr, "Exception running {}:".format(finalizer) - traceback.print_exc() - -_finalize_refs = {} - -def track(owner, item, finalizer): - """Register an object for finalization. - - ``owner`` is the the object which is responsible for ``item``. - ``finalizer`` will be called with ``item`` as its only argument when - ``owner`` is destroyed by the garbage collector. - """ - if id(owner) in _finalize_refs: - ref = _finalize_refs[id(owner)] - else: - ref = OwnerRef(owner, _run_finalizer) - ref.owner = id(owner) - ref.items = [] - ref.items.append((item, finalizer)) - _finalize_refs[id(owner)] = ref - -def untrack(owner, item): - ref = _finalize_refs[id(owner)] - # search and remove the item from the ref - for i, (item_i, _) in enumerate(ref.items): - if item_i is item: - del ref.items[i] - # remove the ref if it is empty - if not ref.items: - del _finalize_refs[id(owner)] - -class OwnerMixin(object): - def _finalizer_track(self, item): - if not hasattr(self, '_finalize'): - raise AttributeError("%s must define a _finalize method" % self) - track(self, item, type(self)._finalize) - - def _finalizer_untrack(self, item): - untrack(self, item) diff --git a/llvm/core.py b/llvm/core.py index a6f7147..ba74ec2 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -397,9 +397,7 @@ class Module(llvm.Ownable, llvm.Cacheable): Use the static method `Module.new' instead. """ - llvm.Ownable.__init__(self, ptr) - - _finalizer = _core.LLVMDisposeModule + llvm.Ownable.__init__(self, ptr, _core.LLVMDisposeModule) def __str__(self): """Text representation of a module. @@ -1801,7 +1799,7 @@ def _make_value(ptr): # Builder #===----------------------------------------------------------------------=== -class Builder(llvm.Handle): +class Builder(object): @staticmethod def new(basic_block): @@ -1811,9 +1809,10 @@ class Builder(llvm.Handle): return b def __init__(self, ptr): - llvm.Handle.__init__(self, ptr) + self.ptr = ptr - _finalizer = _core.LLVMDisposeBuilder + def __del__(self): + _core.LLVMDisposeBuilder(self.ptr) def position_at_beginning(self, bblk): """Position the builder at the beginning of the given block. @@ -2302,7 +2301,7 @@ class Builder(llvm.Handle): # Memory buffer #===----------------------------------------------------------------------=== -class MemoryBuffer(llvm.Handle): +class MemoryBuffer(object): @staticmethod def from_file(fname): @@ -2323,9 +2322,10 @@ class MemoryBuffer(llvm.Handle): return (obj, "") def __init__(self, ptr): - llvm.Handle.__init__(self, ptr) + self.ptr = ptr - _finalizer = _core.LLVMDisposeMemoryBuffer + def __del__(self): + _core.LLVMDisposeMemoryBuffer(self.ptr) #===----------------------------------------------------------------------=== diff --git a/llvm/ee.py b/llvm/ee.py index 8d778df..4e1f97b 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -63,7 +63,7 @@ CM_LARGE = 5 # Generic value #===----------------------------------------------------------------------=== -class GenericValue(llvm.Handle): +class GenericValue(object): @staticmethod def int(ty, intval): @@ -106,9 +106,10 @@ class GenericValue(llvm.Handle): return GenericValue(ptr) def __init__(self, ptr): - llvm.Handle.__init__(self, ptr) + self.ptr = ptr - _finalizer = _core.LLVMDisposeGenericValue + def __del__(self): + _core.LLVMDisposeGenericValue(self.ptr) def as_int(self): return _core.LLVMGenericValueToInt(self.ptr, 0) @@ -134,7 +135,7 @@ def _unpack_generic_values(objlist): # Engine builder #===----------------------------------------------------------------------=== -class EngineBuilder(llvm.Handle): +class EngineBuilder(object): @staticmethod def new(module): core.check_is_module(module) @@ -143,10 +144,11 @@ class EngineBuilder(llvm.Handle): return EngineBuilder(obj, module) def __init__(self, ptr, module): - llvm.Handle.__init__(self, ptr) + self.ptr = ptr self._module = module - _finalizer = _core.LLVMDisposeEngineBuilder + def __del__(self): + _core.LLVMDisposeEngineBuilder(self.ptr) def force_jit(self): _core.LLVMEngineBuilderForceJIT(self.ptr) @@ -199,7 +201,7 @@ class EngineBuilder(llvm.Handle): # Execution engine #===----------------------------------------------------------------------=== -class ExecutionEngine(llvm.Handle): +class ExecutionEngine(object): @staticmethod def new(module, force_interpreter=False): @@ -211,10 +213,11 @@ class ExecutionEngine(llvm.Handle): return ExecutionEngine(ret, module) def __init__(self, ptr, module): - llvm.Handle.__init__(self, ptr) + self.ptr = ptr module._own(self) - _finalizer = _core.LLVMDisposeExecutionEngine + def __del__(self): + _core.LLVMDisposeExecutionEngine(self.ptr) def run_function(self, fn, args): core.check_is_function(fn) @@ -313,9 +316,7 @@ class TargetMachine(llvm.Ownable): return TargetMachine(ptr) def __init__(self, ptr): - llvm.Ownable.__init__(self, ptr) - - _finalizer = _core.LLVMDisposeTargetMachine + llvm.Ownable.__init__(self, ptr, _core.LLVMDisposeTargetMachine) def emit_assembly(self, module): '''returns byte string of the module as assembly code of the target machine diff --git a/llvm/passes.py b/llvm/passes.py index 7cc2b31..2b50aca 100644 --- a/llvm/passes.py +++ b/llvm/passes.py @@ -45,15 +45,16 @@ import warnings # Pass manager builder #===----------------------------------------------------------------------=== -class PassManagerBuilder(llvm.Handle): +class PassManagerBuilder(object): @staticmethod def new(): return PassManagerBuilder(_core.LLVMPassManagerBuilderCreate()) def __init__(self, ptr): - llvm.Handle.__init__(self, ptr) + self.ptr = ptr - _finalizer = _core.LLVMPassManagerBuilderDispose + def __del__(self): + _core.LLVMPassManagerBuilderDispose(self.ptr) def populate(self, pm): if isinstance(pm, FunctionPassManager): @@ -141,7 +142,7 @@ class PassManagerBuilder(llvm.Handle): # Pass manager #===----------------------------------------------------------------------=== -class PassManager(llvm.Handle): +class PassManager(object): @staticmethod def new(): @@ -150,7 +151,8 @@ class PassManager(llvm.Handle): def __init__(self, ptr): self.ptr = ptr - _finalizer = _core.LLVMDisposePassManager + def __del__(self): + _core.LLVMDisposePassManager(self.ptr) def add(self, pass_obj): '''Add a pass to the pass manager. @@ -206,11 +208,9 @@ class Pass(llvm.Ownable): '''Pass Inferface ''' def __init__(self, ptr): - llvm.Ownable.__init__(self, ptr) + llvm.Ownable.__init__(self, ptr, _core.LLVMDisposePass) self.__name = '' - _finalizer = _core.LLVMDisposePass - @staticmethod def new(name): '''Create a new pass by name. diff --git a/setup.py b/setup.py index d6d6a3b..94c9f95 100644 --- a/setup.py +++ b/setup.py @@ -131,7 +131,7 @@ setup( maintainer = 'Continuum Analytics, Inc.', maintainer_email = 'llvmpy@continuum.io', url = 'http://www.llvmpy.org/', - packages = ['llvm', 'llvm_cbuilder', 'llpython', 'llvm._utils'], + packages = ['llvm', 'llvm_cbuilder', 'llpython'], py_modules = ['llvm.core'], license = "BSD", classifiers = [ From 64880e7d69bf6de33117bdc0e7e9ad792cc7d720 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 8 Jan 2013 16:09:45 -0600 Subject: [PATCH 141/516] Fix invalid use of long for address. Use unsigned long long for cross-platform 64-bit int. --- llvm/_core.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 2c95a12..0dd1f7b 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -1348,16 +1348,13 @@ _wLLVMAddGlobalMapping(PyObject *self, PyObject *args) LLVMPY_TRY PyObject *obj_ee; PyObject *obj_val; - long int address; + unsigned long long address; - if (!PyArg_ParseTuple(args, "OOl", &obj_ee, &obj_val, &address)) + if (!PyArg_ParseTuple(args, "OOK", &obj_ee, &obj_val, &address)) return NULL; const LLVMExecutionEngineRef ee = pycap_get( obj_ee ); const LLVMValueRef val = pycap_get( obj_val ); - - if (address == (unsigned long long)-1) - return NULL; LLVMAddGlobalMapping(ee, val, (void*) address); From cc8b16b9ca307b00e18e795f79e7bd7de1dfcb68 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Tue, 8 Jan 2013 16:12:26 -0600 Subject: [PATCH 142/516] next version will be 0.10.0 --- llvm/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/__init__.py b/llvm/__init__.py index 318ba9d..b89e5a9 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -2,7 +2,7 @@ Common classes related to LLVM. """ -__version__ = '0.9.1' +__version__ = '0.10.0' from weakref import WeakValueDictionary From 9dadd9f1dff1e176da362bd40bde8833c16ebfaf Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 10 Jan 2013 09:44:00 -0600 Subject: [PATCH 143/516] Use 'L' format for unsigned long long to be consistent --- llvm/_core.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 0dd1f7b..7a87c5c 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -1350,7 +1350,7 @@ _wLLVMAddGlobalMapping(PyObject *self, PyObject *args) PyObject *obj_val; unsigned long long address; - if (!PyArg_ParseTuple(args, "OOK", &obj_ee, &obj_val, &address)) + if (!PyArg_ParseTuple(args, "OOL", &obj_ee, &obj_val, &address)) return NULL; const LLVMExecutionEngineRef ee = pycap_get( obj_ee ); From f731332360f3601f3b73e00fe113d97a15037b47 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 10 Jan 2013 16:43:14 -0600 Subject: [PATCH 144/516] Builder.branch will check if the basicblock has terminator when running in debug mode. --- llvm/core.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/llvm/core.py b/llvm/core.py index ba74ec2..3baae95 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -1865,6 +1865,8 @@ class Builder(object): def branch(self, bblk): check_is_basic_block(bblk) + for instr in self.basic_block.instructions: + assert not instr.is_terminator, "BasicBlock can only have one terminator" return _make_value(_core.LLVMBuildBr(self.ptr, bblk.ptr)) def cbranch(self, if_value, then_blk, else_blk): From ee62b0c96c5eca76522a6809354eac24569f1d3c Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 10 Jan 2013 16:52:25 -0600 Subject: [PATCH 145/516] Fix Module.link_in so it reports error and destory the other module when preserve=False --- llvm/_core.cpp | 2 +- llvm/core.py | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 7a87c5c..5acfa83 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -280,7 +280,7 @@ _wLLVMLinkModules(PyObject *self, PyObject *args) PyObject *ret; char *errmsg; - if (!LLVMLinkModules(dest, src, (LLVMLinkerMode)mode, &errmsg)) { + if (LLVMLinkModules(dest, src, (LLVMLinkerMode)mode, &errmsg)) { if (errmsg) { ret = PyUnicode_FromString(errmsg); LLVMDisposeMessage(errmsg); diff --git a/llvm/core.py b/llvm/core.py index 3baae95..66d7fbc 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -466,10 +466,12 @@ class Module(llvm.Ownable, llvm.Cacheable): check_is_module(other) if not preserve: other.forget() # remove it from object cache - _core.LLVMLinkModules(self.ptr, other.ptr, int(bool(preserve))) + result = _core.LLVMLinkModules(self.ptr, other.ptr, int(bool(preserve))) + if result is not None: + raise llvm.LLVMException(result) if not preserve: - # Do not try to destroy the other module's llvm::Module*. - other._own(llvm.DummyOwner()) + # Prevent user from using the other module + del other.ptr def get_type_named(self, name): """Return a Type object with the given name.""" @@ -1865,8 +1867,9 @@ class Builder(object): def branch(self, bblk): check_is_basic_block(bblk) - for instr in self.basic_block.instructions: - assert not instr.is_terminator, "BasicBlock can only have one terminator" + if __debug__: + for instr in self.basic_block.instructions: + assert not instr.is_terminator, "BasicBlock can only have one terminator" return _make_value(_core.LLVMBuildBr(self.ptr, bblk.ptr)) def cbranch(self, if_value, then_blk, else_blk): From a0a777e1aa46efb9ba569592a429b580caf4efcc Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 10 Jan 2013 16:58:50 -0600 Subject: [PATCH 146/516] llvm_cbuilder: global string should use LINKONCE_ODR --- llvm_cbuilder/builder.py | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 45e58d1..6aa5e1d 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -494,6 +494,7 @@ class CBuilder(object): # new constant string globalstr = mod.add_global_variable(content.type, name=name) globalstr.initializer = content + globalstr.linkage = lc.LINKAGE_LINKONCE_ODR globalstr.global_constant = True else: # compare existing content From 31fbc3ae64d4f406953626303b859f7a240d0c90 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 10 Jan 2013 17:10:40 -0600 Subject: [PATCH 147/516] Module.link_in should not delete other.ptr and should prevent the other.ptr from being destroyed --- llvm/core.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/llvm/core.py b/llvm/core.py index 66d7fbc..e4c60a7 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -471,7 +471,9 @@ class Module(llvm.Ownable, llvm.Cacheable): raise llvm.LLVMException(result) if not preserve: # Prevent user from using the other module - del other.ptr + other.ptr = None + # Use a dummy owner to prevent other.ptr to be deleted + other._own(llvm.DummyOwner()) def get_type_named(self, name): """Return a Type object with the given name.""" From 207254fe504fce32bff294ab6a685107acaebed0 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 10 Jan 2013 17:13:06 -0600 Subject: [PATCH 148/516] Make note about preverifier bug in LLVM that *.verify() will abort upon error --- llvm/core.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/llvm/core.py b/llvm/core.py index e4c60a7..4e59675 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -522,6 +522,8 @@ class Module(llvm.Ownable, llvm.Cacheable): Checks module for errors. Raises `llvm.LLVMException' on any error.""" ret = _core.LLVMVerifyModule(self.ptr) + # Note: LLVM has a bug in preverifier that will always abort + # the process upon failure. if ret != "": raise llvm.LLVMException(ret) @@ -1508,6 +1510,9 @@ class Function(GlobalValue): def verify(self): # Although we're just asking LLVM to return the success or # failure, it appears to print result to stderr and abort. + + # Note: LLVM has a bug in preverifier that will always abort + # the process upon failure. return _core.LLVMVerifyFunction(self.ptr) != 0 #===----------------------------------------------------------------------=== From 995d14e1d0734654c83d7534595f89228f815ef3 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Fri, 11 Jan 2013 11:20:24 -0600 Subject: [PATCH 149/516] fix (Windows) issue #42 --- llvm-config-win32.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/llvm-config-win32.py b/llvm-config-win32.py index 2370625..d8fa5c1 100644 --- a/llvm-config-win32.py +++ b/llvm-config-win32.py @@ -34,6 +34,8 @@ LLVMJIT LLVMLinker LLVMMC LLVMMCParser +LLVMObject +LLVMRuntimeDyld LLVMScalarOpts LLVMSelectionDAG LLVMSupport From 9874d8048db7c49ab37e253e58040ba8fbe6bfcb Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Sun, 13 Jan 2013 17:00:17 -0600 Subject: [PATCH 150/516] Run 2to3 for python 3 install --- setup.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/setup.py b/setup.py index 94c9f95..eeaf162 100644 --- a/setup.py +++ b/setup.py @@ -118,6 +118,21 @@ kwds = dict(ext_modules = [Extension( extra_objects = objs_core, extra_link_args = extra_link_args)]) +def run_2to3(): + import lib2to3.refactor + from distutils.command.build_py import build_py_2to3 as build_py + print("Installing 2to3 fixers") + # need to convert sources to Py3 on installation + fixes = lib2to3.refactor.get_fixers_from_package("lib2to3.fixes") + #fixes = [fix for fix in fixes + # if fix.split('fix_')[-1] not in ('next',) + #] + + kwds["cmdclass"] = {"build_py": build_py} + +if sys.version_info[0] >= 3: + run_2to3() + # Read version from llvm/__init__.py pat = re.compile(r'__version__\s*=\s*(\S+)', re.M) data = open('llvm/__init__.py').read() From 8b58488bbd2a647e879c17493107cb8125bc9d48 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 14 Jan 2013 10:30:46 -0600 Subject: [PATCH 151/516] Add GEP inbounds --- llvm/_core.cpp | 4 ++++ llvm/core.py | 9 ++++++--- llvm_cbuilder/builder.py | 9 ++++----- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 5acfa83..6f13c61 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -878,6 +878,9 @@ _wrap_objobj2obj(LLVMBuildFree, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) _wrap_objobjstr2obj(LLVMBuildLoad, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) _wrap_objobjobj2obj(LLVMBuildStore, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) _wrap_objobjliststr2obj(LLVMBuildGEP, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) +_wrap_objobjliststr2obj(LLVMBuildInBoundsGEP, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) + + _wrap_objint2none(LLVMLdSetAlignment, LLVMValueRef) _wrap_objint2none(LLVMStSetAlignment, LLVMValueRef) @@ -1959,6 +1962,7 @@ static PyMethodDef core_methods[] = { _method( LLVMBuildLoad ) _method( LLVMBuildStore ) _method( LLVMBuildGEP ) + _method( LLVMBuildInBoundsGEP ) _method( LLVMLdSetAlignment ) _method( LLVMStSetAlignment ) diff --git a/llvm/core.py b/llvm/core.py index 4e59675..fa9dc77 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -2066,11 +2066,14 @@ class Builder(object): inst.set_volatile(volatile) return inst - def gep(self, ptr, indices, name=""): + def gep(self, ptr, indices, name="", inbounds=False): check_is_value(ptr) index_ptrs = unpack_values(indices) - return _make_value( - _core.LLVMBuildGEP(self.ptr, ptr.ptr, index_ptrs, name)) + if inbounds: + ret = _core.LLVMBuildInBoundsGEP(self.ptr, ptr.ptr, index_ptrs, name) + else: + ret = _core.LLVMBuildGEP(self.ptr, ptr.ptr, index_ptrs, name) + return _make_value(ret) # casts and extensions diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 6aa5e1d..64083b1 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -818,8 +818,7 @@ class CDefinition(object): if optimize: fpm = lp.FunctionPassManager.new(module) pmb = lp.PassManagerBuilder.new() - pmb.opt_level = 3 - pmb.vectorize = True + pmb.opt_level = 2 pmb.populate(fpm) fpm.run(func) @@ -1135,11 +1134,11 @@ class PointerIndexing(OperatorMixin): # Case #1: A[idx:] get pointer offset by idx if not idx.step and not idx.stop: idx = _auto_coerce_index(self.parent, idx.start) - ptr = bldr.gep(self.value, [idx.value]) + ptr = bldr.gep(self.value, [idx.value], inbounds=True) return CArray(self.parent, ptr) else: # return an variable at idx idx = _auto_coerce_index(self.parent, idx) - ptr = bldr.gep(self.value, [idx.value]) + ptr = bldr.gep(self.value, [idx.value], inbounds=True) return CVar(self.parent, ptr) def __setitem__(self, idx, val): @@ -1184,7 +1183,7 @@ class PointerValue(PointerIndexing, PointerCasting): inst = self.parent.builder.store(val.value, self.value, **kws) if nontemporal: self.parent.set_memop_non_temporal(inst) - + return inst def atomic_load(self, ordering, align=None, crossthread=True): '''atomic load memory for pointer types From 91a10e6a8e655b3c7b1e5ef117940edb0e48a560 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 14 Jan 2013 20:34:29 -0600 Subject: [PATCH 152/516] Fix TargetMachine ownership in EngineBuilder. --- llvm/ee.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/ee.py b/llvm/ee.py index 4e1f97b..b6ce31d 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -188,7 +188,7 @@ class EngineBuilder(object): raise llvm.LLVMException(ret) engine = ExecutionEngine(ret, self._module) if tm: - tm._own(owner=engine) + tm._own(owner=llvm.DummyOwner) return engine def select_target(self): From bdac4a809d120b4f89249c6e94a0daed87e575b8 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 16 Jan 2013 17:52:33 -0600 Subject: [PATCH 153/516] Add lazy compilation option. Unify execution engine creation through engine-builder internally. --- llvm/_core.cpp | 69 +++++++++++++++++++++++++++----------------------- llvm/ee.py | 14 +++++----- llvm/extra.cpp | 5 ++++ llvm/extra.h | 5 ++++ 4 files changed, 55 insertions(+), 38 deletions(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 6f13c61..435ebf0 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -1279,37 +1279,38 @@ _wLLVMEngineBuilderCreateTM(PyObject *self, PyObject *args) /* Execution Engine */ /*===----------------------------------------------------------------------===*/ -static PyObject * -_wLLVMCreateExecutionEngine(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - PyObject *obj; - int force_interpreter; - char *outmsg = 0; - int error; - - if (!PyArg_ParseTuple(args, "Oi", &obj, &force_interpreter)) - return NULL; - - const LLVMModuleRef mod = pycap_get( obj ) ; - - LLVMExecutionEngineRef ee; - if (force_interpreter) - error = LLVMCreateInterpreterForModule(&ee, mod, &outmsg); - else - error = LLVMCreateJITCompilerForModule(&ee, mod, 1 /*fast*/, &outmsg); - - PyObject *ret; - if (error) { - ret = PyUnicode_FromString(outmsg); - LLVMDisposeMessage(outmsg); - } else { - ret = pycap_new(ee); - } - - return ret; - LLVMPY_CATCH_ALL -} +// Use EngineBuilder +//static PyObject * +//_wLLVMCreateExecutionEngine(PyObject *self, PyObject *args) +//{ +// LLVMPY_TRY +// PyObject *obj; +// int force_interpreter; +// char *outmsg = 0; +// int error; +// +// if (!PyArg_ParseTuple(args, "Oi", &obj, &force_interpreter)) +// return NULL; +// +// const LLVMModuleRef mod = pycap_get( obj ) ; +// +// LLVMExecutionEngineRef ee; +// if (force_interpreter) +// error = LLVMCreateInterpreterForModule(&ee, mod, &outmsg); +// else +// error = LLVMCreateJITCompilerForModule(&ee, mod, 1 /*fast*/, &outmsg); +// +// PyObject *ret; +// if (error) { +// ret = PyUnicode_FromString(outmsg); +// LLVMDisposeMessage(outmsg); +// } else { +// ret = pycap_new(ee); +// } +// +// return ret; +// LLVMPY_CATCH_ALL +//} static PyObject * _wLLVMGetPointerToFunction(PyObject *self, PyObject *args) @@ -1405,6 +1406,8 @@ _wLLVMRemoveModule2(PyObject *self, PyObject *args) } _wrap_obj2none(LLVMDisposeExecutionEngine, LLVMExecutionEngineRef) +_wrap_objint2none(LLVMExecutionEngineDisableLazyCompilation, + LLVMExecutionEngineRef) _wrap_objobjlist2obj(LLVMRunFunction2, LLVMExecutionEngineRef, LLVMValueRef, LLVMGenericValueRef, LLVMGenericValueRef) _wrap_obj2obj(LLVMGetExecutionEngineTargetData, LLVMExecutionEngineRef, @@ -2116,8 +2119,10 @@ static PyMethodDef core_methods[] = { _method( LLVMEngineBuilderCreateTM ) /* Execution Engine */ - _method( LLVMCreateExecutionEngine ) +// Use EngineBuilder instead +// _method( LLVMCreateExecutionEngine ) _method( LLVMDisposeExecutionEngine ) + _method( LLVMExecutionEngineDisableLazyCompilation ) _method( LLVMRunFunction2 ) _method( LLVMGetPointerToFunction ) _method( LLVMGetPointerToGlobal ) diff --git a/llvm/ee.py b/llvm/ee.py index b6ce31d..12c987a 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -205,12 +205,10 @@ class ExecutionEngine(object): @staticmethod def new(module, force_interpreter=False): - core.check_is_module(module) - _util.check_is_unowned(module) - ret = _core.LLVMCreateExecutionEngine(module.ptr, int(force_interpreter)) - if isinstance(ret, str): - raise llvm.LLVMException(ret) - return ExecutionEngine(ret, module) + eb = EngineBuilder.new(module) + if force_interpreter: + eb.force_interpreter() + return eb.create() def __init__(self, ptr, module): self.ptr = ptr @@ -219,6 +217,10 @@ class ExecutionEngine(object): def __del__(self): _core.LLVMDisposeExecutionEngine(self.ptr) + def disable_lazy_compilation(self, disabled=True): + _core.LLVMExecutionEngineDisableLazyCompilation(self.ptr, + int(bool(disabled))) + def run_function(self, fn, args): core.check_is_function(fn) ptrs = _unpack_generic_values(args) diff --git a/llvm/extra.cpp b/llvm/extra.cpp index e200eec..726ebab 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -1254,6 +1254,11 @@ unsigned LLVMLoadLibraryPermanently(const char* filename, char **errmsg) return 1; } +void LLVMExecutionEngineDisableLazyCompilation(LLVMExecutionEngineRef ee, int flag) +{ + llvm::unwrap(ee)->DisableLazyCompilation(flag); +} + void *LLVMGetPointerToFunction(LLVMExecutionEngineRef ee, LLVMValueRef fn) { llvm::ExecutionEngine *eep = llvm::unwrap(ee); diff --git a/llvm/extra.h b/llvm/extra.h index 6080bdb..829de23 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -590,6 +590,11 @@ unsigned char *LLVMGetBitcodeFromModule(LLVMModuleRef module, size_t *len); * use, via LLVMDisposeMessage(). */ unsigned LLVMLoadLibraryPermanently(const char* filename, char **errmsg); +/* Wraps llvm::ExecutionEngine::DisableLazyCompilation(bool) + */ +void LLVMExecutionEngineDisableLazyCompilation(LLVMExecutionEngineRef ee, + int flag); + /* Wraps llvm::ExecutionEngine::getPointerToFunction(). Returns a pointer * to the JITted function. */ void *LLVMGetPointerToFunction(LLVMExecutionEngineRef ee, LLVMValueRef fn); From 5d4759bd5503b0caa31272c274206bb051ed703f Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 16 Jan 2013 18:11:05 -0600 Subject: [PATCH 154/516] Workaround for AVX on old kernels. --- llvm/ee.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/llvm/ee.py b/llvm/ee.py index 12c987a..8ca24d2 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -37,6 +37,7 @@ import llvm.core as core # module, function etc. import llvm._core as _core # C wrappers import llvm._util as _util # utility functions import logging +import os logger = logging.getLogger(__name__) @@ -44,6 +45,29 @@ logger = logging.getLogger(__name__) # re-export TargetData for backward compatibility. from llvm.passes import TargetData +def _detect_avx_support(): + '''FIXME: This is a workaround for AVX support. + ''' + disable_avx_detect = int(os.environ.get('LLVMPY_DISABLE_AVX_DETECT', 0)) + if disable_avx_detect: + return False # enable AVX if user disable AVX detect + force_disable_avx = int(os.environ.get('LLVMPY_FORCE_DISABLE_AVX', 0)) + if force_disable_avx: + return True # force disable AVX + # auto-detect avx + try: + lines = open('/proc/cpuinfo').read().splitlines() + except IOError: + return True # disable AVX if no /proc/cpuinfo is found + flags = [l for l in lines if l.lstrip().startswith('flags')] + if not flags: + return True # disable AVX if flags are empty + if 'avx' in flags[0]: + return False # enable AVX if flags contain AVX + return True # disable AVX if flags does not have AVX + +FORCE_DISABLE_AVX = _detect_avx_support() + #===----------------------------------------------------------------------=== # Enumerations #===----------------------------------------------------------------------=== @@ -146,6 +170,7 @@ class EngineBuilder(object): def __init__(self, ptr, module): self.ptr = ptr self._module = module + self.__has_mattrs = False def __del__(self): _core.LLVMDisposeEngineBuilder(self.ptr) @@ -171,6 +196,11 @@ class EngineBuilder(object): e.g: +sse,-3dnow ''' + self.__has_mattrs = True + if FORCE_DISABLE_AVX: + if 'avx' not in map(lambda x: x.strip(), string.split(',')): + # User did not override + string += ',-avx' _core.LLVMEngineBuilderSetMAttrs(self.ptr, string.replace(',', ' ')) return self @@ -179,6 +209,9 @@ class EngineBuilder(object): tm --- Optional. Provide a TargetMachine. Ownership is transfered to the returned execution engine. ''' + if not self.__has_mattrs and FORCE_DISABLE_AVX: + self.mattrs('-avx') + if tm: _util.check_is_unowned(tm) ret = _core.LLVMEngineBuilderCreateTM(self.ptr, tm.ptr) From 00b3449443b0af6e5b8cf0dc83390c606d45cd23 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 16 Jan 2013 19:36:26 -0600 Subject: [PATCH 155/516] Try PY_LONG_LONG replacement for unsigned long long --- llvm/_core.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 435ebf0..efff340 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -1352,9 +1352,10 @@ _wLLVMAddGlobalMapping(PyObject *self, PyObject *args) LLVMPY_TRY PyObject *obj_ee; PyObject *obj_val; - unsigned long long address; + unsigned PY_LONG_LONG address; + assert(sizeof(address) >= sizeof(void*)); - if (!PyArg_ParseTuple(args, "OOL", &obj_ee, &obj_val, &address)) + if (!PyArg_ParseTuple(args, "OOK", &obj_ee, &obj_val, &address)) return NULL; const LLVMExecutionEngineRef ee = pycap_get( obj_ee ); From 0f3dfb85d440e20d290a0f0db801bdf0289e1125 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Wed, 16 Jan 2013 19:56:42 -0600 Subject: [PATCH 156/516] simplified avx detection on Linux --- llvm/ee.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/llvm/ee.py b/llvm/ee.py index 8ca24d2..15ede87 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -56,14 +56,12 @@ def _detect_avx_support(): return True # force disable AVX # auto-detect avx try: - lines = open('/proc/cpuinfo').read().splitlines() + for line in open('/proc/cpuinfo'): + if line.lstrip().startswith('flags') and 'avx' in line.split(): + # enable AVX if flags contain AVX + return False except IOError: - return True # disable AVX if no /proc/cpuinfo is found - flags = [l for l in lines if l.lstrip().startswith('flags')] - if not flags: - return True # disable AVX if flags are empty - if 'avx' in flags[0]: - return False # enable AVX if flags contain AVX + pass # disable AVX if no /proc/cpuinfo is found return True # disable AVX if flags does not have AVX FORCE_DISABLE_AVX = _detect_avx_support() From 2d3889111b544aae9fb2cb28f35172cfcf99d3ec Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 17 Jan 2013 13:16:48 -0600 Subject: [PATCH 157/516] Cleanup usage of long long; replace with PY_LONG_LONG. For address, use PyLong_AsVoidPtr. --- llvm/_core.cpp | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index efff340..18b39f3 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -88,12 +88,12 @@ template <> PyObject* pycap_new(LLVMByteOrdering i) return PyLong_FromLong(static_cast(i)); } -template <> PyObject* pycap_new(unsigned long long ull) +template <> PyObject* pycap_new(unsigned PY_LONG_LONG ull) { return PyLong_FromUnsignedLongLong(ull); } -template <> PyObject* pycap_new(long long ll) +template <> PyObject* pycap_new(PY_LONG_LONG ll) { return PyLong_FromLongLong(ll); } @@ -483,7 +483,7 @@ _wLLVMConstInt(PyObject *self, PyObject *args) { LLVMPY_TRY PyObject *obj; - unsigned long long n; + unsigned PY_LONG_LONG n; int sign_extend; if (!PyArg_ParseTuple(args, "OKi", &obj, &n, &sign_extend)) @@ -1352,16 +1352,19 @@ _wLLVMAddGlobalMapping(PyObject *self, PyObject *args) LLVMPY_TRY PyObject *obj_ee; PyObject *obj_val; - unsigned PY_LONG_LONG address; - assert(sizeof(address) >= sizeof(void*)); + PyObject *obj_long; + void* address; - if (!PyArg_ParseTuple(args, "OOK", &obj_ee, &obj_val, &address)) + if (!PyArg_ParseTuple(args, "OOO", &obj_ee, &obj_val, &obj_long)) return NULL; + address = PyLong_AsVoidPtr(obj_long); + if (PyErr_Occurred()) return NULL; + const LLVMExecutionEngineRef ee = pycap_get( obj_ee ); const LLVMValueRef val = pycap_get( obj_val ); - LLVMAddGlobalMapping(ee, val, (void*) address); + LLVMAddGlobalMapping(ee, val, address); Py_RETURN_NONE; @@ -1430,11 +1433,11 @@ _wLLVMCreateGenericValueOfInt(PyObject *self, PyObject *args) { LLVMPY_TRY PyObject *obj1; - unsigned long long n; + unsigned PY_LONG_LONG n; int is_signed; LLVMGenericValueRef gv; - if (!PyArg_ParseTuple(args, "OLi", &obj1, &n, &is_signed)) + if (!PyArg_ParseTuple(args, "OKi", &obj1, &n, &is_signed)) return NULL; const LLVMTypeRef ty = pycap_get( obj1 ) ; @@ -1468,10 +1471,10 @@ _wLLVMCreateGenericValueOfPointer(PyObject *self, PyObject *args) LLVMPY_TRY // PyObject *obj1; // LLVMTypeRef ty; //unused? - unsigned long long n_; + unsigned PY_LONG_LONG n_; size_t n; - if (!PyArg_ParseTuple(args, "L", &n_)) + if (!PyArg_ParseTuple(args, "K", &n_)) return NULL; n=n_; @@ -1487,7 +1490,7 @@ _wLLVMGenericValueToInt(PyObject *self, PyObject *args) LLVMPY_TRY PyObject *obj1; int is_signed; - unsigned long long val; + unsigned PY_LONG_LONG val; if (!PyArg_ParseTuple(args, "Oi", &obj1, &is_signed)) return NULL; @@ -1496,7 +1499,7 @@ _wLLVMGenericValueToInt(PyObject *self, PyObject *args) val = LLVMGenericValueToInt(gv, is_signed); return is_signed ? - PyLong_FromLongLong((long long)val) : + PyLong_FromLongLong((PY_LONG_LONG)val) : PyLong_FromUnsignedLongLong(val); LLVMPY_CATCH_ALL } From ea315a58cbd24ca376dac11db2c94175c0d174c8 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 17 Jan 2013 14:13:03 -0600 Subject: [PATCH 158/516] Workaround for LLVM-3.2 invalid reporting of host triple on darwin9.8 --- llvm/ee.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/llvm/ee.py b/llvm/ee.py index 15ede87..2b9571f 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -214,7 +214,10 @@ class EngineBuilder(object): _util.check_is_unowned(tm) ret = _core.LLVMEngineBuilderCreateTM(self.ptr, tm.ptr) else: - ret = _core.LLVMEngineBuilderCreate(self.ptr) + # Fix wrong host-triple reported by LLVM 3.2 on darwin9.8 + # ret = _core.LLVMEngineBuilderCreate(self.ptr) + tm = self.select_target() + ret = _core.LLVMEngineBuilderCreateTM(self.ptr, tm.ptr) if isinstance(ret, str): raise llvm.LLVMException(ret) engine = ExecutionEngine(ret, self._module) @@ -224,9 +227,11 @@ class EngineBuilder(object): def select_target(self): '''get the corresponding target machine - ''' - ptr = _core.LLVMTargetMachineFromEngineBuilder(self.ptr) - return TargetMachine(ptr) + ''' + # Fix wrong host-triple reported by LLVM 3.2 on darwin9.8 + # ptr = _core.LLVMTargetMachineFromEngineBuilder(self.ptr) + # return TargetMachine(ptr) + return TargetMachine.new(cm=CM_JITDEFAULT) #===----------------------------------------------------------------------=== # Execution engine From d0fd53fda33030c15ff4a6c4e596f1ab7938ac79 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 17 Jan 2013 14:22:27 -0600 Subject: [PATCH 159/516] Revert "Workaround for LLVM-3.2 invalid reporting of host triple on darwin9.8" This reverts commit ea315a58cbd24ca376dac11db2c94175c0d174c8. --- llvm/ee.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/llvm/ee.py b/llvm/ee.py index 2b9571f..15ede87 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -214,10 +214,7 @@ class EngineBuilder(object): _util.check_is_unowned(tm) ret = _core.LLVMEngineBuilderCreateTM(self.ptr, tm.ptr) else: - # Fix wrong host-triple reported by LLVM 3.2 on darwin9.8 - # ret = _core.LLVMEngineBuilderCreate(self.ptr) - tm = self.select_target() - ret = _core.LLVMEngineBuilderCreateTM(self.ptr, tm.ptr) + ret = _core.LLVMEngineBuilderCreate(self.ptr) if isinstance(ret, str): raise llvm.LLVMException(ret) engine = ExecutionEngine(ret, self._module) @@ -227,11 +224,9 @@ class EngineBuilder(object): def select_target(self): '''get the corresponding target machine - ''' - # Fix wrong host-triple reported by LLVM 3.2 on darwin9.8 - # ptr = _core.LLVMTargetMachineFromEngineBuilder(self.ptr) - # return TargetMachine(ptr) - return TargetMachine.new(cm=CM_JITDEFAULT) + ''' + ptr = _core.LLVMTargetMachineFromEngineBuilder(self.ptr) + return TargetMachine(ptr) #===----------------------------------------------------------------------=== # Execution engine From c7320e84de2e3ebcc964987bd39050b0604debdd Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 17 Jan 2013 16:08:47 -0600 Subject: [PATCH 160/516] Add tests for cpu features support --- llvm/test_llvmpy.py | 54 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 9b6b1a6..1f2279f 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -859,6 +859,60 @@ class TestOpaque(unittest.TestCase): tests.append(TestOpaque) +# --------------------------------------------------------------------------- +class TestCPUSupport(unittest.TestCase): + + def _build_test_module(self): + 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) + 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.float(), 1.234) + retval = ee.run_function(func, [arg]) + + golden = math.sin(1.234) + answer = retval.as_real(Type.float()) + 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_support(self): + features = 'sse2', 'sse3', 'sse41', 'sse42', 'avx' + n = len(features) + for i in range(n): + mattrs = ','.join(map(lambda s: '-%s' % s, features[i:])) + print 'disable mattrs', mattrs + self._template(mattrs) + +tests.append(TestCPUSupport) + # --------------------------------------------------------------------------- class TestIntrinsic(unittest.TestCase): From 1daec8ff637f3914c0ce5a0f46dc97c1af807dc7 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 17 Jan 2013 16:43:27 -0600 Subject: [PATCH 161/516] Add simpler intrinsic tests for debug llvm-3.2 on windows 32-bit --- llvm/test_llvmpy.py | 52 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 1f2279f..256e3e0 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -913,6 +913,58 @@ class TestCPUSupport(unittest.TestCase): tests.append(TestCPUSupport) +# --------------------------------------------------------------------------- +class TestIntrinsicBasic(unittest.TestCase): + + def _build_module(self): + mod = Module.new('test') + + float = Type.float() + functy = Type.function( float, [float] ) + func = mod.add_function(functy, "mysin") + block = func.append_basic_block("entry") + b = Builder.new(block) + + return mod, func, b + + def _template(self, mod, func, pyfunc): + ee = le.ExecutionEngine.new(mod) + + arg = le.GenericValue.real(Type.float(), 1.234) + retval = ee.run_function(func, [arg]) + + golden = pyfunc(1.234) + answer = retval.as_real(Type.float()) + self.assertTrue(abs(answer - golden) / golden < 1e-7) + + def test_sqrt(self): + mod, func, b = self._build_module() + intr = Function.intrinsic(mod, lc.INTR_SQRT, [Type.float()]) + b.ret(b.call(intr, func.args)) + self._template(mod, func, math.sqrt) + + def test_cos(self): + mod, func, b = self._build_module() + intr = Function.intrinsic(mod, lc.INTR_COS, [Type.float()]) + b.ret(b.call(intr, func.args)) + self._template(mod, func, math.cos) + + def test_sin(self): + mod, func, b = self._build_module() + intr = Function.intrinsic(mod, lc.INTR_SIN, [Type.float()]) + b.ret(b.call(intr, func.args)) + self._template(mod, func, math.sin) + + def test_powi(self): + mod, func, b = self._build_module() + intr = Function.intrinsic(mod, lc.INTR_POWI, [Type.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) + # --------------------------------------------------------------------------- class TestIntrinsic(unittest.TestCase): From 343efc6379747c95e039f503f8d07fa1b82bfeca Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 17 Jan 2013 16:44:01 -0600 Subject: [PATCH 162/516] C-wrapper includes file and lineno when unknown exceptino is encountered --- llvm/wrap.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/llvm/wrap.h b/llvm/wrap.h index f19c80b..ce2dd88 100644 --- a/llvm/wrap.h +++ b/llvm/wrap.h @@ -60,6 +60,7 @@ #include "llvm_c_extra.h" #include +#include class py_exception: public std::exception{}; @@ -75,9 +76,10 @@ class py_exception: public std::exception{}; PyErr_SetString(PyExc_RuntimeError, e.what()); \ return NULL; \ } catch (...) { \ - PyErr_SetString(PyExc_RuntimeError, \ - "Unknown exception"); \ - return NULL; \ + std::ostringstream oss; \ + oss << "Unknown exception " << __FILE__ << ":" << __LINE__; \ + PyErr_SetString(PyExc_RuntimeError, oss.str().c_str()); \ + return NULL; \ } /*===----------------------------------------------------------------------===*/ From 7451f6ca4a2882b6d4ce9f6f4b03787ac73ebf60 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 17 Jan 2013 17:12:11 -0600 Subject: [PATCH 163/516] Add tests for double-precision intrinsics --- llvm/test_llvmpy.py | 72 +++++++++++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 22 deletions(-) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 256e3e0..f177af3 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -916,48 +916,76 @@ tests.append(TestCPUSupport) # --------------------------------------------------------------------------- class TestIntrinsicBasic(unittest.TestCase): - def _build_module(self): + def _build_module(self, float): mod = Module.new('test') - - float = Type.float() - functy = Type.function( float, [float] ) - func = mod.add_function(functy, "mysin") + 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 ee = le.ExecutionEngine.new(mod) - - arg = le.GenericValue.real(Type.float(), 1.234) + arg = le.GenericValue.real(float, 1.234) retval = ee.run_function(func, [arg]) - golden = pyfunc(1.234) - answer = retval.as_real(Type.float()) + answer = retval.as_real(float) self.assertTrue(abs(answer - golden) / golden < 1e-7) - def test_sqrt(self): - mod, func, b = self._build_module() - intr = Function.intrinsic(mod, lc.INTR_SQRT, [Type.float()]) + 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_cos(self): - mod, func, b = self._build_module() - intr = Function.intrinsic(mod, lc.INTR_COS, [Type.float()]) + 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): + 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_sin(self): - mod, func, b = self._build_module() - intr = Function.intrinsic(mod, lc.INTR_SIN, [Type.float()]) + 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): + 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_powi(self): - mod, func, b = self._build_module() - intr = Function.intrinsic(mod, lc.INTR_POWI, [Type.float()]) + 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) From 206d512c10dbf97446b740903869c3810d3e5005 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 17 Jan 2013 18:59:20 -0600 Subject: [PATCH 164/516] Fix LLVMLinkModules for LLVM-3.1 --- llvm/_core.cpp | 4 ++-- llvm/extra.cpp | 24 +++++++++--------------- llvm/extra.h | 7 +++---- 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 18b39f3..db5287e 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -278,8 +278,8 @@ _wLLVMLinkModules(PyObject *self, PyObject *args) const LLVMModuleRef dest = pycap_get(dest_obj ) ; const LLVMModuleRef src = pycap_get(src_obj) ; - PyObject *ret; - char *errmsg; + PyObject *ret = NULL; + char *errmsg = NULL; if (LLVMLinkModules(dest, src, (LLVMLinkerMode)mode, &errmsg)) { if (errmsg) { ret = PyUnicode_FromString(errmsg); diff --git a/llvm/extra.cpp b/llvm/extra.cpp index 726ebab..7b6c064 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -1191,21 +1191,15 @@ LLVMModuleRef LLVMGetModuleFromBitcode(const char *bitcode, unsigned bclen, } #if LLVM_VERSION_MAJOR <= 3 && LLVM_VERSION_MINOR < 2 -unsigned LLVMLinkModules(LLVMModuleRef dest, LLVMModuleRef src, unsigned int mode, - char **out) -{ - llvm::Module *sourcep = llvm::unwrap(src); - assert(sourcep); - llvm::Module *destinationp = llvm::unwrap(dest); - assert(destinationp); - - std::string msg; - if (llvm::Linker::LinkModules(destinationp, sourcep, mode, &msg)) { - *out = strdup(msg.c_str()); - return 0; - } - - return 1; +// Shamelessly copy from LLVM-3.2 +unsigned LLVMLinkModules(LLVMModuleRef Dest, LLVMModuleRef Src, + int Mode, char **OutMessages) { + std::string Messages; + unsigned Result = Linker::LinkModules(unwrap(Dest), unwrap(Src), Mode, + OutMessages? &Messages : 0); + if (OutMessages) + *OutMessages = strdup(Messages.c_str()); + return Result; } #endif diff --git a/llvm/extra.h b/llvm/extra.h index 829de23..b734f1b 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -46,10 +46,9 @@ #endif #include "llvm-c/Transforms/PassManagerBuilder.h" - - #include "llvm_c_extra.h" + #ifdef __cplusplus extern "C" { #endif @@ -578,8 +577,8 @@ LLVMModuleRef LLVMGetModuleFromBitcode(const char *bc, unsigned bclen, /* Wraps llvm::Linker::LinkModules(). Returns 0 on failure (with errmsg * filled in) and 1 on success. Dispose error message after use with * LLVMDisposeMessage(). */ -unsigned LLVMLinkModules(LLVMModuleRef dest, LLVMModuleRef src, - unsigned int, char **errmsg); +unsigned LLVMLinkModules(LLVMModuleRef dest, LLVMModuleRef src, int mode, + char **errmsg); #endif /* Returns pointer to a heap-allocated block of `*len' bytes containing bit code * for the given module. NULL on error. */ From ca1a23dff5fa5f7bac843fa67424eb2f07338630 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Fri, 18 Jan 2013 11:26:37 -0600 Subject: [PATCH 165/516] skip failing tests on 32-bit Windows --- llvm/test_llvmpy.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index f177af3..7c547e0 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -10,6 +10,7 @@ import subprocess import tempfile is_py3k = bool(sys.version_info[0] == 3) +BITS = tuple.__itemsize__ * 8 if is_py3k: from io import StringIO @@ -948,6 +949,9 @@ class TestIntrinsicBasic(unittest.TestCase): 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]) @@ -962,6 +966,9 @@ class TestIntrinsicBasic(unittest.TestCase): 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]) @@ -1029,6 +1036,10 @@ class TestIntrinsic(unittest.TestCase): 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') From 6bc5b72c71fa0177ee2397226dd337cf5bfe5d15 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 18 Jan 2013 10:00:44 -0600 Subject: [PATCH 166/516] Fix: ExecutionEngine should own TargetData instance returned from ee.target_data --- llvm/ee.py | 4 +++- llvm/passes.py | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/llvm/ee.py b/llvm/ee.py index 15ede87..e5d6ef1 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -366,7 +366,9 @@ class TargetMachine(llvm.Ownable): '''get target data of this machine ''' ptr = _core.LLVMTargetMachineGetTargetData(self.ptr) - return TargetData(ptr) + td = TargetData(ptr) + td._own(self) + return td @property def target_name(self): diff --git a/llvm/passes.py b/llvm/passes.py index 2b50aca..b1f236c 100644 --- a/llvm/passes.py +++ b/llvm/passes.py @@ -160,6 +160,7 @@ class PassManager(object): pass_obj --- Either a Pass instance, a string name of a pass ''' if isinstance(pass_obj, Pass): + _util.check_is_unowned(pass_obj) _core.LLVMAddPass(self.ptr, pass_obj.ptr) pass_obj._own(self) # PassManager owns the pass elif _util.isstring(pass_obj): @@ -365,7 +366,7 @@ def build_pass_managers(tm, opt=2, loop_vectorize=False, vectorize=False, if inline_threshold: pmb.use_inliner_with_threshold(inline_threshold) if pm: - pm.add(tm.target_data) + pm.add(tm.target_data.clone()) pm.add(TargetLibraryInfo.new(tm.triple)) if llvm.version >= (3, 2): pm.add(TargetTransformInfo.new(tm)) From 0cb552a1ca6eed4c2f7dcdc2301fb2691d793429 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 18 Jan 2013 11:37:31 -0600 Subject: [PATCH 167/516] Fix TestCPUFeature test; more explicit. --- llvm/test_llvmpy.py | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 7c547e0..d4523ec 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -866,7 +866,7 @@ class TestCPUSupport(unittest.TestCase): def _build_test_module(self): mod = Module.new('test') - float = Type.float() + float = Type.double() mysinty = Type.function( float, [float] ) mysin = mod.add_function(mysinty, "mysin") block = mysin.append_basic_block("entry") @@ -890,11 +890,11 @@ class TestCPUSupport(unittest.TestCase): mod, func = self._build_test_module() ee = self._build_engine(mod, mattrs=mattrs) - arg = le.GenericValue.real(Type.float(), 1.234) + arg = le.GenericValue.real(Type.double(), 1.234) retval = ee.run_function(func, [arg]) golden = math.sin(1.234) - answer = retval.as_real(Type.float()) + answer = retval.as_real(Type.double()) self.assertTrue(abs(answer-golden)/golden < 1e-5) @@ -904,13 +904,35 @@ class TestCPUSupport(unittest.TestCase): else: return EngineBuilder.new(mod).create() - def test_cpu_support(self): - features = 'sse2', 'sse3', 'sse41', 'sse42', 'avx' - n = len(features) - for i in range(n): - mattrs = ','.join(map(lambda s: '-%s' % s, features[i:])) - print 'disable mattrs', mattrs - self._template(mattrs) + 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) + + def test_cpu_support6(self): + features = [] + mattrs = ','.join(map(lambda s: '-%s' % s, features)) + print 'disable mattrs', mattrs + self._template(mattrs) tests.append(TestCPUSupport) From 50e92b4abe54452973ad8f3cde1014a68d8c1dc6 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Fri, 18 Jan 2013 11:44:38 -0600 Subject: [PATCH 168/516] fix known failing tests on MacOSX for now --- llvm/test_llvmpy.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index d4523ec..84a2a0a 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -676,6 +676,10 @@ class TestNative(unittest.TestCase): 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() @@ -686,6 +690,10 @@ class TestNative(unittest.TestCase): self._compile(src) def test_object(self): + if sys.platform == 'darwin': + # skip this test on MacOSX for now + return + m = self._make_module() output = m.to_native_object() From 591d31414f002d7295b19b3634a2172df334ce93 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Fri, 18 Jan 2013 11:47:43 -0600 Subject: [PATCH 169/516] update changelog --- CHANGELOG | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 396ce0e..9200f7c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,8 @@ +0.10, 18-Jan-2013: + * add LLVM 3.2 support + + 0.7, in progress: * Add llvm.core.Argument.alignment property. From d8ffc18ffcbb6a88a5ed21f481d488ceed43390c Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 18 Jan 2013 12:06:19 -0600 Subject: [PATCH 170/516] Update changelog. --- CHANGELOG | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 9200f7c..815ecf7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,11 @@ 0.10, 18-Jan-2013: - * add LLVM 3.2 support + * Add LLVM 3.2 support. + * New TargetData class. + * Fixed windows issue (Issue #42). + * Add ExecutionEngine.add_global_mapping and .get_pointer_to_global. + * Improved TargetMachine class and added code-model constants (CM_*). + * Added llvm.passes.build_pass_managers as a simpler way to build PassManagers. 0.7, in progress: From 203858f417e84e51c37f1aa368c5b71db5b65ca7 Mon Sep 17 00:00:00 2001 From: Christoph Gohlke Date: Fri, 18 Jan 2013 13:40:48 -0800 Subject: [PATCH 171/516] Fix ImportError on Python 3 --- llvm/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/__init__.py b/llvm/__init__.py index b89e5a9..79399ff 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -6,7 +6,7 @@ __version__ = '0.10.0' from weakref import WeakValueDictionary -import _core +from . import _core #===----------------------------------------------------------------------=== # LLVM Version From 5209cdb03233ee1073eb0fabd5fd7748feb65502 Mon Sep 17 00:00:00 2001 From: Christoph Gohlke Date: Fri, 18 Jan 2013 13:49:15 -0800 Subject: [PATCH 172/516] Detect and use NVPTX libraries on Windows --- llvm-config-win32.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/llvm-config-win32.py b/llvm-config-win32.py index d8fa5c1..2b6e8f5 100644 --- a/llvm-config-win32.py +++ b/llvm-config-win32.py @@ -58,6 +58,11 @@ Shell32 print('-lLLVMPTXCodeGen') print('-lLLVMPTXDesc') print('-lLLVMPTXInfo') + elif os.path.exists(os.path.join(llvmbin, '../lib/LLVMNVPTXCodeGen.lib')): + print('-lLLVMNVPTXAsmPrinter') + print('-lLLVMNVPTXCodeGen') + print('-lLLVMNVPTXDesc') + print('-lLLVMNVPTXInfo') elif sys.argv[1] == '--includedir': llvmbin = find_path_of('llvm-tblgen.exe') if llvmbin is None: From 93f8c70d19dd75d477e589febf6a4c72f1a509b7 Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Mon, 21 Jan 2013 10:52:29 -0600 Subject: [PATCH 173/516] Expose dwarf constants for debug info generation --- llvm/_dwarf.cpp | 86 +++++++++++++++++++++++++++++++++++ llvm/_dwarf.h | 101 +++++++++++++++++++++++++++++++++++++++++ setup.py | 7 ++- test/test_debuginfo.py | 30 ++++++++++++ 4 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 llvm/_dwarf.cpp create mode 100644 llvm/_dwarf.h create mode 100644 test/test_debuginfo.py diff --git a/llvm/_dwarf.cpp b/llvm/_dwarf.cpp new file mode 100644 index 0000000..43f75aa --- /dev/null +++ b/llvm/_dwarf.cpp @@ -0,0 +1,86 @@ +#include +#include + +namespace llvmpy { +namespace dwarf { + +using namespace llvm::dwarf; + +const char *constant_names[] = { + "LLVMDebugVersion", + + #define define(x) #x, + #include "_dwarf.h" + #undef define +}; + +int constant_values[] = { + llvm::LLVMDebugVersion, + + #define define(x) x, + #include "_dwarf.h" + #undef define +}; + +enum enum_values { + __llvmpy_LLVMDebugVersion, + + #define define(x) __llvmpy_##x, + #include "_dwarf.h" + #undef define + + NVALUES /* Get the number of constants */ +}; + +} // End namespace dwarf + +int +set_dwarf_constants(PyObject *module) +{ + int i; + for (i = 0; i < dwarf::NVALUES; i++) { + if (PyModule_AddIntConstant(module, dwarf::constant_names[i], + dwarf::constant_values[i]) > 0) + return -1; + } + + return 0; +} + +} // End namespace llvmpy + +#if (PY_MAJOR_VERSION >= 3) + struct PyModuleDef module_def = { + PyModuleDef_HEAD_INIT, + "_dwarf", + NULL, + -1, + NULL, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ + }; + + #define INITERROR return NULL + PyObject *PyInit__dwarf(void) +#else + #define INITERROR return + PyMODINIT_FUNC init_dwarf(void) +#endif +{ +#if PY_MAJOR_VERSION >= 3 + PyObject *module = PyModule_Create( &module_def ); +#else + PyObject *module = Py_InitModule("_dwarf", NULL); +#endif + if (module == NULL) + INITERROR; + + if (llvmpy::set_dwarf_constants(module) < 0) + INITERROR; + +#if PY_MAJOR_VERSION >= 3 + return module; +#endif +} diff --git a/llvm/_dwarf.h b/llvm/_dwarf.h new file mode 100644 index 0000000..78eada0 --- /dev/null +++ b/llvm/_dwarf.h @@ -0,0 +1,101 @@ +/* Dwarf constant wrapping. See include/llvm/Support/Dwarf.h */ + +define(DWARF_VERSION) + +/* Dwarf tags */ +define(DW_TAG_array_type) +define(DW_TAG_class_type) +define(DW_TAG_entry_point) +define(DW_TAG_enumeration_type) +define(DW_TAG_formal_parameter) +define(DW_TAG_imported_declaration) +define(DW_TAG_label) +define(DW_TAG_lexical_block) +define(DW_TAG_member) +define(DW_TAG_pointer_type) +define(DW_TAG_reference_type) +define(DW_TAG_compile_unit) +define(DW_TAG_string_type) +define(DW_TAG_structure_type) +define(DW_TAG_subroutine_type) +define(DW_TAG_typedef) +define(DW_TAG_union_type) +define(DW_TAG_unspecified_parameters) +define(DW_TAG_variant) +define(DW_TAG_common_block) +define(DW_TAG_common_inclusion) +define(DW_TAG_inheritance) +define(DW_TAG_inlined_subroutine) +define(DW_TAG_module) +define(DW_TAG_ptr_to_member_type) +define(DW_TAG_set_type) +define(DW_TAG_subrange_type) +define(DW_TAG_with_stmt) +define(DW_TAG_access_declaration) +define(DW_TAG_base_type) +define(DW_TAG_catch_block) +define(DW_TAG_const_type) +define(DW_TAG_constant) +define(DW_TAG_enumerator) +define(DW_TAG_file_type) +define(DW_TAG_friend) +define(DW_TAG_namelist) +define(DW_TAG_namelist_item) +define(DW_TAG_packed_type) +define(DW_TAG_subprogram) +define(DW_TAG_template_type_parameter) +define(DW_TAG_template_value_parameter) +define(DW_TAG_thrown_type) +define(DW_TAG_try_block) +define(DW_TAG_variant_part) +define(DW_TAG_variable) +define(DW_TAG_volatile_type) +define(DW_TAG_dwarf_procedure) +define(DW_TAG_restrict_type) +define(DW_TAG_interface_type) +define(DW_TAG_namespace) +define(DW_TAG_imported_module) +define(DW_TAG_unspecified_type) +define(DW_TAG_partial_unit) +define(DW_TAG_imported_unit) +define(DW_TAG_condition) +define(DW_TAG_shared_type) +define(DW_TAG_type_unit) +define(DW_TAG_rvalue_reference_type) +define(DW_TAG_template_alias) +define(DW_TAG_MIPS_loop) +define(DW_TAG_format_label) +define(DW_TAG_function_template) +define(DW_TAG_class_template) +define(DW_TAG_GNU_template_template_param) +define(DW_TAG_GNU_template_parameter_pack) +define(DW_TAG_GNU_formal_parameter_pack) +define(DW_TAG_lo_user) +define(DW_TAG_APPLE_property) +define(DW_TAG_hi_user) + +/* Dwarf language constants */ +define(DW_LANG_C89) +define(DW_LANG_C) +define(DW_LANG_Ada83) +define(DW_LANG_C_plus_plus) +define(DW_LANG_Cobol74) +define(DW_LANG_Cobol85) +define(DW_LANG_Fortran77) +define(DW_LANG_Fortran90) +define(DW_LANG_Pascal83) +define(DW_LANG_Modula2) +define(DW_LANG_Java) +define(DW_LANG_C99) +define(DW_LANG_Ada95) +define(DW_LANG_Fortran95) +define(DW_LANG_PLI) +define(DW_LANG_ObjC) +define(DW_LANG_ObjC_plus_plus) +define(DW_LANG_UPC) +define(DW_LANG_D) +define(DW_LANG_Python) +define(DW_LANG_lo_user) +define(DW_LANG_Mips_Assembler) +define(DW_LANG_hi_user) + diff --git a/setup.py b/setup.py index eeaf162..25b69ee 100644 --- a/setup.py +++ b/setup.py @@ -116,7 +116,12 @@ kwds = dict(ext_modules = [Extension( library_dirs = [libdir], libraries = libs_core, extra_objects = objs_core, - extra_link_args = extra_link_args)]) + extra_link_args = extra_link_args), + + Extension(name='llvm._dwarf', + sources=['llvm/_dwarf.cpp'], + include_dirs=[incdir]) +]) def run_2to3(): import lib2to3.refactor diff --git a/test/test_debuginfo.py b/test/test_debuginfo.py new file mode 100644 index 0000000..d2f156b --- /dev/null +++ b/test/test_debuginfo.py @@ -0,0 +1,30 @@ +import os +import unittest + +from llvm.core import * +from llvm import _dwarf + +class TestDebugInfo(unittest.TestCase): + + def test_dwarf_constants(self): + dwarf_constants = vars(_dwarf) + + # Version numbers + self.assertIn("LLVMDebugVersion", dwarf_constants) + self.assertIn("DWARF_VERSION", dwarf_constants) + + # Tags + self.assertIn("DW_TAG_compile_unit", dwarf_constants) + + # Language identifiers + self.assertIn("DW_LANG_Python", dwarf_constants) + self.assertIn("DW_LANG_C89", dwarf_constants) + self.assertIn("DW_LANG_C99", dwarf_constants) + + # print sorted([constname for constname in dwarf_constants + # if constname.startswith("DW_LANG_")]) + + +if __name__ == '__main__': +# TestDebugInfo("test_dwarf_constants").debug() + unittest.main() \ No newline at end of file From 7c9f73ccc76b7ff8a5fc2d703ef25a4688caf843 Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Mon, 21 Jan 2013 11:14:17 -0600 Subject: [PATCH 174/516] Allow debug description of compilation unit --- llvm/debuginfo.py | 81 ++++++++++++++++++++++++++++++++++++++++++ test/test_debuginfo.py | 30 ++++++++++++++-- 2 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 llvm/debuginfo.py diff --git a/llvm/debuginfo.py b/llvm/debuginfo.py new file mode 100644 index 0000000..7f2c16e --- /dev/null +++ b/llvm/debuginfo.py @@ -0,0 +1,81 @@ +""" +Support for debug info metadata. +""" + +import functools + +import llvm.core +from llvm import _dwarf + +int32_t = llvm.core.Type.int(32) +bool_t = llvm.core.Type.int(1) + +i32 = functools.partial(llvm.core.Constant.int, int32_t) +i1 = functools.partial(llvm.core.Constant.int, bool_t) + +class CompileUnitDescriptor(object): + """ + !0 = metadata !{ + i32, ;; Tag = 17 + LLVMDebugVersion (DW_TAG_compile_unit) + i32, ;; Unused field. + i32, ;; DWARF language identifier (ex. DW_LANG_C89) + metadata, ;; Source file name + metadata, ;; Source file directory (includes trailing slash) + metadata ;; Producer (ex. "4.0.1 LLVM (LLVM research group)") + i1, ;; True if this is a main compile unit. + i1, ;; True if this is optimized. + metadata, ;; Flags + i32 ;; Runtime version + metadata ;; List of enums types + metadata ;; List of retained types + metadata ;; List of subprograms + metadata ;; List of global variables + } + """ + + def __init__(self, langid, source_filename, source_filedir, + producer, is_main=False, is_optimized=False, + compile_flags=None, runtime_version=0, enum_types=None, + retained_types=None, subprograms=None, global_vars=None): + self.langid = langid + self.source_filename = source_filename + self.source_filedir = source_filedir + self.producer = producer + self.is_main = is_main + self.is_optimized = is_optimized + self.compile_flags = compile_flags + self.runtime_version = runtime_version + self.enum_types = enum_types + self.retained_types = retained_types + self.subprograms = subprograms + self.global_vars = global_vars + + def build_metadata(self, llvm_module): + md = functools.partial(llvm.core.MetaData.get, llvm_module) + mstr = functools.partial(llvm.core.MetaDataString.get, llvm_module) + + operands = [ + i32(_dwarf.DW_TAG_compile_unit + + _dwarf.LLVMDebugVersion), # tag + i32(0), # unused + i32(self.langid), # Language identifier + mstr(self.source_filename), + mstr(self.source_filedir), + mstr(self.producer), + i1(self.is_main), + i1(self.is_optimized), + mstr(self.compile_flags or ""), + md(self.enum_types or []), + md(self.retained_types or []), + md(self.subprograms or []), + md(self.global_vars or []), + ] + + node = llvm.core.MetaData.get(llvm_module, operands) + llvm.core.MetaData.add_named_operand(llvm_module, "dbg", node) + + print "printing metadata compile unit..." + print node + print "---- done ----" + + return node diff --git a/test/test_debuginfo.py b/test/test_debuginfo.py index d2f156b..3641d22 100644 --- a/test/test_debuginfo.py +++ b/test/test_debuginfo.py @@ -2,7 +2,7 @@ import os import unittest from llvm.core import * -from llvm import _dwarf +from llvm import _dwarf, debuginfo class TestDebugInfo(unittest.TestCase): @@ -24,7 +24,33 @@ class TestDebugInfo(unittest.TestCase): # print sorted([constname for constname in dwarf_constants # if constname.startswith("DW_LANG_")]) + def test_debug_info_compile_unit(self): + mod = Module.new('test_debug_info') + fty = Type.function(Type.float(), [Type.float()]) + square = mod.add_function(fty, 'square') + bb = square.append_basic_block('entry') + bldr = Builder.new(bb) + + info = debuginfo.CompileUnitDescriptor( + _dwarf.DW_LANG_Python, + "test_debug_info.py", + os.path.expanduser("~/"), + "my_cool_compiler", + ) + + info.build_metadata(mod) + + value = square.args[0] + result = bldr.fmul(value, value) + bldr.ret(result) + +# info.build_metadata(mod) + print mod +# modstr = str(mod) +# print modstr + # self.assertIn("my_cool_compiler", modstr) if __name__ == '__main__': # TestDebugInfo("test_dwarf_constants").debug() - unittest.main() \ No newline at end of file + TestDebugInfo("test_debug_info_compile_unit").debug() +# unittest.main() \ No newline at end of file From 8c6384f24270d66549baea4336c5d60967117046 Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Mon, 21 Jan 2013 12:41:49 -0600 Subject: [PATCH 175/516] Test dwarf compile unit with DW_LANG_C89 --- llvm/debuginfo.py | 9 ++++++--- test/test_debuginfo.py | 22 ++++++++++++++-------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/llvm/debuginfo.py b/llvm/debuginfo.py index 7f2c16e..c9f6a2b 100644 --- a/llvm/debuginfo.py +++ b/llvm/debuginfo.py @@ -71,11 +71,14 @@ class CompileUnitDescriptor(object): md(self.global_vars or []), ] +# for op in operands: +# print op + node = llvm.core.MetaData.get(llvm_module, operands) llvm.core.MetaData.add_named_operand(llvm_module, "dbg", node) - print "printing metadata compile unit..." - print node - print "---- done ----" +# print "printing metadata compile unit..." +# print node +# print "---- done ----" return node diff --git a/test/test_debuginfo.py b/test/test_debuginfo.py index 3641d22..86cbe2d 100644 --- a/test/test_debuginfo.py +++ b/test/test_debuginfo.py @@ -32,7 +32,11 @@ class TestDebugInfo(unittest.TestCase): bldr = Builder.new(bb) info = debuginfo.CompileUnitDescriptor( - _dwarf.DW_LANG_Python, + # DW_LANG_Python segfaults: + # llvm/ADT/StringRef.h:79: llvm::StringRef::StringRef(const char*): + # Assertion `Str && "StringRef cannot be built from a NULL argument"' + # _dwarf.DW_LANG_Python, + _dwarf.DW_LANG_C89, "test_debug_info.py", os.path.expanduser("~/"), "my_cool_compiler", @@ -44,13 +48,15 @@ class TestDebugInfo(unittest.TestCase): result = bldr.fmul(value, value) bldr.ret(result) -# info.build_metadata(mod) - print mod -# modstr = str(mod) -# print modstr - # self.assertIn("my_cool_compiler", modstr) +# print mod + modstr = str(mod) + self.assertIn("my_cool_compiler", modstr) + self.assertIn("test_debug_info.py", modstr) + self.assertIn(os.path.expanduser("~/"), modstr) + self.assertIn("my_cool_compiler", modstr) + if __name__ == '__main__': # TestDebugInfo("test_dwarf_constants").debug() - TestDebugInfo("test_debug_info_compile_unit").debug() -# unittest.main() \ No newline at end of file +# TestDebugInfo("test_debug_info_compile_unit").debug() + unittest.main() \ No newline at end of file From f05222caec125b8da115a1c50733b83952d935a1 Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Mon, 21 Jan 2013 13:04:50 -0600 Subject: [PATCH 176/516] Add file descriptors and per-module metadata caching --- llvm/debuginfo.py | 76 +++++++++++++++++++++++++++++++++++++----- test/test_debuginfo.py | 4 ++- 2 files changed, 70 insertions(+), 10 deletions(-) diff --git a/llvm/debuginfo.py b/llvm/debuginfo.py index c9f6a2b..7afd563 100644 --- a/llvm/debuginfo.py +++ b/llvm/debuginfo.py @@ -13,7 +13,36 @@ bool_t = llvm.core.Type.int(1) i32 = functools.partial(llvm.core.Constant.int, int32_t) i1 = functools.partial(llvm.core.Constant.int, bool_t) -class CompileUnitDescriptor(object): +class DebugInfoBase(object): + def __init__(self): + self.metadata_cache = {} + + def get_metadata(self, llvm_module): + """ + Get an existing metadata node for the given LLVM module, or build + one from this instance. + """ + if llvm_module in self.metadata_cache: + node = self.metadata_cache[llvm_module] + else: + node = self.build_metadata(llvm_module) + self.metadata_cache[llvm_module] = node + + return node + + def build_metadata(self, llvm_module): + "Build a metadata node for the given LLVM module" + raise NotImplementedError + + def define(self, llvm_module): + """ + Define this debug descriptor as named debug metadata for the module. + """ + md = self.get_metadata(llvm_module) + llvm.core.MetaData.add_named_operand(llvm_module, "dbg", md) + + +class CompileUnitDescriptor(DebugInfoBase): """ !0 = metadata !{ i32, ;; Tag = 17 + LLVMDebugVersion (DW_TAG_compile_unit) @@ -37,6 +66,7 @@ class CompileUnitDescriptor(object): producer, is_main=False, is_optimized=False, compile_flags=None, runtime_version=0, enum_types=None, retained_types=None, subprograms=None, global_vars=None): + super(CompileUnitDescriptor, self).__init__() self.langid = langid self.source_filename = source_filename self.source_filedir = source_filedir @@ -71,14 +101,42 @@ class CompileUnitDescriptor(object): md(self.global_vars or []), ] -# for op in operands: -# print op + return md(operands) - node = llvm.core.MetaData.get(llvm_module, operands) - llvm.core.MetaData.add_named_operand(llvm_module, "dbg", node) -# print "printing metadata compile unit..." -# print node -# print "---- done ----" +class FileDescriptor(DebugInfoBase): + """ + !0 = metadata !{ + i32, ;; Tag = 41 + LLVMDebugVersion (DW_TAG_file_type) + metadata, ;; Source file name + metadata, ;; Source file directory (includes trailing slash) + metadata ;; Unused + } + """ + + def __init__(self, source_filename, source_filedir, compile_unit_descriptor): + super(FileDescriptor, self).__init__() + self.source_filename = source_filename + self.source_filedir = source_filedir + self.compile_unit_descriptor = compile_unit_descriptor + + @classmethod + def from_compileunit(cls, compile_unit_descriptor): + return cls(compile_unit_descriptor.source_filename, + compile_unit_descriptor.source_filedir, + compile_unit_descriptor) + + def build_metadata(self, llvm_module): + md = functools.partial(llvm.core.MetaData.get, llvm_module) + mstr = functools.partial(llvm.core.MetaDataString.get, llvm_module) + + operands = [ + i32(_dwarf.DW_TAG_file_type + _dwarf.LLVMDebugVersion), + mstr(self.source_filename), + mstr(self.source_filedir), + self.compile_unit_descriptor.get_metadata(llvm_module), + ] + + return md(operands) + - return node diff --git a/test/test_debuginfo.py b/test/test_debuginfo.py index 86cbe2d..4dc0f13 100644 --- a/test/test_debuginfo.py +++ b/test/test_debuginfo.py @@ -42,13 +42,15 @@ class TestDebugInfo(unittest.TestCase): "my_cool_compiler", ) - info.build_metadata(mod) + filedesc = debuginfo.FileDescriptor.from_compileunit(info) + filedesc.define(mod) value = square.args[0] result = bldr.fmul(value, value) bldr.ret(result) # print mod + modstr = str(mod) self.assertIn("my_cool_compiler", modstr) self.assertIn("test_debug_info.py", modstr) From f6e687ae6642430c95a54f8a74977efaef63f5ae Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Mon, 21 Jan 2013 16:54:51 -0600 Subject: [PATCH 177/516] Allow declarative specification of debug descriptors --- llvm/debuginfo.py | 301 +++++++++++++++++++++++++++++++++-------- test/test_debuginfo.py | 24 +++- 2 files changed, 261 insertions(+), 64 deletions(-) diff --git a/llvm/debuginfo.py b/llvm/debuginfo.py index 7afd563..245bef4 100644 --- a/llvm/debuginfo.py +++ b/llvm/debuginfo.py @@ -7,16 +7,108 @@ import functools import llvm.core from llvm import _dwarf +#---------------------------------------------------------------------------- +# Callbacks for debug type descriptors +#---------------------------------------------------------------------------- + int32_t = llvm.core.Type.int(32) bool_t = llvm.core.Type.int(1) i32 = functools.partial(llvm.core.Constant.int, int32_t) i1 = functools.partial(llvm.core.Constant.int, bool_t) -class DebugInfoBase(object): - def __init__(self): +def get_i32(llvm_module, value): + return i32(value) + +def get_i1(llvm_module, value): + return i1(value) + +def get_md(llvm_module, value): + return value.get_metadata(llvm_module) + +def get_mdstr(llvm_module, value): + return llvm.core.MetaDataString.get(llvm_module, value) + +def get_lfunc(llvm_module, lfunc): + assert lfunc.module is llvm_module + return lfunc + +#---------------------------------------------------------------------------- +# Debug descriptors that generate LLVM Metadata +#---------------------------------------------------------------------------- + +def build_operand_list(type_descriptors, idx2name, operands, kwargs): + """ + Build the list of operands from the positional and keyword arguments + to a DebugInfoDescriptor. + + E.g. FileDescriptor("foo.c", "/path/to/file", compile_unit=compile_unit) + + idx2name: {0 : 'source_filename', + 1 : 'source_filedir', + 2 : 'compile_unit' } + operands: ["foo.c", "/path/to/file"] + kwargs: { 'compile_unit' : compile_unit } + """ + for i in range(len(operands), len(type_descriptors)): + name = idx2name[i] + if name in kwargs: + op = kwargs[name] + else: + typedesc = type_descriptors[i] + assert typedesc.default is not None, ( + "No value found for field %s" % typedesc.field_name) + op = typedesc.default + + operands.append(op) + + return operands + + +class DebugInfoDescriptor(object): + """ + Base class to describe a debug info descriptor. + + See http://llvm.org/docs/SourceLevelDebugging.html + """ + + type_descriptors = None # [desc(...)] + idx2name = None # { "field_idx" : field_name } + name2idx = None # { "field_name" : field_idx } + + def __init__(self, *args, **kwargs): + self.class_init() self.metadata_cache = {} + operands = list(args) + self.operands = build_operand_list(self.type_descriptors, + self.idx2name, operands, kwargs) + + self.operands_dict = dict( + (typedesc.field_name, operand) + for typedesc, operand in zip(self.type_descriptors, operands)) + + @classmethod + def class_init(cls): + if cls.idx2name is None and cls.type_descriptors is not None: + cls.name2idx = {} + cls.idx2name = {} + + for i, typedesc in enumerate(cls.type_descriptors): + cls.name2idx[typedesc.field_name] = i + cls.idx2name[i] = typedesc.field_name + + def add_metadata(self, metadata_name, metadata): + """ + Replace a metadata value in the operand list. + """ + idx = self.name2idx[metadata_name] + self.operands[idx] = metadata + + #------------------------------------------------------------------------ + # Define metadata in a module + #------------------------------------------------------------------------ + def get_metadata(self, llvm_module): """ Get an existing metadata node for the given LLVM module, or build @@ -32,7 +124,20 @@ class DebugInfoBase(object): def build_metadata(self, llvm_module): "Build a metadata node for the given LLVM module" - raise NotImplementedError + mdops = [] + for type_desc, operand in zip(self.type_descriptors, self.operands): + try: + field_value = type_desc.build_metadata(llvm_module, operand) + except Exception, e: + if type_desc.build_metadata is get_md: + raise + + raise ValueError("Invalid value for field %r: %s" % ( + type_desc.field_name, e)) + + mdops.append(field_value) + + return llvm.core.MetaData.get(llvm_module, mdops) def define(self, llvm_module): """ @@ -41,8 +146,42 @@ class DebugInfoBase(object): md = self.get_metadata(llvm_module) llvm.core.MetaData.add_named_operand(llvm_module, "dbg", md) +class desc(object): + """ + Descriptor of a debug field. -class CompileUnitDescriptor(DebugInfoBase): + field_name: + name of the field (keyword argument name) + build_metadata: + metadata callback :: (llvm_module, Python value) -> LLVM Value + default: + default value for this field + """ + + def __init__(self, field_name, build_metadata, default=None): + self.field_name = field_name + self.build_metadata = build_metadata + self.default = default + +class EmptyMetadata(DebugInfoDescriptor): + """ + Metadata without any fields. Same as MDList([]) + """ + + type_descriptors = [] + + +class MDList(DebugInfoDescriptor): + """ + [MetaData] + """ + + def __init__(self, operands): + self.type_descriptors = [desc("op", get_md)] * len(operands) + super(MDList, self).__init__(*operands) + + +class CompileUnitDescriptor(DebugInfoDescriptor): """ !0 = metadata !{ i32, ;; Tag = 17 + LLVMDebugVersion (DW_TAG_compile_unit) @@ -62,49 +201,40 @@ class CompileUnitDescriptor(DebugInfoBase): } """ - def __init__(self, langid, source_filename, source_filedir, - producer, is_main=False, is_optimized=False, - compile_flags=None, runtime_version=0, enum_types=None, - retained_types=None, subprograms=None, global_vars=None): - super(CompileUnitDescriptor, self).__init__() - self.langid = langid - self.source_filename = source_filename - self.source_filedir = source_filedir - self.producer = producer - self.is_main = is_main - self.is_optimized = is_optimized - self.compile_flags = compile_flags - self.runtime_version = runtime_version - self.enum_types = enum_types - self.retained_types = retained_types - self.subprograms = subprograms - self.global_vars = global_vars + type_descriptors = [ + desc("tag", get_i32), + desc("unused", get_i32), - def build_metadata(self, llvm_module): - md = functools.partial(llvm.core.MetaData.get, llvm_module) - mstr = functools.partial(llvm.core.MetaDataString.get, llvm_module) + # Positional argument list starts here: + desc("langid", get_i32), + desc("source_filename", get_mdstr), + desc("source_filedir", get_mdstr), + desc("producer", get_mdstr), + desc("is_main", get_i1, default=False), + desc("is_optimized", get_i1, default=False), + desc("compile_flags", get_mdstr, default=""), + desc("runtime_version", get_i32, default=0), + desc("enum_types", get_md, default=EmptyMetadata()), + desc("retained_types", get_md, default=EmptyMetadata()), + desc("subprograms", get_md, default=EmptyMetadata()), + desc("global_vars", get_md, default=EmptyMetadata()), + ] - operands = [ - i32(_dwarf.DW_TAG_compile_unit + - _dwarf.LLVMDebugVersion), # tag - i32(0), # unused - i32(self.langid), # Language identifier - mstr(self.source_filename), - mstr(self.source_filedir), - mstr(self.producer), - i1(self.is_main), - i1(self.is_optimized), - mstr(self.compile_flags or ""), - md(self.enum_types or []), - md(self.retained_types or []), - md(self.subprograms or []), - md(self.global_vars or []), - ] + def __init__(self, *args, **kwargs): + super(CompileUnitDescriptor, self).__init__( + _dwarf.DW_TAG_compile_unit + _dwarf.LLVMDebugVersion, # tag + 0, # unused + *args, **kwargs) - return md(operands) + def define(self, llvm_module): + """ + Define this debug descriptor as named debug metadata for the module. + """ + md = self.get_metadata(llvm_module) + llvm.core.MetaData.add_named_operand(llvm_module, "llvm.dbg.cu", md) -class FileDescriptor(DebugInfoBase): +class FileDescriptor(DebugInfoDescriptor): """ !0 = metadata !{ i32, ;; Tag = 41 + LLVMDebugVersion (DW_TAG_file_type) @@ -114,29 +244,82 @@ class FileDescriptor(DebugInfoBase): } """ - def __init__(self, source_filename, source_filedir, compile_unit_descriptor): - super(FileDescriptor, self).__init__() - self.source_filename = source_filename - self.source_filedir = source_filedir - self.compile_unit_descriptor = compile_unit_descriptor + type_descriptors = [ + desc("tag", get_i32), + + # Positional argument list starts here: + desc("source_filename", get_mdstr), + desc("source_filedir", get_mdstr), + desc("compile_unit", get_md), + ] + + def __init__(self, *args, **kwargs): + super(FileDescriptor, self).__init__( + _dwarf.DW_TAG_file_type + _dwarf.LLVMDebugVersion, # Tag + *args, **kwargs) @classmethod def from_compileunit(cls, compile_unit_descriptor): - return cls(compile_unit_descriptor.source_filename, - compile_unit_descriptor.source_filedir, + return cls(compile_unit_descriptor.operands_dict["source_filename"], + compile_unit_descriptor.operands_dict["source_filedir"], compile_unit_descriptor) - def build_metadata(self, llvm_module): - md = functools.partial(llvm.core.MetaData.get, llvm_module) - mstr = functools.partial(llvm.core.MetaDataString.get, llvm_module) - operands = [ - i32(_dwarf.DW_TAG_file_type + _dwarf.LLVMDebugVersion), - mstr(self.source_filename), - mstr(self.source_filedir), - self.compile_unit_descriptor.get_metadata(llvm_module), - ] +class SubprogramDescriptor(DebugInfoDescriptor): + """ + !2 = metadata !{ + i32, ;; Tag = 46 + LLVMDebugVersion (DW_TAG_subprogram) + i32, ;; Unused field. + metadata, ;; Reference to context descriptor + metadata, ;; Name + metadata, ;; Display name (fully qualified C++ name) + metadata, ;; MIPS linkage name (for C++) + metadata, ;; Reference to file where defined + i32, ;; Line number where defined + metadata, ;; Reference to type descriptor + i1, ;; True if the global is local to compile unit (static) + i1, ;; True if the global is defined in the compile unit (not extern) + i32, ;; Line number where the scope of the subprogram begins + i32, ;; Virtuality, e.g. dwarf::DW_VIRTUALITY__virtual + i32, ;; Index into a virtual function + metadata, ;; indicates which base type contains the vtable pointer for the + ;; derived class + i32, ;; Flags - Artifical, Private, Protected, Explicit, Prototyped. + i1, ;; isOptimized + Function * , ;; Pointer to LLVM function + metadata, ;; Lists function template parameters + metadata, ;; Function declaration descriptor + metadata ;; List of function variables + } + """ - return md(operands) + type_descriptors = [ + desc("tag", get_i32), + desc("unused", get_i32), + # Positional argument list starts here: + desc("compile_unit", get_md), + desc("name", get_mdstr), + desc("display_name", get_mdstr), + desc("mips_linkage_name", get_mdstr), + desc("source_file_ref", get_md), + desc("line_number", get_i32), + desc("signature", get_md), + desc("is_local", get_i1, default=False), + desc("is_definition", get_i1, default=True), + desc("virtual_attribute", get_i32, default=0), + desc("virtual_index", get_i32, default=0), + desc("virttab", get_i32, default=0), + desc("flags", get_i32, default=0), + desc("is_optimized", get_i1, default=False), + desc("llvm_func", get_lfunc), + # Template params + # Func decl + # Func vars + ] + def __init__(self, *args, **kwargs): + super(SubprogramDescriptor, self).__init__( + _dwarf.DW_TAG_subprogram + _dwarf.LLVMDebugVersion, # Tag + 0, # Unused + *args, **kwargs) diff --git a/test/test_debuginfo.py b/test/test_debuginfo.py index 4dc0f13..b6d5029 100644 --- a/test/test_debuginfo.py +++ b/test/test_debuginfo.py @@ -31,25 +31,39 @@ class TestDebugInfo(unittest.TestCase): bb = square.append_basic_block('entry') bldr = Builder.new(bb) - info = debuginfo.CompileUnitDescriptor( + compile_unit = debuginfo.CompileUnitDescriptor( # DW_LANG_Python segfaults: # llvm/ADT/StringRef.h:79: llvm::StringRef::StringRef(const char*): # Assertion `Str && "StringRef cannot be built from a NULL argument"' # _dwarf.DW_LANG_Python, _dwarf.DW_LANG_C89, "test_debug_info.py", - os.path.expanduser("~/"), + os.path.expanduser("~"), "my_cool_compiler", ) - filedesc = debuginfo.FileDescriptor.from_compileunit(info) - filedesc.define(mod) + filedesc = debuginfo.FileDescriptor.from_compileunit(compile_unit) + + subprogram = debuginfo.SubprogramDescriptor( + compile_unit, + "some_function", + "some_function", + "some_function", + filedesc, + 1, # line number + debuginfo.EmptyMetadata(), # Type descriptor + llvm_func=square, + ) + subprograms = debuginfo.MDList([subprogram]) + + # compile_unit.add_metadata("subprograms", subprograms) + compile_unit.define(mod) value = square.args[0] result = bldr.fmul(value, value) bldr.ret(result) -# print mod + print mod modstr = str(mod) self.assertIn("my_cool_compiler", modstr) From 3fba8e4adf8453fe1adede29c9587f4a947a846d Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Mon, 21 Jan 2013 19:30:46 -0600 Subject: [PATCH 178/516] Support optional LLVM-level debug info --- llvm/debuginfo.py | 44 +++++++++++++++++++++++------------------- test/test_debuginfo.py | 7 ++++++- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/llvm/debuginfo.py b/llvm/debuginfo.py index 245bef4..dfbdcac 100644 --- a/llvm/debuginfo.py +++ b/llvm/debuginfo.py @@ -37,6 +37,24 @@ def get_lfunc(llvm_module, lfunc): # Debug descriptors that generate LLVM Metadata #---------------------------------------------------------------------------- +class desc(object): + """ + Descriptor of a debug field. + + field_name: + name of the field (keyword argument name) + build_metadata: + metadata callback :: (llvm_module, Python value) -> LLVM Value + default: + default value for this field + """ + + def __init__(self, field_name, build_metadata, default=None): + self.field_name = field_name + self.build_metadata = build_metadata + self.default = default + + def build_operand_list(type_descriptors, idx2name, operands, kwargs): """ Build the list of operands from the positional and keyword arguments @@ -57,7 +75,7 @@ def build_operand_list(type_descriptors, idx2name, operands, kwargs): else: typedesc = type_descriptors[i] assert typedesc.default is not None, ( - "No value found for field %s" % typedesc.field_name) + "No value found for field %s" % typedesc.field_name) op = typedesc.default operands.append(op) @@ -81,9 +99,11 @@ class DebugInfoDescriptor(object): self.metadata_cache = {} operands = list(args) - self.operands = build_operand_list(self.type_descriptors, - self.idx2name, operands, kwargs) + if kwargs: + operands = build_operand_list(self.type_descriptors, + self.idx2name, operands, kwargs) + self.operands = operands self.operands_dict = dict( (typedesc.field_name, operand) for typedesc, operand in zip(self.type_descriptors, operands)) @@ -146,26 +166,10 @@ class DebugInfoDescriptor(object): md = self.get_metadata(llvm_module) llvm.core.MetaData.add_named_operand(llvm_module, "dbg", md) -class desc(object): - """ - Descriptor of a debug field. - - field_name: - name of the field (keyword argument name) - build_metadata: - metadata callback :: (llvm_module, Python value) -> LLVM Value - default: - default value for this field - """ - - def __init__(self, field_name, build_metadata, default=None): - self.field_name = field_name - self.build_metadata = build_metadata - self.default = default class EmptyMetadata(DebugInfoDescriptor): """ - Metadata without any fields. Same as MDList([]) + Metadata without any fields. """ type_descriptors = [] diff --git a/test/test_debuginfo.py b/test/test_debuginfo.py index b6d5029..22d3deb 100644 --- a/test/test_debuginfo.py +++ b/test/test_debuginfo.py @@ -58,6 +58,7 @@ class TestDebugInfo(unittest.TestCase): # compile_unit.add_metadata("subprograms", subprograms) compile_unit.define(mod) + subprogram.define(mod) value = square.args[0] result = bldr.fmul(value, value) @@ -66,11 +67,15 @@ class TestDebugInfo(unittest.TestCase): print mod modstr = str(mod) + + # Test compile unit self.assertIn("my_cool_compiler", modstr) self.assertIn("test_debug_info.py", modstr) - self.assertIn(os.path.expanduser("~/"), modstr) + self.assertIn(os.path.expanduser("~"), modstr) self.assertIn("my_cool_compiler", modstr) + # Test subprogram + self.assertIn("some_function", modstr) if __name__ == '__main__': # TestDebugInfo("test_dwarf_constants").debug() From 3b75974731ce3c2199978f8d21fd031d918f2327 Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Mon, 21 Jan 2013 20:58:32 -0600 Subject: [PATCH 179/516] Add basic block and instruction position descriptors --- llvm/debuginfo.py | 60 +++++++++++++++++++++++++++++++++++++++--- test/test_debuginfo.py | 59 ++++++++++++++++++++++++++++------------- 2 files changed, 97 insertions(+), 22 deletions(-) diff --git a/llvm/debuginfo.py b/llvm/debuginfo.py index dfbdcac..8249aef 100644 --- a/llvm/debuginfo.py +++ b/llvm/debuginfo.py @@ -13,6 +13,7 @@ from llvm import _dwarf int32_t = llvm.core.Type.int(32) bool_t = llvm.core.Type.int(1) +p_int32_t = llvm.core.Type.pointer(int32_t) i32 = functools.partial(llvm.core.Constant.int, int32_t) i1 = functools.partial(llvm.core.Constant.int, bool_t) @@ -94,12 +95,16 @@ class DebugInfoDescriptor(object): idx2name = None # { "field_idx" : field_name } name2idx = None # { "field_name" : field_idx } + # Whether the debug descriptor is allowed to be incomplete + # The policy seems unclear ? + accept_optional_data = False + def __init__(self, *args, **kwargs): self.class_init() self.metadata_cache = {} operands = list(args) - if kwargs: + if kwargs or not self.accept_optional_data: operands = build_operand_list(self.type_descriptors, self.idx2name, operands, kwargs) @@ -184,6 +189,12 @@ class MDList(DebugInfoDescriptor): self.type_descriptors = [desc("op", get_md)] * len(operands) super(MDList, self).__init__(*operands) +class NULLDescriptor(DebugInfoDescriptor): + + type_descriptors = [] + + def build_metadata(self, llvm_module): + return llvm.core.Constant.null(p_int32_t) class CompileUnitDescriptor(DebugInfoDescriptor): """ @@ -205,6 +216,8 @@ class CompileUnitDescriptor(DebugInfoDescriptor): } """ + accept_optional_data = True + type_descriptors = [ desc("tag", get_i32), desc("unused", get_i32), @@ -254,7 +267,7 @@ class FileDescriptor(DebugInfoDescriptor): # Positional argument list starts here: desc("source_filename", get_mdstr), desc("source_filedir", get_mdstr), - desc("compile_unit", get_md), + desc("compile_unit", get_md, default=NULLDescriptor()), ] def __init__(self, *args, **kwargs): @@ -297,12 +310,14 @@ class SubprogramDescriptor(DebugInfoDescriptor): } """ + accept_optional_data = True + type_descriptors = [ desc("tag", get_i32), desc("unused", get_i32), # Positional argument list starts here: - desc("compile_unit", get_md), + desc("file_desc", get_md), desc("name", get_mdstr), desc("display_name", get_mdstr), desc("mips_linkage_name", get_mdstr), @@ -327,3 +342,42 @@ class SubprogramDescriptor(DebugInfoDescriptor): _dwarf.DW_TAG_subprogram + _dwarf.LLVMDebugVersion, # Tag 0, # Unused *args, **kwargs) + +class BlockDescriptor(DebugInfoDescriptor): + """ + !3 = metadata !{ + i32, ;; Tag = 11 + LLVMDebugVersion (DW_TAG_lexical_block) + metadata,;; Reference to context descriptor + i32, ;; Line number + i32 ;; Column number + } + """ + + type_descriptors = [ + desc("tag", get_i32), + + # Positional argument list starts here: + desc("context_descr", get_md), # FileDescr | BlockDescr | + # SubprogDescr | ComputeUnit + desc("line_number", get_i32), + desc("col_number", get_i32), + ] + + def __init__(self, *args, **kwargs): + super(BlockDescriptor, self).__init__( + _dwarf.DW_TAG_lexical_block + _dwarf.LLVMDebugVersion, + *args, **kwargs) + +class PositionInfoDescriptor(DebugInfoDescriptor): + """ + line number, column number, scope, and original scope + """ + + type_descriptors = [ + desc("line_number", get_i32), + desc("col_number", get_i32), + desc("context_descr", get_md), # Scope of instruction + # (FileDescr etc) + desc("original_context_descr", get_md, # The original scope if inlined + default=NULLDescriptor()), + ] diff --git a/test/test_debuginfo.py b/test/test_debuginfo.py index 22d3deb..528ae6f 100644 --- a/test/test_debuginfo.py +++ b/test/test_debuginfo.py @@ -31,21 +31,15 @@ class TestDebugInfo(unittest.TestCase): bb = square.append_basic_block('entry') bldr = Builder.new(bb) - compile_unit = debuginfo.CompileUnitDescriptor( - # DW_LANG_Python segfaults: - # llvm/ADT/StringRef.h:79: llvm::StringRef::StringRef(const char*): - # Assertion `Str && "StringRef cannot be built from a NULL argument"' - # _dwarf.DW_LANG_Python, - _dwarf.DW_LANG_C89, - "test_debug_info.py", - os.path.expanduser("~"), - "my_cool_compiler", - ) + source_filename = "test_debug_info.py" + source_filedir = os.path.expanduser("~") - filedesc = debuginfo.FileDescriptor.from_compileunit(compile_unit) + # Debug info for our file + filedesc = debuginfo.FileDescriptor(source_filename, source_filedir) + # Debug info for our function subprogram = debuginfo.SubprogramDescriptor( - compile_unit, + filedesc, "some_function", "some_function", "some_function", @@ -56,26 +50,53 @@ class TestDebugInfo(unittest.TestCase): ) subprograms = debuginfo.MDList([subprogram]) - # compile_unit.add_metadata("subprograms", subprograms) - compile_unit.define(mod) - subprogram.define(mod) + # Debug info for our basic blocks + blockdescr1 = debuginfo.BlockDescriptor(subprogram, 2, 4) # lineno, col + blockdescr2 = debuginfo.BlockDescriptor(blockdescr1, 3, 4) # lineno, col + # Debug info for our instructions + posinfo1 = debuginfo.PositionInfoDescriptor(2, 4, blockdescr1) + posinfo2 = debuginfo.PositionInfoDescriptor(2, 4, blockdescr2) + + # Debug info for our module + compile_unit = debuginfo.CompileUnitDescriptor( + # DW_LANG_Python segfaults: + # llvm/ADT/StringRef.h:79: llvm::StringRef::StringRef(const char*): + # Assertion `Str && "StringRef cannot be built from a NULL argument"' + # _dwarf.DW_LANG_Python, + _dwarf.DW_LANG_C89, + source_filename, + source_filedir, + "my_cool_compiler", + subprograms=subprograms, + ) + + # Define our module debug data + compile_unit.define(mod) + + # Build some instructions value = square.args[0] result = bldr.fmul(value, value) - bldr.ret(result) + ret = bldr.ret(result) - print mod + # Annotate instructions with source position + result.set_metadata("dbg", posinfo1.get_metadata(mod)) + ret.set_metadata("dbg", posinfo2.get_metadata(mod)) + + # ... Aaaand, test... + # print mod modstr = str(mod) # Test compile unit self.assertIn("my_cool_compiler", modstr) - self.assertIn("test_debug_info.py", modstr) - self.assertIn(os.path.expanduser("~"), modstr) + self.assertIn(source_filename, modstr) + self.assertIn(source_filedir, modstr) self.assertIn("my_cool_compiler", modstr) # Test subprogram self.assertIn("some_function", modstr) + self.assertIn("float (float)* @square", modstr) if __name__ == '__main__': # TestDebugInfo("test_dwarf_constants").debug() From b46757f492c9e0ce6aa810263ab10652a1fcc6c6 Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Tue, 22 Jan 2013 11:21:17 -0600 Subject: [PATCH 180/516] Accept list of values and LLVM values as debug descriptors --- llvm/debuginfo.py | 55 +++++++++++++++++++++++++++--------------- test/test_debuginfo.py | 2 +- 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/llvm/debuginfo.py b/llvm/debuginfo.py index 8249aef..0f18b33 100644 --- a/llvm/debuginfo.py +++ b/llvm/debuginfo.py @@ -8,16 +8,28 @@ import llvm.core from llvm import _dwarf #---------------------------------------------------------------------------- -# Callbacks for debug type descriptors +# Some types and type checking functions #---------------------------------------------------------------------------- int32_t = llvm.core.Type.int(32) bool_t = llvm.core.Type.int(1) p_int32_t = llvm.core.Type.pointer(int32_t) +null = llvm.core.Constant.null(p_int32_t) i32 = functools.partial(llvm.core.Constant.int, int32_t) i1 = functools.partial(llvm.core.Constant.int, bool_t) +def is_md(value): + return isinstance(value, (llvm.core.MetaData, llvm.core.NamedMetaData, + llvm.core.Value)) + +def is_mdstr(value): + return isinstance(value, (llvm.core.MetaDataString, llvm.core.Value)) + +#---------------------------------------------------------------------------- +# Callbacks for debug type descriptors +#---------------------------------------------------------------------------- + def get_i32(llvm_module, value): return i32(value) @@ -25,11 +37,20 @@ def get_i1(llvm_module, value): return i1(value) def get_md(llvm_module, value): + if is_md(value): + return value return value.get_metadata(llvm_module) def get_mdstr(llvm_module, value): + if is_mdstr(value): + return value return llvm.core.MetaDataString.get(llvm_module, value) +def get_mdlist(llvm_module, value): + if isinstance(value, list): + value = MDList([value]) + return get_md(llvm_module, value) + def get_lfunc(llvm_module, lfunc): assert lfunc.module is llvm_module return lfunc @@ -171,14 +192,9 @@ class DebugInfoDescriptor(object): md = self.get_metadata(llvm_module) llvm.core.MetaData.add_named_operand(llvm_module, "dbg", md) - -class EmptyMetadata(DebugInfoDescriptor): - """ - Metadata without any fields. - """ - - type_descriptors = [] - +#---------------------------------------------------------------------------- +# Convenience descriptors +#---------------------------------------------------------------------------- class MDList(DebugInfoDescriptor): """ @@ -189,12 +205,11 @@ class MDList(DebugInfoDescriptor): self.type_descriptors = [desc("op", get_md)] * len(operands) super(MDList, self).__init__(*operands) -class NULLDescriptor(DebugInfoDescriptor): +empty = MDList([]) - type_descriptors = [] - - def build_metadata(self, llvm_module): - return llvm.core.Constant.null(p_int32_t) +#---------------------------------------------------------------------------- +# Dwarf Debug descriptors +#---------------------------------------------------------------------------- class CompileUnitDescriptor(DebugInfoDescriptor): """ @@ -231,10 +246,10 @@ class CompileUnitDescriptor(DebugInfoDescriptor): desc("is_optimized", get_i1, default=False), desc("compile_flags", get_mdstr, default=""), desc("runtime_version", get_i32, default=0), - desc("enum_types", get_md, default=EmptyMetadata()), - desc("retained_types", get_md, default=EmptyMetadata()), - desc("subprograms", get_md, default=EmptyMetadata()), - desc("global_vars", get_md, default=EmptyMetadata()), + desc("enum_types", get_mdlist, default=empty), + desc("retained_types", get_mdlist, default=empty), + desc("subprograms", get_mdlist, default=empty), + desc("global_vars", get_mdlist, default=empty), ] def __init__(self, *args, **kwargs): @@ -267,7 +282,7 @@ class FileDescriptor(DebugInfoDescriptor): # Positional argument list starts here: desc("source_filename", get_mdstr), desc("source_filedir", get_mdstr), - desc("compile_unit", get_md, default=NULLDescriptor()), + desc("compile_unit", get_md, default=null), ] def __init__(self, *args, **kwargs): @@ -379,5 +394,5 @@ class PositionInfoDescriptor(DebugInfoDescriptor): desc("context_descr", get_md), # Scope of instruction # (FileDescr etc) desc("original_context_descr", get_md, # The original scope if inlined - default=NULLDescriptor()), + default=null), ] diff --git a/test/test_debuginfo.py b/test/test_debuginfo.py index 528ae6f..68ab29c 100644 --- a/test/test_debuginfo.py +++ b/test/test_debuginfo.py @@ -45,7 +45,7 @@ class TestDebugInfo(unittest.TestCase): "some_function", filedesc, 1, # line number - debuginfo.EmptyMetadata(), # Type descriptor + debuginfo.empty, # Type descriptor llvm_func=square, ) subprograms = debuginfo.MDList([subprogram]) From 2bef762ba2a90f2f52881e47cb5a06aaa0a09116 Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Wed, 23 Jan 2013 19:49:38 -0600 Subject: [PATCH 181/516] Add testcase with debuginfo and trap for gdb --- test/test_debuginfo.py | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/test/test_debuginfo.py b/test/test_debuginfo.py index 68ab29c..8ecaa3a 100644 --- a/test/test_debuginfo.py +++ b/test/test_debuginfo.py @@ -1,6 +1,7 @@ import os import unittest +import llvm.ee from llvm.core import * from llvm import _dwarf, debuginfo @@ -76,11 +77,17 @@ class TestDebugInfo(unittest.TestCase): # Build some instructions value = square.args[0] - result = bldr.fmul(value, value) + # result = bldr.fmul(value, value) + + # Generate an instruction that will result in a signal + result = bldr.fdiv(value, llvm.core.Constant.real(value.type, 0)) + ltrap = llvm.core.Function.intrinsic(mod, INTR_TRAP, []) + lcall = bldr.call(ltrap, []) ret = bldr.ret(result) # Annotate instructions with source position result.set_metadata("dbg", posinfo1.get_metadata(mod)) + lcall.set_metadata("dbg", posinfo1.get_metadata(mod)) ret.set_metadata("dbg", posinfo2.get_metadata(mod)) # ... Aaaand, test... @@ -98,7 +105,28 @@ class TestDebugInfo(unittest.TestCase): self.assertIn("some_function", modstr) self.assertIn("float (float)* @square", modstr) + return square + + +def debug_in_gdb(lfunc): + # Create an execution engine object. This will create a JIT compiler + # on platforms that support it, or an interpreter otherwise. + module = lfunc.module + ee = llvm.ee.ExecutionEngine.new(module) + float_type = lfunc.args[0].type + + # The arguments needs to be passed as "GenericValue" objects. + arg1_value = 5.0 + arg1 = llvm.ee.GenericValue.real(float_type, arg1_value) + + # Now let's compile and run! + retval = ee.run_function(lfunc, [arg1]) + print retval.as_real(float_type) + + if __name__ == '__main__': # TestDebugInfo("test_dwarf_constants").debug() # TestDebugInfo("test_debug_info_compile_unit").debug() +# tester = TestDebugInfo("test_debug_info_compile_unit") +# debug_in_gdb(tester.test_debug_info_compile_unit()) unittest.main() \ No newline at end of file From 3b1ae9889dc8744ca7ab28d05bb09e34efba23c6 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 24 Jan 2013 11:44:25 -0600 Subject: [PATCH 182/516] Ensure python2.6 support --- llvm/test_llvmpy.py | 76 ++++++++++++++++++++++++++++++------------ test/inlineasm.py | 3 +- test/loopvectorize.py | 3 +- test/metadata.py | 4 +-- test/tbaa.py | 3 +- test/test.py | 10 +++--- test/test_debuginfo.py | 3 +- 7 files changed, 70 insertions(+), 32 deletions(-) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 84a2a0a..a5fe957 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -8,6 +8,7 @@ import shutil import unittest import subprocess import tempfile +import contextlib is_py3k = bool(sys.version_info[0] == 3) BITS = tuple.__itemsize__ * 8 @@ -29,9 +30,40 @@ import llvm.ee as le tests = [] + # --------------------------------------------------------------------------- -class TestAsm(unittest.TestCase): +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 TestAsm(TestCase): def setUp(self): self.tmpdir = tempfile.mkdtemp() @@ -82,7 +114,7 @@ tests.append(TestAsm) # --------------------------------------------------------------------------- -class TestAttr(unittest.TestCase): +class TestAttr(TestCase): def make_module(self): test_module = """ define i32 @sum(i32, i32) { @@ -104,7 +136,7 @@ tests.append(TestAttr) # --------------------------------------------------------------------------- -class TestAtomic(unittest.TestCase): +class TestAtomic(TestCase): orderings = ['unordered', 'monotonic', 'acquire', 'release', 'acq_rel', 'seq_cst'] @@ -187,7 +219,7 @@ tests.append(TestAtomic) # --------------------------------------------------------------------------- -class TestConstExpr(unittest.TestCase): +class TestConstExpr(TestCase): def test_constexpr_opcode(self): mod = Module.new('test_constexpr_opcode') @@ -203,7 +235,7 @@ tests.append(TestConstExpr) # --------------------------------------------------------------------------- -class TestOperands(unittest.TestCase): +class TestOperands(TestCase): # implement a test function test_module = """ define i32 @prod(i32, i32) { @@ -259,7 +291,7 @@ tests.append(TestOperands) # --------------------------------------------------------------------------- -class TestPasses(unittest.TestCase): +class TestPasses(TestCase): # Create a module. asm = """ @@ -385,7 +417,7 @@ tests.append(TestPasses) # --------------------------------------------------------------------------- -class TestEngineBuilder(unittest.TestCase): +class TestEngineBuilder(TestCase): def make_test_module(self): module = Module.new("testmodule") @@ -452,7 +484,7 @@ tests.append(TestEngineBuilder) # --------------------------------------------------------------------------- -class TestExecutionEngine(unittest.TestCase): +class TestExecutionEngine(TestCase): def test_get_pointer_to_global(self): module = lc.Module.new(str(self)) gvar = module.add_global_variable(Type.int(), 'hello') @@ -492,7 +524,7 @@ class TestExecutionEngine(unittest.TestCase): tests.append(TestExecutionEngine) # --------------------------------------------------------------------------- -class TestObjCache(unittest.TestCase): +class TestObjCache(TestCase): def test_objcache(self): # Testing module aliasing @@ -593,7 +625,7 @@ tests.append(TestObjCache) # --------------------------------------------------------------------------- -class TestTargetMachines(unittest.TestCase): +class TestTargetMachines(TestCase): '''Exercise target machines Require PTX backend @@ -646,7 +678,7 @@ tests.append(TestTargetMachines) # --------------------------------------------------------------------------- -class TestNative(unittest.TestCase): +class TestNative(TestCase): def setUp(self): self.tmpdir = tempfile.mkdtemp() @@ -708,7 +740,7 @@ if sys.platform != 'win32': # --------------------------------------------------------------------------- -class TestNativeAsm(unittest.TestCase): +class TestNativeAsm(TestCase): def test_asm(self): m = Module.new('module1') @@ -731,7 +763,7 @@ tests.append(TestNativeAsm) # --------------------------------------------------------------------------- -class TestUses(unittest.TestCase): +class TestUses(TestCase): def test_uses(self): m = Module.new('a') @@ -768,7 +800,7 @@ tests.append(TestUses) # --------------------------------------------------------------------------- -class TestMetaData(unittest.TestCase): +class TestMetaData(TestCase): # test module metadata def test_metadata(self): m = Module.new('a') @@ -788,7 +820,7 @@ tests.append(TestMetaData) # --------------------------------------------------------------------------- -class TestInlining(unittest.TestCase): +class TestInlining(TestCase): def test_inline_call(self): mod = Module.new(__name__) callee = mod.add_function(Type.function(Type.int(), [Type.int()]), @@ -817,7 +849,7 @@ tests.append(TestInlining) # --------------------------------------------------------------------------- -class TestIssue10(unittest.TestCase): +class TestIssue10(TestCase): def test_issue10(self): m = Module.new('a') ti = Type.int() @@ -838,7 +870,7 @@ tests.append(TestIssue10) # --------------------------------------------------------------------------- -class TestOpaque(unittest.TestCase): +class TestOpaque(TestCase): def test_opaque(self): # Create an opaque type @@ -869,7 +901,7 @@ class TestOpaque(unittest.TestCase): tests.append(TestOpaque) # --------------------------------------------------------------------------- -class TestCPUSupport(unittest.TestCase): +class TestCPUSupport(TestCase): def _build_test_module(self): mod = Module.new('test') @@ -945,7 +977,7 @@ class TestCPUSupport(unittest.TestCase): tests.append(TestCPUSupport) # --------------------------------------------------------------------------- -class TestIntrinsicBasic(unittest.TestCase): +class TestIntrinsicBasic(TestCase): def _build_module(self, float): mod = Module.new('test') @@ -1032,7 +1064,7 @@ tests.append(TestIntrinsicBasic) # --------------------------------------------------------------------------- -class TestIntrinsic(unittest.TestCase): +class TestIntrinsic(TestCase): def test_bswap(self): # setup a function and a builder mod = Module.new('test') @@ -1130,7 +1162,7 @@ tests.append(TestIntrinsic) # --------------------------------------------------------------------------- -class TestVolatile(unittest.TestCase): +class TestVolatile(TestCase): def test_volatile(self): mod = Module.new('mod') @@ -1184,7 +1216,7 @@ tests.append(TestVolatile) # --------------------------------------------------------------------------- -class TestNamedMetaData(unittest.TestCase): +class TestNamedMetaData(TestCase): def test_named_md(self): m = Module.new('test_named_md') nmd = m.get_or_insert_named_metadata('something') diff --git a/test/inlineasm.py b/test/inlineasm.py index 635e6bf..df91d71 100644 --- a/test/inlineasm.py +++ b/test/inlineasm.py @@ -3,12 +3,13 @@ # Import the llvm-py modules. from llvm import * from llvm.core import * +from llvm.test_llvmpy import TestCase import logging import unittest -class TestInlineAsm(unittest.TestCase): +class TestInlineAsm(TestCase): def test_inline_asm(self): mod = Module.new(__name__) fnty = Type.function(Type.int(), [Type.int()]) diff --git a/test/loopvectorize.py b/test/loopvectorize.py index ff7cb10..9cf1654 100644 --- a/test/loopvectorize.py +++ b/test/loopvectorize.py @@ -2,13 +2,14 @@ from llvm.core import * from llvm.passes import * from llvm.ee import * import llvm +from llvm.test_llvmpy import TestCase from os.path import dirname, join as join_path import unittest import re -class TestLoopVectorizer(unittest.TestCase): +class TestLoopVectorizer(TestCase): def test_loop_vectorizer(self): if llvm.version <= (3, 1): return # SKIP diff --git a/test/metadata.py b/test/metadata.py index 90b6ae8..3228159 100644 --- a/test/metadata.py +++ b/test/metadata.py @@ -1,10 +1,10 @@ from __future__ import print_function import unittest - +from llvm.test_llvmpy import TestCase from llvm.core import * -class TestMetaData(unittest.TestCase): +class TestMetaData(TestCase): def test_metadata_get(self): module = Module.new('test_metadata') md = MetaData.get(module, [Constant.int(Type.int(), 1234)]) diff --git a/test/tbaa.py b/test/tbaa.py index d775a53..242ed19 100644 --- a/test/tbaa.py +++ b/test/tbaa.py @@ -1,8 +1,9 @@ from llvm.core import * from llvm.tbaa import * +from llvm.test_llvmpy import TestCase import unittest -class TestTBAABuilder(unittest.TestCase): +class TestTBAABuilder(TestCase): def test_tbaa_builder(self): mod = Module.new('test_tbaa_builder') fty = Type.function(Type.void(), [Type.pointer(Type.float())]) diff --git a/test/test.py b/test/test.py index bbc43f4..3b46281 100644 --- a/test/test.py +++ b/test/test.py @@ -7,9 +7,9 @@ import unittest, sys, logging from llvm import * from llvm.core import * +from llvm.test_llvmpy import TestCase - -class TestModule(unittest.TestCase): +class TestModule(TestCase): def setUp(self): pass @@ -100,8 +100,10 @@ def main(): gc.set_debug(gc.DEBUG_LEAK) # run tests - unittest.main(exit=False) # set exit to False so that it will return. - + if sys.version_info[:2] > (2, 6): + unittest.main(exit=False) # set exit to False so that it will return. + else: + unittest.main() # done for it in gc.garbage: logging.debug('garbage = %s', it) diff --git a/test/test_debuginfo.py b/test/test_debuginfo.py index 8ecaa3a..0340c1b 100644 --- a/test/test_debuginfo.py +++ b/test/test_debuginfo.py @@ -4,8 +4,9 @@ import unittest import llvm.ee from llvm.core import * from llvm import _dwarf, debuginfo +from llvm.test_llvmpy import TestCase -class TestDebugInfo(unittest.TestCase): +class TestDebugInfo(TestCase): def test_dwarf_constants(self): dwarf_constants = vars(_dwarf) From 60795adb5ecb6d57265e94b179669df21de48eb8 Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Thu, 24 Jan 2013 20:10:34 -0600 Subject: [PATCH 183/516] Implement JUMP_IF_FALSE bytecode instruction in llpython --- llpython/byte_translator.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/llpython/byte_translator.py b/llpython/byte_translator.py index 08b4560..93ccb6f 100644 --- a/llpython/byte_translator.py +++ b/llpython/byte_translator.py @@ -449,7 +449,11 @@ class LLVMTranslator (BytecodeFlowVisitor): return [self.builder.branch(self.llvm_blocks[i + arg + 3])] def op_JUMP_IF_FALSE (self, i, op, arg, *args, **kws): - raise NotImplementedError("LLVMTranslator.op_JUMP_IF_FALSE") + cond = args[0] + block_false = self.llvm_blocks[op] + block_true = self.llvm_blocks[i + 3] + return [self.builder.cbranch(cond, block_true, block_false)] + # raise NotImplementedError("LLVMTranslator.op_JUMP_IF_FALSE") def op_JUMP_IF_FALSE_OR_POP (self, i, op, arg, *args, **kws): raise NotImplementedError("LLVMTranslator.op_JUMP_IF_FALSE_OR_POP") From c0ff3615eeadf966e26b8b9bce3e76f5e5947404 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Fri, 25 Jan 2013 13:48:52 -0600 Subject: [PATCH 184/516] update changelog --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 815ecf7..5c8960c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +0.10.1, 25-Jan-2013: + * fix support for Python 2.6 + 0.10, 18-Jan-2013: * Add LLVM 3.2 support. From d355facf25bfd4316c5fa58b88beddf5fae1d099 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Fri, 25 Jan 2013 13:55:19 -0600 Subject: [PATCH 185/516] DOC: formatting --- CHANGELOG | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 5c8960c..f93e98e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,8 +1,10 @@ -0.10.1, 25-Jan-2013: +2013-01-25 0.10.1: +-------------------- * fix support for Python 2.6 -0.10, 18-Jan-2013: +2013-01-18 0.10.0: +-------------------- * Add LLVM 3.2 support. * New TargetData class. * Fixed windows issue (Issue #42). @@ -11,16 +13,16 @@ * Added llvm.passes.build_pass_managers as a simpler way to build PassManagers. -0.7, in progress: - +in progress, 0.7: +----------------- * Add llvm.core.Argument.alignment property. * Migrate to LLVM 2.8. * Fix ffi link issue on darwin (Albert Mietus) (Issue #29). * LLVM tutorial ported (Max Shawabkeh) (Issue #33). -0.6, 31-Aug-2010: - +2010-08-31 0.6: +----------------- * Add and remove function attributes (Krzysztof Goj) (Issue #21). * Wrap fadd,fsub,fmul (Aaron S Lav) (Issue #31). * Migrate to LLVM 2.7. @@ -39,16 +41,16 @@ * Migrate to LLVM 2.5. -0.5, 22-Nov-2008: - +2008-11-22 0.5: +----------------- * Added vicmp, vfcmp instructions and constant expressions. * Builds on FreeBSD. * Updated documentation. * Migrate to LLVM 2.4. -0.4, 21-Nov-2008: - +2008-11-21 0.4: +----------------- * Code cleanup, added license headers. * Added llvm.core.load_library_permanently() (Issue #12). * Fix comparison using != (Issue #11). @@ -57,8 +59,8 @@ * Added viewCFG methods to Function (Paulo Silva). -0.3, 8-Sep-2008: - +2008-09-08 0.3: +----------------- * Passes added. * Assembly support: create modules from .ll files. * Various bug fixes. @@ -70,13 +72,13 @@ * Updated documentation. -0.2.1, 18-Jun-2008: - +2008-06-28 0.2.1: +------------------- * Build cleanly with LLVM 2.3 and 2.3svn. -0.2, 15-Jun-2008: - +2008-06-15 0.2: +----------------- * Independent package, need not be unpacked into llvm/bindings. * Fixed ownership issues with Module/ModuleProvider. * Modules, values and types can be stringified, to get their LLVM @@ -91,7 +93,6 @@ * Lots of cleanup. -0.1, 10-May-2008: - - * Initial release. - +2008-05-10 0.1: +----------------- + * Initial release From 4ab6791e786d1951a8e4537ae162efb861e46a6d Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Fri, 25 Jan 2013 13:57:43 -0600 Subject: [PATCH 186/516] fix version string --- llvm/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/__init__.py b/llvm/__init__.py index 79399ff..defc483 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -2,7 +2,7 @@ Common classes related to LLVM. """ -__version__ = '0.10.0' +__version__ = '0.10.1' from weakref import WeakValueDictionary From 3772b8ba6e3794b64cfbd5a9580a51618f489e81 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Fri, 25 Jan 2013 14:05:40 -0600 Subject: [PATCH 187/516] REL: master now 0.10.2 --- CHANGELOG | 5 +++++ llvm/__init__.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index f93e98e..0efe307 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +2013-??-?? 0.10.2: +-------------------- + + + 2013-01-25 0.10.1: -------------------- * fix support for Python 2.6 diff --git a/llvm/__init__.py b/llvm/__init__.py index defc483..1935514 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -2,7 +2,7 @@ Common classes related to LLVM. """ -__version__ = '0.10.1' +__version__ = '0.10.2' from weakref import WeakValueDictionary From 8b918f37d6d2a34e0a8d7b980946a72b76eed74d Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Fri, 25 Jan 2013 17:01:54 -0600 Subject: [PATCH 188/516] change default --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 25b69ee..ce51a7c 100644 --- a/setup.py +++ b/setup.py @@ -11,8 +11,8 @@ else: default_llvm_config = 'llvm-config' llvm_config = os.environ.get('LLVM_CONFIG_PATH', default_llvm_config) -# set LLVMPY_DYNLINK=1, if you want to link _core.so dynamically to libLLVM.so -dynlink = int(os.environ.get('LLVMPY_DYNLINK', 0)) +# set LLVMPY_DYNLINK=0, if you want to link _core.so statically +dynlink = int(os.environ.get('LLVMPY_DYNLINK', 1)) def run_llvm_config(args): cmd = llvm_config + ' ' + ' '.join(args) From 3d66981cc1dc8a1700ffcc7f33e91b3c8072aebe Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Fri, 25 Jan 2013 17:06:42 -0600 Subject: [PATCH 189/516] update changelog --- CHANGELOG | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 0efe307..cc465d6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ 2013-??-?? 0.10.2: -------------------- - + * change default to link dynamically to LLVM (use LLVMPY_DYNLINK=0 to link + statically) 2013-01-25 0.10.1: From 7e7b362e478088142a33bc8a9217fa47219ebd18 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sat, 26 Jan 2013 11:20:53 -0600 Subject: [PATCH 190/516] Get llvm version as a string. It may contain 'svn' postfix. --- setup.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/setup.py b/setup.py index ce51a7c..0807ead 100644 --- a/setup.py +++ b/setup.py @@ -38,12 +38,7 @@ def get_enabled_components(): return run_llvm_config(['--components']).split() def get_llvm_version(): - # get version number; treat it as fixed point - pat = re.compile(r'(\d+)\.(\d+)') - m = pat.search(run_llvm_config([' --version'])) - if m is None: - sys.exit('could not determine llvm version') - return tuple(map(int, m.groups())) + return run_llvm_config([' --version']) def auto_intrinsic_gen(incdir): @@ -60,14 +55,14 @@ libdir = run_llvm_config(['--libdir']) ldflags = run_llvm_config(['--ldflags']) llvm_version = get_llvm_version() -print('LLVM version = %d.%d' % llvm_version) +print('LLVM version = %s' % llvm_version) auto_intrinsic_gen(incdir) macros = [('__STDC_CONSTANT_MACROS', None), ('__STDC_LIMIT_MACROS', None)] if dynlink: - libs_core = ['LLVM-%d.%d' % llvm_version] + libs_core = ['LLVM-%s' % llvm_version] objs_core = [] else: enabled_components = set(get_enabled_components()) From ffc067f8526773f7478d74f85c1b6c979f6f2e7f Mon Sep 17 00:00:00 2001 From: Jon Riehl Date: Mon, 28 Jan 2013 20:08:09 -0600 Subject: [PATCH 191/516] Attempt at a fix for issue #48. --- llpython/byte_control.py | 52 +++++++++++++++++---------- llpython/byte_flow.py | 69 ++++++++++++++++++++++++++---------- llpython/byte_translator.py | 7 ++-- llpython/bytecode_visitor.py | 26 ++++++++++++++ llpython/opcode_util.py | 19 +++++++--- llpython/phi_injector.py | 3 +- 6 files changed, 132 insertions(+), 44 deletions(-) diff --git a/llpython/byte_control.py b/llpython/byte_control.py index 34ebae4..9df6d5c 100644 --- a/llpython/byte_control.py +++ b/llpython/byte_control.py @@ -5,13 +5,13 @@ import opcode import opcode_util import pprint -from bytecode_visitor import BytecodeFlowVisitor, BenignBytecodeVisitorMixin +from bytecode_visitor import BasicBlockVisitor, BenignBytecodeVisitorMixin from control_flow import ControlFlowGraph # ______________________________________________________________________ -class ControlFlowBuilder (BenignBytecodeVisitorMixin, BytecodeFlowVisitor): - '''Visitor responsible for traversing a bytecode flow object and +class ControlFlowBuilder (BenignBytecodeVisitorMixin, BasicBlockVisitor): + '''Visitor responsible for traversing a bytecode basic block map and building a control flow graph (CFG). The primary purpose of this transformation is to create a CFG, @@ -27,21 +27,26 @@ class ControlFlowBuilder (BenignBytecodeVisitorMixin, BytecodeFlowVisitor): del self.nargs return ret_val - def enter_flow_object (self, flow): - super(ControlFlowBuilder, self).enter_flow_object(flow) - self.flow = flow + def enter_blocks (self, blocks): + super(ControlFlowBuilder, self).enter_blocks(blocks) + self.blocks = blocks + self.block_list = list(blocks.keys()) + self.block_list.sort() self.cfg = ControlFlowGraph() - for block in flow.keys(): - self.cfg.add_block(block, flow[block]) + self.loop_stack = [] + for block in self.block_list: + self.cfg.add_block(block, blocks[block]) - def exit_flow_object (self, flow): - super(ControlFlowBuilder, self).exit_flow_object(flow) - assert self.flow == flow + def exit_blocks (self, blocks): + super(ControlFlowBuilder, self).exit_blocks(blocks) + assert self.blocks == blocks self.cfg.compute_dataflow() self.cfg.update_for_ssa() ret_val = self.cfg + del self.loop_stack del self.cfg - del self.flow + del self.block_list + del self.blocks return ret_val def enter_block (self, block): @@ -58,13 +63,15 @@ class ControlFlowBuilder (BenignBytecodeVisitorMixin, BytecodeFlowVisitor): def exit_block (self, block): assert block == self.block del self.block - i, op, opname, arg, args = self.flow[block][-1] + i, op, arg = self.blocks[block][-1] + opname = opcode.opname[op] if op in opcode.hasjabs: self.cfg.add_edge(block, arg) elif op in opcode.hasjrel: self.cfg.add_edge(block, i + arg + 3) elif opname == 'BREAK_LOOP': - self.cfg.add_edge(block, arg) + loop_i, _, loop_arg = self.loop_stack[-1] + self.cfg.add_edge(block, loop_i + loop_arg + 3) elif opname != 'RETURN_VALUE': self.cfg.add_edge(block, self._get_next_block(block)) if op in opcode_util.hascbranch: @@ -80,15 +87,24 @@ class ControlFlowBuilder (BenignBytecodeVisitorMixin, BytecodeFlowVisitor): return super(ControlFlowBuilder, self).op_STORE_FAST(i, op, arg, *args, **kws) + def op_SETUP_LOOP (self, i, op, arg, *args, **kws): + self.loop_stack.append((i, op, arg)) + return super(ControlFlowBuilder, self).op_SETUP_LOOP(i, op, arg, *args, + **kws) + + def op_POP_BLOCK (self, i, op, arg, *args, **kws): + self.loop_stack.pop() + return super(ControlFlowBuilder, self).op_POP_BLOCK(i, op, arg, *args, + **kws) + # ______________________________________________________________________ def build_cfg (func): '''Given a Python function, create a bytecode flow, visit the flow object, and return a control flow graph.''' - import byte_flow - return ControlFlowBuilder().visit( - byte_flow.build_flow(func), - opcode_util.get_code_object(func).co_argcount) + co_obj = opcode_util.get_code_object(func) + return ControlFlowBuilder().visit(opcode_util.build_basic_blocks(co_obj), + co_obj.co_argcount) # ______________________________________________________________________ # Main (self-test) routine diff --git a/llpython/byte_flow.py b/llpython/byte_flow.py index 822e564..4a878b2 100644 --- a/llpython/byte_flow.py +++ b/llpython/byte_flow.py @@ -4,13 +4,13 @@ import dis import opcode -from bytecode_visitor import BytecodeIterVisitor +from bytecode_visitor import BasicBlockVisitor import opcode_util # ______________________________________________________________________ -class BytecodeFlowBuilder (BytecodeIterVisitor): - '''Transforms a bytecode vector into a bytecode "flow tree". +class BytecodeFlowBuilder (BasicBlockVisitor): + '''Transforms a CFG into a bytecode "flow tree". The flow tree is a Python dictionary, described loosely by the following set of productions: @@ -36,6 +36,8 @@ class BytecodeFlowBuilder (BytecodeIterVisitor): if pops: if pops < 0: pops = arg - pops - 1 + assert pops <= len(self.stack), ("Stack underflow at instruction " + "%d (%s)!" % (i, opname)) stk_args = self.stack[-pops:] del self.stack[-pops:] else: @@ -51,27 +53,50 @@ class BytecodeFlowBuilder (BytecodeIterVisitor): opname, pops, pushes, appends = self.opmap[op] return self._visit_op(i, op, arg, opname, pops, pushes, appends) - def enter_code_object (self, co_obj): - labels = dis.findlabels(co_obj.co_code) - labels = opcode_util.extendlabels(co_obj.co_code, labels) + def visit_cfg (self, cfg): + self.cfg = cfg + ret_val = self.visit(cfg.blocks) + del self.cfg + return ret_val + + def enter_blocks (self, blocks): + labels = list(blocks.keys()) + labels.sort() self.blocks = dict((index, []) for index in labels) - self.stack = [] self.loop_stack = [] - self.blocks[0] = self.block = [] + self.stacks = {} - def exit_code_object (self, co_obj): + def exit_blocks (self, blocks): ret_val = self.blocks - del self.stack + del self.stacks del self.loop_stack - del self.block del self.blocks return ret_val - def visit_op (self, i, op, arg): - if i in self.blocks: - self.block = self.blocks[i] - return super(BytecodeFlowBuilder, self).visit_op(i, op, arg) + def enter_block (self, block): + self.block_no = block + self.block = self.blocks[block] + in_blocks = self.cfg.blocks_in[block] + if len(in_blocks) == 0: + self.stack = [] + else: + pred_stack = None + for pred in in_blocks: + if pred in self.stacks: + pred_stack = self.stacks[pred] + break + if pred_stack is not None: + self.stack = pred_stack[:] + else: + raise NotImplementedError() + + def exit_block (self, block): + assert self.block_no == block + self.stacks[block] = self.stack + del self.stack + del self.block + del self.block_no op_BINARY_ADD = _op op_BINARY_AND = _op @@ -140,8 +165,14 @@ class BytecodeFlowBuilder (BytecodeIterVisitor): op_INPLACE_XOR = _op op_JUMP_ABSOLUTE = _op op_JUMP_FORWARD = _op - op_JUMP_IF_FALSE = _op - op_JUMP_IF_TRUE = _op + + def op_JUMP_IF_FALSE (self, i, op, arg): + opname, _, _, _ = self.opmap[op] + ret_val = (i, op, opname, arg, [self.stack[-1]]) + self.block.append(ret_val) + return ret_val + + op_JUMP_IF_TRUE = op_JUMP_IF_FALSE op_LIST_APPEND = _op op_LOAD_ATTR = _op op_LOAD_CLOSURE = _op @@ -211,7 +242,9 @@ class BytecodeFlowBuilder (BytecodeIterVisitor): def build_flow (func): '''Given a Python function, return a bytecode flow tree for that function.''' - return BytecodeFlowBuilder().visit(opcode_util.get_code_object(func)) + import byte_control + cfg = byte_control.build_cfg(func) + return BytecodeFlowBuilder().visit_cfg(cfg) # ______________________________________________________________________ # Main (self-test) routine diff --git a/llpython/byte_translator.py b/llpython/byte_translator.py index 93ccb6f..de36640 100644 --- a/llpython/byte_translator.py +++ b/llpython/byte_translator.py @@ -153,7 +153,7 @@ class LLVMTranslator (BytecodeFlowVisitor): environment.''' if llvm_type is None: if llvm_function is None: - llvm_type = lc.Type.function(lvoid, ()) + llvm_type = lc.Type.function(bytetype.lvoid, ()) else: llvm_type = llvm_function.type.pointee if env is None: @@ -178,7 +178,8 @@ class LLVMTranslator (BytecodeFlowVisitor): self.globals = func_globals nargs = self.code_obj.co_argcount self.cfg = self.control_flow_builder.visit( - self.bytecode_flow_builder.visit(self.code_obj), nargs) + opcode_util.build_basic_blocks(self.code_obj), nargs) + self.cfg.blocks = self.bytecode_flow_builder.visit_cfg(self.cfg) self.llvm_function = llvm_function flow = self.phi_injector.visit_cfg(self.cfg, nargs) ret_val = self.visit(flow) @@ -450,7 +451,7 @@ class LLVMTranslator (BytecodeFlowVisitor): def op_JUMP_IF_FALSE (self, i, op, arg, *args, **kws): cond = args[0] - block_false = self.llvm_blocks[op] + block_false = self.llvm_blocks[i + 3 + arg] block_true = self.llvm_blocks[i + 3] return [self.builder.cbranch(cond, block_true, block_false)] # raise NotImplementedError("LLVMTranslator.op_JUMP_IF_FALSE") diff --git a/llpython/bytecode_visitor.py b/llpython/bytecode_visitor.py index 091e138..dcc3a0c 100644 --- a/llpython/bytecode_visitor.py +++ b/llpython/bytecode_visitor.py @@ -164,6 +164,32 @@ class BytecodeIterVisitor (BytecodeVisitor): # ______________________________________________________________________ +class BasicBlockVisitor (BytecodeVisitor): + def visit (self, blocks): + self.enter_blocks(blocks) + block_indices = list(blocks.keys()) + block_indices.sort() + for block_index in block_indices: + self.enter_block(block_index) + for i, op, arg in blocks[block_index]: + self.visit_op(i, op, arg) + self.exit_block(block_index) + return self.exit_blocks(blocks) + + def enter_blocks (self, blocks): + pass + + def exit_blocks (self, blocks): + pass + + def enter_block (self, block_index): + pass + + def exit_block (self, block_index): + pass + +# ______________________________________________________________________ + class BytecodeFlowVisitor (BytecodeVisitor): def visit (self, flow): self.block_list = list(flow.keys()) diff --git a/llpython/opcode_util.py b/llpython/opcode_util.py index 5c0cff9..efd0c5c 100644 --- a/llpython/opcode_util.py +++ b/llpython/opcode_util.py @@ -79,9 +79,9 @@ OPCODE_MAP = { 'INPLACE_XOR': (2, 1, None), 'JUMP_ABSOLUTE': (0, None, 1), 'JUMP_FORWARD': (0, None, 1), - 'JUMP_IF_FALSE': (1, None, 1), + 'JUMP_IF_FALSE': (1, 1, 1), 'JUMP_IF_FALSE_OR_POP': (None, None, None), - 'JUMP_IF_TRUE': (1, None, 1), + 'JUMP_IF_TRUE': (1, 1, 1), 'JUMP_IF_TRUE_OR_POP': (None, None, None), 'LIST_APPEND': (2, 0, 1), 'LOAD_ATTR': (1, 1, None), @@ -148,7 +148,7 @@ OPCODE_MAP = { # ______________________________________________________________________ # Module functions -def itercode(code): +def itercode(code, start = 0): """Return a generator of byte-offset, opcode, and argument from a byte-code-string """ @@ -159,7 +159,7 @@ def itercode(code): n = len(code) while i < n: op = code[i] - num = i + num = i + start i = i + 1 oparg = None if op >= opcode.HAVE_ARGUMENT: @@ -211,5 +211,16 @@ def extendlabels(code, labels = None): def get_code_object (func): return getattr(func, '__code__', getattr(func, 'func_code', None)) +# ______________________________________________________________________ + +def build_basic_blocks (co_obj): + co_code = co_obj.co_code + labels = extendlabels(co_code, dis.findlabels(co_code)) + labels.sort() + blocks = dict((index, list(itercode(co_code[index:next_index], index))) + for index, next_index in zip([0] + labels, + labels + [len(co_code)])) + return blocks + # ______________________________________________________________________ # End of opcode_util.py diff --git a/llpython/phi_injector.py b/llpython/phi_injector.py index 2618e97..6cccb66 100644 --- a/llpython/phi_injector.py +++ b/llpython/phi_injector.py @@ -127,9 +127,10 @@ class PhiInjector (BenignBytecodeVisitorMixin, BytecodeFlowVisitor): def inject_phis (func): '''Given a Python function, return a bytecode flow object that has been transformed by a fresh PhiInjector instance.''' - import byte_control + import byte_control, byte_flow argcount = byte_control.opcode_util.get_code_object(func).co_argcount cfg = byte_control.build_cfg(func) + cfg.blocks = byte_flow.BytecodeFlowBuilder().visit_cfg(cfg) return PhiInjector().visit_cfg(cfg, argcount) # ______________________________________________________________________ From b895f1fc99e4dd76444e1ba011a31a515c03eb8e Mon Sep 17 00:00:00 2001 From: Jon Riehl Date: Tue, 29 Jan 2013 16:44:03 -0600 Subject: [PATCH 192/516] Added explicit branch to otherwise unterminated basic blocks in llpython.byte_translator. --- llpython/byte_translator.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/llpython/byte_translator.py b/llpython/byte_translator.py index de36640..3922099 100644 --- a/llpython/byte_translator.py +++ b/llpython/byte_translator.py @@ -225,6 +225,12 @@ class LLVMTranslator (BytecodeFlowVisitor): return ret_val def exit_block (self, block): + bb_instrs = self.llvm_block.instructions + if ((len(bb_instrs) == 0) or + (not bb_instrs[-1].is_terminator)): + out_blocks = list(self.cfg.blocks_out[block]) + assert len(out_blocks) == 1 + self.builder.branch(self.llvm_blocks[out_blocks[0]]) del self.llvm_block del self.builder From 5d54bbb1cdc3c14f885135fdf365246e25b180ed Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 31 Jan 2013 16:00:39 -0600 Subject: [PATCH 193/516] Autodetect libLLVM*.so and use it if it exists; or, user can override if LLVMPY_DYNLINK. --- setup.py | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index 0807ead..4ad1b35 100644 --- a/setup.py +++ b/setup.py @@ -11,8 +11,6 @@ else: default_llvm_config = 'llvm-config' llvm_config = os.environ.get('LLVM_CONFIG_PATH', default_llvm_config) -# set LLVMPY_DYNLINK=0, if you want to link _core.so statically -dynlink = int(os.environ.get('LLVMPY_DYNLINK', 1)) def run_llvm_config(args): cmd = llvm_config + ' ' + ' '.join(args) @@ -20,8 +18,7 @@ def run_llvm_config(args): if run_llvm_config(['--version']) == '': sys.exit("Cannot invoke llvm-config.\n" - "Try setting LLVM_CONFIG_PATH=/path/to/llvm-config") - + "Try setting LLVM_CONFIG_PATH=/path/to/llvm-config") def get_libs_and_objs(components): parts = run_llvm_config(['--libs'] + components).split() @@ -61,7 +58,37 @@ auto_intrinsic_gen(incdir) macros = [('__STDC_CONSTANT_MACROS', None), ('__STDC_LIMIT_MACROS', None)] + +def determine_to_use_dynlink(libdir, llvm_version): + user_envvar = os.environ.get('LLVMPY_DYNLINK', None) + if user_envvar is not None: + # if users sets LLVMPY_DYNLINK=[0|1] + # respect the user setting + print('User sets LLVMPY_DYNLINK to %s' % user_envvar) + return bool(int(user_envvar)) + else: + # otherwise, determine by scanning the libdir + libfile = 'libLLVM-%s' % llvm_version + print('Searching shared library %s in %s' % (libfile, libdir)) + so = '%s.so' % libfile + dylib = '%s.dylib' % libfile + dll = '%s.dll' % libfile + libdir_content = os.listdir(libdir) + if sys.platform.startswith('linux'): + return so in libdir_content + elif sys.platform.startswith('darwin'): + return dylib in libdir_content or so in libdir_content + elif sys.platform.startswith('win32'): + return dll in libdir_content + else: # other platforms + return any((x in libdir_content) for x in [so, dyld, dll]) + + +dynlink = determine_to_use_dynlink(libdir, llvm_version) + + if dynlink: + print('Using dynamic linking') libs_core = ['LLVM-%s' % llvm_version] objs_core = [] else: From 1d4c431b23283a844ea9c58f8d53f027b5601f3b Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Thu, 31 Jan 2013 17:53:01 -0600 Subject: [PATCH 194/516] minor simplification --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 4ad1b35..839d816 100644 --- a/setup.py +++ b/setup.py @@ -60,8 +60,8 @@ macros = [('__STDC_CONSTANT_MACROS', None), ('__STDC_LIMIT_MACROS', None)] def determine_to_use_dynlink(libdir, llvm_version): - user_envvar = os.environ.get('LLVMPY_DYNLINK', None) - if user_envvar is not None: + user_envvar = os.getenv('LLVMPY_DYNLINK') + if user_envvar: # if users sets LLVMPY_DYNLINK=[0|1] # respect the user setting print('User sets LLVMPY_DYNLINK to %s' % user_envvar) From 5dd0948c6505591f25531e3be88424ca5eef56c8 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Thu, 31 Jan 2013 17:54:20 -0600 Subject: [PATCH 195/516] cleanup --- docs/gh-pages.py | 2 +- llpython/nobitey.py | 2 +- llvm-config-win32.py | 4 ++-- llvm/passes.py | 4 ++-- llvm/tbaa.py | 8 ++++---- llvm/test_llvmpy.py | 4 ++-- setup.py | 2 +- test/loopvectorize.c | 2 +- test/loopvectorize.py | 2 +- test/test_debuginfo.py | 2 +- www/makeweb.py | 2 +- www/src/license.txt | 4 ++-- www/src/userguide.txt | 10 +++++----- 13 files changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/gh-pages.py b/docs/gh-pages.py index d9c8614..dd30e28 100755 --- a/docs/gh-pages.py +++ b/docs/gh-pages.py @@ -86,7 +86,7 @@ if __name__ == '__main__': tag = sh2('git describe --exact-match') except CalledProcessError: tag = "dev" # Fallback - + startdir = os.getcwdu() if not os.path.exists(pages_dir): # init the repo diff --git a/llpython/nobitey.py b/llpython/nobitey.py index b756fc8..014216b 100644 --- a/llpython/nobitey.py +++ b/llpython/nobitey.py @@ -16,7 +16,7 @@ from pyaddfunc import pyaddfunc LLVM_TO_INT_PARSE_STR_MAP = { 8 : 'b', - 16 : 'h', + 16 : 'h', 32 : 'i', # Note that on 32-bit systems sizeof(int) == sizeof(long) 64 : 'L', # Seeing sizeof(long long) == 8 on both 32 and 64-bit platforms } diff --git a/llvm-config-win32.py b/llvm-config-win32.py index 2b6e8f5..595452c 100644 --- a/llvm-config-win32.py +++ b/llvm-config-win32.py @@ -63,7 +63,7 @@ Shell32 print('-lLLVMNVPTXCodeGen') print('-lLLVMNVPTXDesc') print('-lLLVMNVPTXInfo') -elif sys.argv[1] == '--includedir': +elif sys.argv[1] == '--includedir': llvmbin = find_path_of('llvm-tblgen.exe') if llvmbin is None: raise RuntimeError('Could not find LLVM') @@ -71,7 +71,7 @@ elif sys.argv[1] == '--includedir': if not os.path.exists(os.path.join(incdir, 'llvm/BasicBlock.h')): raise RuntimeError('Could not find LLVM include dir') print incdir -elif sys.argv[1] == '--libdir': +elif sys.argv[1] == '--libdir': llvmbin = find_path_of('llvm-tblgen.exe') if llvmbin is None: raise RuntimeError('Could not find LLVM') diff --git a/llvm/passes.py b/llvm/passes.py index b1f236c..4d7efb4 100644 --- a/llvm/passes.py +++ b/llvm/passes.py @@ -156,7 +156,7 @@ class PassManager(object): def add(self, pass_obj): '''Add a pass to the pass manager. - + pass_obj --- Either a Pass instance, a string name of a pass ''' if isinstance(pass_obj, Pass): @@ -340,7 +340,7 @@ def build_pass_managers(tm, opt=2, loop_vectorize=False, vectorize=False, inline_threshold=2000, pm=True, fpm=True, mod=None): ''' tm --- The TargetMachine for which the passes are optimizing for. - The TargetMachine must stay alive until the pass managers + The TargetMachine must stay alive until the pass managers are removed. opt --- [0-3] Optimization level. Default to 2. loop_vectorize --- [boolean] Whether to use loop-vectorizer. diff --git a/llvm/tbaa.py b/llvm/tbaa.py index d8e0074..b510ce2 100644 --- a/llvm/tbaa.py +++ b/llvm/tbaa.py @@ -2,11 +2,11 @@ from llvm.core import * class TBAABuilder(object): '''Simplify creation of TBAA metadata. - - Each TBAABuidler object operates on a module. + + Each TBAABuidler object operates on a module. User can create multiple TBAABuilder on a module ''' - + def __init__(self, module, rootid): ''' module --- the module to use. @@ -23,7 +23,7 @@ class TBAABuilder(object): def get_node(self, name, parent=None, const=False): '''Returns a MetaData object representing a TBAA node. - Use loadstore_instruction.set_metadata('tbaa', node) to + Use loadstore_instruction.set_metadata('tbaa', node) to bind a type to a memory. ''' parent = parent or self.root diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index a5fe957..05b7d72 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -454,7 +454,7 @@ class TestEngineBuilder(TestCase): with self.assertRaises(llvm.LLVMException): # Ensure the targetmachine is owned. llvm._util.check_is_unowned(tm) - + with self.assertRaises(llvm.LLVMException): # Ensure the module is owned. @@ -932,7 +932,7 @@ class TestCPUSupport(TestCase): 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) diff --git a/setup.py b/setup.py index 839d816..afbf56e 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ def run_llvm_config(args): if run_llvm_config(['--version']) == '': sys.exit("Cannot invoke llvm-config.\n" - "Try setting LLVM_CONFIG_PATH=/path/to/llvm-config") + "Try setting LLVM_CONFIG_PATH=/path/to/llvm-config") def get_libs_and_objs(components): parts = run_llvm_config(['--libs'] + components).split() diff --git a/test/loopvectorize.c b/test/loopvectorize.c index a46b633..a498898 100644 --- a/test/loopvectorize.c +++ b/test/loopvectorize.c @@ -41,4 +41,4 @@ void ex7(int *A, int *B, int n, int k) { void ex8(int *A, char *B, int n, int k) { for (int i = 0; i < n; ++i) A[i] += 4 * B[i]; -} \ No newline at end of file +} diff --git a/test/loopvectorize.py b/test/loopvectorize.py index 9cf1654..2c12d5b 100644 --- a/test/loopvectorize.py +++ b/test/loopvectorize.py @@ -40,4 +40,4 @@ class TestLoopVectorizer(TestCase): if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() diff --git a/test/test_debuginfo.py b/test/test_debuginfo.py index 0340c1b..33dbbdb 100644 --- a/test/test_debuginfo.py +++ b/test/test_debuginfo.py @@ -130,4 +130,4 @@ if __name__ == '__main__': # TestDebugInfo("test_debug_info_compile_unit").debug() # tester = TestDebugInfo("test_debug_info_compile_unit") # debug_in_gdb(tester.test_debug_info_compile_unit()) - unittest.main() \ No newline at end of file + unittest.main() diff --git a/www/makeweb.py b/www/makeweb.py index 936b69e..81c9283 100755 --- a/www/makeweb.py +++ b/www/makeweb.py @@ -139,7 +139,7 @@ def get_opts(): usage = "usage: %prog [options] srcdir destdir" p = OptionParser(usage=usage) - p.add_option("-f", "--force", action="store_true", dest="force", default=False, + p.add_option("-f", "--force", action="store_true", dest="force", default=False, help="ignore timestamps and force build of all files") p.add_option("-v", "--verbose", action="count", dest="verbose", default=0, help="be chatty (use more v's to be more friendly)") diff --git a/www/src/license.txt b/www/src/license.txt index e40da20..9465a49 100644 --- a/www/src/license.txt +++ b/www/src/license.txt @@ -1,12 +1,12 @@ License ======= -llvm-py is distributed under the +llvm-py is distributed under the http://www.opensource.org/licenses/bsd-license.php[new BSD license]. This is similar to LLVM's license. You should be able to use llvm-py where-ever and how-ever you're able to use LLVM itself. -The license text is present in the +The license text is present in the http://code.google.com/p/llvm-py/source/browse/trunk/LICENSE[LICENSE] file in the distribution, and is reproduced here: diff --git a/www/src/userguide.txt b/www/src/userguide.txt index cf67e1c..bbd7ad3 100644 --- a/www/src/userguide.txt +++ b/www/src/userguide.txt @@ -35,7 +35,7 @@ information is available link:license.html[here]. .Platforms llvm-py has been built/tested/reported to work on various GNU/Linux flavours, *BSD, Mac OS X; on i386 and amd64 architectures. Windows is not -supported, for a variety of reasons. +supported, for a variety of reasons. .Versions llvm-py 0.6 requires verion 2.7 of LLVM. It will not work with previous @@ -433,7 +433,7 @@ Here is a quick overview of the contents of each package: sizes and alignment of primitive types, endinanness etc) .llvm.passes -- PassManager -- represents an LLVM pass manager +- PassManager -- represents an LLVM pass manager - FunctionPassManager -- represents an LLVM function pass manager - constants +PASS_*+ that represent various passes @@ -1007,7 +1007,7 @@ The `Function` object represents an instance of a function type. Such objects contain `Argument` objects, which represent the actual, local-variable-like arguments of the function (not to be confused with the arguments returned by a function _type_ object -- these represent -the _type_ of the arguments). +the _type_ of the arguments). The various `Instruction`-s are created by the `Builder` class. Most instructions are represented by `Instruction` itself, but there are @@ -1260,7 +1260,7 @@ Global Value (llvm.core) The class `llvm.core.GlobalValue` represents module-scope aliases, variables and functions. Global variables are represented by the sub-class -`llvm.core.GlobalVariable` and functions by `llvm.core.Function`. +`llvm.core.GlobalVariable` and functions by `llvm.core.Function`. Global values have the read-write properties `linkage`, `section`, `visibility` and `alignment`. Use one of the following constants (from @@ -1841,7 +1841,7 @@ The `llvm.core.PHINode` is a subclass of created (using `Builder.phi`) the phi node contains no incoming blocks (nor their corresponding values). To add an incoming arc to the phi node, use the `add_incoming` method, which takes a source -block (`llvm.core.BasicBlock` object) and a value (object of +block (`llvm.core.BasicBlock` object) and a value (object of `llvm.core.Value` or of a class derived from it) that the phi node will take on if control branches in from that block. From fe37d8bae0b095f7a23cc3b325fbc27124399ba2 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Thu, 31 Jan 2013 20:21:15 -0600 Subject: [PATCH 196/516] DOC: explain link detection in changelog --- CHANGELOG | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index cc465d6..14e4503 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,10 @@ 2013-??-?? 0.10.2: -------------------- - * change default to link dynamically to LLVM (use LLVMPY_DYNLINK=0 to link - statically) + * change default to link dynamically to LLVM use: + $ export LLVMPY_DYNLINK=0 # link statically + $ export LLVMPY_DYNLINK=1 # link dynamically + $ unset LLVMPY_DYNLINK # tries to link dynamically if LLVM shared + # objects are found and statically otherwise 2013-01-25 0.10.1: From 7bd02ef91a3969a872721cd4c7fe61ba21b0e8e1 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 1 Feb 2013 12:06:17 -0600 Subject: [PATCH 197/516] Update changelog about recent llpython fixes. --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 14e4503..fb9e40e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,7 +5,7 @@ $ export LLVMPY_DYNLINK=1 # link dynamically $ unset LLVMPY_DYNLINK # tries to link dynamically if LLVM shared # objects are found and statically otherwise - + * fix llpython for Python 2.6 support. 2013-01-25 0.10.1: -------------------- From 4fb754924386d931c2a2d2305bb1ae9779b32d4a Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Fri, 1 Feb 2013 14:16:38 -0600 Subject: [PATCH 198/516] add release date --- CHANGELOG | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index fb9e40e..3d19ab8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,11 +1,12 @@ -2013-??-?? 0.10.2: +2013-02-01 0.10.2: -------------------- * change default to link dynamically to LLVM use: $ export LLVMPY_DYNLINK=0 # link statically $ export LLVMPY_DYNLINK=1 # link dynamically $ unset LLVMPY_DYNLINK # tries to link dynamically if LLVM shared # objects are found and statically otherwise - * fix llpython for Python 2.6 support. + * fix llpython for Python 2.6 support + 2013-01-25 0.10.1: -------------------- From 3f789913f533ce85f3f6e80116e4993cb4cb5654 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Fri, 1 Feb 2013 15:55:12 -0600 Subject: [PATCH 199/516] add versioneer --- setup.py | 46 ++-- versioneer.py | 642 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 669 insertions(+), 19 deletions(-) create mode 100644 versioneer.py diff --git a/setup.py b/setup.py index afbf56e..6816f81 100644 --- a/setup.py +++ b/setup.py @@ -1,8 +1,15 @@ import sys import os -import re from distutils.core import setup, Extension +import versioneer + + +versioneer.versionfile_source = 'llvm/_version.py' +versioneer.versionfile_build = 'llvm/_version.py' +versioneer.tag_prefix = '' +versioneer.parentdir_prefix = 'llvmpy-' + # On win32, there is a fake llvm-config since llvm doesn't supply one if sys.platform == 'win32': @@ -130,20 +137,24 @@ else: macros.append(('_GNU_SOURCE', None)) extra_link_args = ldflags.split() -kwds = dict(ext_modules = [Extension( - name='llvm._core', - sources=['llvm/_core.cpp', 'llvm/wrap.cpp', 'llvm/extra.cpp'], - define_macros = macros, - include_dirs = ['/usr/include', incdir], - library_dirs = [libdir], - libraries = libs_core, - extra_objects = objs_core, - extra_link_args = extra_link_args), +kwds = dict( + ext_modules = [ + Extension( + name='llvm._core', + sources=['llvm/_core.cpp', 'llvm/wrap.cpp', 'llvm/extra.cpp'], + define_macros = macros, + include_dirs = ['/usr/include', incdir], + library_dirs = [libdir], + libraries = libs_core, + extra_objects = objs_core, + extra_link_args = extra_link_args), - Extension(name='llvm._dwarf', - sources=['llvm/_dwarf.cpp'], - include_dirs=[incdir]) -]) + Extension(name='llvm._dwarf', + sources=['llvm/_dwarf.cpp'], + include_dirs=[incdir]) + ], + cmdclass = versioneer.get_cmdclass(), +) def run_2to3(): import lib2to3.refactor @@ -155,19 +166,16 @@ def run_2to3(): # if fix.split('fix_')[-1] not in ('next',) #] - kwds["cmdclass"] = {"build_py": build_py} + kwds["cmdclass"].update(dict(build_py=build_py)) if sys.version_info[0] >= 3: run_2to3() -# Read version from llvm/__init__.py -pat = re.compile(r'__version__\s*=\s*(\S+)', re.M) -data = open('llvm/__init__.py').read() -kwds['version'] = eval(pat.search(data).group(1)) kwds['long_description'] = open('README.rst').read() setup( name = 'llvmpy', + version=versioneer.get_version(), description = 'Python bindings for LLVM', author = 'R Mahadevan', maintainer = 'Continuum Analytics, Inc.', diff --git a/versioneer.py b/versioneer.py new file mode 100644 index 0000000..02bc76a --- /dev/null +++ b/versioneer.py @@ -0,0 +1,642 @@ +#! /usr/bin/python + +"""versioneer.py + +(like a rocketeer, but for versions) + +* https://github.com/warner/python-versioneer +* Brian Warner +* License: Public Domain +* Version: 0.7+ + +This file helps distutils-based projects manage their version number by just +creating version-control tags. + +For developers who work from a VCS-generated tree (e.g. 'git clone' etc), +each 'setup.py version', 'setup.py build', 'setup.py sdist' will compute a +version number by asking your version-control tool about the current +checkout. The version number will be written into a generated _version.py +file of your choosing, where it can be included by your __init__.py + +For users who work from a VCS-generated tarball (e.g. 'git archive'), it will +compute a version number by looking at the name of the directory created when +te tarball is unpacked. This conventionally includes both the name of the +project and a version number. + +For users who work from a tarball built by 'setup.py sdist', it will get a +version number from a previously-generated _version.py file. + +As a result, loading code directly from the source tree will not result in a +real version. If you want real versions from VCS trees (where you frequently +update from the upstream repository, or do new development), you will need to +do a 'setup.py version' after each update, and load code from the build/ +directory. + +You need to provide this code with a few configuration values: + + versionfile_source: + A project-relative pathname into which the generated version strings + should be written. This is usually a _version.py next to your project's + main __init__.py file. If your project uses src/myproject/__init__.py, + this should be 'src/myproject/_version.py'. This file should be checked + in to your VCS as usual: the copy created below by 'setup.py + update_files' will include code that parses expanded VCS keywords in + generated tarballs. The 'build' and 'sdist' commands will replace it with + a copy that has just the calculated version string. + + versionfile_build: + Like versionfile_source, but relative to the build directory instead of + the source directory. These will differ when your setup.py uses + 'package_dir='. If you have package_dir={'myproject': 'src/myproject'}, + then you will probably have versionfile_build='myproject/_version.py' and + versionfile_source='src/myproject/_version.py'. + + tag_prefix: a string, like 'PROJECTNAME-', which appears at the start of all + VCS tags. If your tags look like 'myproject-1.2.0', then you + should use tag_prefix='myproject-'. If you use unprefixed tags + like '1.2.0', this should be an empty string. + + parentdir_prefix: a string, frequently the same as tag_prefix, which + appears at the start of all unpacked tarball filenames. If + your tarball unpacks into 'myproject-1.2.0', this should + be 'myproject-'. + +To use it: + + 1: include this file in the top level of your project + 2: make the following changes to the top of your setup.py: + import versioneer + versioneer.versionfile_source = 'src/myproject/_version.py' + versioneer.versionfile_build = 'myproject/_version.py' + versioneer.tag_prefix = '' # tags are like 1.2.0 + versioneer.parentdir_prefix = 'myproject-' # dirname like 'myproject-1.2.0' + 3: add the following arguments to the setup() call in your setup.py: + version=versioneer.get_version(), + cmdclass=versioneer.get_cmdclass(), + 4: run 'setup.py update_files', which will create _version.py, and will + append the following to your __init__.py: + from _version import __version__ + 5: modify your MANIFEST.in to include versioneer.py + 6: add both versioneer.py and the generated _version.py to your VCS +""" + +import os +import sys +import re +import subprocess +from distutils.core import Command +from distutils.command.sdist import sdist as _sdist +from distutils.command.build import build as _build + +versionfile_source = None +versionfile_build = None +tag_prefix = None +parentdir_prefix = None + +VCS = "git" +IN_LONG_VERSION_PY = False +GIT = "git" + + +LONG_VERSION_PY = ''' +IN_LONG_VERSION_PY = True +# This file helps to compute a version number in source trees obtained from +# git-archive tarball (such as those provided by github's download-from-tag +# feature). Distribution tarballs (build by setup.py sdist) and build +# directories (produced by setup.py build) will contain a much shorter file +# that just contains the computed version number. + +# This file is released into the public domain. Generated by +# versioneer-0.7+ (https://github.com/warner/python-versioneer) + +# these strings will be replaced by git during git-archive +git_refnames = "%(DOLLAR)sFormat:%%d%(DOLLAR)s" +git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s" + + +import subprocess +import sys + +def run_command(args, cwd=None, verbose=False): + try: + # remember shell=False, so use git.cmd on windows, not just git + p = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd) + except EnvironmentError: + e = sys.exc_info()[1] + if verbose: + print("unable to run %%s" %% args[0]) + print(e) + return None + stdout = p.communicate()[0].strip() + if sys.version >= '3': + stdout = stdout.decode() + if p.returncode != 0: + if verbose: + print("unable to run %%s (error)" %% args[0]) + return None + return stdout + + +import sys +import re +import os.path + +def get_expanded_variables(versionfile_source): + # the code embedded in _version.py can just fetch the value of these + # variables. When used from setup.py, we don't want to import + # _version.py, so we do it with a regexp instead. This function is not + # used from _version.py. + variables = {} + try: + for line in open(versionfile_source,"r").readlines(): + if line.strip().startswith("git_refnames ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + variables["refnames"] = mo.group(1) + if line.strip().startswith("git_full ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + variables["full"] = mo.group(1) + except EnvironmentError: + pass + return variables + +def versions_from_expanded_variables(variables, tag_prefix, verbose=False): + refnames = variables["refnames"].strip() + if refnames.startswith("$Format"): + if verbose: + print("variables are unexpanded, not using") + return {} # unexpanded, so not in an unpacked git-archive tarball + refs = set([r.strip() for r in refnames.strip("()").split(",")]) + for ref in list(refs): + if not re.search(r'\d', ref): + if verbose: + print("discarding '%%s', no digits" %% ref) + refs.discard(ref) + # Assume all version tags have a digit. git's %%d expansion + # behaves like git log --decorate=short and strips out the + # refs/heads/ and refs/tags/ prefixes that would let us + # distinguish between branches and tags. By ignoring refnames + # without digits, we filter out many common branch names like + # "release" and "stabilization", as well as "HEAD" and "master". + if verbose: + print("remaining refs: %%s" %% ",".join(sorted(refs))) + for ref in sorted(refs): + # sorting will prefer e.g. "2.0" over "2.0rc1" + if ref.startswith(tag_prefix): + r = ref[len(tag_prefix):] + if verbose: + print("picking %%s" %% r) + return { "version": r, + "full": variables["full"].strip() } + # no suitable tags, so we use the full revision id + if verbose: + print("no suitable tags, using full revision id") + return { "version": variables["full"].strip(), + "full": variables["full"].strip() } + +def versions_from_vcs(tag_prefix, versionfile_source, verbose=False): + # this runs 'git' from the root of the source tree. That either means + # someone ran a setup.py command (and this code is in versioneer.py, so + # IN_LONG_VERSION_PY=False, thus the containing directory is the root of + # the source tree), or someone ran a project-specific entry point (and + # this code is in _version.py, so IN_LONG_VERSION_PY=True, thus the + # containing directory is somewhere deeper in the source tree). This only + # gets called if the git-archive 'subst' variables were *not* expanded, + # and _version.py hasn't already been rewritten with a short version + # string, meaning we're inside a checked out source tree. + + try: + here = os.path.abspath(__file__) + except NameError: + # some py2exe/bbfreeze/non-CPython implementations don't do __file__ + return {} # not always correct + + # versionfile_source is the relative path from the top of the source tree + # (where the .git directory might live) to this file. Invert this to find + # the root from __file__. + root = here + if IN_LONG_VERSION_PY: + for i in range(len(versionfile_source.split("/"))): + root = os.path.dirname(root) + else: + root = os.path.dirname(here) + if not os.path.exists(os.path.join(root, ".git")): + if verbose: + print("no .git in %%s" %% root) + return {} + + stdout = run_command([GIT, "describe", "--tags", "--dirty", "--always"], + cwd=root) + if stdout is None: + return {} + if not stdout.startswith(tag_prefix): + if verbose: + print("tag '%%s' doesn't start with prefix '%%s'" %% (stdout, tag_prefix)) + return {} + tag = stdout[len(tag_prefix):] + stdout = run_command([GIT, "rev-parse", "HEAD"], cwd=root) + if stdout is None: + return {} + full = stdout.strip() + if tag.endswith("-dirty"): + full += "-dirty" + return {"version": tag, "full": full} + + +def versions_from_parentdir(parentdir_prefix, versionfile_source, verbose=False): + if IN_LONG_VERSION_PY: + # We're running from _version.py. If it's from a source tree + # (execute-in-place), we can work upwards to find the root of the + # tree, and then check the parent directory for a version string. If + # it's in an installed application, there's no hope. + try: + here = os.path.abspath(__file__) + except NameError: + # py2exe/bbfreeze/non-CPython don't have __file__ + return {} # without __file__, we have no hope + # versionfile_source is the relative path from the top of the source + # tree to _version.py. Invert this to find the root from __file__. + root = here + for i in range(len(versionfile_source.split("/"))): + root = os.path.dirname(root) + else: + # we're running from versioneer.py, which means we're running from + # the setup.py in a source tree. sys.argv[0] is setup.py in the root. + here = os.path.abspath(sys.argv[0]) + root = os.path.dirname(here) + + # Source tarballs conventionally unpack into a directory that includes + # both the project name and a version string. + dirname = os.path.basename(root) + if not dirname.startswith(parentdir_prefix): + if verbose: + print("guessing rootdir is '%%s', but '%%s' doesn't start with prefix '%%s'" %% + (root, dirname, parentdir_prefix)) + return None + return {"version": dirname[len(parentdir_prefix):], "full": ""} + +tag_prefix = "%(TAG_PREFIX)s" +parentdir_prefix = "%(PARENTDIR_PREFIX)s" +versionfile_source = "%(VERSIONFILE_SOURCE)s" + +def get_versions(default={"version": "unknown", "full": ""}, verbose=False): + variables = { "refnames": git_refnames, "full": git_full } + ver = versions_from_expanded_variables(variables, tag_prefix, verbose) + if not ver: + ver = versions_from_vcs(tag_prefix, versionfile_source, verbose) + if not ver: + ver = versions_from_parentdir(parentdir_prefix, versionfile_source, + verbose) + if not ver: + ver = default + return ver + +''' + +def run_command(args, cwd=None, verbose=False): + try: + # remember shell=False, so use git.cmd on windows, not just git + p = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd) + except EnvironmentError: + e = sys.exc_info()[1] + if verbose: + print("unable to run %s" % args[0]) + print(e) + return None + stdout = p.communicate()[0].strip() + if sys.version >= '3': + stdout = stdout.decode() + if p.returncode != 0: + if verbose: + print("unable to run %s (error)" % args[0]) + return None + return stdout + + +def get_expanded_variables(versionfile_source): + # the code embedded in _version.py can just fetch the value of these + # variables. When used from setup.py, we don't want to import + # _version.py, so we do it with a regexp instead. This function is not + # used from _version.py. + variables = {} + try: + for line in open(versionfile_source,"r").readlines(): + if line.strip().startswith("git_refnames ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + variables["refnames"] = mo.group(1) + if line.strip().startswith("git_full ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + variables["full"] = mo.group(1) + except EnvironmentError: + pass + return variables + +def versions_from_expanded_variables(variables, tag_prefix, verbose=False): + refnames = variables["refnames"].strip() + if refnames.startswith("$Format"): + if verbose: + print("variables are unexpanded, not using") + return {} # unexpanded, so not in an unpacked git-archive tarball + refs = set([r.strip() for r in refnames.strip("()").split(",")]) + for ref in list(refs): + if not re.search(r'\d', ref): + if verbose: + print("discarding '%s', no digits" % ref) + refs.discard(ref) + # Assume all version tags have a digit. git's %d expansion + # behaves like git log --decorate=short and strips out the + # refs/heads/ and refs/tags/ prefixes that would let us + # distinguish between branches and tags. By ignoring refnames + # without digits, we filter out many common branch names like + # "release" and "stabilization", as well as "HEAD" and "master". + if verbose: + print("remaining refs: %s" % ",".join(sorted(refs))) + for ref in sorted(refs): + # sorting will prefer e.g. "2.0" over "2.0rc1" + if ref.startswith(tag_prefix): + r = ref[len(tag_prefix):] + if verbose: + print("picking %s" % r) + return { "version": r, + "full": variables["full"].strip() } + # no suitable tags, so we use the full revision id + if verbose: + print("no suitable tags, using full revision id") + return { "version": variables["full"].strip(), + "full": variables["full"].strip() } + +def versions_from_vcs(tag_prefix, versionfile_source, verbose=False): + # this runs 'git' from the root of the source tree. That either means + # someone ran a setup.py command (and this code is in versioneer.py, so + # IN_LONG_VERSION_PY=False, thus the containing directory is the root of + # the source tree), or someone ran a project-specific entry point (and + # this code is in _version.py, so IN_LONG_VERSION_PY=True, thus the + # containing directory is somewhere deeper in the source tree). This only + # gets called if the git-archive 'subst' variables were *not* expanded, + # and _version.py hasn't already been rewritten with a short version + # string, meaning we're inside a checked out source tree. + + try: + here = os.path.abspath(__file__) + except NameError: + # some py2exe/bbfreeze/non-CPython implementations don't do __file__ + return {} # not always correct + + # versionfile_source is the relative path from the top of the source tree + # (where the .git directory might live) to this file. Invert this to find + # the root from __file__. + root = here + if IN_LONG_VERSION_PY: + for i in range(len(versionfile_source.split("/"))): + root = os.path.dirname(root) + else: + root = os.path.dirname(here) + if not os.path.exists(os.path.join(root, ".git")): + if verbose: + print("no .git in %s" % root) + return {} + + stdout = run_command([GIT, "describe", "--tags", "--dirty", "--always"], + cwd=root) + if stdout is None: + return {} + if not stdout.startswith(tag_prefix): + if verbose: + print("tag '%s' doesn't start with prefix '%s'" % (stdout, tag_prefix)) + return {} + tag = stdout[len(tag_prefix):] + stdout = run_command([GIT, "rev-parse", "HEAD"], cwd=root) + if stdout is None: + return {} + full = stdout.strip() + if tag.endswith("-dirty"): + full += "-dirty" + return {"version": tag, "full": full} + + +def versions_from_parentdir(parentdir_prefix, versionfile_source, verbose=False): + if IN_LONG_VERSION_PY: + # We're running from _version.py. If it's from a source tree + # (execute-in-place), we can work upwards to find the root of the + # tree, and then check the parent directory for a version string. If + # it's in an installed application, there's no hope. + try: + here = os.path.abspath(__file__) + except NameError: + # py2exe/bbfreeze/non-CPython don't have __file__ + return {} # without __file__, we have no hope + # versionfile_source is the relative path from the top of the source + # tree to _version.py. Invert this to find the root from __file__. + root = here + for i in range(len(versionfile_source.split("/"))): + root = os.path.dirname(root) + else: + # we're running from versioneer.py, which means we're running from + # the setup.py in a source tree. sys.argv[0] is setup.py in the root. + here = os.path.abspath(sys.argv[0]) + root = os.path.dirname(here) + + # Source tarballs conventionally unpack into a directory that includes + # both the project name and a version string. + dirname = os.path.basename(root) + if not dirname.startswith(parentdir_prefix): + if verbose: + print("guessing rootdir is '%s', but '%s' doesn't start with prefix '%s'" % + (root, dirname, parentdir_prefix)) + return None + return {"version": dirname[len(parentdir_prefix):], "full": ""} + + +def do_vcs_install(versionfile_source, ipy): + run_command([GIT, "add", "versioneer.py"]) + run_command([GIT, "add", versionfile_source]) + run_command([GIT, "add", ipy]) + present = False + try: + f = open(".gitattributes", "r") + for line in f.readlines(): + if line.strip().startswith(versionfile_source): + if "export-subst" in line.strip().split()[1:]: + present = True + f.close() + except EnvironmentError: + pass + if not present: + f = open(".gitattributes", "a+") + f.write("%s export-subst\n" % versionfile_source) + f.close() + run_command([GIT, "add", ".gitattributes"]) + + +SHORT_VERSION_PY = """ +# This file was generated by 'versioneer.py' (0.7+) from +# revision-control system data, or from the parent directory name of an +# unpacked source archive. Distribution tarballs contain a pre-generated copy +# of this file. + +version_version = '%(version)s' +version_full = '%(full)s' +def get_versions(default={}, verbose=False): + return {'version': version_version, 'full': version_full} + +""" + +DEFAULT = {"version": "unknown", "full": "unknown"} + +def versions_from_file(filename): + versions = {} + try: + f = open(filename) + except EnvironmentError: + return versions + for line in f.readlines(): + mo = re.match("version_version = '([^']+)'", line) + if mo: + versions["version"] = mo.group(1) + mo = re.match("version_full = '([^']+)'", line) + if mo: + versions["full"] = mo.group(1) + return versions + +def write_to_version_file(filename, versions): + f = open(filename, "w") + f.write(SHORT_VERSION_PY % versions) + f.close() + print("set %s to '%s'" % (filename, versions["version"])) + + +def get_best_versions(versionfile, tag_prefix, parentdir_prefix, + default=DEFAULT, verbose=False): + # returns dict with two keys: 'version' and 'full' + # + # extract version from first of _version.py, 'git describe', parentdir. + # This is meant to work for developers using a source checkout, for users + # of a tarball created by 'setup.py sdist', and for users of a + # tarball/zipball created by 'git archive' or github's download-from-tag + # feature. + + variables = get_expanded_variables(versionfile_source) + if variables: + ver = versions_from_expanded_variables(variables, tag_prefix) + if ver: + if verbose: print("got version from expanded variable %s" % ver) + return ver + + ver = versions_from_file(versionfile) + if ver: + if verbose: print("got version from file %s %s" % (versionfile, ver)) + return ver + + ver = versions_from_vcs(tag_prefix, versionfile_source, verbose) + if ver: + if verbose: print("got version from git %s" % ver) + return ver + + ver = versions_from_parentdir(parentdir_prefix, versionfile_source, verbose) + if ver: + if verbose: print("got version from parentdir %s" % ver) + return ver + + if verbose: print("got version from default %s" % ver) + return default + +def get_versions(default=DEFAULT, verbose=False): + assert versionfile_source is not None, "please set versioneer.versionfile_source" + assert tag_prefix is not None, "please set versioneer.tag_prefix" + assert parentdir_prefix is not None, "please set versioneer.parentdir_prefix" + return get_best_versions(versionfile_source, tag_prefix, parentdir_prefix, + default=default, verbose=verbose) +def get_version(verbose=False): + return get_versions(verbose=verbose)["version"] + +class cmd_version(Command): + description = "report generated version string" + user_options = [] + boolean_options = [] + def initialize_options(self): + pass + def finalize_options(self): + pass + def run(self): + ver = get_version(verbose=True) + print("Version is currently: %s" % ver) + + +class cmd_build(_build): + def run(self): + versions = get_versions(verbose=True) + _build.run(self) + # now locate _version.py in the new build/ directory and replace it + # with an updated value + target_versionfile = os.path.join(self.build_lib, versionfile_build) + print("UPDATING %s" % target_versionfile) + os.unlink(target_versionfile) + f = open(target_versionfile, "w") + f.write(SHORT_VERSION_PY % versions) + f.close() + +class cmd_sdist(_sdist): + def run(self): + versions = get_versions(verbose=True) + self._versioneer_generated_versions = versions + # unless we update this, the command will keep using the old version + self.distribution.metadata.version = versions["version"] + return _sdist.run(self) + + def make_release_tree(self, base_dir, files): + _sdist.make_release_tree(self, base_dir, files) + # now locate _version.py in the new base_dir directory (remembering + # that it may be a hardlink) and replace it with an updated value + target_versionfile = os.path.join(base_dir, versionfile_source) + print("UPDATING %s" % target_versionfile) + os.unlink(target_versionfile) + f = open(target_versionfile, "w") + f.write(SHORT_VERSION_PY % self._versioneer_generated_versions) + f.close() + +INIT_PY_SNIPPET = """ +from ._version import get_versions +__version__ = get_versions()['version'] +del get_versions +""" + +class cmd_update_files(Command): + description = "modify __init__.py and create _version.py" + user_options = [] + boolean_options = [] + def initialize_options(self): + pass + def finalize_options(self): + pass + def run(self): + ipy = os.path.join(os.path.dirname(versionfile_source), "__init__.py") + print(" creating %s" % versionfile_source) + f = open(versionfile_source, "w") + f.write(LONG_VERSION_PY % {"DOLLAR": "$", + "TAG_PREFIX": tag_prefix, + "PARENTDIR_PREFIX": parentdir_prefix, + "VERSIONFILE_SOURCE": versionfile_source, + }) + f.close() + try: + old = open(ipy, "r").read() + except EnvironmentError: + old = "" + if INIT_PY_SNIPPET not in old: + print(" appending to %s" % ipy) + f = open(ipy, "a") + f.write(INIT_PY_SNIPPET) + f.close() + else: + print(" %s unmodified" % ipy) + do_vcs_install(versionfile_source, ipy) + +def get_cmdclass(): + return {'version': cmd_version, + 'update_files': cmd_update_files, + 'build': cmd_build, + 'sdist': cmd_sdist, + } From 0a6a11f35adc1425800abb34d148b5ddd3db550d Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Fri, 1 Feb 2013 16:04:58 -0600 Subject: [PATCH 200/516] add missing llvm/_version.py --- .gitattributes | 1 + llvm/__init__.py | 4 +- llvm/_version.py | 194 +++++++++++++++++++++++++++++++++++++++++++++++ setup.py | 2 +- 4 files changed, 199 insertions(+), 2 deletions(-) create mode 100644 .gitattributes create mode 100644 llvm/_version.py diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3a05aa8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +llvm/_version.py export-subst diff --git a/llvm/__init__.py b/llvm/__init__.py index 1935514..8f61f35 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -2,7 +2,9 @@ Common classes related to LLVM. """ -__version__ = '0.10.2' +from ._version import get_versions +__version__ = get_versions()['version'] +del get_versions from weakref import WeakValueDictionary diff --git a/llvm/_version.py b/llvm/_version.py new file mode 100644 index 0000000..4b60157 --- /dev/null +++ b/llvm/_version.py @@ -0,0 +1,194 @@ + +IN_LONG_VERSION_PY = True +# This file helps to compute a version number in source trees obtained from +# git-archive tarball (such as those provided by github's download-from-tag +# feature). Distribution tarballs (build by setup.py sdist) and build +# directories (produced by setup.py build) will contain a much shorter file +# that just contains the computed version number. + +# This file is released into the public domain. Generated by +# versioneer-0.7+ (https://github.com/warner/python-versioneer) + +# these strings will be replaced by git during git-archive +git_refnames = "$Format:%d$" +git_full = "$Format:%H$" + + +import subprocess +import sys + +def run_command(args, cwd=None, verbose=False): + try: + # remember shell=False, so use git.cmd on windows, not just git + p = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd) + except EnvironmentError: + e = sys.exc_info()[1] + if verbose: + print("unable to run %s" % args[0]) + print(e) + return None + stdout = p.communicate()[0].strip() + if sys.version >= '3': + stdout = stdout.decode() + if p.returncode != 0: + if verbose: + print("unable to run %s (error)" % args[0]) + return None + return stdout + + +import sys +import re +import os.path + +def get_expanded_variables(versionfile_source): + # the code embedded in _version.py can just fetch the value of these + # variables. When used from setup.py, we don't want to import + # _version.py, so we do it with a regexp instead. This function is not + # used from _version.py. + variables = {} + try: + for line in open(versionfile_source,"r").readlines(): + if line.strip().startswith("git_refnames ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + variables["refnames"] = mo.group(1) + if line.strip().startswith("git_full ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + variables["full"] = mo.group(1) + except EnvironmentError: + pass + return variables + +def versions_from_expanded_variables(variables, tag_prefix, verbose=False): + refnames = variables["refnames"].strip() + if refnames.startswith("$Format"): + if verbose: + print("variables are unexpanded, not using") + return {} # unexpanded, so not in an unpacked git-archive tarball + refs = set([r.strip() for r in refnames.strip("()").split(",")]) + for ref in list(refs): + if not re.search(r'\d', ref): + if verbose: + print("discarding '%s', no digits" % ref) + refs.discard(ref) + # Assume all version tags have a digit. git's %d expansion + # behaves like git log --decorate=short and strips out the + # refs/heads/ and refs/tags/ prefixes that would let us + # distinguish between branches and tags. By ignoring refnames + # without digits, we filter out many common branch names like + # "release" and "stabilization", as well as "HEAD" and "master". + if verbose: + print("remaining refs: %s" % ",".join(sorted(refs))) + for ref in sorted(refs): + # sorting will prefer e.g. "2.0" over "2.0rc1" + if ref.startswith(tag_prefix): + r = ref[len(tag_prefix):] + if verbose: + print("picking %s" % r) + return { "version": r, + "full": variables["full"].strip() } + # no suitable tags, so we use the full revision id + if verbose: + print("no suitable tags, using full revision id") + return { "version": variables["full"].strip(), + "full": variables["full"].strip() } + +def versions_from_vcs(tag_prefix, versionfile_source, verbose=False): + # this runs 'git' from the root of the source tree. That either means + # someone ran a setup.py command (and this code is in versioneer.py, so + # IN_LONG_VERSION_PY=False, thus the containing directory is the root of + # the source tree), or someone ran a project-specific entry point (and + # this code is in _version.py, so IN_LONG_VERSION_PY=True, thus the + # containing directory is somewhere deeper in the source tree). This only + # gets called if the git-archive 'subst' variables were *not* expanded, + # and _version.py hasn't already been rewritten with a short version + # string, meaning we're inside a checked out source tree. + + try: + here = os.path.abspath(__file__) + except NameError: + # some py2exe/bbfreeze/non-CPython implementations don't do __file__ + return {} # not always correct + + # versionfile_source is the relative path from the top of the source tree + # (where the .git directory might live) to this file. Invert this to find + # the root from __file__. + root = here + if IN_LONG_VERSION_PY: + for i in range(len(versionfile_source.split("/"))): + root = os.path.dirname(root) + else: + root = os.path.dirname(here) + if not os.path.exists(os.path.join(root, ".git")): + if verbose: + print("no .git in %s" % root) + return {} + + stdout = run_command([GIT, "describe", "--tags", "--dirty", "--always"], + cwd=root) + if stdout is None: + return {} + if not stdout.startswith(tag_prefix): + if verbose: + print("tag '%s' doesn't start with prefix '%s'" % (stdout, tag_prefix)) + return {} + tag = stdout[len(tag_prefix):] + stdout = run_command([GIT, "rev-parse", "HEAD"], cwd=root) + if stdout is None: + return {} + full = stdout.strip() + if tag.endswith("-dirty"): + full += "-dirty" + return {"version": tag, "full": full} + + +def versions_from_parentdir(parentdir_prefix, versionfile_source, verbose=False): + if IN_LONG_VERSION_PY: + # We're running from _version.py. If it's from a source tree + # (execute-in-place), we can work upwards to find the root of the + # tree, and then check the parent directory for a version string. If + # it's in an installed application, there's no hope. + try: + here = os.path.abspath(__file__) + except NameError: + # py2exe/bbfreeze/non-CPython don't have __file__ + return {} # without __file__, we have no hope + # versionfile_source is the relative path from the top of the source + # tree to _version.py. Invert this to find the root from __file__. + root = here + for i in range(len(versionfile_source.split("/"))): + root = os.path.dirname(root) + else: + # we're running from versioneer.py, which means we're running from + # the setup.py in a source tree. sys.argv[0] is setup.py in the root. + here = os.path.abspath(sys.argv[0]) + root = os.path.dirname(here) + + # Source tarballs conventionally unpack into a directory that includes + # both the project name and a version string. + dirname = os.path.basename(root) + if not dirname.startswith(parentdir_prefix): + if verbose: + print("guessing rootdir is '%s', but '%s' doesn't start with prefix '%s'" % + (root, dirname, parentdir_prefix)) + return None + return {"version": dirname[len(parentdir_prefix):], "full": ""} + +tag_prefix = "" +parentdir_prefix = "llvmpy-" +versionfile_source = "llvm/_version.py" + +def get_versions(default={"version": "unknown", "full": ""}, verbose=False): + variables = { "refnames": git_refnames, "full": git_full } + ver = versions_from_expanded_variables(variables, tag_prefix, verbose) + if not ver: + ver = versions_from_vcs(tag_prefix, versionfile_source, verbose) + if not ver: + ver = versions_from_parentdir(parentdir_prefix, versionfile_source, + verbose) + if not ver: + ver = default + return ver + diff --git a/setup.py b/setup.py index 6816f81..78079fd 100644 --- a/setup.py +++ b/setup.py @@ -88,7 +88,7 @@ def determine_to_use_dynlink(libdir, llvm_version): elif sys.platform.startswith('win32'): return dll in libdir_content else: # other platforms - return any((x in libdir_content) for x in [so, dyld, dll]) + return any((x in libdir_content) for x in [so, dylib, dll]) dynlink = determine_to_use_dynlink(libdir, llvm_version) From c822f5f9f7746b930f403cd6258311012272064a Mon Sep 17 00:00:00 2001 From: Phillip Cloud Date: Sat, 2 Feb 2013 20:44:27 -0500 Subject: [PATCH 201/516] add GIT variable to _version.py --- llvm/_version.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/llvm/_version.py b/llvm/_version.py index 4b60157..a90c5b8 100644 --- a/llvm/_version.py +++ b/llvm/_version.py @@ -12,7 +12,7 @@ IN_LONG_VERSION_PY = True # these strings will be replaced by git during git-archive git_refnames = "$Format:%d$" git_full = "$Format:%H$" - +GIT = "git" import subprocess import sys @@ -191,4 +191,3 @@ def get_versions(default={"version": "unknown", "full": ""}, verbose=False): if not ver: ver = default return ver - From a12c4da93d1147384c08f8d4ffed16ddcb383e99 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 22 Jan 2013 10:09:14 -0600 Subject: [PATCH 202/516] Init commit for work on new binding This contains the foundation for the new binding as well as early work on Module and Type. --- newbinding/Makefile | 18 + .../binding/AssemblyAnnotationWriter.py | 6 + newbinding/binding/DerivedTypes.py | 13 + newbinding/binding/LLVMContext.py | 8 + newbinding/binding/Makefile | 0 newbinding/binding/Module.py | 25 + newbinding/binding/StringRef.py | 6 + newbinding/binding/Type.py | 96 ++++ newbinding/binding/_Debug.py | 3 + newbinding/binding/binding.py | 498 ++++++++++++++++++ newbinding/binding/gen.py | 206 ++++++++ newbinding/binding/namespace.py | 4 + newbinding/binding/raw_ostream.py | 17 + newbinding/binding/utils.py | 6 + newbinding/capsule.cpp | 143 +++++ newbinding/capsule.py | 74 +++ newbinding/include/llvm_binding/binding.h | 73 +++ .../include/llvm_binding/capsule_context.h | 48 ++ newbinding/include/llvm_binding/conversion.h | 93 ++++ newbinding/include/llvm_binding/extra.h | 34 ++ newbinding/setup.py | 54 ++ newbinding/test.py | 32 ++ newbinding/test2.py | 20 + 23 files changed, 1477 insertions(+) create mode 100644 newbinding/Makefile create mode 100644 newbinding/binding/AssemblyAnnotationWriter.py create mode 100644 newbinding/binding/DerivedTypes.py create mode 100644 newbinding/binding/LLVMContext.py create mode 100644 newbinding/binding/Makefile create mode 100644 newbinding/binding/Module.py create mode 100644 newbinding/binding/StringRef.py create mode 100644 newbinding/binding/Type.py create mode 100644 newbinding/binding/_Debug.py create mode 100644 newbinding/binding/binding.py create mode 100644 newbinding/binding/gen.py create mode 100644 newbinding/binding/namespace.py create mode 100644 newbinding/binding/raw_ostream.py create mode 100644 newbinding/binding/utils.py create mode 100644 newbinding/capsule.cpp create mode 100644 newbinding/capsule.py create mode 100644 newbinding/include/llvm_binding/binding.h create mode 100644 newbinding/include/llvm_binding/capsule_context.h create mode 100644 newbinding/include/llvm_binding/conversion.h create mode 100644 newbinding/include/llvm_binding/extra.h create mode 100644 newbinding/setup.py create mode 100644 newbinding/test.py create mode 100644 newbinding/test2.py diff --git a/newbinding/Makefile b/newbinding/Makefile new file mode 100644 index 0000000..ba902e3 --- /dev/null +++ b/newbinding/Makefile @@ -0,0 +1,18 @@ +PYMODS = _Debug raw_ostream Type DerivedTypes LLVMContext StringRef AssemblyAnnotationWriter Module + +all: _api.so _capsule.so + +_api.so _capsule.so: api.cpp capsule.cpp + python setup.py build_ext --inplace + + +api.cpp api.py: binding/*.py include/llvm_binding/*.h + cd binding; python gen.py api $(PYMODS) + mv binding/api.cpp api.cpp + mv binding/api.py api.py + +clean: + rm -f _api.so _capsule.so + rm -f api.cpp api.py + + diff --git a/newbinding/binding/AssemblyAnnotationWriter.py b/newbinding/binding/AssemblyAnnotationWriter.py new file mode 100644 index 0000000..5641232 --- /dev/null +++ b/newbinding/binding/AssemblyAnnotationWriter.py @@ -0,0 +1,6 @@ +from binding import * +from namespace import llvm + +AssemblyAnnotationWriter = llvm.Class() +AssemblyAnnotationWriter.include.add("llvm/Assembly/AssemblyAnnotationWriter.h") + diff --git a/newbinding/binding/DerivedTypes.py b/newbinding/binding/DerivedTypes.py new file mode 100644 index 0000000..10d5fbf --- /dev/null +++ b/newbinding/binding/DerivedTypes.py @@ -0,0 +1,13 @@ +from binding import * +from namespace import llvm +from LLVMContext import LLVMContext +from Type import Type + +FunctionType = Type.Subclass() +FunctionType.include.add('llvm/DerivedTypes.h') + +get = FunctionType.staticmethod(FunctionType.Pointer, Type.Pointer, Bool.From(bool)) +isVarArg = FunctionType.method(Bool.To(bool)) +getReturnType = FunctionType.method(Type.Pointer) +getParamType = FunctionType.method(Type.Pointer, Unsigned.From(int)) +getNumParams = FunctionType.method(Unsigned.To(int)) diff --git a/newbinding/binding/LLVMContext.py b/newbinding/binding/LLVMContext.py new file mode 100644 index 0000000..0965748 --- /dev/null +++ b/newbinding/binding/LLVMContext.py @@ -0,0 +1,8 @@ +from binding import * +from namespace import llvm + +LLVMContext = llvm.Class() +LLVMContext.include.add("llvm/LLVMContext.h") + +getGlobalContext = llvm.Function(LLVMContext.Ref) + diff --git a/newbinding/binding/Makefile b/newbinding/binding/Makefile new file mode 100644 index 0000000..e69de29 diff --git a/newbinding/binding/Module.py b/newbinding/binding/Module.py new file mode 100644 index 0000000..a458401 --- /dev/null +++ b/newbinding/binding/Module.py @@ -0,0 +1,25 @@ +from binding import * +from namespace import llvm +from LLVMContext import LLVMContext +from StringRef import StringRef +from raw_ostream import raw_svector_ostream_helper +from AssemblyAnnotationWriter import AssemblyAnnotationWriter + +Module = llvm.Class() +Module.include.add("llvm/Module.h") + +new = Module.new(StringRef.From(str), LLVMContext.Ref) +delete = Module.delete() +getModuleIdentifier = Module.method(ConstStdString.To(str)) +setModuleIdentifier = Module.method(Void, StringRef.From(str)) +setDataLayout = Module.method(Void, StringRef.From(str)) +setTargetTriple = Module.method(Void, StringRef.From(str)) +setModuleInlineAsm = Module.method(Void, StringRef.From(str)) +appendModuleInlineAsm = Module.method(Void, StringRef.From(str)) +getContext = Module.method(LLVMContext.Ref) +dump = Module.method(Void) +print_ = Module.method(Void, raw_svector_ostream_helper.Ref, + AssemblyAnnotationWriter.Pointer) +print_.realname = 'print' +#getOrInsertFunction = Module.method(Constant, StringRef.From(str), FunctionType.Pointer) + diff --git a/newbinding/binding/StringRef.py b/newbinding/binding/StringRef.py new file mode 100644 index 0000000..554629b --- /dev/null +++ b/newbinding/binding/StringRef.py @@ -0,0 +1,6 @@ +from binding import * +from namespace import llvm + +StringRef = llvm.Class() +StringRef.include.add("llvm/ADT/StringRef.h") + diff --git a/newbinding/binding/Type.py b/newbinding/binding/Type.py new file mode 100644 index 0000000..19f6d61 --- /dev/null +++ b/newbinding/binding/Type.py @@ -0,0 +1,96 @@ +from binding import * +from namespace import llvm +from LLVMContext import LLVMContext +from raw_ostream import raw_svector_ostream_helper + +Type = llvm.Class() +Type.include.add('llvm/Type.h') + +IntegerType = Type.Subclass() +CompositeType = Type.Subclass() +SequentialType = CompositeType.Subclass() +PointerType = SequentialType.Subclass() + +getContext = Type.method(LLVMContext.Ref) +dump = Type.method(Void) +print_ = Type.method(Void, raw_svector_ostream_helper.Ref) +print_.realname = 'print' + +def type_checker(): + return Type.method(Bool.To(bool)) + +isVoidTy = type_checker() +isHalfTy = type_checker() +isFloatTy = type_checker() +isDoubleTy = type_checker() +isX86_FP80Ty = type_checker() +isFP128Ty = type_checker() +isPPC_FP128Ty = type_checker() +isFloatingPointTy = type_checker() +isX86_MMXTy = type_checker() +isFPOrFPVectorTy = type_checker() +isLabelTy = type_checker() +isMetadataTy = type_checker() +isIntOrIntVectorTy = type_checker() +isFunctionTy = type_checker() +isStructTy = type_checker() +isArrayTy = type_checker() +isPointerTy = type_checker() +isPtrOrPtrVectorTy = type_checker() +isVectorTy = type_checker() +isEmptyTy = type_checker() +isPrimitiveType = type_checker() +isDerivedType = type_checker() +isFirstClassType = type_checker() +isSingleValueType = type_checker() +isAggregateType = type_checker() +isSized = type_checker() + +isIntegerTy = Type.multimethod([Bool.To(bool)], + [Bool.To(bool), Unsigned.From(int)]) + + +def type_factory(): + return Type.staticmethod(Type.Pointer, LLVMContext.Ref) + +getVoidTy = type_factory() +getLabelTy = type_factory() +getHalfTy = type_factory() +getFloatTy = type_factory() +getDoubleTy = type_factory() +getMetadataTy = type_factory() +getX86_FP80Ty = type_factory() +getFP128Ty = type_factory() +getPPC_FP128Ty = type_factory() +getX86_MMXTy = type_factory() + +getIntNTy = Type.staticmethod(IntegerType.Pointer, LLVMContext.Ref, Unsigned.From(int)) + +def integer_factory(): + return Type.staticmethod(IntegerType.Pointer, LLVMContext.Ref) + +getInt1Ty = integer_factory() +getInt8Ty = integer_factory() +getInt16Ty = integer_factory() +getInt32Ty = integer_factory() +getInt64Ty = integer_factory() + +def pointer_factory(): + return Type.staticmethod(PointerType.Pointer, LLVMContext.Ref) + +getHalfPtrTy = pointer_factory() +getFloatPtrTy = pointer_factory() +getDoublePtrTy = pointer_factory() +getX86_FP80PtrTy = pointer_factory() +getFP128PtrTy = pointer_factory() +getPPC_FP128PtrTy = pointer_factory() +getX86_MMXPtrTy = pointer_factory() +getInt1PtrTy = pointer_factory() +getInt8PtrTy = pointer_factory() +getInt16PtrTy = pointer_factory() +getInt32PtrTy = pointer_factory() +getInt64PtrTy = pointer_factory() +getIntNPtrTy = Type.staticmethod(PointerType.Pointer, + LLVMContext.Ref, Unsigned.From(int)) + + diff --git a/newbinding/binding/_Debug.py b/newbinding/binding/_Debug.py new file mode 100644 index 0000000..be092f3 --- /dev/null +++ b/newbinding/binding/_Debug.py @@ -0,0 +1,3 @@ +from binding import * + +enable_capsule_dtor_debug = Function('', Void, Bool.From(bool)) diff --git a/newbinding/binding/binding.py b/newbinding/binding/binding.py new file mode 100644 index 0000000..1230813 --- /dev/null +++ b/newbinding/binding/binding.py @@ -0,0 +1,498 @@ +from utils import * + +_py2capi_fmtmap = { + str: 's#', +} + +NULL = 'NULL' + +_symbols = set() + +def new_symbol(name): + if name in _symbols: + ct = 1 + orig = name + while name in _symbols: + name = '%s%d' % (orig, ct) + ct += 1 + _symbols.add(name) + return name + +def parse_arguments(println, var, *args): + typecodes = [] + holders = [] + argvals = [] + for arg in args: + typecodes.append(arg.format) + val = declare(println, 'PyObject*') + argvals.append(val) + holders.append('&' + val) + + items = [var, '"%s"' % (''.join(typecodes))] + holders + println('if(!PyArg_ParseTuple(%s)) return NULL;' % ', '.join(items)) + + # unwrap + unwrapped = [] + for arg, val in zip(args, argvals): + unwrapped.append(arg.unwrap(println, val)) + + return unwrapped + +def mangle(name): + name = name.replace('_', '__').replace(' ', '_') + return name.replace('::', '_').rstrip('*&') + +def pycapsule_new(println, ptr, name, clsname, dtor='capsule_destructor'): + # build capsule + name_soften = mangle(name) + var = new_symbol('pycap_%s' % name_soften) + fmt = 'PyObject* %(var)s = PyCapsule_New(%(ptr)s, "%(name)s", %(dtor)s);' + println(fmt % locals()) + + # build context + fmt = 'new CapsuleContext("%(clsname)s")' + context = declare(println, 'CapsuleContext*', fmt % locals()) + + fmt = 'PyCapsule_SetContext(%(var)s, (void*)%(context)s)' + err = declare(println, 'int', fmt % locals()) + + println('if (%(err)s) return NULL;' % locals()) + return var + + +def declare(println, typ, init=None): + typ_soften = mangle(typ) + var = new_symbol('var_%s' % typ_soften) + if init is None: + println('%(typ)s %(var)s;' % locals()) + else: + println('%(typ)s %(var)s = %(init)s;' % locals()) + return var + + +def return_value(println, var): + println('return %(var)s;' % locals()) + + +def return_none(println): + println('Py_RETURN_NONE;') + + +def die_if_null(println, var): + println('if (!%(var)s) return NULL;' % locals()) + + +class Binding(object): + __rank_global = 0 + def __init__(self): + self.rank = Binding.__rank_global + Binding.__rank_global += 1 + self.include = set() + + def compile(self, name, println): + raise NotImplementedError(type(self)) + +class Ref(object): + def __init__(self, elem): + self.element = elem + + @property + def fullname(self): + return '%s&' % self.element.fullname + + @property + def capsule_name(self): + return self.element.capsule_name + + @property + def pointer(self): + return self.element.pointer + + def as_pointer(self, println, var): + init = '&%s' % (var) + casted = declare(println, self.pointer, init) + return casted + + @property + def format(self): + return 'O' + + def unwrap(self, println, var): + ptr = self.element.unwrap(println, var) + return declare(println, self.fullname, '*%s' % ptr) + + def wrap(self, println, var): + return self.element.wrap(println, self.as_pointer(println, var)) + + +class Pointer(object): + def __init__(self, elem): + self.element = elem + + @property + def fullname(self): + return '%s*' % self.element.fullname + + @property + def capsule_name(self): + return self.element.capsule_name + + @property + def pointer(self): + return self.element.pointer + + @property + def format(self): + return 'O' + + def unwrap(self, println, var): + ret = declare(println, self.fullname) + println2 = indent_println(println) + println('if (%(var)s == Py_None) {' % locals()) + println2('%(ret)s = NULL;' % locals()) + println('} else {') + ptr = self.element.unwrap(println2, var) + println2('%(ret)s = %(ptr)s;' % locals()) + println('}') + return ret + + def wrap(self, println, var): + return self.element.wrap(println, var) + + +class BuiltinType(object): + def __init__(self, name): + self.name = name + self.Ref = Ref(self) + self.Pointer = Pointer(self) + + @property + def fullname(self): + return self.name + + @property + def capsule_name(self): + return self.fullname + + def To(self, pytype): + return Wrapper(self, pytype) + + def From(self, pytype): + return Unwrapper(self, pytype) + +Void = BuiltinType('void') +Bool = BuiltinType('bool') +Unsigned = BuiltinType('unsigned') +ConstStdString = BuiltinType('const std::string') + +class Unwrapper(object): + def __init__(self, cls, pytype): + self.cls = cls + self.pytype = pytype + + @property + def fullname(self): + return str(self.pytype) + + @property + def format(self): + return 'O' + + def unwrap(self, println, var): + out = declare(println, self.cls.fullname) + conv = 'py_%s_to' % (self.pytype.__name__) + status = '%(conv)s(%(var)s, %(out)s)' % locals() + println('if (!%(status)s) return NULL;' % locals()) + return out + + +class Wrapper(object): + def __init__(self, cls, pytype): + self.cls = cls + self.pytype = pytype + + @property + def fullname(self): + return self.cls.fullname + + def wrap(self, println, var): + conv = 'py_%s_from' % (self.pytype.__name__) + func = '%(conv)s(%(var)s)' % locals() + out = declare(println, 'PyObject*', func) + println('if (!%(out)s) return NULL;' % locals()) + return out + +class Class(Binding): + def __init__(self, ns): + super(Class, self).__init__() + self.ctor = None + self.Ref = Ref(self) + self.Pointer = Pointer(self) + self.Subclass = lambda: Subclass(self) + self.ns = ns + self.methods = [] + self.name = None + + def To(self, pytype): + return Wrapper(self, pytype) + + def From(self, pytype): + return Unwrapper(self, pytype) + + def new(self, *args): + method = Constructor(self, self.Pointer, *args) + self.methods.append(method) + return method + + def delete(self): + method = Destructor(self, Void, self.Pointer) + self.methods.append(method) + return method + + def method(self, return_type, *args): + method = Method(self, return_type, self.Pointer, *args) + self.methods.append(method) + return method + + def staticmethod(self, return_type, *args): + sm = StaticMethod(self, return_type, *args) + self.methods.append(sm) + return sm + + def multimethod(self, *signatures): + mm = MultiMethod(self, signatures) + self.methods.append(mm) + return mm + + def compile(self, name, println): + # set name + self.name = self.name or name + + @property + def capsule_name(self): + return self.fullname + + @property + def pointer(self): + return '%s*' % self.fullname + + @property + def fullname(self): + return '::'.join([self.ns, self.name]) + + @property + def mangled_name(self): + return mangle(self.fullname) + + @property + def format(self): + return 'O' + + def unwrap(self, println, var): + typ = self.pointer + elty = self.fullname + cap = self.capsule_name + capptr = 'PyCapsule_GetPointer(%(var)s, "%(cap)s")' % locals() + ptr = declare(println, 'void*', capptr) + unwrapped = 'typecast<%(elty)s>::from(%(ptr)s)' % locals() + var = declare(println, typ, unwrapped) + println('if (!%(var)s) {' % locals()) + println2 = indent_println(println) + println2('PyErr_SetString(PyExc_TypeError, "Invalid cast");') + println2('return NULL;') + println('}') + die_if_null(println, var) + return var + + def wrap(self, println, var): + return pycapsule_new(println, var, self.capsule_name, self.fullname) + +class Subclass(Class): + def __init__(self, parent): + super(Subclass, self).__init__(parent.ns) + self.parent = parent + self.ns = self.parent.ns + + @property + def capsule_name(self): + return self.parent.capsule_name + +class Function(Binding): + def __init__(self, ns, return_type, *args): + super(Function, self).__init__() + self.return_type = return_type + self.args = args + self.ns = ns + self.name = None + + def compile(self, name, println): + # set name + self.name = self.name or name + # generate wrapper + println('static') + println('PyObject*') + println('%(name)s(PyObject* self, PyObject* args)' % locals()) + println('{') + self.compile_body(indent_println(println)) + println('}') + + def compile_body(self, println): + args = parse_arguments(println, 'args', *self.args) + call = '%s(%s)' % (self.fullname, ', '.join(args)) + if self.return_type is not Void: + callres = declare(println, self.return_type.fullname, call) + pycap = self.return_type.wrap(println, callres) + return_value(println, pycap) + else: + println('%s;' % call) + return_none(println) + + + @property + def fullname(self): + return '::'.join([self.ns, self.name]) + +class Method(Binding): + def __init__(self, cls, return_type, *args): + super(Method, self).__init__() + self.cls = cls + self.return_type = return_type + self.args = args + self.name = None + self._realname = None + + def compile(self, name, println): + # set name + self.name = self.name or name + # generate wrapper + println('static') + println('PyObject*') + mangled = self.mangled_name + println('%(mangled)s(PyObject* self, PyObject* args)' % locals()) + println('{') + self.compile_body(indent_println(println)) + println('}') + + def compile_body(self, println): + args = parse_arguments(println, 'args', *self.args) + this = args[0] + args = ', '.join(args[1:]) + name = self.realname + call = '%(this)s->%(name)s(%(args)s)' % locals() + if self.return_type is not Void: + obj = declare(println, self.return_type.fullname, call) + ret = self.return_type.wrap(println, obj) + return_value(println, ret) + else: + println('%s;' % call) + return_none(println) + + @property + def fullname(self): + return '::'.join([self.cls.fullname, self.name]) + + @property + def realname(self): + if not self._realname: + return self.name + else: + return self._realname + + @realname.setter + def realname(self, v): + self._realname = v + + + @property + def mangled_name(self): + return mangle(self.fullname) + +class MultiMethod(Binding): + '''Can only differs by the number of arguments. + ''' + def __init__(self, cls, signatures): + super(MultiMethod, self).__init__() + nargs = set() + for sig in signatures: + n = len(sig) + if n in nargs: + raise TypeError("MultiMethod only supports overloaded version" + "with different number of arguments") + nargs.add(n) + self.cls = cls + self.signatures = signatures + self.name = None + + def compile(self, name, println): + # set name + self.name = self.name or name + # generate wrapper + println('static') + println('PyObject*') + mangled = self.mangled_name + println('%(mangled)s(PyObject* self, PyObject* args)' % locals()) + println('{') + println2 = indent_println(println) + nargs = declare(println2, 'Py_ssize_t', 'PyTuple_Size(args)') + for sig in self.signatures: + expect = len(sig) + println2('if (%(nargs)s == %(expect)d) {' % locals()) + method = Method(self.cls, sig[0], self.cls.Pointer, *sig[1:]) + method.name = self.name + method.compile_body(indent_println(println2)) + println2('}') + println2('PyErr_SetString(PyExc_TypeError, "Wrong # of args");') + println2('return NULL;') + println('}') + + @property + def fullname(self): + return '::'.join([self.cls.fullname, self.name]) + + @property + def mangled_name(self): + return mangle(self.fullname) + +class StaticMethod(Method): + def compile_body(self, println): + args = parse_arguments(println, 'args', *self.args) + args = ', '.join(args) + fullname = self.fullname + call = '%(fullname)s(%(args)s)' % locals() + if self.return_type is not Void: + obj = declare(println, self.return_type.fullname, call) + ret = self.return_type.wrap(println, obj) + return_value(println, ret) + else: + println('%s;' % call) + return_none(println) + +class Constructor(StaticMethod): + def compile_body(self, println): + args = parse_arguments(println, 'args', *self.args) + args = ', '.join(args) + name = self.cls.fullname + ctor = 'new %(name)s(%(args)s)' % locals() + obj = declare(println, self.cls.pointer, ctor) + ret = self.return_type.wrap(println, obj) + return_value(println, ret) + +class Destructor(Method): + def compile_body(self, println): + args = parse_arguments(println, 'args', *self.args) + assert len(args) == 1 + dtor = 'delete %s;' % args[0] + println(dtor) + return_none(println) + + +class Namespace(object): + def __init__(self, name): + self.name = name + + def Class(self, *args, **kwargs): + return Class(self.name, *args, **kwargs) + + def Function(self, *args, **kwargs): + return Function(self.name, *args, **kwargs) + diff --git a/newbinding/binding/gen.py b/newbinding/binding/gen.py new file mode 100644 index 0000000..f662979 --- /dev/null +++ b/newbinding/binding/gen.py @@ -0,0 +1,206 @@ +import sys +from binding import * +from utils import * +from cStringIO import StringIO + +extension_entry = ''' + +extern "C" { + +#if (PY_MAJOR_VERSION >= 3) + +PyObject * +PyInit_%(module)s(void) +{ + PyObject *module = create_python_module("%(module)s", %(methtable)s); + if (module) { + if (populate_submodules(module, submodules)) + return module; + } + return NULL; +} + +#else + +PyMODINIT_FUNC +init%(module)s(void) +{ + PyObject *module = create_python_module("%(module)s", %(methtable)s); + if (module) { + populate_submodules(module, submodules); + } +} +#endif + +} // end extern C + +''' + +def build_methoddef(name, defns, println): + println('static PyMethodDef %s[] = {' % name) + for name, func in defns: + println('{ "%(name)s", (PyCFunction)%(func)s, METH_VARARGS, NULL },' % + locals()) + else: + println('{ NULL }') + println('};') + println('') + + +class Context(object): + def __init__(self): + self.includes = set() + self.functions = {} + self.classes = {} + self.definitions = [] + + def generate_cpp(self, println): + for i in self.includes: + println('#include "%s"' % i) + + println('\n'.join(self.definitions)) + + # global function + defns = [] + for name, func in self.functions.items(): + defns.append((name, func.name)) + build_methoddef('global_functions', defns, println) + + # classes + for name, cls in self.classes.items(): + defns = [] + for meth in cls.methods: + defns.append((meth.name, meth.mangled_name)) + println("// %s" % cls.fullname) + build_methoddef(cls.mangled_name, defns, println) + + println('static SubModuleEntry submodules[] = {') + for name, cls in self.classes.items(): + table = cls.mangled_name + println('{ "%(name)s", %(table)s },' % locals()) + println('{ NULL },') + println('};') + println('') + + # generate entry + println(extension_entry % {'module': '_api', + 'methtable': 'global_functions',}) + + def generate_py(self, println): + println('import _api, capsule') + println('') + # global function + for name in self.functions: + println('def %(name)s(*args):' % locals()) + println2 = indent_println(println) + println2('args = map(capsule.unwrap, args)') + println2('ptr = _api.%(name)s(*args)' % locals()) + println2('return capsule.wrap(ptr)') + println('') + # classes + classes = sorted(self.classes.items(), key=lambda x: x[1].rank) + + for name, cls in classes: + if isinstance(cls, Subclass): + parent = cls.parent.name + else: + parent = 'capsule.Wrapper' + println('@capsule.register_class') + println('class %(name)s(%(parent)s):' % locals()) + self.generate_py_class(indent_println(println), cls) + println('') + + def generate_py_class(self, println, cls): + if len(cls.methods) == 0: + println('pass') + else: + mod = cls.name + for method in cls.methods: + name = method.name + if isinstance(method, StaticMethod): + println('@staticmethod') + println('def %(name)s(*args):' % locals()) + println2 = indent_println(println) + println2('args = map(capsule.unwrap, args)') + println2('ret = _api.%(mod)s.%(name)s(*args)' % locals()) + println2('return capsule.wrap(ret)') + elif isinstance(method, Destructor): + println('_delete_ = _api.%(mod)s.%(name)s' % locals()) + else: + println('def %(name)s(self, *args):' % locals()) + println2 = indent_println(println) + println2('args = map(capsule.unwrap, args)') + println2('ret = _api.%(mod)s.%(name)s(self._ptr, *args)' % + locals()) + println2('return capsule.wrap(ret)') + println('') + + + def add_module(self, modname): + module = __import__(modname) + allsyms = [(k, v) for k, v in vars(module).items() + if isinstance(v, Binding)] + symtab = sorted(allsyms, key=lambda x: x[1].rank) + + # generate includes + for k, v in symtab: + self.includes |= v.include + + # compile everything + for k, v in symtab: + buf = StringIO() + def println_to_def(s): + buf.write(s) + buf.write('\n') + v.compile(k, println_to_def) + self.definitions.append(buf.getvalue()) + buf.close() + + # generate py defintion table for global functions + for k, v in symtab: + if isinstance(v, Function): + if v.name in self.functions: + raise NameError("Duplicated function name: %s" % v.name) + self.functions[v.name] = v + + # generate sub module tables for classes + submodules = [] + for k, v in symtab: + if isinstance(v, Class): + if v.name in self.classes: + if v is not self.classes[v.name]: + raise NameError("Duplicated class: %s" % v.name) + self.classes[v.name] = v + + +def populate_headers(println): + includes = [ + 'llvm_binding/conversion.h', + 'llvm_binding/binding.h', + 'llvm_binding/extra.h', + 'llvm_binding/capsule_context.h', + ] + for inc in includes: + println('#include "%s"' % inc) + +def wrap_println(f): + def println(s): + f.write(s) + f.write('\n') + return println + +if __name__ == '__main__': + + context = Context() + for mod in sys.argv[2:]: + context.add_module(mod) + + filename = sys.argv[1] + with open('%s.cpp' % filename, 'w') as outfile: + println = wrap_println(outfile) + populate_headers(println) + context.generate_cpp(println) + with open('%s.py' % filename, 'w') as outfile: + println = wrap_println(outfile) + context.generate_py(println) + diff --git a/newbinding/binding/namespace.py b/newbinding/binding/namespace.py new file mode 100644 index 0000000..02af8c9 --- /dev/null +++ b/newbinding/binding/namespace.py @@ -0,0 +1,4 @@ +from binding import * + +extra = Namespace('llvm_extra') +llvm = Namespace('llvm') diff --git a/newbinding/binding/raw_ostream.py b/newbinding/binding/raw_ostream.py new file mode 100644 index 0000000..0275db4 --- /dev/null +++ b/newbinding/binding/raw_ostream.py @@ -0,0 +1,17 @@ +from binding import * +from namespace import llvm +from LLVMContext import LLVMContext +from StringRef import StringRef + +raw_ostream = llvm.Class() +raw_ostream.include.add("llvm/Support/raw_ostream.h") + +raw_svector_ostream = raw_ostream.Subclass() +raw_svector_ostream.include.add("llvm/Support/raw_os_ostream.h") + +# extra class to help binding +raw_svector_ostream_helper = raw_svector_ostream.Subclass() +create = raw_svector_ostream_helper.staticmethod( + raw_svector_ostream_helper.Pointer) +delete = raw_svector_ostream_helper.delete() +str = raw_svector_ostream_helper.method(StringRef.To(str)) diff --git a/newbinding/binding/utils.py b/newbinding/binding/utils.py new file mode 100644 index 0000000..6c39990 --- /dev/null +++ b/newbinding/binding/utils.py @@ -0,0 +1,6 @@ + +def indent_println(println): + def _println(s): + println("%s%s" % (' '* 4, s)) + return _println + diff --git a/newbinding/capsule.cpp b/newbinding/capsule.cpp new file mode 100644 index 0000000..40d135b --- /dev/null +++ b/newbinding/capsule.cpp @@ -0,0 +1,143 @@ +#include +#include + +static +PyObject* getName(PyObject* self, PyObject* args) { + PyObject* obj; + if (!PyArg_ParseTuple(args, "O", &obj)){ + return NULL; + } + const char* name = PyCapsule_GetName(obj); + if (!name) return NULL; + + return PyString_FromString(name); +} + +static +PyObject* getPointer(PyObject* self, PyObject* args) { + PyObject* obj; + if (!PyArg_ParseTuple(args, "O", &obj)){ + return NULL; + } + void* pointer = PyCapsule_GetPointer(obj, PyCapsule_GetName(obj)); + if (!pointer) return NULL; + + return PyLong_FromVoidPtr(pointer); +} + +static +PyObject* check(PyObject* self, PyObject* args) { + PyObject* obj; + if (!PyArg_ParseTuple(args, "O", &obj)){ + return NULL; + } + if (PyCapsule_CheckExact(obj)) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } +} + +// ------------------ +// PyCapsule Context +// ------------------ + +static +CapsuleContext* getContext(PyObject* self, PyObject* args) { + PyObject* obj; + if (!PyArg_ParseTuple(args, "O", &obj)) { + return NULL; + } + void* context = PyCapsule_GetContext(obj); + if (!context) { + PyErr_SetString(PyExc_TypeError, "PyCapsule has no context."); + return NULL; + } + return (CapsuleContext*)context; +} + +static +PyObject* getClassName(PyObject* self, PyObject* args) { + CapsuleContext* context = getContext(self, args); + if (!context) { + return NULL; + } else { + return PyString_FromString(context->className); + } +} + +static +PyObject* setDestructor(PyObject* self, PyObject* args) { + PyObject* cap; + PyObject* callable; + if (!PyArg_ParseTuple(args, "OO", &cap, &callable)) { + return NULL; + } + PyObject* arglist = Py_BuildValue("(O)", cap); + CapsuleContext* context = getContext(self, arglist); + Py_DECREF(arglist); + if (!context) { + return NULL; + } else { + void* ptr; + if (callable != Py_None) { + if (PyCallable_Check(callable)) { + ptr = callable; + } else { + PyErr_SetString(PyExc_TypeError, "Argument is not callable."); + return NULL; + } + } else { + ptr = NULL; + } + context->destructor = (Destructor_Fn)ptr; + } + Py_RETURN_NONE; +} + +static PyMethodDef core_methods[] = { +#define declmethod(func) { #func , ( PyCFunction )func , METH_VARARGS , NULL } + declmethod(getName), + declmethod(getPointer), + declmethod(check), + declmethod(getClassName), + declmethod(setDestructor), + { NULL }, +#undef declmethod +}; + +// Module main function, hairy because of py3k port +extern "C" { + +#if (PY_MAJOR_VERSION >= 3) + struct PyModuleDef module_def = { + PyModuleDef_HEAD_INIT, + "_capsule", + NULL, + -1, + core_methods, + NULL, NULL, NULL, NULL + }; +#define INITERROR return NULL + PyObject * + PyInit__capsule(void) +#else +#define INITERROR return + PyMODINIT_FUNC + init_capsule(void) +#endif + { +#if PY_MAJOR_VERSION >= 3 + PyObject *module = PyModule_Create( &module_def ); +#else + PyObject *module = Py_InitModule("_capsule", core_methods); +#endif + if (module == NULL) + INITERROR; +#if PY_MAJOR_VERSION >= 3 + + return module; +#endif + } + +} // end extern C diff --git a/newbinding/capsule.py b/newbinding/capsule.py new file mode 100644 index 0000000..b82154b --- /dev/null +++ b/newbinding/capsule.py @@ -0,0 +1,74 @@ +import _capsule +from weakref import WeakValueDictionary + +_pyclasses = {} +_addr2obj = WeakValueDictionary() + + +def _sentry(ptr): + assert _capsule.check(ptr) + + +def classof(cap): + cls = _capsule.getClassName(cap) + return _pyclasses[cls] + + +def wrap(cap): + '''Wrap a PyCapsule with the corresponding Wrapper class. + If `cap` is not a PyCapsule, returns `cap` + ''' + if not _capsule.check(cap): # bypass if cap is not a PyCapsule + return cap + addr = _capsule.getPointer(cap) + try: + # find cached object by pointer address + obj = _addr2obj[addr] + except KeyError: + # create new object and cache it + cls = classof(cap) + obj = cls(cap) + _addr2obj[addr] = obj # cache object by address + # set destructor if cls.delete is defined + if hasattr(cls, '_delete_'): + _capsule.setDestructor(cap, cls._delete_) + else: + assert classof(obj._ptr) is classof(cap) + # Unset destructor for capsules that are repeated + _capsule.setDestructor(cap, None) + return obj + + +def unwrap(obj): + '''Unwrap a Wrapper instance into the underlying PyCapsule. + If `obj` is not a Wrapper instance, returns `obj`. + ''' + if isinstance(obj, Wrapper): + return obj._ptr + else: + return obj + + +def register_class(cls): + clsname = cls.__name__ + _pyclasses['llvm::%s' % clsname] = cls + return cls + + +class Wrapper(object): + + __slots__ = '__ptr' + + def __init__(self, ptr): + _sentry(ptr) + self.__ptr = ptr + + @property + def _ptr(self): + return self.__ptr + + def _release_ownership(self): + _capsule.setDestructor(self._ptr, None) + + + diff --git a/newbinding/include/llvm_binding/binding.h b/newbinding/include/llvm_binding/binding.h new file mode 100644 index 0000000..f7bfde6 --- /dev/null +++ b/newbinding/include/llvm_binding/binding.h @@ -0,0 +1,73 @@ +#include +#include + +#if (PY_MAJOR_VERSION >= 3) + +static +PyObject* +create_python_module(const char *name, PyMethodDef* methtable){ + PyModuleDef module_def_tmp = { + PyModuleDef_HEAD_INIT, + name, + NULL, + -1, + methtable, + NULL, NULL, NULL, NULL + }; + + PyModuleDef* module_def = new PyModuleDef(module_def_tmp); // will leak?? + PyObject* module = PyModule_Create(module_def); + if (module == NULL){ + delete module_def; + return NULL; + } + return module; +} + +#else + +static +PyObject* +create_python_module(const char *name, PyMethodDef* methtable){ + PyObject* module = Py_InitModule(name, methtable); + if (module == NULL) return NULL; + return module; +} + +#endif + +static +PyObject* +create_python_submodule(PyObject* parent, const char* name, + PyMethodDef* methtable) +{ + const char* parentname = PyModule_GetName(parent); + const unsigned len_parent = strlen(parentname); + const unsigned len_sub = strlen(name); + const unsigned len = len_parent + 1 + len_sub; + char* fullname = new char[len + 1]; + strcpy(fullname, parentname); + fullname[len_parent] = '.'; + strcpy(fullname + len_parent + 1, name); + PyObject* submod = create_python_module(fullname, methtable); + delete [] fullname; + if (!submod) + return NULL; + if( -1 == PyModule_AddObject(parent, name, submod) ) + return NULL; + return submod; +} + +struct SubModuleEntry{ + const char* name; + PyMethodDef* methtable; +}; + +static +int populate_submodules(PyObject* parent, SubModuleEntry* entries){ + for(SubModuleEntry* iter = entries; iter->name; ++iter){ + if (!create_python_submodule(parent, iter->name, iter->methtable)) + return 0; + } + return 1; +} \ No newline at end of file diff --git a/newbinding/include/llvm_binding/capsule_context.h b/newbinding/include/llvm_binding/capsule_context.h new file mode 100644 index 0000000..bb45566 --- /dev/null +++ b/newbinding/include/llvm_binding/capsule_context.h @@ -0,0 +1,48 @@ +#ifndef LLVMPY_CAPSULE_CONTEXT_H_ +#define LLVMPY_CAPSULE_CONTEXT_H_ +#include +#include + +typedef PyObject* Destructor_Fn; + +static bool CapsuleContextDebug = false; + +struct CapsuleContext { + const char* className; + Destructor_Fn destructor; + + CapsuleContext(const char* cn, Destructor_Fn dtor=NULL) + : className(cn), destructor(dtor) { } +}; + +void capsule_destructor(PyObject* capsule){ + using std::cerr; + using std::endl; + CapsuleContext* context = (CapsuleContext*)PyCapsule_GetContext(capsule); + if (context->destructor) { + if (CapsuleContextDebug) { + cerr << clock() + << " == DEBUG ==" + << " destroy pointer: " + << context->className + << endl; + } + PyObject_CallMethodObjArgs(context->destructor, capsule, NULL); + } else { + if (CapsuleContextDebug) { + cerr << clock() + << " == DEBUG ==" + << " keep pointer alive: " + << context->className + << endl; + } + } + delete context; +} + +void enable_capsule_dtor_debug(bool enabled){ + CapsuleContextDebug = enabled; +} + +#endif //LLVMPY_CAPSULE_CONTEXT_H_ + diff --git a/newbinding/include/llvm_binding/conversion.h b/newbinding/include/llvm_binding/conversion.h new file mode 100644 index 0000000..c3d6e36 --- /dev/null +++ b/newbinding/include/llvm_binding/conversion.h @@ -0,0 +1,93 @@ +#include +#include +#include + +// python object unwrapper + +static +int py_str_to(PyObject *strobj, llvm::StringRef &strref){ + // type check + if (!PyString_Check(strobj)) { + // raises TypeError + PyErr_SetString(PyExc_TypeError, "Expecting a str"); + return 0; + } + // get len and buffer + const Py_ssize_t len = PyString_Size(strobj); + const char * buf = PyString_AsString(strobj); + if (!buf) { + // raises TypeError + return 0; + } + // set output + strref = llvm::StringRef(buf, len); + // success + return 1; +} + +static +int py_int_to(PyObject *intobj, unsigned & val){ + if (!PyInt_Check(intobj)) { + // raise TypeError + PyErr_SetString(PyExc_TypeError, "Expecting an int"); + return 0; + } + val = PyInt_AsUnsignedLongMask(intobj); + // success + return 1; +} + +static +int py_bool_to(PyObject *boolobj, bool & val){ + if (!PyBool_Check(boolobj)) { + // raise TypeError + PyErr_SetString(PyExc_TypeError, "Expecting a bool"); + return 0; + } + if (boolobj == Py_True) { + val = true; + } else if (boolobj == Py_False) { + val = false; + } else { + PyErr_SetString(PyExc_TypeError, "Invalid boolean object"); + return 0; + } + // success + return 1; +} + +// python object wrapper + +static +PyObject* py_str_from(const std::string &str){ + return PyString_FromStringAndSize(str.c_str(), str.size()); +} + +static +PyObject* py_bool_from(bool val){ + if (val) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } +} + +static +PyObject* py_int_from(int val){ + return PyInt_FromLong(val); +} + +// casting +template +struct typecast { + template static + Td* from(Ts* src) { + return llvm::dyn_cast(src); + } + + static + Td* from(void* src) { + return static_cast(src); + } +}; + diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h new file mode 100644 index 0000000..a7388a2 --- /dev/null +++ b/newbinding/include/llvm_binding/extra.h @@ -0,0 +1,34 @@ +#include +#include +#include + +namespace llvm{ + +class raw_svector_ostream_helper: public raw_svector_ostream { + SmallVectorImpl *SV; +public: + static + raw_svector_ostream_helper* create(){ + SmallVectorImpl* sv = new SmallVector(); + return new raw_svector_ostream_helper(sv); + } + + ~raw_svector_ostream_helper(){ + delete SV; + } + +protected: + + explicit + raw_svector_ostream_helper(SmallVectorImpl* sv) + : raw_svector_ostream(*sv), SV(sv) {} + +private: + // no copy + raw_svector_ostream_helper(const raw_svector_ostream_helper&); + // no assign + void operator = (const raw_svector_ostream_helper&); +}; + +} + diff --git a/newbinding/setup.py b/newbinding/setup.py new file mode 100644 index 0000000..6e2ceb5 --- /dev/null +++ b/newbinding/setup.py @@ -0,0 +1,54 @@ +import sys, os +from distutils.core import setup, Extension + +llvm_config = os.environ.get('LLVM_CONFIG_PATH') + +def run_llvm_config(args): + cmd = llvm_config + ' ' + ' '.join(args) + return os.popen(cmd).read().rstrip() + +def get_libs_and_objs(components): + parts = run_llvm_config(['--libs'] + components).split() + libs = [] + objs = [] + for part in parts: + if part.startswith('-l'): + libs.append(part[2:]) + elif part.endswith('.o'): + objs.append(part) + return libs, objs + +incdir = run_llvm_config(['--includedir']) +libdir = run_llvm_config(['--libdir']) +ldflags = run_llvm_config(['--ldflags']) +macros = [('__STDC_CONSTANT_MACROS', None), + ('__STDC_LIMIT_MACROS', None)] + +extra_link_args = ldflags.split() + +libs_core, objs_core = get_libs_and_objs(['core', 'analysis', 'scalaropts', + 'executionengine', 'jit', 'native', + 'interpreter', 'bitreader', + 'bitwriter', 'instrumentation', 'ipa', + 'ipo', 'transformutils', 'asmparser', + 'linker', 'support', 'vectorize']) + +ext_modules = [Extension(name='_api', + sources=['api.cpp'], + include_dirs = ['include', incdir], + library_dirs = [libdir], + libraries = libs_core, + define_macros = macros, + extra_objects = objs_core, + extra_link_args = extra_link_args), + Extension(name='_capsule', + sources=['capsule.cpp'], + include_dirs = ['include'],), + ] + + +setup(name = 'llvmpy2', + description = 'Python bindings for LLVM', + author = 'Siu Kwan Lam', + ext_modules = ext_modules, + license = "BSD") diff --git a/newbinding/test.py b/newbinding/test.py new file mode 100644 index 0000000..bed9e1a --- /dev/null +++ b/newbinding/test.py @@ -0,0 +1,32 @@ +import _api + +context = _api.getGlobalContext() +modname = "modname" +module = _api.Module.new(modname, context) +assert modname == _api.Module.getModuleIdentifier(module) +modname2 = "newmodname" +_api.Module.setModuleIdentifier(module, modname2) +assert modname2 == _api.Module.getModuleIdentifier(module) + +_api.Module.dump(module) + +_api.Module.delete(module) + +voidty = _api.Type.getVoidTy(context) +assert _api.Type.isVoidTy(voidty) +assert not _api.Type.isLabelTy(voidty) + +int21ty = _api.Type.getIntNTy(context, 21) +assert _api.Type.isIntegerTy(int21ty) +assert _api.Type.isIntegerTy(int21ty, 21) +_api.Type.dump(int21ty) + +halfty = _api.Type.getHalfTy(context) +assert _api.Type.isHalfTy(halfty) +_api.Type.dump(halfty) + +fnty = _api.FunctionType.get(halfty, False) +_api.Type.dump(fnty) + + + diff --git a/newbinding/test2.py b/newbinding/test2.py new file mode 100644 index 0000000..25a59d7 --- /dev/null +++ b/newbinding/test2.py @@ -0,0 +1,20 @@ +import api +#api.enable_capsule_dtor_debug(True) +context = api.getGlobalContext() + +m = api.Module.new("modname", context) +print m.getModuleIdentifier() +m.setModuleIdentifier('modname2') +print m.getModuleIdentifier() +m.dump() +os = api.raw_svector_ostream_helper.create() +m.print_(os, None) +print os.str() + +int1ty = api.Type.getInt1Ty(context) +int1ty.dump() + +print int1ty.isIntegerTy(1) + + + From 47771d8dbcd61d86c01dab07696e1238b7d64d9b Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 22 Jan 2013 10:13:41 -0600 Subject: [PATCH 203/516] Add README --- newbinding/README | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 newbinding/README diff --git a/newbinding/README b/newbinding/README new file mode 100644 index 0000000..2bfabcd --- /dev/null +++ b/newbinding/README @@ -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. From 5c1e8985a13f2ef4deb44015d74a856ec7977d29 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 22 Jan 2013 10:16:15 -0600 Subject: [PATCH 204/516] Delete empty unused Makefile --- newbinding/binding/Makefile | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 newbinding/binding/Makefile diff --git a/newbinding/binding/Makefile b/newbinding/binding/Makefile deleted file mode 100644 index e69de29..0000000 From d0935fe53383a3916d3fdd62aeb448c0339726af Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 22 Jan 2013 10:41:22 -0600 Subject: [PATCH 205/516] Organize code layout --- newbinding/Makefile | 10 ++++---- newbinding/{binding => }/binding.py | 0 newbinding/{binding => }/gen.py | 23 ++++++++++++++----- .../AssemblyAnnotationWriter.py | 0 newbinding/{binding => src}/DerivedTypes.py | 0 newbinding/{binding => src}/LLVMContext.py | 0 newbinding/{binding => src}/Module.py | 0 newbinding/{binding => src}/StringRef.py | 0 newbinding/{binding => src}/Type.py | 0 newbinding/{binding => src}/_Debug.py | 0 newbinding/src/__init__.py | 0 newbinding/{binding => src}/namespace.py | 0 newbinding/{binding => src}/raw_ostream.py | 0 newbinding/{binding => }/utils.py | 0 14 files changed, 22 insertions(+), 11 deletions(-) rename newbinding/{binding => }/binding.py (100%) rename newbinding/{binding => }/gen.py (92%) rename newbinding/{binding => src}/AssemblyAnnotationWriter.py (100%) rename newbinding/{binding => src}/DerivedTypes.py (100%) rename newbinding/{binding => src}/LLVMContext.py (100%) rename newbinding/{binding => src}/Module.py (100%) rename newbinding/{binding => src}/StringRef.py (100%) rename newbinding/{binding => src}/Type.py (100%) rename newbinding/{binding => src}/_Debug.py (100%) create mode 100644 newbinding/src/__init__.py rename newbinding/{binding => src}/namespace.py (100%) rename newbinding/{binding => src}/raw_ostream.py (100%) rename newbinding/{binding => }/utils.py (100%) diff --git a/newbinding/Makefile b/newbinding/Makefile index ba902e3..0db1f29 100644 --- a/newbinding/Makefile +++ b/newbinding/Makefile @@ -5,14 +5,14 @@ all: _api.so _capsule.so _api.so _capsule.so: api.cpp capsule.cpp python setup.py build_ext --inplace - -api.cpp api.py: binding/*.py include/llvm_binding/*.h - cd binding; python gen.py api $(PYMODS) - mv binding/api.cpp api.cpp - mv binding/api.py api.py +api.cpp api.py: src/*.py include/llvm_binding/*.h + python gen.py api src $(PYMODS) clean: rm -f _api.so _capsule.so rm -f api.cpp api.py +check: _api.so api.py + python test2.py +@PHONY: all clean check diff --git a/newbinding/binding/binding.py b/newbinding/binding.py similarity index 100% rename from newbinding/binding/binding.py rename to newbinding/binding.py diff --git a/newbinding/binding/gen.py b/newbinding/gen.py similarity index 92% rename from newbinding/binding/gen.py rename to newbinding/gen.py index f662979..c2126ab 100644 --- a/newbinding/binding/gen.py +++ b/newbinding/gen.py @@ -136,8 +136,7 @@ class Context(object): println('') - def add_module(self, modname): - module = __import__(modname) + def add_module(self, module): allsyms = [(k, v) for k, v in vars(module).items() if isinstance(v, Binding)] symtab = sorted(allsyms, key=lambda x: x[1].rank) @@ -190,17 +189,29 @@ def wrap_println(f): return println if __name__ == '__main__': + outputfilename = sys.argv[1] + srcdir = sys.argv[2] + modnames = sys.argv[3:] + + modules = [] + for m in modnames: + path = '%s.%s' % (srcdir, m) + print path + module = __import__(path) + for token in path.split('.')[1:]: + module = getattr(module, token) + modules.append(module) context = Context() - for mod in sys.argv[2:]: + + for mod in modules: context.add_module(mod) - filename = sys.argv[1] - with open('%s.cpp' % filename, 'w') as outfile: + with open('%s.cpp' % outputfilename, 'w') as outfile: println = wrap_println(outfile) populate_headers(println) context.generate_cpp(println) - with open('%s.py' % filename, 'w') as outfile: + with open('%s.py' % outputfilename, 'w') as outfile: println = wrap_println(outfile) context.generate_py(println) diff --git a/newbinding/binding/AssemblyAnnotationWriter.py b/newbinding/src/AssemblyAnnotationWriter.py similarity index 100% rename from newbinding/binding/AssemblyAnnotationWriter.py rename to newbinding/src/AssemblyAnnotationWriter.py diff --git a/newbinding/binding/DerivedTypes.py b/newbinding/src/DerivedTypes.py similarity index 100% rename from newbinding/binding/DerivedTypes.py rename to newbinding/src/DerivedTypes.py diff --git a/newbinding/binding/LLVMContext.py b/newbinding/src/LLVMContext.py similarity index 100% rename from newbinding/binding/LLVMContext.py rename to newbinding/src/LLVMContext.py diff --git a/newbinding/binding/Module.py b/newbinding/src/Module.py similarity index 100% rename from newbinding/binding/Module.py rename to newbinding/src/Module.py diff --git a/newbinding/binding/StringRef.py b/newbinding/src/StringRef.py similarity index 100% rename from newbinding/binding/StringRef.py rename to newbinding/src/StringRef.py diff --git a/newbinding/binding/Type.py b/newbinding/src/Type.py similarity index 100% rename from newbinding/binding/Type.py rename to newbinding/src/Type.py diff --git a/newbinding/binding/_Debug.py b/newbinding/src/_Debug.py similarity index 100% rename from newbinding/binding/_Debug.py rename to newbinding/src/_Debug.py diff --git a/newbinding/src/__init__.py b/newbinding/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/newbinding/binding/namespace.py b/newbinding/src/namespace.py similarity index 100% rename from newbinding/binding/namespace.py rename to newbinding/src/namespace.py diff --git a/newbinding/binding/raw_ostream.py b/newbinding/src/raw_ostream.py similarity index 100% rename from newbinding/binding/raw_ostream.py rename to newbinding/src/raw_ostream.py diff --git a/newbinding/binding/utils.py b/newbinding/utils.py similarity index 100% rename from newbinding/binding/utils.py rename to newbinding/utils.py From 36df29ba71df48beb838e60d9a5a2616fb3a8fb3 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 22 Jan 2013 11:49:41 -0600 Subject: [PATCH 206/516] Add enum support --- newbinding/binding.py | 46 +++++++++++++++++++++++++++++++++++++++++++ newbinding/gen.py | 8 ++++++++ 2 files changed, 54 insertions(+) diff --git a/newbinding/binding.py b/newbinding/binding.py index 1230813..fa9ce90 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -222,6 +222,50 @@ class Wrapper(object): println('if (!%(out)s) return NULL;' % locals()) return out +class Enum(Binding): + def __init__(self, ns, *values): + super(Enum, self).__init__() + self.values = values + self.ns = ns + self.name = None + + def compile(self, name, println): + self.name = self.name or name + + @property + def fullname(self): + return '::'.join([self.ns, self.name]) + +class ClassEnum(Enum): + def __init__(self, cls, *values): + super(ClassEnum, self).__init__(None, *values) + self.cls = cls + self.cls.enums.append(self) + + def compile(self, name, println): + self.ns = self.cls.fullname + super(ClassEnum, self).compile(name, println) + + def wrap(self, println, var): + println2 = indent_println(println) + ret = declare(println, 'PyObject*', NULL) + println('switch(%s) { ' % var) + for v in self.values: + println('case %s::%s:' % (self.ns, v)) + println2('%(ret)s = PyString_FromString("%(v)s");' % locals()) + println2('break;') + else: + println('default:') + println2('PyErr_SetString(PyExc_TypeError, "Invalid enum: %s");' % + v) + println2('return NULL;') + println('}') + return ret + + def unwrap(self, println, var): + pass + + class Class(Binding): def __init__(self, ns): super(Class, self).__init__() @@ -229,6 +273,8 @@ class Class(Binding): self.Ref = Ref(self) self.Pointer = Pointer(self) self.Subclass = lambda: Subclass(self) + self.Enum = lambda *v: ClassEnum(self, *v) + self.enums = [] self.ns = ns self.methods = [] self.name = None diff --git a/newbinding/gen.py b/newbinding/gen.py index c2126ab..87c0697 100644 --- a/newbinding/gen.py +++ b/newbinding/gen.py @@ -115,6 +115,14 @@ class Context(object): println('pass') else: mod = cls.name + # generate class enums + for enum in cls.enums: + println('class %s:' % enum.name) + println2 = indent_println(println) + for v in enum.values: + println2('%(v)s = "%(v)s"' % locals()) + println('') + # generate class methods for method in cls.methods: name = method.name if isinstance(method, StaticMethod): From e39e1c72057981f2cf3bbc42354e3f85e7592c62 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 22 Jan 2013 11:50:06 -0600 Subject: [PATCH 207/516] Add logging --- newbinding/binding.py | 3 +++ newbinding/gen.py | 11 +++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/newbinding/binding.py b/newbinding/binding.py index fa9ce90..ab0e1c0 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -1,5 +1,8 @@ +import logging from utils import * +logger = logging.getLogger(__name__) + _py2capi_fmtmap = { str: 's#', } diff --git a/newbinding/gen.py b/newbinding/gen.py index 87c0697..81a4815 100644 --- a/newbinding/gen.py +++ b/newbinding/gen.py @@ -1,8 +1,11 @@ -import sys +import sys, logging from binding import * from utils import * from cStringIO import StringIO +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + extension_entry = ''' extern "C" { @@ -143,7 +146,6 @@ class Context(object): println2('return capsule.wrap(ret)') println('') - def add_module(self, module): allsyms = [(k, v) for k, v in vars(module).items() if isinstance(v, Binding)] @@ -159,6 +161,7 @@ class Context(object): def println_to_def(s): buf.write(s) buf.write('\n') + logger.info('compiling %s', k) v.compile(k, println_to_def) self.definitions.append(buf.getvalue()) buf.close() @@ -200,11 +203,11 @@ if __name__ == '__main__': outputfilename = sys.argv[1] srcdir = sys.argv[2] modnames = sys.argv[3:] - + modules = [] for m in modnames: path = '%s.%s' % (srcdir, m) - print path + logger.info("import module %s", path) module = __import__(path) for token in path.split('.')[1:]: module = getattr(module, token) From 089c825b0cdd89384b639f1f1b233f8aab59074d Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 22 Jan 2013 11:50:39 -0600 Subject: [PATCH 208/516] Add cleantemp rule in Makefile --- newbinding/Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/newbinding/Makefile b/newbinding/Makefile index 0db1f29..77a012b 100644 --- a/newbinding/Makefile +++ b/newbinding/Makefile @@ -8,9 +8,13 @@ _api.so _capsule.so: api.cpp capsule.cpp api.cpp api.py: src/*.py include/llvm_binding/*.h python gen.py api src $(PYMODS) -clean: +clean: cleantemp rm -f _api.so _capsule.so + +cleantemp: rm -f api.cpp api.py + rm -f src/*.pyc + check: _api.so api.py python test2.py From f88036274a3d9e7de2a7cbcd3e064f16e847962e Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 22 Jan 2013 15:31:13 -0600 Subject: [PATCH 209/516] Fix and rewrite the memory management for capsules. --- newbinding/Makefile | 3 +- newbinding/binding.py | 4 +- newbinding/capsule.cpp | 29 -------------- newbinding/capsule.py | 39 ++++++++++++++++--- .../include/llvm_binding/capsule_context.h | 39 +++---------------- newbinding/src/_Debug.py | 3 -- newbinding/test2.py | 26 ++++++++++++- 7 files changed, 69 insertions(+), 74 deletions(-) delete mode 100644 newbinding/src/_Debug.py diff --git a/newbinding/Makefile b/newbinding/Makefile index 77a012b..49e244b 100644 --- a/newbinding/Makefile +++ b/newbinding/Makefile @@ -1,4 +1,5 @@ -PYMODS = _Debug raw_ostream Type DerivedTypes LLVMContext StringRef AssemblyAnnotationWriter Module +PYTHON = python +PYMODS = raw_ostream Type DerivedTypes LLVMContext StringRef AssemblyAnnotationWriter Module all: _api.so _capsule.so diff --git a/newbinding/binding.py b/newbinding/binding.py index ab0e1c0..63fcf9e 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -45,13 +45,15 @@ def mangle(name): name = name.replace('_', '__').replace(' ', '_') return name.replace('::', '_').rstrip('*&') -def pycapsule_new(println, ptr, name, clsname, dtor='capsule_destructor'): +def pycapsule_new(println, ptr, name, clsname, dtor=NULL): # build capsule name_soften = mangle(name) var = new_symbol('pycap_%s' % name_soften) fmt = 'PyObject* %(var)s = PyCapsule_New(%(ptr)s, "%(name)s", %(dtor)s);' println(fmt % locals()) + println('if (!%(var)s) return NULL;' % locals()) + # build context fmt = 'new CapsuleContext("%(clsname)s")' context = declare(println, 'CapsuleContext*', fmt % locals()) diff --git a/newbinding/capsule.cpp b/newbinding/capsule.cpp index 40d135b..e7e4932 100644 --- a/newbinding/capsule.cpp +++ b/newbinding/capsule.cpp @@ -66,34 +66,6 @@ PyObject* getClassName(PyObject* self, PyObject* args) { } } -static -PyObject* setDestructor(PyObject* self, PyObject* args) { - PyObject* cap; - PyObject* callable; - if (!PyArg_ParseTuple(args, "OO", &cap, &callable)) { - return NULL; - } - PyObject* arglist = Py_BuildValue("(O)", cap); - CapsuleContext* context = getContext(self, arglist); - Py_DECREF(arglist); - if (!context) { - return NULL; - } else { - void* ptr; - if (callable != Py_None) { - if (PyCallable_Check(callable)) { - ptr = callable; - } else { - PyErr_SetString(PyExc_TypeError, "Argument is not callable."); - return NULL; - } - } else { - ptr = NULL; - } - context->destructor = (Destructor_Fn)ptr; - } - Py_RETURN_NONE; -} static PyMethodDef core_methods[] = { #define declmethod(func) { #func , ( PyCFunction )func , METH_VARARGS , NULL } @@ -101,7 +73,6 @@ static PyMethodDef core_methods[] = { declmethod(getPointer), declmethod(check), declmethod(getClassName), - declmethod(setDestructor), { NULL }, #undef declmethod }; diff --git a/newbinding/capsule.py b/newbinding/capsule.py index b82154b..509b4c4 100644 --- a/newbinding/capsule.py +++ b/newbinding/capsule.py @@ -1,18 +1,44 @@ import _capsule -from weakref import WeakValueDictionary +from weakref import WeakValueDictionary, ref +import logging +logger = logging.getLogger(__name__) + +def set_debug(enabled): + ''' + Side-effect: configure logger with it is not configured. + ''' + if enabled: + # If no handlers are configured for the root logger, + # build a default handler for debugging. + # Can we do better? + if not logger.root.handlers: + logging.basicConfig() + logger.setLevel(logging.DEBUG) + else: + logger.setLevel(logging.WARNING) + + +class WeakRef(ref): + __slots__ = 'capsule', 'dtor' _pyclasses = {} _addr2obj = WeakValueDictionary() - +_owners = {} def _sentry(ptr): assert _capsule.check(ptr) - def classof(cap): cls = _capsule.getClassName(cap) return _pyclasses[cls] +def _capsule_destructor(weak): + cap = weak.capsule + addr = _capsule.getPointer(cap) + cls = _capsule.getClassName(cap) + logger.debug("destroy pointer %s to %s", addr, cls) + weak.dtor(cap) + del _owners[addr] def wrap(cap): '''Wrap a PyCapsule with the corresponding Wrapper class. @@ -29,9 +55,12 @@ def wrap(cap): cls = classof(cap) obj = cls(cap) _addr2obj[addr] = obj # cache object by address - # set destructor if cls.delete is defined + # set ownership if *cls* defines *_delete_* if hasattr(cls, '_delete_'): - _capsule.setDestructor(cap, cls._delete_) + weak = WeakRef(obj, _capsule_destructor) + _owners[addr] = weak + weak.capsule = cap + weak.dtor = cls._delete_ else: assert classof(obj._ptr) is classof(cap) # Unset destructor for capsules that are repeated diff --git a/newbinding/include/llvm_binding/capsule_context.h b/newbinding/include/llvm_binding/capsule_context.h index bb45566..dacfc89 100644 --- a/newbinding/include/llvm_binding/capsule_context.h +++ b/newbinding/include/llvm_binding/capsule_context.h @@ -1,48 +1,19 @@ #ifndef LLVMPY_CAPSULE_CONTEXT_H_ #define LLVMPY_CAPSULE_CONTEXT_H_ + #include #include typedef PyObject* Destructor_Fn; -static bool CapsuleContextDebug = false; - struct CapsuleContext { const char* className; - Destructor_Fn destructor; - - CapsuleContext(const char* cn, Destructor_Fn dtor=NULL) - : className(cn), destructor(dtor) { } + + CapsuleContext(const char* cn) + : className(cn) + { } }; -void capsule_destructor(PyObject* capsule){ - using std::cerr; - using std::endl; - CapsuleContext* context = (CapsuleContext*)PyCapsule_GetContext(capsule); - if (context->destructor) { - if (CapsuleContextDebug) { - cerr << clock() - << " == DEBUG ==" - << " destroy pointer: " - << context->className - << endl; - } - PyObject_CallMethodObjArgs(context->destructor, capsule, NULL); - } else { - if (CapsuleContextDebug) { - cerr << clock() - << " == DEBUG ==" - << " keep pointer alive: " - << context->className - << endl; - } - } - delete context; -} - -void enable_capsule_dtor_debug(bool enabled){ - CapsuleContextDebug = enabled; -} #endif //LLVMPY_CAPSULE_CONTEXT_H_ diff --git a/newbinding/src/_Debug.py b/newbinding/src/_Debug.py deleted file mode 100644 index be092f3..0000000 --- a/newbinding/src/_Debug.py +++ /dev/null @@ -1,3 +0,0 @@ -from binding import * - -enable_capsule_dtor_debug = Function('', Void, Bool.From(bool)) diff --git a/newbinding/test2.py b/newbinding/test2.py index 25a59d7..872dfc0 100644 --- a/newbinding/test2.py +++ b/newbinding/test2.py @@ -1,20 +1,44 @@ import api -#api.enable_capsule_dtor_debug(True) +#api.capsule.set_debug(True) context = api.getGlobalContext() +def test(): + print '*' * 80 + m = api.Module.new("modname", context) + print m.getModuleIdentifier() + m.setModuleIdentifier('modname2') + print m.getModuleIdentifier() + print 'endianness', m.getEndianness() + assert m.getEndianness() == api.Module.Endianness.AnyEndianness + print 'pointer-size', m.getPointerSize() + assert m.getPointerSize() == api.Module.PointerSize.AnyPointerSize + m.dump() + m = api.Module.new("modname", context) print m.getModuleIdentifier() m.setModuleIdentifier('modname2') print m.getModuleIdentifier() +print 'endianness', m.getEndianness() +assert m.getEndianness() == api.Module.Endianness.AnyEndianness +print 'pointer-size', m.getPointerSize() +assert m.getPointerSize() == api.Module.PointerSize.AnyPointerSize m.dump() + + + os = api.raw_svector_ostream_helper.create() m.print_(os, None) print os.str() + int1ty = api.Type.getInt1Ty(context) int1ty.dump() print int1ty.isIntegerTy(1) +fnty = api.FunctionType.get(int1ty, False) +os2 = api.raw_svector_ostream_helper.create() +fnty.print_(os2) +print os2.str() From bd550e3c0ed70dfe4c55864c3ea3b95a4c250d24 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 22 Jan 2013 15:33:23 -0600 Subject: [PATCH 210/516] Implement StaticMultiMethod --- newbinding/binding.py | 52 ++++++++++++++++++++++++++++++++++ newbinding/gen.py | 3 +- newbinding/src/DerivedTypes.py | 6 +++- 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/newbinding/binding.py b/newbinding/binding.py index 63fcf9e..de68b55 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -314,6 +314,11 @@ class Class(Binding): mm = MultiMethod(self, signatures) self.methods.append(mm) return mm + + def staticmultimethod(self, *signatures): + smm = StaticMultiMethod(self, signatures) + self.methods.append(smm) + return smm def compile(self, name, println): # set name @@ -518,6 +523,53 @@ class StaticMethod(Method): println('%s;' % call) return_none(println) +class StaticMultiMethod(Binding): + '''Can only differs by the number of arguments. + ''' + def __init__(self, cls, signatures): + super(StaticMultiMethod, self).__init__() + nargs = set() + for sig in signatures: + n = len(sig) + if n in nargs: + raise TypeError("StaticMultiMethod only supports overloaded " + "version with different number of arguments") + nargs.add(n) + self.cls = cls + self.signatures = signatures + self.name = None + + + def compile(self, name, println): + # set name + self.name = self.name or name + # generate wrapper + println('static') + println('PyObject*') + mangled = self.mangled_name + println('%(mangled)s(PyObject* self, PyObject* args)' % locals()) + println('{') + println2 = indent_println(println) + nargs = declare(println2, 'Py_ssize_t', 'PyTuple_Size(args)') + for sig in self.signatures: + expect = len(sig) - 1 + println2('if (%(nargs)s == %(expect)d) {' % locals()) + method = StaticMethod(self.cls, sig[0], *sig[1:]) + method.name = self.name + method.compile_body(indent_println(println2)) + println2('}') + println2('PyErr_SetString(PyExc_TypeError, "Wrong # of args");') + println2('return NULL;') + println('}') + + @property + def fullname(self): + return '::'.join([self.cls.fullname, self.name]) + + @property + def mangled_name(self): + return mangle(self.fullname) + class Constructor(StaticMethod): def compile_body(self, println): args = parse_arguments(println, 'args', *self.args) diff --git a/newbinding/gen.py b/newbinding/gen.py index 81a4815..4081f01 100644 --- a/newbinding/gen.py +++ b/newbinding/gen.py @@ -128,7 +128,8 @@ class Context(object): # generate class methods for method in cls.methods: name = method.name - if isinstance(method, StaticMethod): + if(isinstance(method, StaticMethod) or + isinstance(method, StaticMultiMethod)): println('@staticmethod') println('def %(name)s(*args):' % locals()) println2 = indent_println(println) diff --git a/newbinding/src/DerivedTypes.py b/newbinding/src/DerivedTypes.py index 10d5fbf..edf4297 100644 --- a/newbinding/src/DerivedTypes.py +++ b/newbinding/src/DerivedTypes.py @@ -6,7 +6,11 @@ from Type import Type FunctionType = Type.Subclass() FunctionType.include.add('llvm/DerivedTypes.h') -get = FunctionType.staticmethod(FunctionType.Pointer, Type.Pointer, Bool.From(bool)) +get = FunctionType.staticmultimethod([FunctionType.Pointer, + Type.Pointer, Bool.From(bool)],) +# (FunctionType.Pointer, +# Type.Pointer, )]) + isVarArg = FunctionType.method(Bool.To(bool)) getReturnType = FunctionType.method(Type.Pointer) getParamType = FunctionType.method(Type.Pointer, Unsigned.From(int)) From 3e89a97fdb22e97c529f55380ca632dd53f18fb0 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 22 Jan 2013 15:33:50 -0600 Subject: [PATCH 211/516] Improve Makefile --- newbinding/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/newbinding/Makefile b/newbinding/Makefile index 49e244b..3996d8b 100644 --- a/newbinding/Makefile +++ b/newbinding/Makefile @@ -4,10 +4,10 @@ PYMODS = raw_ostream Type DerivedTypes LLVMContext StringRef AssemblyAnnotationW all: _api.so _capsule.so _api.so _capsule.so: api.cpp capsule.cpp - python setup.py build_ext --inplace + $(PYTHON) setup.py build_ext --inplace api.cpp api.py: src/*.py include/llvm_binding/*.h - python gen.py api src $(PYMODS) + $(PYTHON) gen.py api src $(PYMODS) clean: cleantemp rm -f _api.so _capsule.so @@ -18,6 +18,6 @@ cleantemp: check: _api.so api.py - python test2.py + $(PYTHON) test2.py @PHONY: all clean check From f95b691b61520f8f0d6a7be12ca112ab8bf6e841 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 22 Jan 2013 15:35:05 -0600 Subject: [PATCH 212/516] Expand Module binding --- newbinding/src/Module.py | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/newbinding/src/Module.py b/newbinding/src/Module.py index a458401..5923859 100644 --- a/newbinding/src/Module.py +++ b/newbinding/src/Module.py @@ -5,21 +5,42 @@ from StringRef import StringRef from raw_ostream import raw_svector_ostream_helper from AssemblyAnnotationWriter import AssemblyAnnotationWriter +# class Module Module = llvm.Class() Module.include.add("llvm/Module.h") +# Enumerators +Endianness = Module.Enum('AnyEndianness', 'LittleEndian', 'BigEndian') +PointerSize = Module.Enum('AnyPointerSize', 'Pointer32', 'Pointer64') + +# Constructors & Destructors new = Module.new(StringRef.From(str), LLVMContext.Ref) delete = Module.delete() + +# Module Level Accessor getModuleIdentifier = Module.method(ConstStdString.To(str)) +getDataLayout = Module.method(ConstStdString.To(str)) +getTargetTriple = Module.method(ConstStdString.To(str)) +getEndianness = Module.method(Endianness) +getPointerSize = Module.method(PointerSize) +getContext = Module.method(LLVMContext.Ref) +getModuleInlineAsm = Module.method(ConstStdString.To(str)) + +# Module Level Mutators setModuleIdentifier = Module.method(Void, StringRef.From(str)) setDataLayout = Module.method(Void, StringRef.From(str)) setTargetTriple = Module.method(Void, StringRef.From(str)) setModuleInlineAsm = Module.method(Void, StringRef.From(str)) appendModuleInlineAsm = Module.method(Void, StringRef.From(str)) -getContext = Module.method(LLVMContext.Ref) + +# Function Accessors +#getOrInsertFunction = Module.method(Constant, StringRef.From(str), FunctionType.Pointer) + + + +# Utilities dump = Module.method(Void) print_ = Module.method(Void, raw_svector_ostream_helper.Ref, AssemblyAnnotationWriter.Pointer) print_.realname = 'print' -#getOrInsertFunction = Module.method(Constant, StringRef.From(str), FunctionType.Pointer) - +dropAllReferences = Module.method(Void) From ce103975b853d5fc53246153f617a392a6a79a8d Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 22 Jan 2013 15:40:44 -0600 Subject: [PATCH 213/516] Clean up test --- newbinding/test2.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/newbinding/test2.py b/newbinding/test2.py index 872dfc0..0d64716 100644 --- a/newbinding/test2.py +++ b/newbinding/test2.py @@ -2,17 +2,6 @@ import api #api.capsule.set_debug(True) context = api.getGlobalContext() -def test(): - print '*' * 80 - m = api.Module.new("modname", context) - print m.getModuleIdentifier() - m.setModuleIdentifier('modname2') - print m.getModuleIdentifier() - print 'endianness', m.getEndianness() - assert m.getEndianness() == api.Module.Endianness.AnyEndianness - print 'pointer-size', m.getPointerSize() - assert m.getPointerSize() == api.Module.PointerSize.AnyPointerSize - m.dump() m = api.Module.new("modname", context) print m.getModuleIdentifier() From 6b88ffbaed4757f95814aa650c7297bd8e6d8f6a Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 22 Jan 2013 21:23:20 -0600 Subject: [PATCH 214/516] Add custom binding to SmallVector --- newbinding/Makefile | 4 +++- newbinding/binding.py | 10 ++++++++++ newbinding/include/llvm_binding/extra.h | 24 +++++++++++++++++++++++- newbinding/src/DerivedTypes.py | 11 +++++++---- newbinding/test2.py | 10 ++++++++-- 5 files changed, 51 insertions(+), 8 deletions(-) diff --git a/newbinding/Makefile b/newbinding/Makefile index 3996d8b..6ae50be 100644 --- a/newbinding/Makefile +++ b/newbinding/Makefile @@ -1,5 +1,7 @@ PYTHON = python -PYMODS = raw_ostream Type DerivedTypes LLVMContext StringRef AssemblyAnnotationWriter Module + +PYMODS = raw_ostream SmallVector Type DerivedTypes StringRef +PYMODS += LLVMContext AssemblyAnnotationWriter Module all: _api.so _capsule.so diff --git a/newbinding/binding.py b/newbinding/binding.py index de68b55..adeb284 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -190,6 +190,16 @@ Bool = BuiltinType('bool') Unsigned = BuiltinType('unsigned') ConstStdString = BuiltinType('const std::string') +class PyObjectImpl(object): + name = 'PyObject*' + fullname = name + format = 'O' + + def unwrap(self, println, var): + return var + +PyObject = PyObjectImpl() + class Unwrapper(object): def __init__(self, cls, pytype): self.cls = cls diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h index a7388a2..e78f0e2 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/extra.h @@ -4,6 +4,8 @@ namespace llvm{ +class Type; //forward declaration + class raw_svector_ostream_helper: public raw_svector_ostream { SmallVectorImpl *SV; public: @@ -30,5 +32,25 @@ private: void operator = (const raw_svector_ostream_helper&); }; -} + +class SmallVector_Type : public SmallVector { +public: + static + SmallVector_Type* fromPySequence(PyObject* obj) { + SmallVector_Type* SV = new SmallVector_Type; + Py_ssize_t sz = PySequence_Size(obj); + for (Py_ssize_t i = 0; i < sz; ++i) { + PyObject* item = PySequence_GetItem(obj, i); + PyObject* cap = PyObject_GetAttrString(item, "_ptr"); + Type* type = (Type*)PyCapsule_GetPointer(cap, "llvm::Type"); + SV->push_back(type); + Py_XDECREF(cap); + Py_XDECREF(item); + } + return SV; + } +}; + + +} // end namespace llvm diff --git a/newbinding/src/DerivedTypes.py b/newbinding/src/DerivedTypes.py index edf4297..d9dbb53 100644 --- a/newbinding/src/DerivedTypes.py +++ b/newbinding/src/DerivedTypes.py @@ -2,14 +2,17 @@ from binding import * from namespace import llvm from LLVMContext import LLVMContext from Type import Type +from SmallVector import SmallVector_Type FunctionType = Type.Subclass() FunctionType.include.add('llvm/DerivedTypes.h') -get = FunctionType.staticmultimethod([FunctionType.Pointer, - Type.Pointer, Bool.From(bool)],) -# (FunctionType.Pointer, -# Type.Pointer, )]) +_get_signatures = [(FunctionType.Pointer, + Type.Pointer, Bool.From(bool)), + (FunctionType.Pointer, + Type.Pointer, SmallVector_Type.Ref, Bool.From(bool))] + +get = FunctionType.staticmultimethod(*_get_signatures) isVarArg = FunctionType.method(Bool.To(bool)) getReturnType = FunctionType.method(Type.Pointer) diff --git a/newbinding/test2.py b/newbinding/test2.py index 0d64716..6cb8a06 100644 --- a/newbinding/test2.py +++ b/newbinding/test2.py @@ -1,5 +1,5 @@ import api -#api.capsule.set_debug(True) +api.capsule.set_debug(True) context = api.getGlobalContext() @@ -14,7 +14,6 @@ assert m.getPointerSize() == api.Module.PointerSize.AnyPointerSize m.dump() - os = api.raw_svector_ostream_helper.create() m.print_(os, None) print os.str() @@ -26,6 +25,13 @@ int1ty.dump() print int1ty.isIntegerTy(1) fnty = api.FunctionType.get(int1ty, False) +fnty.dump() +print + +types = [int1ty, api.Type.getIntNTy(context, 21)] +sv = api.SmallVector_Type.fromPySequence(types) + +fnty = api.FunctionType.get(int1ty, sv, False) os2 = api.raw_svector_ostream_helper.create() fnty.print_(os2) From 6afab6268cca2ff0bdd3c689a22e98dfc1395cb9 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 22 Jan 2013 21:24:14 -0600 Subject: [PATCH 215/516] Refactor mangle --- newbinding/binding.py | 17 +++++++++++++++-- newbinding/capsule.py | 2 +- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/newbinding/binding.py b/newbinding/binding.py index adeb284..57d7c7d 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -1,4 +1,5 @@ import logging +import re from utils import * logger = logging.getLogger(__name__) @@ -41,9 +42,21 @@ def parse_arguments(println, var, *args): return unwrapped +_re_mangle_pattern = re.compile(r'[ _<>\*&]') + def mangle(name): - name = name.replace('_', '__').replace(' ', '_') - return name.replace('::', '_').rstrip('*&') + def repl(m): + s = m.group(0) + if s in '<>*&': + return '' + elif s in ' ': + return '_' + elif s in '_': + return '__' + else: + assert False + name = _re_mangle_pattern.sub(repl, name) + return name.replace('::', '_') def pycapsule_new(println, ptr, name, clsname, dtor=NULL): # build capsule diff --git a/newbinding/capsule.py b/newbinding/capsule.py index 509b4c4..e4cd4fa 100644 --- a/newbinding/capsule.py +++ b/newbinding/capsule.py @@ -36,7 +36,7 @@ def _capsule_destructor(weak): cap = weak.capsule addr = _capsule.getPointer(cap) cls = _capsule.getClassName(cap) - logger.debug("destroy pointer %s to %s", addr, cls) + logger.debug("destroy pointer 0x%08X to %s", addr, cls) weak.dtor(cap) del _owners[addr] From ef4c0d3be395a3c756d414667b4f07ec4a3a48e1 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 23 Jan 2013 11:18:06 -0600 Subject: [PATCH 216/516] Rename extra.h to llvm_extra.h --- newbinding/gen.py | 10 +++++----- .../include/llvm_binding/{extra.h => llvm_extra.h} | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) rename newbinding/include/llvm_binding/{extra.h => llvm_extra.h} (98%) diff --git a/newbinding/gen.py b/newbinding/gen.py index 4081f01..bfde891 100644 --- a/newbinding/gen.py +++ b/newbinding/gen.py @@ -186,11 +186,11 @@ class Context(object): def populate_headers(println): includes = [ - 'llvm_binding/conversion.h', - 'llvm_binding/binding.h', - 'llvm_binding/extra.h', - 'llvm_binding/capsule_context.h', - ] + 'llvm_binding/conversion.h', + 'llvm_binding/binding.h', + 'llvm_binding/llvm_extra.h', + 'llvm_binding/capsule_context.h', + ] for inc in includes: println('#include "%s"' % inc) diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/llvm_extra.h similarity index 98% rename from newbinding/include/llvm_binding/extra.h rename to newbinding/include/llvm_binding/llvm_extra.h index e78f0e2..620c3e2 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/llvm_extra.h @@ -2,10 +2,10 @@ #include #include -namespace llvm{ +namespace llvm{ class Type; //forward declaration - + class raw_svector_ostream_helper: public raw_svector_ostream { SmallVectorImpl *SV; public: @@ -51,6 +51,6 @@ public: } }; - + } // end namespace llvm From 6a861d82e6a46fca38565946dac1e604c8bcd093 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 23 Jan 2013 14:50:17 -0600 Subject: [PATCH 217/516] Implement SmallVector_Type, pycapsule_new --- newbinding/binding.py | 14 ++--------- newbinding/gen.py | 21 ++++++++++++++++- newbinding/include/llvm_binding/binding.h | 9 +++++--- .../include/llvm_binding/capsule_context.h | 22 ++++++++++++++++++ newbinding/include/llvm_binding/extra.h | 23 +++++++++++++++++++ newbinding/include/llvm_binding/llvm_extra.h | 20 +--------------- newbinding/src/SmallVector.py | 5 ++++ newbinding/test2.py | 7 +++--- 8 files changed, 82 insertions(+), 39 deletions(-) create mode 100644 newbinding/include/llvm_binding/extra.h create mode 100644 newbinding/src/SmallVector.py diff --git a/newbinding/binding.py b/newbinding/binding.py index 57d7c7d..c9de593 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -58,23 +58,13 @@ def mangle(name): name = _re_mangle_pattern.sub(repl, name) return name.replace('::', '_') -def pycapsule_new(println, ptr, name, clsname, dtor=NULL): +def pycapsule_new(println, ptr, name, clsname): # build capsule name_soften = mangle(name) var = new_symbol('pycap_%s' % name_soften) - fmt = 'PyObject* %(var)s = PyCapsule_New(%(ptr)s, "%(name)s", %(dtor)s);' + fmt = 'PyObject* %(var)s = pycapsule_new(%(ptr)s, "%(name)s", "%(clsname)s");' println(fmt % locals()) - println('if (!%(var)s) return NULL;' % locals()) - - # build context - fmt = 'new CapsuleContext("%(clsname)s")' - context = declare(println, 'CapsuleContext*', fmt % locals()) - - fmt = 'PyCapsule_SetContext(%(var)s, (void*)%(context)s)' - err = declare(println, 'int', fmt % locals()) - - println('if (%(err)s) return NULL;' % locals()) return var diff --git a/newbinding/gen.py b/newbinding/gen.py index bfde891..d73b29a 100644 --- a/newbinding/gen.py +++ b/newbinding/gen.py @@ -81,7 +81,8 @@ class Context(object): for name, cls in self.classes.items(): table = cls.mangled_name println('{ "%(name)s", %(table)s },' % locals()) - println('{ NULL },') + println('{ "extra", extra_methodtable },') + println('{ NULL }') println('};') println('') @@ -92,6 +93,23 @@ class Context(object): def generate_py(self, println): println('import _api, capsule') println('') + # wraps all extras + extra_wrapper = ''' +def _init_extra_wrapper(): + def wrap(callee): + def _wrapped(*args): + args = map(capsule.unwrap, args) + ret = callee(*args) + return capsule.wrap(ret) + return _wrapped + for k in dir(_api.extra): + v = getattr(_api.extra, k) + if not k.startswith('__') and callable(v): + globals()[k] = wrap(v) +_init_extra_wrapper() + ''' + println(extra_wrapper) + println('') # global function for name in self.functions: println('def %(name)s(*args):' % locals()) @@ -190,6 +208,7 @@ def populate_headers(println): 'llvm_binding/binding.h', 'llvm_binding/llvm_extra.h', 'llvm_binding/capsule_context.h', + 'llvm_binding/extra.h', # extra submodule to add ] for inc in includes: println('#include "%s"' % inc) diff --git a/newbinding/include/llvm_binding/binding.h b/newbinding/include/llvm_binding/binding.h index f7bfde6..58a8ad0 100644 --- a/newbinding/include/llvm_binding/binding.h +++ b/newbinding/include/llvm_binding/binding.h @@ -51,10 +51,12 @@ create_python_submodule(PyObject* parent, const char* name, strcpy(fullname + len_parent + 1, name); PyObject* submod = create_python_module(fullname, methtable); delete [] fullname; - if (!submod) + if (!submod){ return NULL; - if( -1 == PyModule_AddObject(parent, name, submod) ) + } + if (-1 == PyModule_AddObject(parent, name, submod)) { return NULL; + } return submod; } @@ -70,4 +72,5 @@ int populate_submodules(PyObject* parent, SubModuleEntry* entries){ return 0; } return 1; -} \ No newline at end of file +} + diff --git a/newbinding/include/llvm_binding/capsule_context.h b/newbinding/include/llvm_binding/capsule_context.h index dacfc89..a4070dc 100644 --- a/newbinding/include/llvm_binding/capsule_context.h +++ b/newbinding/include/llvm_binding/capsule_context.h @@ -15,5 +15,27 @@ struct CapsuleContext { }; +static +PyObject* pycapsule_new(void* ptr, + const char* basename, + const char* classname=NULL) +{ + if (!classname) { + classname = basename; + } + PyObject* cap = PyCapsule_New(ptr, basename, NULL); + if (!cap) { + PyErr_SetString(PyExc_TypeError, "Error creating new PyCapsule"); + return NULL; + } + CapsuleContext* context = new CapsuleContext(classname); + if (PyCapsule_SetContext(cap, context)) { + return NULL; + } + return cap; +} + + + #endif //LLVMPY_CAPSULE_CONTEXT_H_ diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h new file mode 100644 index 0000000..23548ff --- /dev/null +++ b/newbinding/include/llvm_binding/extra.h @@ -0,0 +1,23 @@ +#include +#include + +static +PyObject* small_vector_from_types(PyObject* self, PyObject* args) { + using llvm::Type; + using llvm::SmallVector_Type; + SmallVector_Type* SV = new SmallVector_Type; + Py_ssize_t size = PyTuple_Size(args); + for (Py_ssize_t i = 0; i < size; ++i) { + PyObject* cap = PyTuple_GetItem(args, i); + Type* type = (Type*)PyCapsule_GetPointer(cap, "llvm::Type"); + SV->push_back(type); + } + return pycapsule_new(SV, "llvm::SmallVector_Type"); +} + +static PyMethodDef extra_methodtable[] = { +#define method(func) { #func, (PyCFunction)func, METH_VARARGS, NULL } +method( small_vector_from_types ), +{ NULL } +#undef method +}; diff --git a/newbinding/include/llvm_binding/llvm_extra.h b/newbinding/include/llvm_binding/llvm_extra.h index 620c3e2..f920a47 100644 --- a/newbinding/include/llvm_binding/llvm_extra.h +++ b/newbinding/include/llvm_binding/llvm_extra.h @@ -32,25 +32,7 @@ private: void operator = (const raw_svector_ostream_helper&); }; +typedef SmallVector SmallVector_Type; -class SmallVector_Type : public SmallVector { -public: - static - SmallVector_Type* fromPySequence(PyObject* obj) { - SmallVector_Type* SV = new SmallVector_Type; - Py_ssize_t sz = PySequence_Size(obj); - for (Py_ssize_t i = 0; i < sz; ++i) { - PyObject* item = PySequence_GetItem(obj, i); - PyObject* cap = PyObject_GetAttrString(item, "_ptr"); - Type* type = (Type*)PyCapsule_GetPointer(cap, "llvm::Type"); - SV->push_back(type); - Py_XDECREF(cap); - Py_XDECREF(item); - } - return SV; - } -}; - - } // end namespace llvm diff --git a/newbinding/src/SmallVector.py b/newbinding/src/SmallVector.py new file mode 100644 index 0000000..225c720 --- /dev/null +++ b/newbinding/src/SmallVector.py @@ -0,0 +1,5 @@ +from binding import * +from namespace import llvm + +SmallVector_Type = llvm.Class() +delete = SmallVector_Type.delete() diff --git a/newbinding/test2.py b/newbinding/test2.py index 6cb8a06..6f087c2 100644 --- a/newbinding/test2.py +++ b/newbinding/test2.py @@ -1,4 +1,5 @@ import api +import _capsule api.capsule.set_debug(True) context = api.getGlobalContext() @@ -26,12 +27,10 @@ print int1ty.isIntegerTy(1) fnty = api.FunctionType.get(int1ty, False) fnty.dump() -print types = [int1ty, api.Type.getIntNTy(context, 21)] -sv = api.SmallVector_Type.fromPySequence(types) - -fnty = api.FunctionType.get(int1ty, sv, False) +svt = api.small_vector_from_types(*types) +fnty = api.FunctionType.get(int1ty, svt, False) os2 = api.raw_svector_ostream_helper.create() fnty.print_(os2) From e9be14ca0e18fbe8fe4b79af20288db8f9dcad4f Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 23 Jan 2013 15:24:37 -0600 Subject: [PATCH 218/516] Refactor raw_svector_stream_helper --- newbinding/include/llvm_binding/extra.h | 26 +++++++++++++++++++++++-- newbinding/src/Module.py | 11 +++++------ newbinding/src/Type.py | 4 ++-- newbinding/src/raw_ostream.py | 9 ++------- newbinding/test2.py | 14 ++++++++----- 5 files changed, 42 insertions(+), 22 deletions(-) diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h index 23548ff..417c0f8 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/extra.h @@ -1,15 +1,36 @@ #include #include +#include static -PyObject* small_vector_from_types(PyObject* self, PyObject* args) { +PyObject* make_raw_ostream_for_printing(PyObject* self, PyObject* args) { + using llvm::raw_svector_ostream_helper; + using llvm::raw_svector_ostream; + + if (!PyArg_ParseTuple(args, "")) { + return NULL; + } + raw_svector_ostream* RSOH = raw_svector_ostream_helper::create(); + return pycapsule_new(RSOH, "llvm::raw_ostream", + "llvm::raw_svector_ostream"); +} + +static +PyObject* make_small_vector_from_types(PyObject* self, PyObject* args) { using llvm::Type; using llvm::SmallVector_Type; + SmallVector_Type* SV = new SmallVector_Type; Py_ssize_t size = PyTuple_Size(args); for (Py_ssize_t i = 0; i < size; ++i) { PyObject* cap = PyTuple_GetItem(args, i); + if (!cap) { + return NULL; + } Type* type = (Type*)PyCapsule_GetPointer(cap, "llvm::Type"); + if (!type) { + return NULL; + } SV->push_back(type); } return pycapsule_new(SV, "llvm::SmallVector_Type"); @@ -17,7 +38,8 @@ PyObject* small_vector_from_types(PyObject* self, PyObject* args) { static PyMethodDef extra_methodtable[] = { #define method(func) { #func, (PyCFunction)func, METH_VARARGS, NULL } -method( small_vector_from_types ), +method( make_raw_ostream_for_printing ), +method( make_small_vector_from_types ), { NULL } #undef method }; diff --git a/newbinding/src/Module.py b/newbinding/src/Module.py index 5923859..67ac8b0 100644 --- a/newbinding/src/Module.py +++ b/newbinding/src/Module.py @@ -2,7 +2,9 @@ from binding import * from namespace import llvm from LLVMContext import LLVMContext from StringRef import StringRef -from raw_ostream import raw_svector_ostream_helper +from Constant import Constant +from DerivedTypes import FunctionType +from raw_ostream import raw_ostream from AssemblyAnnotationWriter import AssemblyAnnotationWriter # class Module @@ -34,13 +36,10 @@ setModuleInlineAsm = Module.method(Void, StringRef.From(str)) appendModuleInlineAsm = Module.method(Void, StringRef.From(str)) # Function Accessors -#getOrInsertFunction = Module.method(Constant, StringRef.From(str), FunctionType.Pointer) - - +getOrInsertFunction = Module.method(Constant.Pointer, StringRef.From(str), FunctionType.Pointer) # Utilities dump = Module.method(Void) -print_ = Module.method(Void, raw_svector_ostream_helper.Ref, - AssemblyAnnotationWriter.Pointer) +print_ = Module.method(Void, raw_ostream.Ref, AssemblyAnnotationWriter.Pointer) print_.realname = 'print' dropAllReferences = Module.method(Void) diff --git a/newbinding/src/Type.py b/newbinding/src/Type.py index 19f6d61..3703200 100644 --- a/newbinding/src/Type.py +++ b/newbinding/src/Type.py @@ -1,7 +1,7 @@ from binding import * from namespace import llvm from LLVMContext import LLVMContext -from raw_ostream import raw_svector_ostream_helper +from raw_ostream import raw_ostream Type = llvm.Class() Type.include.add('llvm/Type.h') @@ -13,7 +13,7 @@ PointerType = SequentialType.Subclass() getContext = Type.method(LLVMContext.Ref) dump = Type.method(Void) -print_ = Type.method(Void, raw_svector_ostream_helper.Ref) +print_ = Type.method(Void, raw_ostream.Ref) print_.realname = 'print' def type_checker(): diff --git a/newbinding/src/raw_ostream.py b/newbinding/src/raw_ostream.py index 0275db4..64e8046 100644 --- a/newbinding/src/raw_ostream.py +++ b/newbinding/src/raw_ostream.py @@ -5,13 +5,8 @@ from StringRef import StringRef raw_ostream = llvm.Class() raw_ostream.include.add("llvm/Support/raw_ostream.h") +delete = raw_ostream.delete() raw_svector_ostream = raw_ostream.Subclass() raw_svector_ostream.include.add("llvm/Support/raw_os_ostream.h") - -# extra class to help binding -raw_svector_ostream_helper = raw_svector_ostream.Subclass() -create = raw_svector_ostream_helper.staticmethod( - raw_svector_ostream_helper.Pointer) -delete = raw_svector_ostream_helper.delete() -str = raw_svector_ostream_helper.method(StringRef.To(str)) +str = raw_svector_ostream.method(StringRef.To(str)) diff --git a/newbinding/test2.py b/newbinding/test2.py index 6f087c2..b866f59 100644 --- a/newbinding/test2.py +++ b/newbinding/test2.py @@ -15,7 +15,7 @@ assert m.getPointerSize() == api.Module.PointerSize.AnyPointerSize m.dump() -os = api.raw_svector_ostream_helper.create() +os = api.make_raw_ostream_for_printing() m.print_(os, None) print os.str() @@ -29,10 +29,14 @@ fnty = api.FunctionType.get(int1ty, False) fnty.dump() types = [int1ty, api.Type.getIntNTy(context, 21)] -svt = api.small_vector_from_types(*types) +svt = api.make_small_vector_from_types(*types) fnty = api.FunctionType.get(int1ty, svt, False) -os2 = api.raw_svector_ostream_helper.create() -fnty.print_(os2) -print os2.str() +os = api.make_raw_ostream_for_printing() +fnty.print_(os) +print os.str() +fn = m.getOrInsertFunction("foo", fnty) +os = api.make_raw_ostream_for_printing() +fn.print_(os, None) +print os.str() From e9e1f5703dd43b850735397bd005173a8ae9831d Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 23 Jan 2013 15:25:04 -0600 Subject: [PATCH 219/516] Add Value, User, Constant --- newbinding/Makefile | 2 ++ newbinding/src/Constant.py | 5 +++++ newbinding/src/User.py | 5 +++++ newbinding/src/Value.py | 8 ++++++++ 4 files changed, 20 insertions(+) create mode 100644 newbinding/src/Constant.py create mode 100644 newbinding/src/User.py create mode 100644 newbinding/src/Value.py diff --git a/newbinding/Makefile b/newbinding/Makefile index 6ae50be..d07bc8f 100644 --- a/newbinding/Makefile +++ b/newbinding/Makefile @@ -1,8 +1,10 @@ PYTHON = python PYMODS = raw_ostream SmallVector Type DerivedTypes StringRef +PYMODS += Value User Constant PYMODS += LLVMContext AssemblyAnnotationWriter Module + all: _api.so _capsule.so _api.so _capsule.so: api.cpp capsule.cpp diff --git a/newbinding/src/Constant.py b/newbinding/src/Constant.py new file mode 100644 index 0000000..24045bb --- /dev/null +++ b/newbinding/src/Constant.py @@ -0,0 +1,5 @@ +from binding import * +from namespace import llvm +from User import User + +Constant = User.Subclass() diff --git a/newbinding/src/User.py b/newbinding/src/User.py new file mode 100644 index 0000000..8753983 --- /dev/null +++ b/newbinding/src/User.py @@ -0,0 +1,5 @@ +from binding import * +from namespace import llvm +from Value import Value + +User = Value.Subclass() diff --git a/newbinding/src/Value.py b/newbinding/src/Value.py new file mode 100644 index 0000000..ec7aa9a --- /dev/null +++ b/newbinding/src/Value.py @@ -0,0 +1,8 @@ +from binding import * +from namespace import llvm +from raw_ostream import raw_ostream +from AssemblyAnnotationWriter import AssemblyAnnotationWriter + +Value = llvm.Class() +print_ = Value.method(Void, raw_ostream.Ref, AssemblyAnnotationWriter.Pointer) +print_.realname = 'print' From c247cf95271de8ca29d89ffcce3b94920e0599d0 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 23 Jan 2013 15:28:46 -0600 Subject: [PATCH 220/516] Update generator script so that order of modules does not matter. --- newbinding/Makefile | 4 ++-- newbinding/gen.py | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/newbinding/Makefile b/newbinding/Makefile index d07bc8f..61227e5 100644 --- a/newbinding/Makefile +++ b/newbinding/Makefile @@ -1,9 +1,9 @@ PYTHON = python PYMODS = raw_ostream SmallVector Type DerivedTypes StringRef -PYMODS += Value User Constant -PYMODS += LLVMContext AssemblyAnnotationWriter Module +PYMODS += LLVMContext AssemblyAnnotationWriter Module +PYMODS += Value User Constant all: _api.so _capsule.so diff --git a/newbinding/gen.py b/newbinding/gen.py index d73b29a..cee71f1 100644 --- a/newbinding/gen.py +++ b/newbinding/gen.py @@ -56,6 +56,7 @@ class Context(object): self.functions = {} self.classes = {} self.definitions = [] + self._pending_symbols = [] def generate_cpp(self, println): for i in self.includes: @@ -168,12 +169,15 @@ _init_extra_wrapper() def add_module(self, module): allsyms = [(k, v) for k, v in vars(module).items() if isinstance(v, Binding)] - symtab = sorted(allsyms, key=lambda x: x[1].rank) - # generate includes - for k, v in symtab: + for k, v in allsyms: self.includes |= v.include + self._pending_symbols.extend(allsyms) + + def materialize(self): + symtab = sorted(self._pending_symbols, key=lambda x: x[1].rank) + # compile everything for k, v in symtab: buf = StringIO() @@ -237,6 +241,7 @@ if __name__ == '__main__': for mod in modules: context.add_module(mod) + context.materialize() with open('%s.cpp' % outputfilename, 'w') as outfile: println = wrap_println(outfile) From a3da74c416579ebdc6bc1f1b72dd68c7811b53e0 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 23 Jan 2013 15:44:19 -0600 Subject: [PATCH 221/516] Expand Value class --- newbinding/src/Value.py | 18 +++++++++++++++++- newbinding/test2.py | 4 ++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/newbinding/src/Value.py b/newbinding/src/Value.py index ec7aa9a..062ad43 100644 --- a/newbinding/src/Value.py +++ b/newbinding/src/Value.py @@ -2,7 +2,23 @@ from binding import * from namespace import llvm from raw_ostream import raw_ostream from AssemblyAnnotationWriter import AssemblyAnnotationWriter - +from Type import Type +from LLVMContext import LLVMContext +from StringRef import StringRef +# Value = llvm.Class() + +dump = Value.method(Void) + print_ = Value.method(Void, raw_ostream.Ref, AssemblyAnnotationWriter.Pointer) print_.realname = 'print' + +getType = Value.method(Type.Pointer) +getContext = Value.method(LLVMContext.Ref) + +hasName = Value.method(Bool.To(bool)) +# skip getValueName, setValueName +getName = Value.method(StringRef.To(str)) +setName = Value.method(Void, StringRef.From(str)) + +replaceAllUsesWith = Value.method(Void, Value.Pointer) \ No newline at end of file diff --git a/newbinding/test2.py b/newbinding/test2.py index b866f59..ac74594 100644 --- a/newbinding/test2.py +++ b/newbinding/test2.py @@ -40,3 +40,7 @@ fn = m.getOrInsertFunction("foo", fnty) os = api.make_raw_ostream_for_printing() fn.print_(os, None) print os.str() +assert fn.hasName() +assert 'foo' == fn.getName() +fn.setName('bar') +assert 'bar' == fn.getName() From eba88b32ba5fb5597e664f8662fd6dcce00f2dc9 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 25 Jan 2013 12:29:31 -0600 Subject: [PATCH 222/516] Major refactoring --- newbinding/Makefile | 9 +- newbinding/binding.py | 924 +++++++----------- newbinding/codegen.py | 279 ++++++ newbinding/extra.py | 20 + newbinding/gen.py | 305 ++---- .../include/llvm_binding/auto_pyobject.h | 38 + newbinding/include/llvm_binding/conversion.h | 5 + newbinding/src/AssemblyAnnotationWriter.py | 5 +- newbinding/src/Constant.py | 4 +- newbinding/src/DerivedTypes.py | 22 +- newbinding/src/LLVMContext.py | 8 +- newbinding/src/Module.py | 60 +- newbinding/src/SmallVector.py | 5 +- newbinding/src/StringRef.py | 5 +- newbinding/src/Type.py | 169 ++-- newbinding/src/User.py | 5 +- newbinding/src/Value.py | 25 +- newbinding/src/__init__.py | 2 + newbinding/src/namespace.py | 1 - newbinding/src/raw_ostream.py | 17 +- newbinding/test2.py | 9 +- newbinding/utils.py | 6 - 22 files changed, 999 insertions(+), 924 deletions(-) create mode 100644 newbinding/codegen.py create mode 100644 newbinding/extra.py create mode 100644 newbinding/include/llvm_binding/auto_pyobject.h delete mode 100644 newbinding/utils.py diff --git a/newbinding/Makefile b/newbinding/Makefile index 61227e5..735d4ff 100644 --- a/newbinding/Makefile +++ b/newbinding/Makefile @@ -1,17 +1,12 @@ PYTHON = python -PYMODS = raw_ostream SmallVector Type DerivedTypes StringRef - -PYMODS += LLVMContext AssemblyAnnotationWriter Module -PYMODS += Value User Constant - all: _api.so _capsule.so _api.so _capsule.so: api.cpp capsule.cpp $(PYTHON) setup.py build_ext --inplace -api.cpp api.py: src/*.py include/llvm_binding/*.h - $(PYTHON) gen.py api src $(PYMODS) +api.cpp api.py: src/*.py include/llvm_binding/*.h gen.py binding.py + $(PYTHON) gen.py api src clean: cleantemp rm -f _api.so _capsule.so diff --git a/newbinding/binding.py b/newbinding/binding.py index c9de593..fc26d92 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -1,108 +1,352 @@ -import logging -import re -from utils import * +import functools +import codegen as cg -logger = logging.getLogger(__name__) +_rank = 0 +namespaces = {} -_py2capi_fmtmap = { - str: 's#', -} +class Namespace(object): + def __init__(self, name): + self.name = name + self.classes = [] + self.functions = [] + namespaces[name] = self -NULL = 'NULL' + def Class(self, *bases): + cls = Class(self, *bases) + self.classes.append(cls) + return cls -_symbols = set() + def Function(self, *args): + fn = Function(self, *args) + self.functions.append(fn) + return fn -def new_symbol(name): - if name in _symbols: - ct = 1 - orig = name - while name in _symbols: - name = '%s%d' % (orig, ct) - ct += 1 - _symbols.add(name) - return name + @property + def fullname(self): + return self.name -def parse_arguments(println, var, *args): - typecodes = [] - holders = [] - argvals = [] - for arg in args: - typecodes.append(arg.format) - val = declare(println, 'PyObject*') - argvals.append(val) - holders.append('&' + val) + def __str__(self): + return self.name - items = [var, '"%s"' % (''.join(typecodes))] + holders - println('if(!PyArg_ParseTuple(%s)) return NULL;' % ', '.join(items)) +class Type(object): + pass - # unwrap - unwrapped = [] - for arg, val in zip(args, argvals): - unwrapped.append(arg.unwrap(println, val)) +class BuiltinTypes(Type): + def __init__(self, name): + self.name = name - return unwrapped + @property + def fullname(self): + return self.name -_re_mangle_pattern = re.compile(r'[ _<>\*&]') + def wrap(self, writer, var): + return var -def mangle(name): - def repl(m): - s = m.group(0) - if s in '<>*&': - return '' - elif s in ' ': - return '_' - elif s in '_': - return '__' +Void = BuiltinTypes('void') +Unsigned = BuiltinTypes('unsigned') +Bool = BuiltinTypes('bool') +ConstStdString = BuiltinTypes('const std::string') + +class Class(Type): + format = 'O' + + def __init__(self, ns, *bases): + self.ns = ns + self.bases = bases + self._is_defined = False + self.methods = [] + self.enums = [] + self.includes = set() + + def __call__(self, defn): + assert not self._is_defined + self.name = defn.__name__ + for k, v in defn.__dict__.items(): + if isinstance(v, Method): + self.methods.append(v) + if isinstance(v, Constructor): + for sig in v.signatures: + sig[0] = ptr(self) + v.name = k + v.parent = self + elif isinstance(v, Enum): + self.enums.append(v) + v.name = k + v.parent = self + elif k == '_include_': + if isinstance(v, str): + self.includes.add(v) + else: + for i in v: + self.includes.add(i) + return self + + def compile_cpp(self, writer): + # generate methods + for meth in self.methods: + meth.compile_cpp(writer) + + # generate method table + writer.println('static') + writer.println('PyMethodDef %s[] = {' % cg.mangle(self.fullname)) + with writer.indent(): + fmt = '{ "%(name)s", (PyCFunction)%(func)s, METH_VARARGS, NULL },' + for meth in self.methods: + name = meth.name + func = cg.mangle(meth.fullname) + writer.println(fmt % locals()) + writer.println('{ NULL },') + writer.println('};') + writer.println() + + def compile_py(self, writer): + clsname = self.name + bases = 'capsule.Wrapper' + if self.bases: + bases = ', '.join(x.name for x in self.bases) + writer.println('@capsule.register_class') + with writer.block('class %(clsname)s(%(bases)s):' % locals()): + for enum in self.enums: + enum.compile_py(writer) + for meth in self.methods: + meth.compile_py(writer) + if not self.enums and not self.methods: + writer.println('pass') + writer.println() + + @property + def capsule_name(self): + if self.bases: + return self.bases[-1].capsule_name else: - assert False - name = _re_mangle_pattern.sub(repl, name) - return name.replace('::', '_') + return self.fullname -def pycapsule_new(println, ptr, name, clsname): - # build capsule - name_soften = mangle(name) - var = new_symbol('pycap_%s' % name_soften) - fmt = 'PyObject* %(var)s = pycapsule_new(%(ptr)s, "%(name)s", "%(clsname)s");' - println(fmt % locals()) - println('if (!%(var)s) return NULL;' % locals()) - return var + @property + def fullname(self): + try: + name = self.realname + except AttributeError: + name = self.name + return '::'.join([self.ns.fullname, name]) + + def __str__(self): + return self.fullname + + def unwrap(self, writer, val): + fmt = 'PyCapsule_GetPointer(%(val)s, "%(name)s")' + name = self.capsule_name + raw = writer.declare('void*', fmt % locals()) + writer.die_if_false(raw) + ptrty = ptr(self).fullname + ty = self.fullname + fmt = 'typecast<%(ty)s>::from(%(raw)s)' + casted = writer.declare(ptrty, fmt % locals()) + writer.die_if_false(casted) + return casted -def declare(println, typ, init=None): - typ_soften = mangle(typ) - var = new_symbol('var_%s' % typ_soften) - if init is None: - println('%(typ)s %(var)s;' % locals()) - else: - println('%(typ)s %(var)s = %(init)s;' % locals()) - return var +class Enum(object): + def __init__(self, *value_names): + self.parent = None + self.value_names = value_names + + @property + def fullname(self): + try: + name = self.realname + except AttributeError: + name = self.name + return '::'.join([self.parent.fullname, name]) + + def __str__(self): + return self.fullname + + def wrap(self, writer, val): + ret = writer.declare('PyObject*', 'NULL') + with writer.block('switch(%s) ' % val): + for v in self.value_names: + writer.println('case %s::%s:' % (self.parent, v)) + with writer.indent(): + fmt = '%(ret)s = PyString_FromString("%(v)s");' + writer.println(fmt % locals()) + writer.println('break;') + else: + writer.println('default:') + with writer.indent(): + writer.raises(ValueError, 'Invalid enum %s' % v) + return ret + + def compile_py(self, writer): + with writer.block('class %s:' % self.name): + for v in self.value_names: + writer.println('%(v)s = "%(v)s"' % locals()) + writer.println() + +class Method(object): + _kind_ = 'meth' + + def __init__(self, return_type=Void, *args): + self.parent = None + self.signatures = [] + self.includes = set() + self._add_signature(return_type, *args) + + def _add_signature(self, return_type, *args): + prev_lens = set(map(len, self.signatures)) + cur_len = len(args) + 1 + if cur_len in prev_lens: + raise Exception('Only support overloading with different number' + ' of arguments') + self.signatures.append([return_type] + list(args)) + + def __ior__(self, method): + assert type(self) is type(method) + for sig in method.signatures: + self._add_signature(sig[0], *sig[1:]) + return self + + @property + def fullname(self): + return '::'.join([self.parent.fullname, self.realname]) + + @property + def realname(self): + try: + return self.__realname + except AttributeError: + return self.name + + @realname.setter + def realname(self, v): + self.__realname = v + + def __str__(self): + return self.fullname + + def compile_cpp(self, writer): + with writer.py_function(self.fullname): + if len(self.signatures) == 1: + sig = self.signatures[0] + retty = sig[0] + argtys = sig[1:] + self.compile_cpp_body(writer, retty, argtys) + else: + nargs = writer.declare('Py_ssize_t', 'PyTuple_Size(args)') + for sig in self.signatures: + retty = sig[0] + argtys = sig[1:] + expect = len(argtys) + if (not isinstance(self, StaticMethod) and + isinstance(self.parent, Class)): + # Is a instance method, add 1 for "this". + expect += 1 + with writer.block('if (%(expect)d == %(nargs)s)' % locals()): + self.compile_cpp_body(writer, retty, argtys) + writer.raises(TypeError, 'Invalid number of args') + + def compile_cpp_body(self, writer, retty, argtys): + if isinstance(self.parent, Class): + args = writer.parse_arguments('args', ptr(self.parent), *argtys) + ret = writer.method_call(self.realname, retty.fullname, *args) + else: + args = writer.parse_arguments('args', *argtys) + ret = writer.call(self.fullname, retty.fullname, *args) + writer.return_value(retty.wrap(writer, ret)) + + def compile_py(self, writer): + decl = writer.function(self.name, args=('self',), varargs='args') + with decl as (this, varargs): + unwrap_this = writer.unwrap(this) + unwrapped = writer.unwrap_many(varargs) + func = '.'.join([self.parent.name, self.name]) + ret = writer.call('_api.%s' % func, + args=(unwrap_this,), varargs=unwrapped) + wrapped = writer.wrap(ret) + writer.return_value(wrapped) + writer.println() -def return_value(println, var): - println('return %(var)s;' % locals()) +class StaticMethod(Method): + + def compile_cpp_body(self, writer, retty, argtys): + assert isinstance(self.parent, Class) + args = writer.parse_arguments('args', *argtys) + ret = self.compile_cpp_call(writer, retty, args) + writer.return_value(retty.wrap(writer, ret)) + + def compile_cpp_call(self, writer, retty, args): + ret = writer.call(self.fullname, retty.fullname, *args) + return ret + + def compile_py(self, writer): + writer.println('@staticmethod') + decl = writer.function(self.name, varargs='args') + with decl as varargs: + unwrapped = writer.unwrap_many(varargs) + func = '.'.join([self.parent.name, self.name]) + ret = writer.call('_api.%s' % func, varargs=unwrapped) + wrapped = writer.wrap(ret) + writer.return_value(wrapped) + writer.println() -def return_none(println): - println('Py_RETURN_NONE;') +class Function(Method): + _kind_ = 'func' + + def __init__(self, parent, name, return_type=Void, *args): + super(Function, self).__init__(return_type, *args) + self.parent = parent + self.name = name + + def compile_py(self, writer): + with writer.function(self.name, varargs='args') as varargs: + unwrapped = writer.unwrap_many(varargs) + func = self.fullname.split('::', 1)[1].replace('::', '.') + ret = writer.call('_api.%s' % func, + varargs=unwrapped) + wrapped = writer.wrap(ret) + writer.return_value(wrapped) + writer.println() -def die_if_null(println, var): - println('if (!%(var)s) return NULL;' % locals()) +class Destructor(Method): + _kind_ = 'dtor' - -class Binding(object): - __rank_global = 0 def __init__(self): - self.rank = Binding.__rank_global - Binding.__rank_global += 1 - self.include = set() + super(Destructor, self).__init__() - def compile(self, name, println): - raise NotImplementedError(type(self)) + def compile_cpp_body(self, writer, retty, argtys): + assert isinstance(self.parent, Class) + assert not argtys + args = writer.parse_arguments('args', ptr(self.parent), *argtys) + writer.println('delete %s;' % args[0]) + writer.return_value(None) -class Ref(object): - def __init__(self, elem): - self.element = elem + def compile_py(self, writer): + func = '.'.join([self.parent.name, self.name]) + writer.println('_delete_ = _api.%s' % func) + + +class Constructor(StaticMethod): + _kind_ = 'ctor' + + def __init__(self, *args): + super(Constructor, self).__init__(Void, *args) + + def compile_cpp_call(self, writer, retty, args): + alloctype = retty.fullname.rstrip(' *') + arglist = ', '.join(args) + stmt = 'new %(alloctype)s(%(arglist)s)' % locals() + ret = writer.declare(retty.fullname, stmt) + return ret + +class ref(Type): + def __init__(self, element): + assert isinstance(element, Class), type(element) + self.element = element + + def __str__(self): + return self.fullname @property def fullname(self): @@ -112,503 +356,79 @@ class Ref(object): def capsule_name(self): return self.element.capsule_name - @property - def pointer(self): - return self.element.pointer - - def as_pointer(self, println, var): - init = '&%s' % (var) - casted = declare(println, self.pointer, init) - return casted - @property def format(self): - return 'O' + return self.element.format - def unwrap(self, println, var): - ptr = self.element.unwrap(println, var) - return declare(println, self.fullname, '*%s' % ptr) + def wrap(self, writer, val): + p = writer.declare(ptr(self.element).fullname, '&%s' % val) + return writer.pycapsule_new(p, self.capsule_name, self.element.fullname) - def wrap(self, println, var): - return self.element.wrap(println, self.as_pointer(println, var)) + def unwrap(self, writer, val): + p = self.element.unwrap(writer, val) + return writer.declare(self.fullname, '*%s' % p) -class Pointer(object): - def __init__(self, elem): - self.element = elem +class ptr(Type): + def __init__(self, element): + assert isinstance(element, Class) + self.element = element @property def fullname(self): - return '%s*' % self.element.fullname - - @property - def capsule_name(self): - return self.element.capsule_name - - @property - def pointer(self): - return self.element.pointer + return '%s*' % self.element @property def format(self): - return 'O' + return self.element.format - def unwrap(self, println, var): - ret = declare(println, self.fullname) - println2 = indent_println(println) - println('if (%(var)s == Py_None) {' % locals()) - println2('%(ret)s = NULL;' % locals()) - println('} else {') - ptr = self.element.unwrap(println2, var) - println2('%(ret)s = %(ptr)s;' % locals()) - println('}') + def unwrap(self, writer, val): + ret = writer.declare(self.fullname, 'NULL') + with writer.block('if (%(val)s != Py_None)' % locals()): + val = self.element.unwrap(writer, val) + writer.println('%(ret)s = %(val)s;' % locals()) return ret - def wrap(self, println, var): - return self.element.wrap(println, var) + def wrap(self, writer, val): + return writer.pycapsule_new(val, self.element.capsule_name, + self.element.fullname) - -class BuiltinType(object): - def __init__(self, name): - self.name = name - self.Ref = Ref(self) - self.Pointer = Pointer(self) - - @property - def fullname(self): - return self.name - - @property - def capsule_name(self): - return self.fullname - - def To(self, pytype): - return Wrapper(self, pytype) - - def From(self, pytype): - return Unwrapper(self, pytype) - -Void = BuiltinType('void') -Bool = BuiltinType('bool') -Unsigned = BuiltinType('unsigned') -ConstStdString = BuiltinType('const std::string') - -class PyObjectImpl(object): - name = 'PyObject*' - fullname = name +class cast(Type): format = 'O' - def unwrap(self, println, var): - return var - -PyObject = PyObjectImpl() - -class Unwrapper(object): - def __init__(self, cls, pytype): - self.cls = cls - self.pytype = pytype + def __init__(self, original, target): + self.original = original + self.target = target @property def fullname(self): - return str(self.pytype) + return self.binding_type.fullname @property - def format(self): - return 'O' - - def unwrap(self, println, var): - out = declare(println, self.cls.fullname) - conv = 'py_%s_to' % (self.pytype.__name__) - status = '%(conv)s(%(var)s, %(out)s)' % locals() - println('if (!%(status)s) return NULL;' % locals()) - return out - - -class Wrapper(object): - def __init__(self, cls, pytype): - self.cls = cls - self.pytype = pytype - - @property - def fullname(self): - return self.cls.fullname - - def wrap(self, println, var): - conv = 'py_%s_from' % (self.pytype.__name__) - func = '%(conv)s(%(var)s)' % locals() - out = declare(println, 'PyObject*', func) - println('if (!%(out)s) return NULL;' % locals()) - return out - -class Enum(Binding): - def __init__(self, ns, *values): - super(Enum, self).__init__() - self.values = values - self.ns = ns - self.name = None - - def compile(self, name, println): - self.name = self.name or name - - @property - def fullname(self): - return '::'.join([self.ns, self.name]) - -class ClassEnum(Enum): - def __init__(self, cls, *values): - super(ClassEnum, self).__init__(None, *values) - self.cls = cls - self.cls.enums.append(self) - - def compile(self, name, println): - self.ns = self.cls.fullname - super(ClassEnum, self).compile(name, println) - - def wrap(self, println, var): - println2 = indent_println(println) - ret = declare(println, 'PyObject*', NULL) - println('switch(%s) { ' % var) - for v in self.values: - println('case %s::%s:' % (self.ns, v)) - println2('%(ret)s = PyString_FromString("%(v)s");' % locals()) - println2('break;') + def python_type(self): + if not isinstance(self.target, Type): + return self.target else: - println('default:') - println2('PyErr_SetString(PyExc_TypeError, "Invalid enum: %s");' % - v) - println2('return NULL;') - println('}') + return self.original + + @property + def binding_type(self): + if isinstance(self.target, Type): + return self.target + else: + return self.original + + def wrap(self, writer, val): + dst = self.python_type.__name__ + return writer.call('py_%(dst)s_from' % locals(), 'PyObject*', val) + + def unwrap(self, writer, val): + src = self.python_type.__name__ + dst = self.binding_type.fullname + ret = writer.declare(dst) + status = writer.call('py_%(src)s_to' % locals(), 'int', val, ret) + writer.die_if_false(status) return ret - def unwrap(self, println, var): - pass -class Class(Binding): - def __init__(self, ns): - super(Class, self).__init__() - self.ctor = None - self.Ref = Ref(self) - self.Pointer = Pointer(self) - self.Subclass = lambda: Subclass(self) - self.Enum = lambda *v: ClassEnum(self, *v) - self.enums = [] - self.ns = ns - self.methods = [] - self.name = None - - def To(self, pytype): - return Wrapper(self, pytype) - - def From(self, pytype): - return Unwrapper(self, pytype) - - def new(self, *args): - method = Constructor(self, self.Pointer, *args) - self.methods.append(method) - return method - - def delete(self): - method = Destructor(self, Void, self.Pointer) - self.methods.append(method) - return method - - def method(self, return_type, *args): - method = Method(self, return_type, self.Pointer, *args) - self.methods.append(method) - return method - - def staticmethod(self, return_type, *args): - sm = StaticMethod(self, return_type, *args) - self.methods.append(sm) - return sm - - def multimethod(self, *signatures): - mm = MultiMethod(self, signatures) - self.methods.append(mm) - return mm - - def staticmultimethod(self, *signatures): - smm = StaticMultiMethod(self, signatures) - self.methods.append(smm) - return smm - - def compile(self, name, println): - # set name - self.name = self.name or name - - @property - def capsule_name(self): - return self.fullname - - @property - def pointer(self): - return '%s*' % self.fullname - - @property - def fullname(self): - return '::'.join([self.ns, self.name]) - - @property - def mangled_name(self): - return mangle(self.fullname) - - @property - def format(self): - return 'O' - - def unwrap(self, println, var): - typ = self.pointer - elty = self.fullname - cap = self.capsule_name - capptr = 'PyCapsule_GetPointer(%(var)s, "%(cap)s")' % locals() - ptr = declare(println, 'void*', capptr) - unwrapped = 'typecast<%(elty)s>::from(%(ptr)s)' % locals() - var = declare(println, typ, unwrapped) - println('if (!%(var)s) {' % locals()) - println2 = indent_println(println) - println2('PyErr_SetString(PyExc_TypeError, "Invalid cast");') - println2('return NULL;') - println('}') - die_if_null(println, var) - return var - - def wrap(self, println, var): - return pycapsule_new(println, var, self.capsule_name, self.fullname) - -class Subclass(Class): - def __init__(self, parent): - super(Subclass, self).__init__(parent.ns) - self.parent = parent - self.ns = self.parent.ns - - @property - def capsule_name(self): - return self.parent.capsule_name - -class Function(Binding): - def __init__(self, ns, return_type, *args): - super(Function, self).__init__() - self.return_type = return_type - self.args = args - self.ns = ns - self.name = None - - def compile(self, name, println): - # set name - self.name = self.name or name - # generate wrapper - println('static') - println('PyObject*') - println('%(name)s(PyObject* self, PyObject* args)' % locals()) - println('{') - self.compile_body(indent_println(println)) - println('}') - - def compile_body(self, println): - args = parse_arguments(println, 'args', *self.args) - call = '%s(%s)' % (self.fullname, ', '.join(args)) - if self.return_type is not Void: - callres = declare(println, self.return_type.fullname, call) - pycap = self.return_type.wrap(println, callres) - return_value(println, pycap) - else: - println('%s;' % call) - return_none(println) - - - @property - def fullname(self): - return '::'.join([self.ns, self.name]) - -class Method(Binding): - def __init__(self, cls, return_type, *args): - super(Method, self).__init__() - self.cls = cls - self.return_type = return_type - self.args = args - self.name = None - self._realname = None - - def compile(self, name, println): - # set name - self.name = self.name or name - # generate wrapper - println('static') - println('PyObject*') - mangled = self.mangled_name - println('%(mangled)s(PyObject* self, PyObject* args)' % locals()) - println('{') - self.compile_body(indent_println(println)) - println('}') - - def compile_body(self, println): - args = parse_arguments(println, 'args', *self.args) - this = args[0] - args = ', '.join(args[1:]) - name = self.realname - call = '%(this)s->%(name)s(%(args)s)' % locals() - if self.return_type is not Void: - obj = declare(println, self.return_type.fullname, call) - ret = self.return_type.wrap(println, obj) - return_value(println, ret) - else: - println('%s;' % call) - return_none(println) - - @property - def fullname(self): - return '::'.join([self.cls.fullname, self.name]) - - @property - def realname(self): - if not self._realname: - return self.name - else: - return self._realname - - @realname.setter - def realname(self, v): - self._realname = v - - - @property - def mangled_name(self): - return mangle(self.fullname) - -class MultiMethod(Binding): - '''Can only differs by the number of arguments. - ''' - def __init__(self, cls, signatures): - super(MultiMethod, self).__init__() - nargs = set() - for sig in signatures: - n = len(sig) - if n in nargs: - raise TypeError("MultiMethod only supports overloaded version" - "with different number of arguments") - nargs.add(n) - self.cls = cls - self.signatures = signatures - self.name = None - - def compile(self, name, println): - # set name - self.name = self.name or name - # generate wrapper - println('static') - println('PyObject*') - mangled = self.mangled_name - println('%(mangled)s(PyObject* self, PyObject* args)' % locals()) - println('{') - println2 = indent_println(println) - nargs = declare(println2, 'Py_ssize_t', 'PyTuple_Size(args)') - for sig in self.signatures: - expect = len(sig) - println2('if (%(nargs)s == %(expect)d) {' % locals()) - method = Method(self.cls, sig[0], self.cls.Pointer, *sig[1:]) - method.name = self.name - method.compile_body(indent_println(println2)) - println2('}') - println2('PyErr_SetString(PyExc_TypeError, "Wrong # of args");') - println2('return NULL;') - println('}') - - @property - def fullname(self): - return '::'.join([self.cls.fullname, self.name]) - - @property - def mangled_name(self): - return mangle(self.fullname) - -class StaticMethod(Method): - def compile_body(self, println): - args = parse_arguments(println, 'args', *self.args) - args = ', '.join(args) - fullname = self.fullname - call = '%(fullname)s(%(args)s)' % locals() - if self.return_type is not Void: - obj = declare(println, self.return_type.fullname, call) - ret = self.return_type.wrap(println, obj) - return_value(println, ret) - else: - println('%s;' % call) - return_none(println) - -class StaticMultiMethod(Binding): - '''Can only differs by the number of arguments. - ''' - def __init__(self, cls, signatures): - super(StaticMultiMethod, self).__init__() - nargs = set() - for sig in signatures: - n = len(sig) - if n in nargs: - raise TypeError("StaticMultiMethod only supports overloaded " - "version with different number of arguments") - nargs.add(n) - self.cls = cls - self.signatures = signatures - self.name = None - - - def compile(self, name, println): - # set name - self.name = self.name or name - # generate wrapper - println('static') - println('PyObject*') - mangled = self.mangled_name - println('%(mangled)s(PyObject* self, PyObject* args)' % locals()) - println('{') - println2 = indent_println(println) - nargs = declare(println2, 'Py_ssize_t', 'PyTuple_Size(args)') - for sig in self.signatures: - expect = len(sig) - 1 - println2('if (%(nargs)s == %(expect)d) {' % locals()) - method = StaticMethod(self.cls, sig[0], *sig[1:]) - method.name = self.name - method.compile_body(indent_println(println2)) - println2('}') - println2('PyErr_SetString(PyExc_TypeError, "Wrong # of args");') - println2('return NULL;') - println('}') - - @property - def fullname(self): - return '::'.join([self.cls.fullname, self.name]) - - @property - def mangled_name(self): - return mangle(self.fullname) - -class Constructor(StaticMethod): - def compile_body(self, println): - args = parse_arguments(println, 'args', *self.args) - args = ', '.join(args) - name = self.cls.fullname - ctor = 'new %(name)s(%(args)s)' % locals() - obj = declare(println, self.cls.pointer, ctor) - ret = self.return_type.wrap(println, obj) - return_value(println, ret) - -class Destructor(Method): - def compile_body(self, println): - args = parse_arguments(println, 'args', *self.args) - assert len(args) == 1 - dtor = 'delete %s;' % args[0] - println(dtor) - return_none(println) - - -class Namespace(object): - def __init__(self, name): - self.name = name - - def Class(self, *args, **kwargs): - return Class(self.name, *args, **kwargs) - - def Function(self, *args, **kwargs): - return Function(self.name, *args, **kwargs) - diff --git a/newbinding/codegen.py b/newbinding/codegen.py new file mode 100644 index 0000000..9398b14 --- /dev/null +++ b/newbinding/codegen.py @@ -0,0 +1,279 @@ +import re, contextlib + +NULL = 'NULL' + +_symbols = set() + +def indent(println): + def _println(s=''): + println("%s%s" % (' '* 4, s)) + return _println + +def quote(txt): + return '"%s"' % txt + +def new_symbol(name): + if name in _symbols: + ct = 1 + orig = name + while name in _symbols: + name = '%s%d' % (orig, ct) + ct += 1 + _symbols.add(name) + return name + +def parse_arguments(println, var, *args): + typecodes = [] + holders = [] + argvals = [] + for arg in args: + typecodes.append(arg.format) + val = declare(println, 'PyObject*') + argvals.append(val) + holders.append('&' + val) + + items = [var, '"%s"' % (''.join(typecodes))] + holders + println('if(!PyArg_ParseTuple(%s)) return NULL;' % ', '.join(items)) + + # unwrap + unwrapped = [] + for arg, val in zip(args, argvals): + unwrapped.append(arg.unwrap(println, val)) + + return unwrapped + +_re_mangle_pattern = re.compile(r'[ _<>\*&]') + +def mangle(name): + def repl(m): + s = m.group(0) + if s in '<>*&': + return '' + elif s in ' ': + return '_' + elif s in '_': + return '__' + else: + assert False + name = _re_mangle_pattern.sub(repl, name) + return name.replace('::', '_') + +def pycapsule_new(println, ptr, name, clsname): + # build capsule + name_soften = mangle(name) + var = new_symbol('pycap_%s' % name_soften) + fmt = 'PyObject* %(var)s = pycapsule_new(%(ptr)s, "%(name)s", "%(clsname)s");' + println(fmt % locals()) + println('if (!%(var)s) return NULL;' % locals()) + return var + + +def declare(println, typ, init=None): + typ_soften = mangle(typ) + var = new_symbol('var_%s' % typ_soften) + if init is None: + println('%(typ)s %(var)s;' % locals()) + else: + println('%(typ)s %(var)s = %(init)s;' % locals()) + return var + + +def return_value(println, var): + println('return %(var)s;' % locals()) + + +def return_none(println): + println('Py_RETURN_NONE;') + + +def die_if_null(println, var): + println('if (!%(var)s) return NULL;' % locals()) + + +class CodeWriterBase(object): + def __init__(self, println): + self.println = println + self.used_symbols = set() + + @contextlib.contextmanager + def indent(self): + old = self.println + self.println = indent(self.println) + yield + self.println = old + + @contextlib.contextmanager + def py_function(self, name): + mangled = mangle(name) + self.println('static') + self.println('PyObject*') + with self.block('%(mangled)s(PyObject* self, PyObject* args)' % locals()): + self.used_symbols.add('self') + self.used_symbols.add('args') + yield + self.println() + + def new_symbol(self, name): + if name in self.used_symbols: + ct = 1 + orig = name + while name in self.used_symbols: + name = '%s%d' % (orig, ct) + ct += 1 + self.used_symbols.add(name) + return name + +class CppCodeWriter(CodeWriterBase): + @contextlib.contextmanager + def block(self, lead): + self.println(lead) + self.println('{') + with self.indent(): + yield + self.println('}') + + def declare(self, typ, init=None): + typ_soften = mangle(typ) + var = self.new_symbol('var_%s' % typ_soften) + if init is None: + self.println('%(typ)s %(var)s;' % locals()) + else: + self.println('%(typ)s %(var)s = %(init)s;' % locals()) + return var + + def return_value(self, val): + if val is None: + self.println('Py_RETURN_NONE;') + else: + self.println('return %s;' % val) + + def return_null(self): + self.return_value(NULL) + + def parse_arguments(self, var, *args): + typecodes = [] + holders = [] + argvals = [] + for arg in args: + typecodes.append(arg.format) + val = self.declare('PyObject*') + argvals.append(val) + holders.append('&' + val) + + items = [var, '"%s"' % (''.join(typecodes))] + holders + with self.block('if(!PyArg_ParseTuple(%s))' % ', '.join(items)): + self.return_null() + + # unwrap + unwrapped = [] + for arg, val in zip(args, argvals): + unwrapped.append(arg.unwrap(self, val)) + + return unwrapped + + def call(self, func, retty, *args): + arglist = ', '.join(args) + stmt = '%(func)s(%(arglist)s)' % locals() + if retty == 'void': + self.println(stmt) + else: + return self.declare(retty, stmt) + + def method_call(self, func, retty, *args): + this = args[0] + arglist = ', '.join(args[1:]) + if func == 'delete': + assert not arglist + stmt = 'delete %(this)s;' % locals() + elif func == 'new': + alloctype = retty.rstrip(' *') + stmt = 'new %(alloctype)s(%(arglist)s);' % locals() + else: + stmt = '%(this)s->%(func)s(%(arglist)s);' % locals() + if retty == 'void': + self.println(stmt) + else: + return self.declare(retty, stmt) + + def pycapsule_new(self, ptr, name, clsname): + name_soften = mangle(name) + ret = self.call('pycapsule_new', 'PyObject*', ptr, quote(name), + quote(clsname)) + with self.block('if (!%(ret)s)' % locals()): + self.return_null() + return ret + + def die_if_false(self, val): + with self.block('if(!%(val)s)' % locals()): + self.return_null() + + def raises(self, exccls, msg): + exc = 'PyExc_%s' % exccls.__name__ + self.println('PyErr_SetString(%s, "%s");' % (exc, msg)) + self.return_null() + + +class PyCodeWriter(CodeWriterBase): + @contextlib.contextmanager + def block(self, lead): + self.println(lead) + with self.indent(): + yield + + @contextlib.contextmanager + def function(self, func, args=(), varargs=None): + with self.scope(): + arguments = [] + for arg in args: + arguments.append(self.new_symbol(arg)) + if varargs: + varargs = self.new_symbol(varargs) + arguments.append('*%s' % varargs) + arglist = ', '.join(arguments) + with self.block('def %(func)s(%(arglist)s):' % locals()): + if arguments: + arguments[-1] = arguments[-1].lstrip('*') + if len(arguments) > 1: + yield arguments + else: + yield arguments[0] + else: + yield + + @contextlib.contextmanager + def scope(self): + self.old = self.used_symbols + self.used_symbols = set() + yield + self.used_symbols = self.old + + def unwrap_many(self, args): + unwrapped = self.new_symbol('unwrapped') + self.println('%(unwrapped)s = map(capsule.unwrap, %(args)s)' % locals()) + return unwrapped + + def unwrap(self, val): + return self.call('capsule.unwrap', args=(val,), ret='unwrapped') + + def wrap(self, val): + wrapped = self.new_symbol('wrapped') + self.println('%(wrapped)s = capsule.wrap(%(val)s)' % locals()) + return wrapped + + def call(self, func, args=(), varargs=None, ret='ret'): + arguments = [] + for arg in args: + arguments.append(arg) + if varargs: + arguments.append('*%s' % varargs) + arglist = ', '.join(arguments) + ret = self.new_symbol(ret) + self.println('%(ret)s = %(func)s(%(arglist)s)' % locals()) + return ret + + def return_value(self, val=None): + if val is None: + val = '' + self.println('return %s' % val) + + diff --git a/newbinding/extra.py b/newbinding/extra.py new file mode 100644 index 0000000..1af4e5f --- /dev/null +++ b/newbinding/extra.py @@ -0,0 +1,20 @@ +''' +Wrapped the extra functions in _api.so +''' + +import capsule + +def _wrapper(func): + def _core(*args): + unwrapped = map(capsule.unwrap, args) + ret = func(*unwrapped) + return capsule.wrap(ret) + return _core + +def _init(glob): + from _api import extra + for k, v in extra.__dict__.items(): + glob[k] = _wrapper(v) + +_init(globals()) + diff --git a/newbinding/gen.py b/newbinding/gen.py index cee71f1..4d8709e 100644 --- a/newbinding/gen.py +++ b/newbinding/gen.py @@ -1,26 +1,23 @@ -import sys, logging +import sys from binding import * -from utils import * -from cStringIO import StringIO +import codegen -logging.basicConfig(level=logging.INFO) -logger = logging.getLogger(__name__) extension_entry = ''' - + extern "C" { #if (PY_MAJOR_VERSION >= 3) - + PyObject * PyInit_%(module)s(void) { - PyObject *module = create_python_module("%(module)s", %(methtable)s); - if (module) { - if (populate_submodules(module, submodules)) - return module; - } - return NULL; +PyObject *module = create_python_module("%(module)s", %(methtable)s); +if (module) { +if (populate_submodules(module, submodules)) +return module; +} +return NULL; } #else @@ -28,10 +25,10 @@ PyInit_%(module)s(void) PyMODINIT_FUNC init%(module)s(void) { - PyObject *module = create_python_module("%(module)s", %(methtable)s); - if (module) { - populate_submodules(module, submodules); - } +PyObject *module = create_python_module("%(module)s", %(methtable)s); +if (module) { +populate_submodules(module, submodules); +} } #endif @@ -39,172 +36,6 @@ init%(module)s(void) ''' -def build_methoddef(name, defns, println): - println('static PyMethodDef %s[] = {' % name) - for name, func in defns: - println('{ "%(name)s", (PyCFunction)%(func)s, METH_VARARGS, NULL },' % - locals()) - else: - println('{ NULL }') - println('};') - println('') - - -class Context(object): - def __init__(self): - self.includes = set() - self.functions = {} - self.classes = {} - self.definitions = [] - self._pending_symbols = [] - - def generate_cpp(self, println): - for i in self.includes: - println('#include "%s"' % i) - - println('\n'.join(self.definitions)) - - # global function - defns = [] - for name, func in self.functions.items(): - defns.append((name, func.name)) - build_methoddef('global_functions', defns, println) - - # classes - for name, cls in self.classes.items(): - defns = [] - for meth in cls.methods: - defns.append((meth.name, meth.mangled_name)) - println("// %s" % cls.fullname) - build_methoddef(cls.mangled_name, defns, println) - - println('static SubModuleEntry submodules[] = {') - for name, cls in self.classes.items(): - table = cls.mangled_name - println('{ "%(name)s", %(table)s },' % locals()) - println('{ "extra", extra_methodtable },') - println('{ NULL }') - println('};') - println('') - - # generate entry - println(extension_entry % {'module': '_api', - 'methtable': 'global_functions',}) - - def generate_py(self, println): - println('import _api, capsule') - println('') - # wraps all extras - extra_wrapper = ''' -def _init_extra_wrapper(): - def wrap(callee): - def _wrapped(*args): - args = map(capsule.unwrap, args) - ret = callee(*args) - return capsule.wrap(ret) - return _wrapped - for k in dir(_api.extra): - v = getattr(_api.extra, k) - if not k.startswith('__') and callable(v): - globals()[k] = wrap(v) -_init_extra_wrapper() - ''' - println(extra_wrapper) - println('') - # global function - for name in self.functions: - println('def %(name)s(*args):' % locals()) - println2 = indent_println(println) - println2('args = map(capsule.unwrap, args)') - println2('ptr = _api.%(name)s(*args)' % locals()) - println2('return capsule.wrap(ptr)') - println('') - # classes - classes = sorted(self.classes.items(), key=lambda x: x[1].rank) - - for name, cls in classes: - if isinstance(cls, Subclass): - parent = cls.parent.name - else: - parent = 'capsule.Wrapper' - println('@capsule.register_class') - println('class %(name)s(%(parent)s):' % locals()) - self.generate_py_class(indent_println(println), cls) - println('') - - def generate_py_class(self, println, cls): - if len(cls.methods) == 0: - println('pass') - else: - mod = cls.name - # generate class enums - for enum in cls.enums: - println('class %s:' % enum.name) - println2 = indent_println(println) - for v in enum.values: - println2('%(v)s = "%(v)s"' % locals()) - println('') - # generate class methods - for method in cls.methods: - name = method.name - if(isinstance(method, StaticMethod) or - isinstance(method, StaticMultiMethod)): - println('@staticmethod') - println('def %(name)s(*args):' % locals()) - println2 = indent_println(println) - println2('args = map(capsule.unwrap, args)') - println2('ret = _api.%(mod)s.%(name)s(*args)' % locals()) - println2('return capsule.wrap(ret)') - elif isinstance(method, Destructor): - println('_delete_ = _api.%(mod)s.%(name)s' % locals()) - else: - println('def %(name)s(self, *args):' % locals()) - println2 = indent_println(println) - println2('args = map(capsule.unwrap, args)') - println2('ret = _api.%(mod)s.%(name)s(self._ptr, *args)' % - locals()) - println2('return capsule.wrap(ret)') - println('') - - def add_module(self, module): - allsyms = [(k, v) for k, v in vars(module).items() - if isinstance(v, Binding)] - # generate includes - for k, v in allsyms: - self.includes |= v.include - - self._pending_symbols.extend(allsyms) - - def materialize(self): - symtab = sorted(self._pending_symbols, key=lambda x: x[1].rank) - - # compile everything - for k, v in symtab: - buf = StringIO() - def println_to_def(s): - buf.write(s) - buf.write('\n') - logger.info('compiling %s', k) - v.compile(k, println_to_def) - self.definitions.append(buf.getvalue()) - buf.close() - - # generate py defintion table for global functions - for k, v in symtab: - if isinstance(v, Function): - if v.name in self.functions: - raise NameError("Duplicated function name: %s" % v.name) - self.functions[v.name] = v - - # generate sub module tables for classes - submodules = [] - for k, v in symtab: - if isinstance(v, Class): - if v.name in self.classes: - if v is not self.classes[v.name]: - raise NameError("Duplicated class: %s" % v.name) - self.classes[v.name] = v - def populate_headers(println): includes = [ @@ -216,38 +47,96 @@ def populate_headers(println): ] for inc in includes: println('#include "%s"' % inc) + println() -def wrap_println(f): - def println(s): - f.write(s) - f.write('\n') + +def wrap_println_from_file(file): + def println(s=''): + file.write(s) + file.write('\n') return println -if __name__ == '__main__': +def main(): outputfilename = sys.argv[1] - srcdir = sys.argv[2] - modnames = sys.argv[3:] + entry_modname = sys.argv[2] - modules = [] - for m in modnames: - path = '%s.%s' % (srcdir, m) - logger.info("import module %s", path) - module = __import__(path) - for token in path.split('.')[1:]: - module = getattr(module, token) - modules.append(module) + entry_module = __import__(entry_modname) - context = Context() + units = [] + for ns in namespaces.values(): + print 'namespace', ns + for fn in ns.functions: + print fn + units.append(fn) + for cls in ns.classes: + print cls + units.append(cls) - for mod in modules: - context.add_module(mod) - context.materialize() + with open('%s.cpp' % outputfilename, 'w') as cppfile: + println = wrap_println_from_file(cppfile) - with open('%s.cpp' % outputfilename, 'w') as outfile: - println = wrap_println(outfile) + # extra headers populate_headers(println) - context.generate_cpp(println) - with open('%s.py' % outputfilename, 'w') as outfile: - println = wrap_println(outfile) - context.generate_py(println) + # required headers + includes = set() + for u in units: + includes |= u.includes + + for inc in includes: + println('#include "%s"' % inc) + println() + + # write methods and method tables + for u in units: + writer = codegen.CppCodeWriter(println) + u.compile_cpp(writer) + else: + del writer + + # write function table + writer = codegen.CppCodeWriter(println) + writer.println('static') + writer.println('PyMethodDef methtable[] = {') + with writer.indent(): + fmt = '{ "%(name)s", (PyCFunction)%(func)s, METH_VARARGS, NULL },' + for u in units: + if isinstance(u, Function): + name = u.name + func = codegen.mangle(u.fullname) + writer.println(fmt % locals()) + writer.println('{ NULL },') + writer.println('};') + writer.println() + del writer + + + # write submodule table + writer = codegen.CppCodeWriter(println) + writer.println('static') + writer.println('SubModuleEntry submodules[] = {') + with writer.indent(): + for cls in units: + if isinstance(cls, Class): + name = cls.name + table = codegen.mangle(cls.fullname) + writer.println('{ "%(name)s", %(table)s },' % locals()) + writer.println('{ "extra", extra_methodtable },') + writer.println('{ NULL }') + writer.println('};') + writer.println('') + del writer + + println(extension_entry % {'module': '_api', 'methtable': 'methtable'}) + + with open('%s.py' % outputfilename, 'w') as pyfile: + println = wrap_println_from_file(pyfile) + println('import _api, capsule') + println() + for u in units: + writer = codegen.PyCodeWriter(println) + u.compile_py(writer) + + +if __name__ == '__main__': + main() diff --git a/newbinding/include/llvm_binding/auto_pyobject.h b/newbinding/include/llvm_binding/auto_pyobject.h new file mode 100644 index 0000000..451f2d9 --- /dev/null +++ b/newbinding/include/llvm_binding/auto_pyobject.h @@ -0,0 +1,38 @@ +#ifndef AUTO_PYOBJECT_H_ +#define AUTO_PYOBJECT_H_ + +#include + +class auto_pyobject{ + mutable PyObject* PO; +public: + auto_pyobject(): PO(NULL) { } + + auto_pyobject(PyObject* po) : PO(po) { } + + auto_pyobject(const auto_pyobject& other) : PO(*other){ + other.PO = NULL; + } + + ~auto_pyobject() { + Py_XDECREF(PO); + } + + bool operator ! () const { + return !PO; + } + + PyObject* operator * () const { + return PO; + } + + PyObject* get() const { + return PO; + } +private: + // disable assign + void operator = (const auto_pyobject&); +}; + +#endif AUTO_PYOBJECT_H_ + diff --git a/newbinding/include/llvm_binding/conversion.h b/newbinding/include/llvm_binding/conversion.h index c3d6e36..0e30c60 100644 --- a/newbinding/include/llvm_binding/conversion.h +++ b/newbinding/include/llvm_binding/conversion.h @@ -62,6 +62,11 @@ static PyObject* py_str_from(const std::string &str){ return PyString_FromStringAndSize(str.c_str(), str.size()); } +// +//static +//PyObject* py_str_from(const llvm::StringRef *str){ +// return py_str_from(str->str()); +//} static PyObject* py_bool_from(bool val){ diff --git a/newbinding/src/AssemblyAnnotationWriter.py b/newbinding/src/AssemblyAnnotationWriter.py index 5641232..d2b5a5d 100644 --- a/newbinding/src/AssemblyAnnotationWriter.py +++ b/newbinding/src/AssemblyAnnotationWriter.py @@ -1,6 +1,7 @@ from binding import * from namespace import llvm -AssemblyAnnotationWriter = llvm.Class() -AssemblyAnnotationWriter.include.add("llvm/Assembly/AssemblyAnnotationWriter.h") +@llvm.Class() +class AssemblyAnnotationWriter: + _include_ = "llvm/Assembly/AssemblyAnnotationWriter.h" diff --git a/newbinding/src/Constant.py b/newbinding/src/Constant.py index 24045bb..14ff6bb 100644 --- a/newbinding/src/Constant.py +++ b/newbinding/src/Constant.py @@ -2,4 +2,6 @@ from binding import * from namespace import llvm from User import User -Constant = User.Subclass() +@llvm.Class(User) +class Constant: + pass diff --git a/newbinding/src/DerivedTypes.py b/newbinding/src/DerivedTypes.py index d9dbb53..c57e01b 100644 --- a/newbinding/src/DerivedTypes.py +++ b/newbinding/src/DerivedTypes.py @@ -4,17 +4,15 @@ from LLVMContext import LLVMContext from Type import Type from SmallVector import SmallVector_Type -FunctionType = Type.Subclass() -FunctionType.include.add('llvm/DerivedTypes.h') +FunctionType = llvm.Class(Type) -_get_signatures = [(FunctionType.Pointer, - Type.Pointer, Bool.From(bool)), - (FunctionType.Pointer, - Type.Pointer, SmallVector_Type.Ref, Bool.From(bool))] +@FunctionType +class FunctionType: + _include_ = 'llvm/DerivedTypes.h' + get = StaticMethod(ptr(FunctionType), ptr(Type), cast(bool, Bool)) + get |= StaticMethod(ptr(FunctionType), ptr(Type), ref(SmallVector_Type), cast(bool, Bool)) + isVarArg = Method(cast(Bool, bool)) + getReturnType = Method(ptr(Type)) + getParamType = Method(ptr(Type), cast(int, Unsigned)) + getNumParams = Method(cast(Unsigned, int)) -get = FunctionType.staticmultimethod(*_get_signatures) - -isVarArg = FunctionType.method(Bool.To(bool)) -getReturnType = FunctionType.method(Type.Pointer) -getParamType = FunctionType.method(Type.Pointer, Unsigned.From(int)) -getNumParams = FunctionType.method(Unsigned.To(int)) diff --git a/newbinding/src/LLVMContext.py b/newbinding/src/LLVMContext.py index 0965748..f2526db 100644 --- a/newbinding/src/LLVMContext.py +++ b/newbinding/src/LLVMContext.py @@ -1,8 +1,8 @@ from binding import * from namespace import llvm -LLVMContext = llvm.Class() -LLVMContext.include.add("llvm/LLVMContext.h") - -getGlobalContext = llvm.Function(LLVMContext.Ref) +@llvm.Class() +class LLVMContext: + _include_ = "llvm/LLVMContext.h" +llvm.Function('getGlobalContext', ref(LLVMContext)) diff --git a/newbinding/src/Module.py b/newbinding/src/Module.py index 67ac8b0..6a6a806 100644 --- a/newbinding/src/Module.py +++ b/newbinding/src/Module.py @@ -7,39 +7,39 @@ from DerivedTypes import FunctionType from raw_ostream import raw_ostream from AssemblyAnnotationWriter import AssemblyAnnotationWriter -# class Module -Module = llvm.Class() -Module.include.add("llvm/Module.h") +@llvm.Class() +class Module: + _include_ = "llvm/Module.h" + # Enumerators + Endianness = Enum('AnyEndianness', 'LittleEndian', 'BigEndian') + PointerSize = Enum('AnyPointerSize', 'Pointer32', 'Pointer64') -# Enumerators -Endianness = Module.Enum('AnyEndianness', 'LittleEndian', 'BigEndian') -PointerSize = Module.Enum('AnyPointerSize', 'Pointer32', 'Pointer64') + # Constructors & Destructors + new = Constructor(cast(str, StringRef), ref(LLVMContext)) + delete = Destructor() -# Constructors & Destructors -new = Module.new(StringRef.From(str), LLVMContext.Ref) -delete = Module.delete() + # Module Level Accessor + getModuleIdentifier = Method(cast(ConstStdString, str)) + getDataLayout = Method(cast(ConstStdString, str)) + getTargetTriple = Method(cast(ConstStdString, str)) + getEndianness = Method(Endianness) + getPointerSize = Method(PointerSize) + getContext = Method(ref(LLVMContext)) + getModuleInlineAsm = Method(cast(ConstStdString, str)) -# Module Level Accessor -getModuleIdentifier = Module.method(ConstStdString.To(str)) -getDataLayout = Module.method(ConstStdString.To(str)) -getTargetTriple = Module.method(ConstStdString.To(str)) -getEndianness = Module.method(Endianness) -getPointerSize = Module.method(PointerSize) -getContext = Module.method(LLVMContext.Ref) -getModuleInlineAsm = Module.method(ConstStdString.To(str)) + # Module Level Mutators + setModuleIdentifier = Method(Void, cast(str, StringRef)) + setDataLayout = Method(Void, cast(str, StringRef)) + setTargetTriple = Method(Void, cast(str, StringRef)) + setModuleInlineAsm = Method(Void, cast(str, StringRef)) + appendModuleInlineAsm = Method(Void, cast(str, StringRef)) -# Module Level Mutators -setModuleIdentifier = Module.method(Void, StringRef.From(str)) -setDataLayout = Module.method(Void, StringRef.From(str)) -setTargetTriple = Module.method(Void, StringRef.From(str)) -setModuleInlineAsm = Module.method(Void, StringRef.From(str)) -appendModuleInlineAsm = Module.method(Void, StringRef.From(str)) + # Function Accessors + getOrInsertFunction = Method(ptr(Constant), cast(str, StringRef), ptr(FunctionType)) -# Function Accessors -getOrInsertFunction = Module.method(Constant.Pointer, StringRef.From(str), FunctionType.Pointer) + # Utilities + dump = Method(Void) + print_ = Method(Void, ref(raw_ostream), ptr(AssemblyAnnotationWriter)) + print_.realname = 'print' -# Utilities -dump = Module.method(Void) -print_ = Module.method(Void, raw_ostream.Ref, AssemblyAnnotationWriter.Pointer) -print_.realname = 'print' -dropAllReferences = Module.method(Void) + dropAllReferences = Method() diff --git a/newbinding/src/SmallVector.py b/newbinding/src/SmallVector.py index 225c720..d00b294 100644 --- a/newbinding/src/SmallVector.py +++ b/newbinding/src/SmallVector.py @@ -1,5 +1,6 @@ from binding import * from namespace import llvm -SmallVector_Type = llvm.Class() -delete = SmallVector_Type.delete() +@llvm.Class() +class SmallVector_Type: + delete = Destructor() diff --git a/newbinding/src/StringRef.py b/newbinding/src/StringRef.py index 554629b..fb3b896 100644 --- a/newbinding/src/StringRef.py +++ b/newbinding/src/StringRef.py @@ -1,6 +1,7 @@ from binding import * from namespace import llvm -StringRef = llvm.Class() -StringRef.include.add("llvm/ADT/StringRef.h") +@llvm.Class() +class StringRef: + _include_ = "llvm/ADT/StringRef.h" diff --git a/newbinding/src/Type.py b/newbinding/src/Type.py index 3703200..45f9444 100644 --- a/newbinding/src/Type.py +++ b/newbinding/src/Type.py @@ -4,93 +4,112 @@ from LLVMContext import LLVMContext from raw_ostream import raw_ostream Type = llvm.Class() -Type.include.add('llvm/Type.h') +IntegerType = llvm.Class(Type) +CompositeType = llvm.Class(Type) +SequentialType = llvm.Class(CompositeType) +PointerType = llvm.Class(SequentialType) -IntegerType = Type.Subclass() -CompositeType = Type.Subclass() -SequentialType = CompositeType.Subclass() -PointerType = SequentialType.Subclass() +@Type +class Type: + _include_ = 'llvm/Type.h' -getContext = Type.method(LLVMContext.Ref) -dump = Type.method(Void) -print_ = Type.method(Void, raw_ostream.Ref) -print_.realname = 'print' + getContext = Method(ref(LLVMContext)) + dump = Method() + print_ = Method(Void, ref(raw_ostream)) + print_.realname = 'print' -def type_checker(): - return Type.method(Bool.To(bool)) + def type_checker(): + return Method(cast(Bool, bool)) -isVoidTy = type_checker() -isHalfTy = type_checker() -isFloatTy = type_checker() -isDoubleTy = type_checker() -isX86_FP80Ty = type_checker() -isFP128Ty = type_checker() -isPPC_FP128Ty = type_checker() -isFloatingPointTy = type_checker() -isX86_MMXTy = type_checker() -isFPOrFPVectorTy = type_checker() -isLabelTy = type_checker() -isMetadataTy = type_checker() -isIntOrIntVectorTy = type_checker() -isFunctionTy = type_checker() -isStructTy = type_checker() -isArrayTy = type_checker() -isPointerTy = type_checker() -isPtrOrPtrVectorTy = type_checker() -isVectorTy = type_checker() -isEmptyTy = type_checker() -isPrimitiveType = type_checker() -isDerivedType = type_checker() -isFirstClassType = type_checker() -isSingleValueType = type_checker() -isAggregateType = type_checker() -isSized = type_checker() + isVoidTy = type_checker() + isHalfTy = type_checker() + isFloatTy = type_checker() + isDoubleTy = type_checker() + isX86_FP80Ty = type_checker() + isFP128Ty = type_checker() + isPPC_FP128Ty = type_checker() + isFloatingPointTy = type_checker() + isX86_MMXTy = type_checker() + isFPOrFPVectorTy = type_checker() + isLabelTy = type_checker() + isMetadataTy = type_checker() + isIntOrIntVectorTy = type_checker() + isFunctionTy = type_checker() + isStructTy = type_checker() + isArrayTy = type_checker() + isPointerTy = type_checker() + isPtrOrPtrVectorTy = type_checker() + isVectorTy = type_checker() + isEmptyTy = type_checker() + isPrimitiveType = type_checker() + isDerivedType = type_checker() + isFirstClassType = type_checker() + isSingleValueType = type_checker() + isAggregateType = type_checker() + isSized = type_checker() -isIntegerTy = Type.multimethod([Bool.To(bool)], - [Bool.To(bool), Unsigned.From(int)]) + isIntegerTy = Method(cast(Bool, bool)) + isIntegerTy |= Method(cast(Bool, bool), cast(int, Unsigned)) -def type_factory(): - return Type.staticmethod(Type.Pointer, LLVMContext.Ref) + def type_factory(): + return StaticMethod(ptr(Type), ref(LLVMContext)) -getVoidTy = type_factory() -getLabelTy = type_factory() -getHalfTy = type_factory() -getFloatTy = type_factory() -getDoubleTy = type_factory() -getMetadataTy = type_factory() -getX86_FP80Ty = type_factory() -getFP128Ty = type_factory() -getPPC_FP128Ty = type_factory() -getX86_MMXTy = type_factory() + getVoidTy = type_factory() + getLabelTy = type_factory() + getHalfTy = type_factory() + getFloatTy = type_factory() + getDoubleTy = type_factory() + getMetadataTy = type_factory() + getX86_FP80Ty = type_factory() + getFP128Ty = type_factory() + getPPC_FP128Ty = type_factory() + getX86_MMXTy = type_factory() -getIntNTy = Type.staticmethod(IntegerType.Pointer, LLVMContext.Ref, Unsigned.From(int)) + getIntNTy = StaticMethod(ptr(IntegerType), ref(LLVMContext), cast(Unsigned, int)) -def integer_factory(): - return Type.staticmethod(IntegerType.Pointer, LLVMContext.Ref) + def integer_factory(): + return StaticMethod(ptr(IntegerType), ref(LLVMContext)) -getInt1Ty = integer_factory() -getInt8Ty = integer_factory() -getInt16Ty = integer_factory() -getInt32Ty = integer_factory() -getInt64Ty = integer_factory() + getInt1Ty = integer_factory() + getInt8Ty = integer_factory() + getInt16Ty = integer_factory() + getInt32Ty = integer_factory() + getInt64Ty = integer_factory() -def pointer_factory(): - return Type.staticmethod(PointerType.Pointer, LLVMContext.Ref) + def pointer_factory(): + return StaticMethod(ptr(PointerType), ref(LLVMContext)) -getHalfPtrTy = pointer_factory() -getFloatPtrTy = pointer_factory() -getDoublePtrTy = pointer_factory() -getX86_FP80PtrTy = pointer_factory() -getFP128PtrTy = pointer_factory() -getPPC_FP128PtrTy = pointer_factory() -getX86_MMXPtrTy = pointer_factory() -getInt1PtrTy = pointer_factory() -getInt8PtrTy = pointer_factory() -getInt16PtrTy = pointer_factory() -getInt32PtrTy = pointer_factory() -getInt64PtrTy = pointer_factory() -getIntNPtrTy = Type.staticmethod(PointerType.Pointer, - LLVMContext.Ref, Unsigned.From(int)) + getHalfPtrTy = pointer_factory() + getFloatPtrTy = pointer_factory() + getDoublePtrTy = pointer_factory() + getX86_FP80PtrTy = pointer_factory() + getFP128PtrTy = pointer_factory() + getPPC_FP128PtrTy = pointer_factory() + getX86_MMXPtrTy = pointer_factory() + getInt1PtrTy = pointer_factory() + getInt8PtrTy = pointer_factory() + getInt16PtrTy = pointer_factory() + getInt32PtrTy = pointer_factory() + getInt64PtrTy = pointer_factory() + getIntNPtrTy = StaticMethod(ptr(PointerType), + ref(LLVMContext), cast(int, Unsigned)) +@IntegerType +class IntegerType: + pass + + +@CompositeType +class CompositeType: + pass + +@SequentialType +class SequentialType: + pass + +@PointerType +class PointerType: + pass + diff --git a/newbinding/src/User.py b/newbinding/src/User.py index 8753983..dbc290d 100644 --- a/newbinding/src/User.py +++ b/newbinding/src/User.py @@ -2,4 +2,7 @@ from binding import * from namespace import llvm from Value import Value -User = Value.Subclass() +@llvm.Class(Value) +class User: + pass + diff --git a/newbinding/src/Value.py b/newbinding/src/Value.py index 062ad43..9d1a2dd 100644 --- a/newbinding/src/Value.py +++ b/newbinding/src/Value.py @@ -5,20 +5,23 @@ from AssemblyAnnotationWriter import AssemblyAnnotationWriter from Type import Type from LLVMContext import LLVMContext from StringRef import StringRef -# + Value = llvm.Class() -dump = Value.method(Void) +@Value +class Value: -print_ = Value.method(Void, raw_ostream.Ref, AssemblyAnnotationWriter.Pointer) -print_.realname = 'print' + dump = Method() -getType = Value.method(Type.Pointer) -getContext = Value.method(LLVMContext.Ref) + print_ = Method(Void, ref(raw_ostream), ptr(AssemblyAnnotationWriter)) + print_.realname = 'print' -hasName = Value.method(Bool.To(bool)) -# skip getValueName, setValueName -getName = Value.method(StringRef.To(str)) -setName = Value.method(Void, StringRef.From(str)) + getType = Method(ptr(Type)) + getContext = Method(ref(LLVMContext)) -replaceAllUsesWith = Value.method(Void, Value.Pointer) \ No newline at end of file + hasName = Method(cast(Bool, bool)) + # skip getValueName, setValueName + getName = Method(cast(StringRef, str)) + setName = Method(Void, cast(str, StringRef)) + + replaceAllUsesWith = Method(Void, ptr(Value)) \ No newline at end of file diff --git a/newbinding/src/__init__.py b/newbinding/src/__init__.py index e69de29..6e24918 100644 --- a/newbinding/src/__init__.py +++ b/newbinding/src/__init__.py @@ -0,0 +1,2 @@ +from . import Module + diff --git a/newbinding/src/namespace.py b/newbinding/src/namespace.py index 02af8c9..c50256d 100644 --- a/newbinding/src/namespace.py +++ b/newbinding/src/namespace.py @@ -1,4 +1,3 @@ from binding import * -extra = Namespace('llvm_extra') llvm = Namespace('llvm') diff --git a/newbinding/src/raw_ostream.py b/newbinding/src/raw_ostream.py index 64e8046..2f5a6f5 100644 --- a/newbinding/src/raw_ostream.py +++ b/newbinding/src/raw_ostream.py @@ -3,10 +3,15 @@ from namespace import llvm from LLVMContext import LLVMContext from StringRef import StringRef -raw_ostream = llvm.Class() -raw_ostream.include.add("llvm/Support/raw_ostream.h") -delete = raw_ostream.delete() +@llvm.Class() +class raw_ostream: + _include_ = "llvm/Support/raw_ostream.h" + delete = Destructor() + +@llvm.Class(raw_ostream) +class raw_svector_ostream: + _include_ = "llvm/Support/raw_os_ostream.h" + _base_ = raw_ostream + + str = Method(cast(str, StringRef)) -raw_svector_ostream = raw_ostream.Subclass() -raw_svector_ostream.include.add("llvm/Support/raw_os_ostream.h") -str = raw_svector_ostream.method(StringRef.To(str)) diff --git a/newbinding/test2.py b/newbinding/test2.py index ac74594..afb3608 100644 --- a/newbinding/test2.py +++ b/newbinding/test2.py @@ -1,4 +1,5 @@ import api +import extra import _capsule api.capsule.set_debug(True) context = api.getGlobalContext() @@ -15,7 +16,7 @@ assert m.getPointerSize() == api.Module.PointerSize.AnyPointerSize m.dump() -os = api.make_raw_ostream_for_printing() +os = extra.make_raw_ostream_for_printing() m.print_(os, None) print os.str() @@ -29,15 +30,15 @@ fnty = api.FunctionType.get(int1ty, False) fnty.dump() types = [int1ty, api.Type.getIntNTy(context, 21)] -svt = api.make_small_vector_from_types(*types) +svt = extra.make_small_vector_from_types(*types) fnty = api.FunctionType.get(int1ty, svt, False) -os = api.make_raw_ostream_for_printing() +os = extra.make_raw_ostream_for_printing() fnty.print_(os) print os.str() fn = m.getOrInsertFunction("foo", fnty) -os = api.make_raw_ostream_for_printing() +os = extra.make_raw_ostream_for_printing() fn.print_(os, None) print os.str() assert fn.hasName() diff --git a/newbinding/utils.py b/newbinding/utils.py deleted file mode 100644 index 6c39990..0000000 --- a/newbinding/utils.py +++ /dev/null @@ -1,6 +0,0 @@ - -def indent_println(println): - def _println(s): - println("%s%s" % (' '* 4, s)) - return _println - From 3c81157ede77dae545dea76988df117441b8bb16 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 25 Jan 2013 15:35:23 -0600 Subject: [PATCH 223/516] Add downcasting --- newbinding/binding.py | 28 +++++++++------ newbinding/capsule.py | 46 +++++++++++++++++-------- newbinding/extra.py | 27 +++++++++++++-- newbinding/gen.py | 26 ++++++++++++++ newbinding/include/llvm_binding/extra.h | 10 +++--- newbinding/src/namespace.py | 1 + 6 files changed, 106 insertions(+), 32 deletions(-) diff --git a/newbinding/binding.py b/newbinding/binding.py index fc26d92..8c58aa9 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -28,10 +28,10 @@ class Namespace(object): def __str__(self): return self.name -class Type(object): +class _Type(object): pass -class BuiltinTypes(Type): +class BuiltinTypes(_Type): def __init__(self, name): self.name = name @@ -47,7 +47,7 @@ Unsigned = BuiltinTypes('unsigned') Bool = BuiltinTypes('bool') ConstStdString = BuiltinTypes('const std::string') -class Class(Type): +class Class(_Type): format = 'O' def __init__(self, ns, *bases): @@ -57,9 +57,11 @@ class Class(Type): self.methods = [] self.enums = [] self.includes = set() + self.downcastables = set() def __call__(self, defn): assert not self._is_defined + # process the definition in "defn" self.name = defn.__name__ for k, v in defn.__dict__.items(): if isinstance(v, Method): @@ -79,6 +81,12 @@ class Class(Type): else: for i in v: self.includes.add(i) + elif k == '_downcast_': + if isinstance(v, Class): + self.downcastables.add(v) + else: + for i in v: + self.downcastables.add(i) return self def compile_cpp(self, writer): @@ -106,12 +114,11 @@ class Class(Type): bases = ', '.join(x.name for x in self.bases) writer.println('@capsule.register_class') with writer.block('class %(clsname)s(%(bases)s):' % locals()): + writer.println('_llvm_type_ = "%s"' % self.fullname) for enum in self.enums: enum.compile_py(writer) for meth in self.methods: meth.compile_py(writer) - if not self.enums and not self.methods: - writer.println('pass') writer.println() @property @@ -178,6 +185,7 @@ class Enum(object): def compile_py(self, writer): with writer.block('class %s:' % self.name): + writer.println('_llvm_type_ = "%s"' % self.fullname) for v in self.value_names: writer.println('%(v)s = "%(v)s"' % locals()) writer.println() @@ -340,7 +348,7 @@ class Constructor(StaticMethod): ret = writer.declare(retty.fullname, stmt) return ret -class ref(Type): +class ref(_Type): def __init__(self, element): assert isinstance(element, Class), type(element) self.element = element @@ -369,7 +377,7 @@ class ref(Type): return writer.declare(self.fullname, '*%s' % p) -class ptr(Type): +class ptr(_Type): def __init__(self, element): assert isinstance(element, Class) self.element = element @@ -393,7 +401,7 @@ class ptr(Type): return writer.pycapsule_new(val, self.element.capsule_name, self.element.fullname) -class cast(Type): +class cast(_Type): format = 'O' def __init__(self, original, target): @@ -406,14 +414,14 @@ class cast(Type): @property def python_type(self): - if not isinstance(self.target, Type): + if not isinstance(self.target, _Type): return self.target else: return self.original @property def binding_type(self): - if isinstance(self.target, Type): + if isinstance(self.target, _Type): return self.target else: return self.original diff --git a/newbinding/capsule.py b/newbinding/capsule.py index e4cd4fa..d999e30 100644 --- a/newbinding/capsule.py +++ b/newbinding/capsule.py @@ -19,7 +19,7 @@ def set_debug(enabled): class WeakRef(ref): - __slots__ = 'capsule', 'dtor' + __slots__ = 'capsule', 'dtor', 'owning' _pyclasses = {} _addr2obj = WeakValueDictionary() @@ -33,12 +33,20 @@ def classof(cap): return _pyclasses[cls] def _capsule_destructor(weak): - cap = weak.capsule - addr = _capsule.getPointer(cap) - cls = _capsule.getClassName(cap) - logger.debug("destroy pointer 0x%08X to %s", addr, cls) - weak.dtor(cap) - del _owners[addr] + if weak.owning: + cap = weak.capsule + addr = _capsule.getPointer(cap) + cls = _capsule.getClassName(cap) + logger.debug("destroy pointer 0x%08X to %s", addr, cls) + weak.dtor(cap) + del _owners[addr] + +def release_ownership(old): + addr = _capsule.getPointer(old) + if hasattr(old, '_delete_'): + oldweak = _owners[addr] + oldweak.owning = False # dis-own + del _owners[addr] def wrap(cap): '''Wrap a PyCapsule with the corresponding Wrapper class. @@ -60,13 +68,26 @@ def wrap(cap): weak = WeakRef(obj, _capsule_destructor) _owners[addr] = weak weak.capsule = cap + weak.owning = True weak.dtor = cls._delete_ else: - assert classof(obj._ptr) is classof(cap) - # Unset destructor for capsules that are repeated - _capsule.setDestructor(cap, None) + oldcls = classof(obj._ptr) + newcls = classof(cap) + if issubclass(oldcls, newcls): + # do auto downcast + pass + else: + assert oldcls is newcls return obj +def downcast(old, new): + assert old is not new + oldcls = classof(old) + newcls = classof(new) + assert issubclass(newcls, oldcls) + release_ownership(old) + del _addr2obj[_capsule.getPointer(old)] # clear cache + return wrap(new) def unwrap(obj): '''Unwrap a Wrapper instance into the underlying PyCapsule. @@ -96,8 +117,3 @@ class Wrapper(object): def _ptr(self): return self.__ptr - def _release_ownership(self): - _capsule.setDestructor(self._ptr, None) - - - diff --git a/newbinding/extra.py b/newbinding/extra.py index 1af4e5f..a613296 100644 --- a/newbinding/extra.py +++ b/newbinding/extra.py @@ -3,8 +3,13 @@ Wrapped the extra functions in _api.so ''' import capsule +import _api +# +# Re-export the native API from the _api.extra and wrap the functions +# def _wrapper(func): + "Wrap the re-exported functions" def _core(*args): unwrapped = map(capsule.unwrap, args) ret = func(*unwrapped) @@ -12,9 +17,27 @@ def _wrapper(func): return _core def _init(glob): - from _api import extra - for k, v in extra.__dict__.items(): + for k, v in _api.extra.__dict__.items(): glob[k] = _wrapper(v) _init(globals()) +# +# Downcasts +# + +def downcast(obj, cls): + if type(obj) is cls: + return obj + fromty = obj._llvm_type_ + toty = cls._llvm_type_ + fname = 'downcast_%s_to_%s' % (fromty, toty) + fname = fname.replace('::', '_') + try: + caster = getattr(_api, fname) + except AttributeError: + fmt = "Downcast from %s to %s is not supported" + raise TypeError(fmt % (fromty, toty)) + old = capsule.unwrap(obj) + new = caster(old) + return capsule.downcast(old, new) \ No newline at end of file diff --git a/newbinding/gen.py b/newbinding/gen.py index 4d8709e..f1af18e 100644 --- a/newbinding/gen.py +++ b/newbinding/gen.py @@ -72,6 +72,20 @@ def main(): print cls units.append(cls) + # add extra stuffs + downcastlist = [] + ## add downcast + for cls in units: + if isinstance(cls, Class): + for bcls in cls.downcastables: + from_to = bcls.fullname, cls.fullname + name = 'downcast_%s_to_%s' % tuple(map(codegen.mangle, from_to)) + fn = Function(namespaces[''], name, ptr(cls), ptr(bcls)) + downcastlist.append((from_to, fn)) + units.append(fn) + + + # generate cpp source with open('%s.cpp' % outputfilename, 'w') as cppfile: println = wrap_println_from_file(cppfile) @@ -87,6 +101,18 @@ def main(): println('#include "%s"' % inc) println() + # generate downcast + for ((fromty, toty), fn) in downcastlist: + name = fn.name + fmt = ''' +static +%(toty)s* %(name)s(%(fromty)s* arg) +{ + return typecast<%(toty)s>::from(arg); +} +''' + println(fmt % locals()) + # write methods and method tables for u in units: writer = codegen.CppCodeWriter(println) diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h index 417c0f8..94887b3 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/extra.h @@ -37,9 +37,9 @@ PyObject* make_small_vector_from_types(PyObject* self, PyObject* args) { } static PyMethodDef extra_methodtable[] = { -#define method(func) { #func, (PyCFunction)func, METH_VARARGS, NULL } -method( make_raw_ostream_for_printing ), -method( make_small_vector_from_types ), -{ NULL } -#undef method + #define method(func) { #func, (PyCFunction)func, METH_VARARGS, NULL } + method( make_raw_ostream_for_printing ), + method( make_small_vector_from_types ), + #undef method + { NULL } }; diff --git a/newbinding/src/namespace.py b/newbinding/src/namespace.py index c50256d..3a081af 100644 --- a/newbinding/src/namespace.py +++ b/newbinding/src/namespace.py @@ -1,3 +1,4 @@ from binding import * llvm = Namespace('llvm') +default = Namespace('') From c76096bbcb01953d43b9a829f28d5e52b7fad9d7 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 25 Jan 2013 15:41:38 -0600 Subject: [PATCH 224/516] Add Function and some Function methods --- newbinding/src/Function.py | 19 +++++++++++++++++++ newbinding/src/GlobalValue.py | 8 ++++++++ newbinding/src/Module.py | 1 + newbinding/src/Value.py | 2 +- newbinding/test2.py | 12 +++++++++++- 5 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 newbinding/src/Function.py create mode 100644 newbinding/src/GlobalValue.py diff --git a/newbinding/src/Function.py b/newbinding/src/Function.py new file mode 100644 index 0000000..7077d3a --- /dev/null +++ b/newbinding/src/Function.py @@ -0,0 +1,19 @@ +from binding import * +from namespace import llvm +from GlobalValue import GlobalValue +from Constant import Constant +from Type import Type +from DerivedTypes import FunctionType +from LLVMContext import LLVMContext + +@llvm.Class(GlobalValue) +class Function: + _include_ = 'llvm/Function.h' + _downcast_ = GlobalValue, Constant + + getReturnType = Method(ptr(Type)) + getFunctionType = Method(ptr(FunctionType)) + getContext = Method(ref(LLVMContext)) + isVarArg = Method(cast(Bool, bool)) + getIntrinsicID = Method(cast(Unsigned, int)) + isIntrinsic = Method(cast(Bool, bool)) \ No newline at end of file diff --git a/newbinding/src/GlobalValue.py b/newbinding/src/GlobalValue.py new file mode 100644 index 0000000..f1a6827 --- /dev/null +++ b/newbinding/src/GlobalValue.py @@ -0,0 +1,8 @@ +from binding import * +from namespace import llvm +from Constant import Constant + +@llvm.Class(Constant) +class GlobalValue: + _include_ = 'llvm/GlobalValue.h' + diff --git a/newbinding/src/Module.py b/newbinding/src/Module.py index 6a6a806..730b757 100644 --- a/newbinding/src/Module.py +++ b/newbinding/src/Module.py @@ -3,6 +3,7 @@ from namespace import llvm from LLVMContext import LLVMContext from StringRef import StringRef from Constant import Constant +from Function import Function from DerivedTypes import FunctionType from raw_ostream import raw_ostream from AssemblyAnnotationWriter import AssemblyAnnotationWriter diff --git a/newbinding/src/Value.py b/newbinding/src/Value.py index 9d1a2dd..30b3f37 100644 --- a/newbinding/src/Value.py +++ b/newbinding/src/Value.py @@ -24,4 +24,4 @@ class Value: getName = Method(cast(StringRef, str)) setName = Method(Void, cast(str, StringRef)) - replaceAllUsesWith = Method(Void, ptr(Value)) \ No newline at end of file + replaceAllUsesWith = Method(Void, ptr(Value)) diff --git a/newbinding/test2.py b/newbinding/test2.py index afb3608..3429f10 100644 --- a/newbinding/test2.py +++ b/newbinding/test2.py @@ -37,7 +37,8 @@ os = extra.make_raw_ostream_for_printing() fnty.print_(os) print os.str() -fn = m.getOrInsertFunction("foo", fnty) +const = m.getOrInsertFunction("foo", fnty) +fn = extra.downcast(const, api.Function) os = extra.make_raw_ostream_for_printing() fn.print_(os, None) print os.str() @@ -45,3 +46,12 @@ assert fn.hasName() assert 'foo' == fn.getName() fn.setName('bar') assert 'bar' == fn.getName() + +os = extra.make_raw_ostream_for_printing() +assert fn.getReturnType() is int1ty + +assert fnty is fn.getFunctionType() + +assert fn.isVarArg() == False +assert fn.getIntrinsicID() == 0 +assert not fn.isIntrinsic() From 4b5cb100f71c5b9624a35e78c97324f48d0dde4f Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 28 Jan 2013 15:18:24 -0600 Subject: [PATCH 225/516] Auto discover binding modules --- newbinding/src/__init__.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/newbinding/src/__init__.py b/newbinding/src/__init__.py index 6e24918..1042826 100644 --- a/newbinding/src/__init__.py +++ b/newbinding/src/__init__.py @@ -1,2 +1,11 @@ -from . import Module +import os.path, importlib +def _init(): + for fname in os.listdir(os.path.dirname(__file__)): + if ((fname.endswith('.py') or fname.endswith('.pyc')) and + not fname.startswith('__init__')): + modname = os.path.basename(fname).rsplit('.', 1)[0] + topname = __name__.rsplit('.', 1)[0] + importlib.import_module('.' + modname, topname) + +_init() From 01683150760f3f0778937590eac769847f7d8b64 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 28 Jan 2013 15:19:16 -0600 Subject: [PATCH 226/516] Explicitly declare class name when registering classes --- newbinding/binding.py | 3 +-- newbinding/capsule.py | 9 +++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/newbinding/binding.py b/newbinding/binding.py index 8c58aa9..85b74e9 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -112,7 +112,7 @@ class Class(_Type): bases = 'capsule.Wrapper' if self.bases: bases = ', '.join(x.name for x in self.bases) - writer.println('@capsule.register_class') + writer.println('@capsule.register_class("%s")' % self.fullname) with writer.block('class %(clsname)s(%(bases)s):' % locals()): writer.println('_llvm_type_ = "%s"' % self.fullname) for enum in self.enums: @@ -151,7 +151,6 @@ class Class(_Type): writer.die_if_false(casted) return casted - class Enum(object): def __init__(self, *value_names): self.parent = None diff --git a/newbinding/capsule.py b/newbinding/capsule.py index d999e30..47c32fb 100644 --- a/newbinding/capsule.py +++ b/newbinding/capsule.py @@ -99,10 +99,11 @@ def unwrap(obj): return obj -def register_class(cls): - clsname = cls.__name__ - _pyclasses['llvm::%s' % clsname] = cls - return cls +def register_class(clsname): + def _wrapped(cls): + _pyclasses[clsname] = cls + return cls + return _wrapped class Wrapper(object): From d1931cc4994c2ee6adf8d611c9a59d5dbc9c0362 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 28 Jan 2013 15:20:07 -0600 Subject: [PATCH 227/516] Fix duplicated semicolon --- newbinding/codegen.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/newbinding/codegen.py b/newbinding/codegen.py index 9398b14..2a85abc 100644 --- a/newbinding/codegen.py +++ b/newbinding/codegen.py @@ -184,14 +184,14 @@ class CppCodeWriter(CodeWriterBase): arglist = ', '.join(args[1:]) if func == 'delete': assert not arglist - stmt = 'delete %(this)s;' % locals() + stmt = 'delete %(this)s' % locals() elif func == 'new': alloctype = retty.rstrip(' *') - stmt = 'new %(alloctype)s(%(arglist)s);' % locals() + stmt = 'new %(alloctype)s(%(arglist)s)' % locals() else: - stmt = '%(this)s->%(func)s(%(arglist)s);' % locals() + stmt = '%(this)s->%(func)s(%(arglist)s)' % locals() if retty == 'void': - self.println(stmt) + self.println('%s;' % stmt) else: return self.declare(retty, stmt) From 821e93783729ff74268e63c329d8a839c47fded9 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 28 Jan 2013 15:20:36 -0600 Subject: [PATCH 228/516] Add binding util for iterator to list --- newbinding/binding.py | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/newbinding/binding.py b/newbinding/binding.py index 85b74e9..1764559 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -46,6 +46,7 @@ Void = BuiltinTypes('void') Unsigned = BuiltinTypes('unsigned') Bool = BuiltinTypes('bool') ConstStdString = BuiltinTypes('const std::string') +PyObjectPtr = BuiltinTypes('PyObject*') class Class(_Type): format = 'O' @@ -81,6 +82,8 @@ class Class(_Type): else: for i in v: self.includes.add(i) + elif k == '_realname_': + self.realname = v elif k == '_downcast_': if isinstance(v, Class): self.downcastables.add(v) @@ -146,7 +149,7 @@ class Class(_Type): writer.die_if_false(raw) ptrty = ptr(self).fullname ty = self.fullname - fmt = 'typecast<%(ty)s>::from(%(raw)s)' + fmt = 'typecast<%(ty)s >::from(%(raw)s)' casted = writer.declare(ptrty, fmt % locals()) writer.die_if_false(casted) return casted @@ -252,12 +255,8 @@ class Method(object): writer.raises(TypeError, 'Invalid number of args') def compile_cpp_body(self, writer, retty, argtys): - if isinstance(self.parent, Class): - args = writer.parse_arguments('args', ptr(self.parent), *argtys) - ret = writer.method_call(self.realname, retty.fullname, *args) - else: - args = writer.parse_arguments('args', *argtys) - ret = writer.call(self.fullname, retty.fullname, *args) + args = writer.parse_arguments('args', ptr(self.parent), *argtys) + ret = writer.method_call(self.realname, retty.fullname, *args) writer.return_value(retty.wrap(writer, ret)) def compile_py(self, writer): @@ -273,6 +272,29 @@ class Method(object): writer.println() +class IterToList(Method): + def __init__(self, elemty, argtys, iterty, begin, end): + super(IterToList, self).__init__(PyObjectPtr, *argtys) + self.elemty = elemty + self.iterty = iterty + self.begin = begin + self.end = end + + def compile_cpp_body(self, writer, retty, argtys): + args = writer.parse_arguments('args', ptr(self.parent), *argtys) + it = writer.method_call(self.begin, self.iterty, *args) + end = writer.method_call(self.end, self.iterty, *args) + con = writer.call('PyList_New', 'PyObject*', '0') + writer.die_if_false(con) + with writer.block('for (; %(it)s != %(end)s; ++%(it)s)' % locals()): + elem = writer.declare(self.elemty.fullname, '*%(it)s;' % locals()) + wrapped = self.elemty.wrap(writer, elem) + ok = writer.call('PyList_Append', 'int', con, wrapped) + with writer.block('if (%(ok)s == -1)' % locals()): + writer.return_value(None) + writer.return_value(con) + + class StaticMethod(Method): def compile_cpp_body(self, writer, retty, argtys): @@ -296,7 +318,6 @@ class StaticMethod(Method): writer.return_value(wrapped) writer.println() - class Function(Method): _kind_ = 'func' @@ -305,6 +326,11 @@ class Function(Method): self.parent = parent self.name = name + def compile_cpp_body(self, writer, retty, argtys): + args = writer.parse_arguments('args', *argtys) + ret = writer.call(self.fullname, retty.fullname, *args) + writer.return_value(retty.wrap(writer, ret)) + def compile_py(self, writer): with writer.function(self.name, varargs='args') as varargs: unwrapped = writer.unwrap_many(varargs) @@ -315,7 +341,6 @@ class Function(Method): writer.return_value(wrapped) writer.println() - class Destructor(Method): _kind_ = 'dtor' From fa4927e1fb6cb195206fbbf4d13d311148921690 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 28 Jan 2013 15:20:50 -0600 Subject: [PATCH 229/516] Start to work on IRBuilder --- newbinding/src/Constant.py | 5 +++-- newbinding/src/Function.py | 8 ++++---- newbinding/src/GlobalValue.py | 4 ++-- newbinding/src/User.py | 5 ++--- newbinding/src/Value.py | 13 +++++++++++++ newbinding/test2.py | 12 ++++++++++++ 6 files changed, 36 insertions(+), 11 deletions(-) diff --git a/newbinding/src/Constant.py b/newbinding/src/Constant.py index 14ff6bb..c59fef4 100644 --- a/newbinding/src/Constant.py +++ b/newbinding/src/Constant.py @@ -1,7 +1,8 @@ from binding import * from namespace import llvm -from User import User +from Value import Constant -@llvm.Class(User) +@Constant class Constant: pass + diff --git a/newbinding/src/Function.py b/newbinding/src/Function.py index 7077d3a..f069e30 100644 --- a/newbinding/src/Function.py +++ b/newbinding/src/Function.py @@ -1,12 +1,11 @@ from binding import * from namespace import llvm -from GlobalValue import GlobalValue -from Constant import Constant +from Value import GlobalValue, Constant, Function from Type import Type from DerivedTypes import FunctionType from LLVMContext import LLVMContext -@llvm.Class(GlobalValue) +@Function class Function: _include_ = 'llvm/Function.h' _downcast_ = GlobalValue, Constant @@ -16,4 +15,5 @@ class Function: getContext = Method(ref(LLVMContext)) isVarArg = Method(cast(Bool, bool)) getIntrinsicID = Method(cast(Unsigned, int)) - isIntrinsic = Method(cast(Bool, bool)) \ No newline at end of file + isIntrinsic = Method(cast(Bool, bool)) + diff --git a/newbinding/src/GlobalValue.py b/newbinding/src/GlobalValue.py index f1a6827..40825a8 100644 --- a/newbinding/src/GlobalValue.py +++ b/newbinding/src/GlobalValue.py @@ -1,8 +1,8 @@ from binding import * from namespace import llvm -from Constant import Constant +from Value import GlobalValue -@llvm.Class(Constant) +@GlobalValue class GlobalValue: _include_ = 'llvm/GlobalValue.h' diff --git a/newbinding/src/User.py b/newbinding/src/User.py index dbc290d..57d58bc 100644 --- a/newbinding/src/User.py +++ b/newbinding/src/User.py @@ -1,8 +1,7 @@ from binding import * from namespace import llvm -from Value import Value +from Value import User -@llvm.Class(Value) +@User class User: pass - diff --git a/newbinding/src/Value.py b/newbinding/src/Value.py index 30b3f37..a901946 100644 --- a/newbinding/src/Value.py +++ b/newbinding/src/Value.py @@ -7,6 +7,12 @@ from LLVMContext import LLVMContext from StringRef import StringRef Value = llvm.Class() +# forward declarations +User = llvm.Class(Value) +BasicBlock = llvm.Class(Value) +Constant = llvm.Class(User) +GlobalValue = llvm.Class(Constant) +Function = llvm.Class(GlobalValue) @Value class Value: @@ -25,3 +31,10 @@ class Value: setName = Method(Void, cast(str, StringRef)) replaceAllUsesWith = Method(Void, ptr(Value)) + + list_use = IterToList(ptr(User), (), 'llvm::Value::use_iterator', + 'use_begin', 'use_end') + + hasOneUse = Method(cast(Bool, bool)) + hasNUses = Method(cast(Bool, bool), cast(int, Unsigned)) + isUsedInBasicBlock = Method(cast(Bool, bool), BasicBlock) diff --git a/newbinding/test2.py b/newbinding/test2.py index 3429f10..810a7ba 100644 --- a/newbinding/test2.py +++ b/newbinding/test2.py @@ -55,3 +55,15 @@ assert fnty is fn.getFunctionType() assert fn.isVarArg() == False assert fn.getIntrinsicID() == 0 assert not fn.isIntrinsic() + +print fn.list_use() + +builder = api.IRBuilder.new(context) +print builder + +bb = api.BasicBlock.Create(context, "entry", fn, None) +builder.SetInsertPoint(bb) + +builder.CreateRetVoid() + +fn.dump() From d9397289383cb0f17ba088cf3946ad6deb46ab0c Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 28 Jan 2013 15:21:30 -0600 Subject: [PATCH 230/516] Forgot to push files for previous commit. --- newbinding/src/BasicBlock.py | 19 +++ newbinding/src/IRBuilder.py | 21 ++++ newbinding/src/Instruction.py | 230 ++++++++++++++++++++++++++++++++++ 3 files changed, 270 insertions(+) create mode 100644 newbinding/src/BasicBlock.py create mode 100644 newbinding/src/IRBuilder.py create mode 100644 newbinding/src/Instruction.py diff --git a/newbinding/src/BasicBlock.py b/newbinding/src/BasicBlock.py new file mode 100644 index 0000000..c7221a5 --- /dev/null +++ b/newbinding/src/BasicBlock.py @@ -0,0 +1,19 @@ +from binding import * +from namespace import llvm +from Value import Function, BasicBlock +from LLVMContext import LLVMContext +from StringRef import StringRef + +@BasicBlock +class BasicBlock: + Create = StaticMethod(ptr(BasicBlock), ref(LLVMContext), + cast(str, StringRef), + ptr(Function), + ptr(BasicBlock)) + + getParent = Method(ptr(Function)) + empty = Method(cast(Bool, bool)) + dropAllReferences = Method() + isLandingPad = Method(cast(Bool, bool)) + removePredecessor = Method(Void, ptr(BasicBlock), cast(bool, Bool)) + removePredecessor |= Method(Void, ptr(BasicBlock)) diff --git a/newbinding/src/IRBuilder.py b/newbinding/src/IRBuilder.py new file mode 100644 index 0000000..0919a67 --- /dev/null +++ b/newbinding/src/IRBuilder.py @@ -0,0 +1,21 @@ +from binding import * +from namespace import llvm +from LLVMContext import LLVMContext +from BasicBlock import BasicBlock +from Instruction import ReturnInst + +IRBuilder = llvm.Class() + +@IRBuilder +class IRBuilder: + _include_ = 'llvm/IRBuilder.h' + _realname_ = 'IRBuilder<>' + + new = Constructor(ref(LLVMContext)) + delete = Destructor() + + SetInsertPoint = Method(Void, ptr(BasicBlock)) + + isNamePreserving = Method(cast(Bool, bool)) + + CreateRetVoid = Method(ptr(ReturnInst)) diff --git a/newbinding/src/Instruction.py b/newbinding/src/Instruction.py new file mode 100644 index 0000000..310e19d --- /dev/null +++ b/newbinding/src/Instruction.py @@ -0,0 +1,230 @@ +from binding import * +from namespace import llvm +from Value import User + +Instruction = llvm.Class(User) +AtomicCmpXchgInst = llvm.Class(Instruction) +AtomicRMWInst = llvm.Class(Instruction) +BinaryOperator = llvm.Class(Instruction) +CallInst = llvm.Class(Instruction) +CmpInst = llvm.Class(Instruction) +ExtractElementInst = llvm.Class(Instruction) +FenceInst = llvm.Class(Instruction) +GetElementPtrInst = llvm.Class(Instruction) +InsertElementInst = llvm.Class(Instruction) +InsertValueInst = llvm.Class(Instruction) +LandingPadInst = llvm.Class(Instruction) +PHINode = llvm.Class(Instruction) +SelectInst = llvm.Class(Instruction) +ShuffleVectorInst = llvm.Class(Instruction) +StoreInst = llvm.Class(Instruction) +TerminatorInst = llvm.Class(Instruction) +UnaryInstruction = llvm.Class(Instruction) + +IntrinsicInst = llvm.Class(CallInst) + +FCmpInst = llvm.Class(CmpInst) +ICmpInst = llvm.Class(CmpInst) + + +BranchInst = llvm.Class(TerminatorInst) +IndirectBrInst = llvm.Class(TerminatorInst) +ResumeInst = llvm.Class(TerminatorInst) +ReturnInst = llvm.Class(TerminatorInst) +SwitchInst = llvm.Class(TerminatorInst) +UnreachableInst = llvm.Class(TerminatorInst) + +AllocaInst = llvm.Class(UnaryInstruction) +CastInst = llvm.Class(UnaryInstruction) +ExtractValueInst = llvm.Class(UnaryInstruction) +LoadInst = llvm.Class(UnaryInstruction) +VAArgInst = llvm.Class(UnaryInstruction) + +DbgInfoIntrinsic = llvm.Class(IntrinsicInst) +MemIntrinsic = llvm.Class(IntrinsicInst) +VACopyInst = llvm.Class(IntrinsicInst) +VAEndInst = llvm.Class(IntrinsicInst) +VAStartInst = llvm.Class(IntrinsicInst) + +BitCastInst = llvm.Class(CastInst) +FPExtInst = llvm.Class(CastInst) +FPToSIInst = llvm.Class(CastInst) +FPToUIInst = llvm.Class(CastInst) +FPTruncInst = llvm.Class(CastInst) + +@Instruction +class Instruction: + pass + + +@AtomicCmpXchgInst +class AtomicCmpXchgInst: + pass + +@AtomicRMWInst +class AtomicRMWInst: + pass + +@BinaryOperator +class BinaryOperator: + pass + +@CallInst +class CallInst: + pass + +@CmpInst +class CmpInst: + pass + +@ExtractElementInst +class ExtractElementInst: + pass + +@FenceInst +class FenceInst: + pass + +@GetElementPtrInst +class GetElementPtrInst: + pass + +@InsertElementInst +class InsertElementInst: + pass + +@InsertValueInst +class InsertValueInst: + pass + +@LandingPadInst +class LandingPadInst: + pass + +@PHINode +class PHINode: + pass + +@SelectInst +class SelectInst: + pass + +@ShuffleVectorInst +class ShuffleVectorInst: + pass + +@StoreInst +class StoreInst: + pass + +@TerminatorInst +class TerminatorInst: + pass + +@UnaryInstruction +class UnaryInstruction: + pass + +#call + +@IntrinsicInst +class IntrinsicInst: + pass + +#compare + +@FCmpInst +class FCmpInst: + pass + +@ICmpInst +class ICmpInst: + pass + +# terminator +@BranchInst +class BranchInst: + pass + + +@IndirectBrInst +class IndirectBrInst: + pass + +@ResumeInst +class ResumeInst: + pass + +@ReturnInst +class ReturnInst: + pass + +@SwitchInst +class SwitchInst: + pass + +@UnreachableInst +class UnreachableInst: + pass + +# unary +@AllocaInst +class AllocaInst: + pass + +@CastInst +class CastInst: + pass + +@ExtractValueInst +class ExtractValueInst: + pass + +@LoadInst +class LoadInst: + pass + +@VAArgInst +class VAArgInst: + pass + +# intrinsic +@DbgInfoIntrinsic +class DbgInfoIntrinsic: + pass + +@MemIntrinsic +class MemIntrinsic: + pass + +@VACopyInst +class VACopyInst: + pass + +@VAEndInst +class VAEndInst: + pass + +@VAStartInst +class VAStartInst: + pass + +@BitCastInst +class BitCastInst: + pass + +@FPExtInst +class FPExtInst: + pass + +@FPToSIInst +class FPToSIInst: + pass + +@FPToUIInst +class FPToUIInst: + pass + +@FPTruncInst +class FPTruncInst: + pass From af7962a2ca835a62074c7b0c881e982ac1655c1c Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 28 Jan 2013 15:53:01 -0600 Subject: [PATCH 231/516] Remove IterToList, llvm_extra.h. Add CustomMethod. --- newbinding/binding.py | 25 +++------ newbinding/codegen.py | 4 +- newbinding/gen.py | 1 - newbinding/include/llvm_binding/extra.h | 53 ++++++++++++++++++-- newbinding/include/llvm_binding/llvm_extra.h | 38 -------------- newbinding/src/SmallVector.py | 1 + newbinding/src/Value.py | 3 +- 7 files changed, 61 insertions(+), 64 deletions(-) delete mode 100644 newbinding/include/llvm_binding/llvm_extra.h diff --git a/newbinding/binding.py b/newbinding/binding.py index 1764559..3538c9a 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -272,28 +272,17 @@ class Method(object): writer.println() -class IterToList(Method): - def __init__(self, elemty, argtys, iterty, begin, end): - super(IterToList, self).__init__(PyObjectPtr, *argtys) - self.elemty = elemty - self.iterty = iterty - self.begin = begin - self.end = end +class CustomMethod(Method): + def __init__(self, methodname, retty, *argtys): + super(CustomMethod, self).__init__(retty, *argtys) + self.methodname = methodname def compile_cpp_body(self, writer, retty, argtys): args = writer.parse_arguments('args', ptr(self.parent), *argtys) - it = writer.method_call(self.begin, self.iterty, *args) - end = writer.method_call(self.end, self.iterty, *args) - con = writer.call('PyList_New', 'PyObject*', '0') - writer.die_if_false(con) - with writer.block('for (; %(it)s != %(end)s; ++%(it)s)' % locals()): - elem = writer.declare(self.elemty.fullname, '*%(it)s;' % locals()) - wrapped = self.elemty.wrap(writer, elem) - ok = writer.call('PyList_Append', 'int', con, wrapped) - with writer.block('if (%(ok)s == -1)' % locals()): - writer.return_value(None) - writer.return_value(con) + ret = writer.call(self.methodname, retty.fullname, *args) + writer.return_value(retty.wrap(writer, ret)) + class StaticMethod(Method): diff --git a/newbinding/codegen.py b/newbinding/codegen.py index 2a85abc..7652447 100644 --- a/newbinding/codegen.py +++ b/newbinding/codegen.py @@ -42,14 +42,14 @@ def parse_arguments(println, var, *args): return unwrapped -_re_mangle_pattern = re.compile(r'[ _<>\*&]') +_re_mangle_pattern = re.compile(r'[ _<>\*&,]') def mangle(name): def repl(m): s = m.group(0) if s in '<>*&': return '' - elif s in ' ': + elif s in ' ,': return '_' elif s in '_': return '__' diff --git a/newbinding/gen.py b/newbinding/gen.py index f1af18e..d9fc14f 100644 --- a/newbinding/gen.py +++ b/newbinding/gen.py @@ -41,7 +41,6 @@ def populate_headers(println): includes = [ 'llvm_binding/conversion.h', 'llvm_binding/binding.h', - 'llvm_binding/llvm_extra.h', 'llvm_binding/capsule_context.h', 'llvm_binding/extra.h', # extra submodule to add ] diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h index 94887b3..639a87c 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/extra.h @@ -1,10 +1,43 @@ #include #include +#include #include + +namespace extra{ + using namespace llvm; + + class raw_svector_ostream_helper: public raw_svector_ostream { + SmallVectorImpl *SV; + public: + static + raw_svector_ostream_helper* create(){ + SmallVectorImpl* sv = new SmallVector(); + return new raw_svector_ostream_helper(sv); + } + + ~raw_svector_ostream_helper(){ + delete SV; + } + + protected: + + explicit + raw_svector_ostream_helper(SmallVectorImpl* sv) + : raw_svector_ostream(*sv), SV(sv) {} + + private: + // no copy + raw_svector_ostream_helper(const raw_svector_ostream_helper&); + // no assign + void operator = (const raw_svector_ostream_helper&); + }; + +} + static PyObject* make_raw_ostream_for_printing(PyObject* self, PyObject* args) { - using llvm::raw_svector_ostream_helper; + using extra::raw_svector_ostream_helper; using llvm::raw_svector_ostream; if (!PyArg_ParseTuple(args, "")) { @@ -18,7 +51,7 @@ PyObject* make_raw_ostream_for_printing(PyObject* self, PyObject* args) { static PyObject* make_small_vector_from_types(PyObject* self, PyObject* args) { using llvm::Type; - using llvm::SmallVector_Type; + typedef llvm::SmallVector SmallVector_Type; SmallVector_Type* SV = new SmallVector_Type; Py_ssize_t size = PyTuple_Size(args); @@ -33,7 +66,7 @@ PyObject* make_small_vector_from_types(PyObject* self, PyObject* args) { } SV->push_back(type); } - return pycapsule_new(SV, "llvm::SmallVector_Type"); + return pycapsule_new(SV, "llvm::SmallVector"); } static PyMethodDef extra_methodtable[] = { @@ -43,3 +76,17 @@ static PyMethodDef extra_methodtable[] = { #undef method { NULL } }; + + +//////////// + +PyObject* Value_use_iterator_to_list(llvm::Value* val){ + typedef llvm::Value::use_iterator iterator; + PyObject* list = PyList_New(0); + for (iterator it = val->use_begin(), end = val->use_end(); it != end; ++it) { + PyObject* cap = pycapsule_new(*it, "llvm::Value", "llvm::User"); + PyList_Append(list, cap); + } + return list; +} + diff --git a/newbinding/include/llvm_binding/llvm_extra.h b/newbinding/include/llvm_binding/llvm_extra.h deleted file mode 100644 index f920a47..0000000 --- a/newbinding/include/llvm_binding/llvm_extra.h +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#include - -namespace llvm{ - -class Type; //forward declaration - -class raw_svector_ostream_helper: public raw_svector_ostream { - SmallVectorImpl *SV; -public: - static - raw_svector_ostream_helper* create(){ - SmallVectorImpl* sv = new SmallVector(); - return new raw_svector_ostream_helper(sv); - } - - ~raw_svector_ostream_helper(){ - delete SV; - } - -protected: - - explicit - raw_svector_ostream_helper(SmallVectorImpl* sv) - : raw_svector_ostream(*sv), SV(sv) {} - -private: - // no copy - raw_svector_ostream_helper(const raw_svector_ostream_helper&); - // no assign - void operator = (const raw_svector_ostream_helper&); -}; - -typedef SmallVector SmallVector_Type; - -} // end namespace llvm - diff --git a/newbinding/src/SmallVector.py b/newbinding/src/SmallVector.py index d00b294..55dadb1 100644 --- a/newbinding/src/SmallVector.py +++ b/newbinding/src/SmallVector.py @@ -3,4 +3,5 @@ from namespace import llvm @llvm.Class() class SmallVector_Type: + _realname_ = 'SmallVector' delete = Destructor() diff --git a/newbinding/src/Value.py b/newbinding/src/Value.py index a901946..3dd5644 100644 --- a/newbinding/src/Value.py +++ b/newbinding/src/Value.py @@ -32,8 +32,7 @@ class Value: replaceAllUsesWith = Method(Void, ptr(Value)) - list_use = IterToList(ptr(User), (), 'llvm::Value::use_iterator', - 'use_begin', 'use_end') + list_use = CustomMethod('Value_use_iterator_to_list', PyObjectPtr) hasOneUse = Method(cast(Bool, bool)) hasNUses = Method(cast(Bool, bool), cast(int, Unsigned)) From 7aa9487f2f66e7003f14fe7835de2293de4b9d60 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 28 Jan 2013 16:00:25 -0600 Subject: [PATCH 232/516] pycapsule_new should return a None object if ptr is NULL. --- newbinding/include/llvm_binding/capsule_context.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/newbinding/include/llvm_binding/capsule_context.h b/newbinding/include/llvm_binding/capsule_context.h index a4070dc..ed63e43 100644 --- a/newbinding/include/llvm_binding/capsule_context.h +++ b/newbinding/include/llvm_binding/capsule_context.h @@ -23,6 +23,9 @@ PyObject* pycapsule_new(void* ptr, if (!classname) { classname = basename; } + if (!ptr) { + Py_RETURN_NONE; + } PyObject* cap = PyCapsule_New(ptr, basename, NULL); if (!cap) { PyErr_SetString(PyExc_TypeError, "Error creating new PyCapsule"); From 895d1147300d13608763aa61b8ab2b9f56bd7662 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 28 Jan 2013 16:36:46 -0600 Subject: [PATCH 233/516] Add CustonPythonMethod and CustonPythonStaticMethod. --- newbinding/binding.py | 24 ++++++++++++++++++++++++ newbinding/src/BasicBlock.py | 3 +++ newbinding/src/DerivedTypes.py | 19 +++++++++++++++++-- newbinding/src/Value.py | 7 +++++++ newbinding/test2.py | 26 +++++++++++++++----------- 5 files changed, 66 insertions(+), 13 deletions(-) diff --git a/newbinding/binding.py b/newbinding/binding.py index 3538c9a..6668452 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -1,3 +1,4 @@ +import inspect, textwrap import functools import codegen as cg @@ -56,6 +57,7 @@ class Class(_Type): self.bases = bases self._is_defined = False self.methods = [] + self.pymethods = [] self.enums = [] self.includes = set() self.downcastables = set() @@ -76,6 +78,8 @@ class Class(_Type): self.enums.append(v) v.name = k v.parent = self + elif isinstance(v, CustomPythonMethod): + self.pymethods.append(v) elif k == '_include_': if isinstance(v, str): self.includes.add(v) @@ -122,6 +126,8 @@ class Class(_Type): enum.compile_py(writer) for meth in self.methods: meth.compile_py(writer) + for meth in self.pymethods: + meth.compile_py(writer) writer.println() @property @@ -453,3 +459,21 @@ class cast(_Type): +class CustomPythonMethod(object): + def __init__(self, fn): + src = inspect.getsource(fn) + lines = textwrap.dedent(src).splitlines() + for i, line in enumerate(lines): + if not line.startswith('@'): + break + self.sourcelines = lines[i:] + + def compile_py(self, writer): + for line in self.sourcelines: + writer.println(line) + +class CustomPythonStaticMethod(CustomPythonMethod): + def compile_py(self, writer): + writer.println('@staticmethod') + super(CustomPythonStaticMethod, self).compile_py(writer) + diff --git a/newbinding/src/BasicBlock.py b/newbinding/src/BasicBlock.py index c7221a5..b0716cd 100644 --- a/newbinding/src/BasicBlock.py +++ b/newbinding/src/BasicBlock.py @@ -1,6 +1,7 @@ from binding import * from namespace import llvm from Value import Function, BasicBlock +from Instruction import Instruction, TerminatorInst from LLVMContext import LLVMContext from StringRef import StringRef @@ -12,6 +13,8 @@ class BasicBlock: ptr(BasicBlock)) getParent = Method(ptr(Function)) + getTerminator = Method(ptr(TerminatorInst)) + empty = Method(cast(Bool, bool)) dropAllReferences = Method() isLandingPad = Method(cast(Bool, bool)) diff --git a/newbinding/src/DerivedTypes.py b/newbinding/src/DerivedTypes.py index c57e01b..efce8b8 100644 --- a/newbinding/src/DerivedTypes.py +++ b/newbinding/src/DerivedTypes.py @@ -9,8 +9,23 @@ FunctionType = llvm.Class(Type) @FunctionType class FunctionType: _include_ = 'llvm/DerivedTypes.h' - get = StaticMethod(ptr(FunctionType), ptr(Type), cast(bool, Bool)) - get |= StaticMethod(ptr(FunctionType), ptr(Type), ref(SmallVector_Type), cast(bool, Bool)) + + _get = StaticMethod(ptr(FunctionType), ptr(Type), cast(bool, Bool)) + _get |= StaticMethod(ptr(FunctionType), ptr(Type), ref(SmallVector_Type), + cast(bool, Bool)) + _get.realname = 'get' + + @CustomPythonStaticMethod + def get(*args): + import extra + if len(args) == 3: + typelist = args[1] + sv = extra.make_small_vector_from_types(*typelist) + return FunctionType._get(args[0], sv, args[2]) + else: + return FunctionType._get(*args) + + isVarArg = Method(cast(Bool, bool)) getReturnType = Method(ptr(Type)) getParamType = Method(ptr(Type), cast(int, Unsigned)) diff --git a/newbinding/src/Value.py b/newbinding/src/Value.py index 3dd5644..5345337 100644 --- a/newbinding/src/Value.py +++ b/newbinding/src/Value.py @@ -37,3 +37,10 @@ class Value: hasOneUse = Method(cast(Bool, bool)) hasNUses = Method(cast(Bool, bool), cast(int, Unsigned)) isUsedInBasicBlock = Method(cast(Bool, bool), BasicBlock) + + @CustomPythonMethod + def __str__(self): + import extra + os = extra.make_raw_ostream_for_printing() + self.print_(os, None) + return os.str() diff --git a/newbinding/test2.py b/newbinding/test2.py index 810a7ba..3e54aee 100644 --- a/newbinding/test2.py +++ b/newbinding/test2.py @@ -30,24 +30,18 @@ fnty = api.FunctionType.get(int1ty, False) fnty.dump() types = [int1ty, api.Type.getIntNTy(context, 21)] -svt = extra.make_small_vector_from_types(*types) -fnty = api.FunctionType.get(int1ty, svt, False) +fnty = api.FunctionType.get(int1ty, types, False) -os = extra.make_raw_ostream_for_printing() -fnty.print_(os) -print os.str() +print fnty const = m.getOrInsertFunction("foo", fnty) fn = extra.downcast(const, api.Function) -os = extra.make_raw_ostream_for_printing() -fn.print_(os, None) -print os.str() +print fn assert fn.hasName() assert 'foo' == fn.getName() fn.setName('bar') assert 'bar' == fn.getName() -os = extra.make_raw_ostream_for_printing() assert fn.getReturnType() is int1ty assert fnty is fn.getFunctionType() @@ -56,14 +50,24 @@ assert fn.isVarArg() == False assert fn.getIntrinsicID() == 0 assert not fn.isIntrinsic() -print fn.list_use() +fn_uselist = fn.list_use() +assert isinstance(fn_uselist, list) +assert len(fn_uselist) == 0 builder = api.IRBuilder.new(context) print builder bb = api.BasicBlock.Create(context, "entry", fn, None) +assert bb.empty() builder.SetInsertPoint(bb) +assert bb.getTerminator() is None + builder.CreateRetVoid() -fn.dump() +assert not bb.empty() +assert bb.getTerminator() is not None + +print bb + + From 59d0dfddc733f44252c244bd0a5d496337f82000 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 28 Jan 2013 17:55:52 -0600 Subject: [PATCH 234/516] Continue to implement IRBuilder --- newbinding/capsule.py | 8 ++- newbinding/include/llvm_binding/extra.h | 87 ++++++++++++++++++++++--- newbinding/src/Argument.py | 9 +++ newbinding/src/Function.py | 4 +- newbinding/src/IRBuilder.py | 19 +++++- newbinding/src/SmallVector.py | 6 ++ newbinding/src/Value.py | 1 + newbinding/test2.py | 10 +-- 8 files changed, 125 insertions(+), 19 deletions(-) create mode 100644 newbinding/src/Argument.py diff --git a/newbinding/capsule.py b/newbinding/capsule.py index 47c32fb..eaef7da 100644 --- a/newbinding/capsule.py +++ b/newbinding/capsule.py @@ -52,8 +52,10 @@ def wrap(cap): '''Wrap a PyCapsule with the corresponding Wrapper class. If `cap` is not a PyCapsule, returns `cap` ''' - if not _capsule.check(cap): # bypass if cap is not a PyCapsule - return cap + if not _capsule.check(cap): + if isinstance(cap, list): + return map(wrap, cap) + return cap # bypass if cap is not a PyCapsule and not a list addr = _capsule.getPointer(cap) try: # find cached object by pointer address @@ -77,7 +79,7 @@ def wrap(cap): # do auto downcast pass else: - assert oldcls is newcls + assert oldcls is newcls, (cap, obj, oldcls, newcls) return obj def downcast(old, new): diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h index 639a87c..9f2bd70 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/extra.h @@ -1,6 +1,7 @@ #include #include #include +#include #include @@ -11,12 +12,14 @@ namespace extra{ SmallVectorImpl *SV; public: static - raw_svector_ostream_helper* create(){ + raw_svector_ostream_helper* create() + { SmallVectorImpl* sv = new SmallVector(); return new raw_svector_ostream_helper(sv); } - ~raw_svector_ostream_helper(){ + ~raw_svector_ostream_helper() + { delete SV; } @@ -36,7 +39,8 @@ namespace extra{ } static -PyObject* make_raw_ostream_for_printing(PyObject* self, PyObject* args) { +PyObject* make_raw_ostream_for_printing(PyObject* self, PyObject* args) +{ using extra::raw_svector_ostream_helper; using llvm::raw_svector_ostream; @@ -49,7 +53,8 @@ PyObject* make_raw_ostream_for_printing(PyObject* self, PyObject* args) { } static -PyObject* make_small_vector_from_types(PyObject* self, PyObject* args) { +PyObject* make_small_vector_from_types(PyObject* self, PyObject* args) +{ using llvm::Type; typedef llvm::SmallVector SmallVector_Type; @@ -69,24 +74,88 @@ PyObject* make_small_vector_from_types(PyObject* self, PyObject* args) { return pycapsule_new(SV, "llvm::SmallVector"); } +static +PyObject* make_small_vector_from_values(PyObject* self, PyObject* args) +{ + using llvm::Value; + typedef llvm::SmallVector SmallVector_Value; + + SmallVector_Value* SV = new SmallVector_Value; + Py_ssize_t size = PyTuple_Size(args); + for (Py_ssize_t i = 0; i < size; ++i) { + PyObject* cap = PyTuple_GetItem(args, i); + if (!cap) { + return NULL; + } + Value* value = (Value*)PyCapsule_GetPointer(cap, "llvm::Value"); + if (!value) { + return NULL; + } + SV->push_back(value); + } + return pycapsule_new(SV, "llvm::SmallVector"); +} + + static PyMethodDef extra_methodtable[] = { #define method(func) { #func, (PyCFunction)func, METH_VARARGS, NULL } method( make_raw_ostream_for_printing ), method( make_small_vector_from_types ), + method( make_small_vector_from_values ), #undef method { NULL } }; //////////// - -PyObject* Value_use_iterator_to_list(llvm::Value* val){ - typedef llvm::Value::use_iterator iterator; +template +PyObject* iterator_to_pylist_deref(iterator begin, iterator end, + const char *capsuleName, const char *className) +{ PyObject* list = PyList_New(0); - for (iterator it = val->use_begin(), end = val->use_end(); it != end; ++it) { - PyObject* cap = pycapsule_new(*it, "llvm::Value", "llvm::User"); + for(; begin != end; ++begin) { + PyObject* cap = pycapsule_new(&*begin, capsuleName, className); PyList_Append(list, cap); } return list; } +template +PyObject* iterator_to_pylist(iterator begin, iterator end, + const char *capsuleName, const char *className) +{ + PyObject* list = PyList_New(0); + for(; begin != end; ++begin) { + PyObject* cap = pycapsule_new(*begin, capsuleName, className); + PyList_Append(list, cap); + } + return list; +} + +template +PyObject* iplist_to_pylist(iplist &IPL, const char * capsuleName, + const char* className){ + return iterator_to_pylist_deref(IPL.begin(), IPL.end(), capsuleName, + className); +} + +static +PyObject* Value_use_iterator_to_list(llvm::Value* val) +{ + return iterator_to_pylist(val->use_begin(), val->use_end(), + "llvm::Value", "llvm::User"); +} + +static +PyObject* Function_getArgumentList(llvm::Function* fn) +{ + return iplist_to_pylist(fn->getArgumentList(), "llvm::Value", + "llvm::Argument"); +} + +static +PyObject* Function_getBasicBlockList(llvm::Function* fn) +{ + return iplist_to_pylist(fn->getBasicBlockList(), "llvm::Value", + "llvm::BasicBlock"); +} \ No newline at end of file diff --git a/newbinding/src/Argument.py b/newbinding/src/Argument.py new file mode 100644 index 0000000..08b35be --- /dev/null +++ b/newbinding/src/Argument.py @@ -0,0 +1,9 @@ +from binding import * +from namespace import llvm +from Value import Argument + +@Argument +class Argument: + _include_ = 'llvm/Argument.h' + + diff --git a/newbinding/src/Function.py b/newbinding/src/Function.py index f069e30..5cebf84 100644 --- a/newbinding/src/Function.py +++ b/newbinding/src/Function.py @@ -1,6 +1,6 @@ from binding import * from namespace import llvm -from Value import GlobalValue, Constant, Function +from Value import GlobalValue, Constant, Function, Argument from Type import Type from DerivedTypes import FunctionType from LLVMContext import LLVMContext @@ -17,3 +17,5 @@ class Function: getIntrinsicID = Method(cast(Unsigned, int)) isIntrinsic = Method(cast(Bool, bool)) + getArgumentList = CustomMethod('Function_getArgumentList', PyObjectPtr) + getBasicBlockList = CustomMethod('Function_getBasicBlockList', PyObjectPtr) diff --git a/newbinding/src/IRBuilder.py b/newbinding/src/IRBuilder.py index 0919a67..41e6681 100644 --- a/newbinding/src/IRBuilder.py +++ b/newbinding/src/IRBuilder.py @@ -2,7 +2,10 @@ from binding import * from namespace import llvm from LLVMContext import LLVMContext from BasicBlock import BasicBlock -from Instruction import ReturnInst +from Instruction import ReturnInst, CallInst +from SmallVector import SmallVector_Value +from StringRef import StringRef +from Value import Value IRBuilder = llvm.Class() @@ -19,3 +22,17 @@ class IRBuilder: isNamePreserving = Method(cast(Bool, bool)) CreateRetVoid = Method(ptr(ReturnInst)) + CreateRet = Method(ptr(ReturnInst), ptr(Value)) + + _CreateCall = Method(ptr(CallInst), ptr(Value), ref(SmallVector_Value), + cast(str, StringRef)) + _CreateCall |= Method(ptr(CallInst), ptr(Value), ref(SmallVector_Value)) + _CreateCall.realname = 'CreateCall' + + @CustomPythonMethod + def CreateCall(self, *args): + import extra + args = list(args) + valuelist = args[1] + args[1] = extra.make_small_vector_from_values(*valuelist) + return IRBuilder._CreateCall(self, *args) diff --git a/newbinding/src/SmallVector.py b/newbinding/src/SmallVector.py index 55dadb1..594faf8 100644 --- a/newbinding/src/SmallVector.py +++ b/newbinding/src/SmallVector.py @@ -5,3 +5,9 @@ from namespace import llvm class SmallVector_Type: _realname_ = 'SmallVector' delete = Destructor() + +@llvm.Class() +class SmallVector_Value: + _realname_ = 'SmallVector' + delete = Destructor() + diff --git a/newbinding/src/Value.py b/newbinding/src/Value.py index 5345337..5b907bd 100644 --- a/newbinding/src/Value.py +++ b/newbinding/src/Value.py @@ -8,6 +8,7 @@ from StringRef import StringRef Value = llvm.Class() # forward declarations +Argument = llvm.Class(Value) User = llvm.Class(Value) BasicBlock = llvm.Class(Value) Constant = llvm.Class(User) diff --git a/newbinding/test2.py b/newbinding/test2.py index 3e54aee..a7a4ddd 100644 --- a/newbinding/test2.py +++ b/newbinding/test2.py @@ -63,11 +63,11 @@ builder.SetInsertPoint(bb) assert bb.getTerminator() is None -builder.CreateRetVoid() +arg0, arg1 = fn.getArgumentList() +print arg0, arg1 -assert not bb.empty() -assert bb.getTerminator() is not None - -print bb +ret = builder.CreateCall(fn, [arg0, arg1], '') +builder.CreateRet(ret) +print fn From 437b1e949012595882f8fbb3065c0c7e4c9b0835 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 29 Jan 2013 17:47:15 -0600 Subject: [PATCH 235/516] All of DataLayout, IRBuilder and started on ExecutionEngine. --- newbinding/binding.py | 114 ++++++++- newbinding/capsule.py | 22 +- newbinding/codegen.py | 12 +- newbinding/gen.py | 11 +- .../include/llvm_binding/capsule_context.h | 10 + newbinding/include/llvm_binding/extra.h | 81 +++++- newbinding/src/CodeGen.py | 19 ++ newbinding/src/DataLayout.py | 97 +++++++ newbinding/src/ExecutionEngine.py | 34 +++ newbinding/src/GlobalVariable.py | 8 + newbinding/src/IRBuilder.py | 241 +++++++++++++++++- newbinding/src/Instruction.py | 32 ++- newbinding/src/JITMemoryManager.py | 7 + newbinding/src/Metadata.py | 7 + newbinding/src/Module.py | 3 +- newbinding/src/SmallVector.py | 4 + newbinding/src/TargetSelect.py | 8 + newbinding/src/Type.py | 4 + newbinding/src/Value.py | 1 + newbinding/test2.py | 14 + 20 files changed, 688 insertions(+), 41 deletions(-) create mode 100644 newbinding/src/CodeGen.py create mode 100644 newbinding/src/DataLayout.py create mode 100644 newbinding/src/ExecutionEngine.py create mode 100644 newbinding/src/GlobalVariable.py create mode 100644 newbinding/src/JITMemoryManager.py create mode 100644 newbinding/src/Metadata.py create mode 100644 newbinding/src/TargetSelect.py diff --git a/newbinding/binding.py b/newbinding/binding.py index 6668452..f7d5ac4 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -5,11 +5,15 @@ import codegen as cg _rank = 0 namespaces = {} +RESERVED = frozenset(['None']) + class Namespace(object): def __init__(self, name): self.name = name + self.enums = [] self.classes = [] self.functions = [] + self.includes = set() namespaces[name] = self def Class(self, *bases): @@ -22,6 +26,13 @@ class Namespace(object): self.functions.append(fn) return fn + def Enum(self, name, *value_names): + enum = Enum(*value_names) + enum.parent = self + enum.name = name + self.enums.append(enum) + return enum + @property def fullname(self): return self.name @@ -43,11 +54,16 @@ class BuiltinTypes(_Type): def wrap(self, writer, var): return var + def unwrap(self, writer, var): + return var + Void = BuiltinTypes('void') Unsigned = BuiltinTypes('unsigned') +Uint64 = BuiltinTypes('uint64_t') Bool = BuiltinTypes('bool') ConstStdString = BuiltinTypes('const std::string') PyObjectPtr = BuiltinTypes('PyObject*') +PyObjectPtr.format='O' class Class(_Type): format = 'O' @@ -78,6 +94,7 @@ class Class(_Type): self.enums.append(v) v.name = k v.parent = self + setattr(self, k, v) elif isinstance(v, CustomPythonMethod): self.pymethods.append(v) elif k == '_include_': @@ -108,7 +125,7 @@ class Class(_Type): fmt = '{ "%(name)s", (PyCFunction)%(func)s, METH_VARARGS, NULL },' for meth in self.methods: name = meth.name - func = cg.mangle(meth.fullname) + func = meth.c_name writer.println(fmt % locals()) writer.println('{ NULL },') writer.println('};') @@ -161,9 +178,12 @@ class Class(_Type): return casted class Enum(object): + format = 'O' + def __init__(self, *value_names): self.parent = None self.value_names = value_names + self.includes = set() @property def fullname(self): @@ -191,11 +211,34 @@ class Enum(object): writer.raises(ValueError, 'Invalid enum %s' % v) return ret + def unwrap(self, writer, val): + tostring = 'PyString_AsString(%(val)s)' % locals() + string = writer.declare('const char*', tostring) + ret = writer.declare('%s::%s' % (self.parent, self.name)) + parent = self.parent + iffmt = 'if (string_equal(%(string)s, "%(v)s"))' + for i, v in enumerate(self.value_names): + with writer.block(iffmt % locals()): + fmt = '%(ret)s = %(parent)s::%(v)s;' + writer.println(fmt % locals()) + if i == 0: + iffmt = 'else ' + iffmt + with writer.block('else'): + writer.raises(ValueError, 'Invalid enum.') + return ret + + def compile_cpp(self, writer): + pass + def compile_py(self, writer): with writer.block('class %s:' % self.name): writer.println('_llvm_type_ = "%s"' % self.fullname) for v in self.value_names: - writer.println('%(v)s = "%(v)s"' % locals()) + if v in RESERVED: + k = '%s_' % v + else: + k = v + writer.println('%(k)s = "%(v)s"' % locals()) writer.println() class Method(object): @@ -236,11 +279,15 @@ class Method(object): def realname(self, v): self.__realname = v + @property + def c_name(self): + return cg.mangle("%s_%s" % (self.parent, self.name)) + def __str__(self): return self.fullname def compile_cpp(self, writer): - with writer.py_function(self.fullname): + with writer.py_function(self.c_name): if len(self.signatures) == 1: sig = self.signatures[0] retty = sig[0] @@ -270,13 +317,40 @@ class Method(object): with decl as (this, varargs): unwrap_this = writer.unwrap(this) unwrapped = writer.unwrap_many(varargs) + self.process_ownedptr_args(writer, unwrapped) + func = '.'.join([self.parent.name, self.name]) ret = writer.call('_api.%s' % func, args=(unwrap_this,), varargs=unwrapped) - wrapped = writer.wrap(ret) + + wrapped = writer.wrap(ret, self.is_return_ownedptr()) + writer.return_value(wrapped) writer.println() + def require_only(self, num): + '''Require only "num" of argument. + ''' + assert len(self.signatures) == 1 + sig = self.signatures[0] + ret = sig[0] + args = sig[1:] + arg_ct = len(args) + + for i in range(num, arg_ct): + self._add_signature(ret, *args[:i]) + + return self + + def is_return_ownedptr(self): + retty = self.signatures[0][0] + return isinstance(retty, ownedptr) + + def process_ownedptr_args(self, writer, unwrapped): + argtys = self.signatures[0][1:] + for i, ty in enumerate(argtys): + if isinstance(ty, ownedptr): + writer.release_ownership('%s[%d]' % (unwrapped, i)) class CustomMethod(Method): def __init__(self, methodname, retty, *argtys): @@ -289,7 +363,6 @@ class CustomMethod(Method): writer.return_value(retty.wrap(writer, ret)) - class StaticMethod(Method): def compile_cpp_body(self, writer, retty, argtys): @@ -307,12 +380,24 @@ class StaticMethod(Method): decl = writer.function(self.name, varargs='args') with decl as varargs: unwrapped = writer.unwrap_many(varargs) + self.process_ownedptr_args(writer, unwrapped) + func = '.'.join([self.parent.name, self.name]) ret = writer.call('_api.%s' % func, varargs=unwrapped) - wrapped = writer.wrap(ret) + wrapped = writer.wrap(ret, self.is_return_ownedptr()) writer.return_value(wrapped) writer.println() +class CustomStaticMethod(StaticMethod): + def __init__(self, methodname, retty, *argtys): + super(CustomStaticMethod, self).__init__(retty, *argtys) + self.methodname = methodname + + def compile_cpp_body(self, writer, retty, argtys): + args = writer.parse_arguments('args', *argtys) + ret = writer.call(self.methodname, retty.fullname, *args) + writer.return_value(retty.wrap(writer, ret)) + class Function(Method): _kind_ = 'func' @@ -329,10 +414,11 @@ class Function(Method): def compile_py(self, writer): with writer.function(self.name, varargs='args') as varargs: unwrapped = writer.unwrap_many(varargs) + self.process_ownedptr_args(writer, unwrapped) func = self.fullname.split('::', 1)[1].replace('::', '.') ret = writer.call('_api.%s' % func, varargs=unwrapped) - wrapped = writer.wrap(ret) + wrapped = writer.wrap(ret, self.is_return_ownedptr()) writer.return_value(wrapped) writer.println() @@ -400,10 +486,14 @@ class ptr(_Type): def __init__(self, element): assert isinstance(element, Class) self.element = element + self.const = False @property def fullname(self): - return '%s*' % self.element + if self.const: + return 'const %s*' % self.element + else: + return '%s*' % self.element @property def format(self): @@ -420,6 +510,13 @@ class ptr(_Type): return writer.pycapsule_new(val, self.element.capsule_name, self.element.fullname) +class ownedptr(ptr): + pass + +def const(ptr): + ptr.const = True + return ptr + class cast(_Type): format = 'O' @@ -458,7 +555,6 @@ class cast(_Type): return ret - class CustomPythonMethod(object): def __init__(self, fn): src = inspect.getsource(fn) diff --git a/newbinding/capsule.py b/newbinding/capsule.py index eaef7da..f489c7f 100644 --- a/newbinding/capsule.py +++ b/newbinding/capsule.py @@ -23,10 +23,11 @@ class WeakRef(ref): _pyclasses = {} _addr2obj = WeakValueDictionary() -_owners = {} +_owners = {} # address to weak reference def _sentry(ptr): - assert _capsule.check(ptr) + if not _capsule.check(ptr): + raise ValueError('Must provide a PyCapsule object.') def classof(cap): cls = _capsule.getClassName(cap) @@ -38,17 +39,16 @@ def _capsule_destructor(weak): addr = _capsule.getPointer(cap) cls = _capsule.getClassName(cap) logger.debug("destroy pointer 0x%08X to %s", addr, cls) - weak.dtor(cap) +# weak.dtor(cap) del _owners[addr] def release_ownership(old): addr = _capsule.getPointer(old) - if hasattr(old, '_delete_'): - oldweak = _owners[addr] - oldweak.owning = False # dis-own - del _owners[addr] + oldweak = _owners[addr] + oldweak.owning = False # dis-own + del _owners[addr] -def wrap(cap): +def wrap(cap, owned=False): '''Wrap a PyCapsule with the corresponding Wrapper class. If `cap` is not a PyCapsule, returns `cap` ''' @@ -66,7 +66,8 @@ def wrap(cap): obj = cls(cap) _addr2obj[addr] = obj # cache object by address # set ownership if *cls* defines *_delete_* - if hasattr(cls, '_delete_'): + if not owned and hasattr(cls, '_delete_'): + assert addr not in _owners, "has existing owner" weak = WeakRef(obj, _capsule_destructor) _owners[addr] = weak weak.capsule = cap @@ -84,10 +85,11 @@ def wrap(cap): def downcast(old, new): assert old is not new + assert _capsule.getPointer(old) not in _owners oldcls = classof(old) newcls = classof(new) assert issubclass(newcls, oldcls) - release_ownership(old) + # release_ownership(old) del _addr2obj[_capsule.getPointer(old)] # clear cache return wrap(new) diff --git a/newbinding/codegen.py b/newbinding/codegen.py index 7652447..5a31e38 100644 --- a/newbinding/codegen.py +++ b/newbinding/codegen.py @@ -104,10 +104,9 @@ class CodeWriterBase(object): @contextlib.contextmanager def py_function(self, name): - mangled = mangle(name) self.println('static') self.println('PyObject*') - with self.block('%(mangled)s(PyObject* self, PyObject* args)' % locals()): + with self.block('%(name)s(PyObject* self, PyObject* args)' % locals()): self.used_symbols.add('self') self.used_symbols.add('args') yield @@ -175,7 +174,7 @@ class CppCodeWriter(CodeWriterBase): arglist = ', '.join(args) stmt = '%(func)s(%(arglist)s)' % locals() if retty == 'void': - self.println(stmt) + self.println(stmt + ';') else: return self.declare(retty, stmt) @@ -247,6 +246,9 @@ class PyCodeWriter(CodeWriterBase): yield self.used_symbols = self.old + def release_ownership(self, val): + self.println('capsule.release_ownership(%(val)s)' % locals()) + def unwrap_many(self, args): unwrapped = self.new_symbol('unwrapped') self.println('%(unwrapped)s = map(capsule.unwrap, %(args)s)' % locals()) @@ -255,9 +257,9 @@ class PyCodeWriter(CodeWriterBase): def unwrap(self, val): return self.call('capsule.unwrap', args=(val,), ret='unwrapped') - def wrap(self, val): + def wrap(self, val, owned): wrapped = self.new_symbol('wrapped') - self.println('%(wrapped)s = capsule.wrap(%(val)s)' % locals()) + self.println('%(wrapped)s = capsule.wrap(%(val)s, %(owned)s)' % locals()) return wrapped def call(self, func, args=(), varargs=None, ret='ret'): diff --git a/newbinding/gen.py b/newbinding/gen.py index d9fc14f..47f5655 100644 --- a/newbinding/gen.py +++ b/newbinding/gen.py @@ -39,6 +39,7 @@ populate_submodules(module, submodules); def populate_headers(println): includes = [ + 'cstring', 'llvm_binding/conversion.h', 'llvm_binding/binding.h', 'llvm_binding/capsule_context.h', @@ -70,6 +71,9 @@ def main(): for cls in ns.classes: print cls units.append(cls) + for enum in ns.enums: + print enum + units.append(enum) # add extra stuffs downcastlist = [] @@ -84,7 +88,7 @@ def main(): units.append(fn) - # generate cpp source + # Generate C++ source with open('%s.cpp' % outputfilename, 'w') as cppfile: println = wrap_println_from_file(cppfile) @@ -93,6 +97,8 @@ def main(): # required headers includes = set() + for ns in namespaces.values(): + includes |= ns.includes for u in units: includes |= u.includes @@ -128,7 +134,7 @@ static for u in units: if isinstance(u, Function): name = u.name - func = codegen.mangle(u.fullname) + func = u.c_name writer.println(fmt % locals()) writer.println('{ NULL },') writer.println('};') @@ -154,6 +160,7 @@ static println(extension_entry % {'module': '_api', 'methtable': 'methtable'}) + # Generate Python source with open('%s.py' % outputfilename, 'w') as pyfile: println = wrap_println_from_file(pyfile) println('import _api, capsule') diff --git a/newbinding/include/llvm_binding/capsule_context.h b/newbinding/include/llvm_binding/capsule_context.h index ed63e43..6ed1381 100644 --- a/newbinding/include/llvm_binding/capsule_context.h +++ b/newbinding/include/llvm_binding/capsule_context.h @@ -39,6 +39,16 @@ PyObject* pycapsule_new(void* ptr, } +static +PyObject* pycapsule_new(const void* ptr, + const char* basename, + const char* classname=NULL) +{ + // Use const_cast to strip the constantness. + // Let the user take the responsibility. + return pycapsule_new(const_cast(ptr), basename, classname); +} + #endif //LLVMPY_CAPSULE_CONTEXT_H_ diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h index 9f2bd70..b5edd2c 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/extra.h @@ -3,7 +3,7 @@ #include #include #include - +#include namespace extra{ using namespace llvm; @@ -97,11 +97,34 @@ PyObject* make_small_vector_from_values(PyObject* self, PyObject* args) } +static +PyObject* make_small_vector_from_unsigned(PyObject* self, PyObject* args) +{ + using llvm::Value; + typedef llvm::SmallVector SmallVector_Unsigned; + + SmallVector_Unsigned* SV = new SmallVector_Unsigned; + Py_ssize_t size = PyTuple_Size(args); + for (Py_ssize_t i = 0; i < size; ++i) { + PyObject* item = PyTuple_GetItem(args, i); + if (!item) { + return NULL; + } + unsigned value = PyLong_AsUnsignedLong(item); + if (PyErr_Occurred()){ + return NULL; + } + SV->push_back(value); + } + return pycapsule_new(SV, "llvm::SmallVector"); +} + static PyMethodDef extra_methodtable[] = { #define method(func) { #func, (PyCFunction)func, METH_VARARGS, NULL } method( make_raw_ostream_for_printing ), method( make_small_vector_from_types ), method( make_small_vector_from_values ), + method( make_small_vector_from_unsigned ), #undef method { NULL } }; @@ -139,11 +162,20 @@ PyObject* iplist_to_pylist(iplist &IPL, const char * capsuleName, className); } +static +bool string_equal(const char *A, const char *B){ + for (; *A and *B; ++A, ++B) { + if (*A != *B) return false; + } + return true; +} + +//////////// static PyObject* Value_use_iterator_to_list(llvm::Value* val) { return iterator_to_pylist(val->use_begin(), val->use_end(), - "llvm::Value", "llvm::User"); + "llvm::Value", "llvm::User"); } static @@ -158,4 +190,47 @@ PyObject* Function_getBasicBlockList(llvm::Function* fn) { return iplist_to_pylist(fn->getBasicBlockList(), "llvm::Value", "llvm::BasicBlock"); -} \ No newline at end of file +} + +/* + * errout --- can be any file object + * + */ +static +llvm::ExecutionEngine* ExecutionEngine_create( + llvm::Module* M, + bool ForceInterpreter = false, + PyObject* errout = 0, + llvm::CodeGenOpt::Level OptLevel = llvm::CodeGenOpt::Default, + bool GVsWithCode = true) +{ + using namespace llvm; + std::string ErrorStr; + ExecutionEngine *ee = ExecutionEngine::create(M, ForceInterpreter, + &ErrorStr, OptLevel, + GVsWithCode); + PyFile_WriteString(ErrorStr.c_str(), errout); + return ee; +} + +/* + * errout --- can be any file object + * + */ +static +llvm::ExecutionEngine* ExecutionEngine_createJIT( + llvm::Module* M, + PyObject* errout = 0, + llvm::JITMemoryManager* JMM = 0, + llvm::CodeGenOpt::Level OL = llvm::CodeGenOpt::Default, + bool GCsWithCode = true, + llvm::Reloc::Model RM = llvm::Reloc::Default, + llvm::CodeModel::Model CMM = llvm::CodeModel::JITDefault) +{ + using namespace llvm; + std::string ErrorStr; + ExecutionEngine *ee = ExecutionEngine::createJIT(M, &ErrorStr, JMM, OL, + GCsWithCode, RM, CMM); + PyFile_WriteString(ErrorStr.c_str(), errout); + return ee; +} diff --git a/newbinding/src/CodeGen.py b/newbinding/src/CodeGen.py new file mode 100644 index 0000000..06821aa --- /dev/null +++ b/newbinding/src/CodeGen.py @@ -0,0 +1,19 @@ +from binding import * +from namespace import llvm + +@llvm.Class() +class Reloc: + Model = Enum('Default', 'Static', 'PIC_', 'DynamicNoPIC') + +@llvm.Class() +class CodeModel: + Model = Enum('Default', 'JITDefault', 'Small', 'Kernel', 'Medium', 'Large') + +@llvm.Class() +class TLSModel: + Model = Enum('GeneralDynamic', 'LocalDynamic', 'InitialExec', 'LocalExec') + +@llvm.Class() +class CodeGenOpt: + 'Actually a namespace' + Level = Enum('None', 'Less', 'Default', 'Aggressive') diff --git a/newbinding/src/DataLayout.py b/newbinding/src/DataLayout.py new file mode 100644 index 0000000..a1ef8bc --- /dev/null +++ b/newbinding/src/DataLayout.py @@ -0,0 +1,97 @@ +from binding import * +from namespace import llvm +from LLVMContext import LLVMContext +from StringRef import StringRef +from Module import Module +from Type import Type, IntegerType, StructType +from SmallVector import SmallVector_Value +from GlobalVariable import GlobalVariable + +DataLayout = llvm.Class() +StructLayout = llvm.Class() + +@DataLayout +class DataLayout: + _include_ = 'llvm/DataLayout.h' + + _new_string = Constructor(cast(str, StringRef)) + _new_module = Constructor(ptr(Module)) + + @CustomPythonStaticMethod + def new(arg): + if isinstance(arg, Module): + return DataLayout._new_module(arg) + else: + return DataLayout._new_string(arg) + + delete = Destructor() + + isLittleEndian = Method(cast(Bool, bool)) + isBigEndian = Method(cast(Bool, bool)) + + getStringRepresentation = Method(cast(StringRef, str)) + + @CustomPythonMethod + def __str__(self): + return self.getStringRepresentation() + + isLegalInteger = Method(cast(Bool, bool), cast(int, Unsigned)) + isIllegalInteger = Method(cast(Bool, bool), cast(int, Unsigned)) + exceedsNaturalStackAlignment = Method(cast(Bool, bool), cast(int, Unsigned)) + fitsInLegalInteger = Method(cast(Bool, bool), cast(int, Unsigned)) + + getPointerABIAlignment = Method(cast(Unsigned, int), + cast(int, Unsigned)).require_only(0) + getPointerPrefAlignment = Method(cast(Unsigned, int), + cast(int, Unsigned)).require_only(0) + getPointerSize = Method(cast(Unsigned, int), + cast(int, Unsigned)).require_only(0) + getPointerSizeInBits = Method(cast(Unsigned, int), + cast(int, Unsigned)).require_only(0) + + getTypeSizeInBits = Method(cast(Uint64, int), ptr(Type)) + getTypeStoreSize = Method(cast(Uint64, int), ptr(Type)) + getTypeStoreSizeInBits = Method(cast(Uint64, int), ptr(Type)) + getTypeAllocSize = Method(cast(Uint64, int), ptr(Type)) + getTypeAllocSizeInBits = Method(cast(Uint64, int), ptr(Type)) + + getABITypeAlignment = Method(cast(Unsigned, int), ptr(Type)) + getABIIntegerTypeAlignment = Method(cast(Unsigned, int), cast(int, Unsigned)) + getCallFrameTypeAlignment = Method(cast(Unsigned, int), ptr(Type)) + getPrefTypeAlignment = Method(cast(Unsigned, int), ptr(Type)) + getPreferredTypeAlignmentShift = Method(cast(Unsigned, int), ptr(Type)) + + _getIntPtrType = Method(ptr(IntegerType), + ref(LLVMContext), cast(int, Unsigned)) + _getIntPtrType.require_only(1) + _getIntPtrType.realname = 'getIntPtrType' + + _getIntPtrType2 = Method(ptr(Type), ptr(Type)) + _getIntPtrType2.realname = 'getIntPtrType' + + @CustomPythonMethod + def getIntPtrType(self, *args): + if isinstance(args[0], LLVMContext): + return self._getIntPtrType(*args) + else: + return self._getIntPtrType(*args) + + _getIndexedOffset = Method(cast(Uint64, int), ptr(Type), + ref(SmallVector_Value)) + _getIndexedOffset.realname = 'getIndexedOffset' + + @CustomPythonMethod + def getIndexedOffset(self, *args): + import extra + args = list(args) + args[1] = extra.make_small_vector_from_values(args[1]) + return self.getIndexedOffset(*args) + + getStructLayout = Method(const(ptr(StructLayout)), ptr(StructType)) + + getPreferredAlignment = Method(cast(Unsigned, int), ptr(GlobalVariable)) + getPreferredAlignmentLog = Method(cast(Unsigned, int), ptr(GlobalVariable)) + +@StructLayout +class StructLayout: + pass diff --git a/newbinding/src/ExecutionEngine.py b/newbinding/src/ExecutionEngine.py new file mode 100644 index 0000000..0fbe387 --- /dev/null +++ b/newbinding/src/ExecutionEngine.py @@ -0,0 +1,34 @@ +from binding import * +from namespace import llvm +from Module import Module +from JITMemoryManager import JITMemoryManager +from CodeGen import CodeGenOpt, Reloc, CodeModel +from DataLayout import DataLayout + +ExecutionEngine = llvm.Class() + +@ExecutionEngine +class ExecutionEngine: + _include_ = ('llvm/ExecutionEngine/ExecutionEngine.h', + 'llvm/ExecutionEngine/JIT.h') # force linking of jit + + delete = Destructor() + + create = CustomStaticMethod('ExecutionEngine_create', + ptr(ExecutionEngine), + ownedptr(Module), cast(bool, Bool), + PyObjectPtr, CodeGenOpt.Level, + cast(bool, Bool)).require_only(1) + + createJIT = CustomStaticMethod('ExecutionEngine_createJIT', + ptr(ExecutionEngine), + ownedptr(Module), PyObjectPtr, + ptr(JITMemoryManager), + CodeGenOpt.Level, + cast(bool, Bool), + Reloc.Model, + CodeModel.Model).require_only(1) + + addModule = Method(Void, ptr(Module)) + getDataLayout = Method(const(ownedptr(DataLayout))) + removeModule = Method(cast(Bool, bool), ptr(Module)) diff --git a/newbinding/src/GlobalVariable.py b/newbinding/src/GlobalVariable.py new file mode 100644 index 0000000..548a8d1 --- /dev/null +++ b/newbinding/src/GlobalVariable.py @@ -0,0 +1,8 @@ +from binding import * +from namespace import llvm +from GlobalValue import GlobalValue + +@llvm.Class(GlobalValue) +class GlobalVariable: + pass + diff --git a/newbinding/src/IRBuilder.py b/newbinding/src/IRBuilder.py index 41e6681..cea94ce 100644 --- a/newbinding/src/IRBuilder.py +++ b/newbinding/src/IRBuilder.py @@ -2,10 +2,16 @@ from binding import * from namespace import llvm from LLVMContext import LLVMContext from BasicBlock import BasicBlock -from Instruction import ReturnInst, CallInst -from SmallVector import SmallVector_Value +from Instruction import ReturnInst, CallInst, BranchInst, SwitchInst +from Instruction import IndirectBrInst, InvokeInst, ResumeInst, PHINode +from Instruction import UnreachableInst, AllocaInst, LoadInst, StoreInst +from Instruction import FenceInst, AtomicCmpXchgInst, AtomicRMWInst, CmpInst +from Instruction import LandingPadInst, VAArgInst +from Instruction import AtomicOrdering, SynchronizationScope +from SmallVector import SmallVector_Value, SmallVector_Unsigned from StringRef import StringRef -from Value import Value +from Value import Value, MDNode +from Type import Type, IntegerType IRBuilder = llvm.Class() @@ -24,15 +30,238 @@ class IRBuilder: CreateRetVoid = Method(ptr(ReturnInst)) CreateRet = Method(ptr(ReturnInst), ptr(Value)) - _CreateCall = Method(ptr(CallInst), ptr(Value), ref(SmallVector_Value), + CreateBr = Method(ptr(BranchInst), ptr(BasicBlock)) + + + CreateCondBr = Method(ptr(BranchInst), ptr(Value), ptr(BasicBlock), + ptr(BasicBlock), ptr(MDNode)).require_only(3) + + CreateSwitch = Method(ptr(SwitchInst), ptr(Value), ptr(BasicBlock), + cast(int, Unsigned), ptr(MDNode)).require_only(2) + + CreateIndirectBr = Method(ptr(IndirectBrInst), ptr(Value), + cast(int, Unsigned)).require_only(1) + + CreateInvoke = Method(ptr(InvokeInst), ptr(Value), ptr(BasicBlock), + ptr(BasicBlock), ref(SmallVector_Value), + cast(str, StringRef)).require_only(4) + + CreateResume = Method(ptr(ResumeInst), ptr(Value)) + + CreateUnreachable = Method(ptr(UnreachableInst)) + + def _binop_has_nsw_nuw(): + sig = [ptr(Value), ptr(Value), ptr(Value), cast(str, StringRef), + cast(bool, Bool), cast(bool, Bool)] + op = Method(*sig).require_only(2) + return op + + CreateAdd = _binop_has_nsw_nuw() + CreateSub = _binop_has_nsw_nuw() + CreateMul = _binop_has_nsw_nuw() + CreateShl = _binop_has_nsw_nuw() + + def _binop_is_exact(): + sig = [ptr(Value), ptr(Value), ptr(Value), cast(str, StringRef), + cast(bool, Bool)] + op = Method(*sig).require_only(2) + return op + + CreateUDiv = _binop_is_exact() + CreateSDiv = _binop_is_exact() + CreateLShr = _binop_is_exact() + CreateAShr = _binop_is_exact() + + def _binop_basic(): + sig = [ptr(Value), ptr(Value), ptr(Value), cast(str, StringRef)] + op = Method(*sig).require_only(2) + return op + + CreateURem = _binop_basic() + CreateSRem = _binop_basic() + CreateAnd = _binop_basic() + CreateOr = _binop_basic() + CreateXor = _binop_basic() + + def _float_binop(): + sig = [ptr(Value), ptr(Value), ptr(Value), cast(str, StringRef), + ptr(MDNode)] + op = Method(*sig).require_only(2) + return op + + CreateFAdd = _float_binop() + CreateFSub = _float_binop() + CreateFMul = _float_binop() + CreateFDiv = _float_binop() + CreateFRem = _float_binop() + + def _unop_has_nsw_nuw(): + sig = [ptr(Value), ptr(Value), cast(str, StringRef), + cast(bool, Bool), cast(bool, Bool)] + op = Method(*sig).require_only(1) + return op + + CreateNeg = _unop_has_nsw_nuw() + + def _float_unop(): + sig = [ptr(Value), ptr(Value), cast(str, StringRef), ptr(MDNode)] + op = Method(*sig).require_only(1) + return op + + CreateFNeg = _float_unop() + + CreateNot = Method(ptr(Value), + ptr(Value), cast(str, StringRef)).require_only(1) + + + CreateAlloca = Method(ptr(AllocaInst), ptr(Type), ptr(Value), + cast(str, StringRef)).require_only(2) + + CreateLoad = Method(ptr(LoadInst), + ptr(Value), cast(str, StringRef)).require_only(1) + + CreateStore = Method(ptr(StoreInst), ptr(Value), ptr(Value), + cast(bool, Bool)).require_only(2) + + CreateAlignedLoad = Method(ptr(LoadInst), ptr(Value), cast(int, Unsigned), + cast(bool, Bool), cast(str, StringRef)) + CreateAlignedLoad.require_only(2) + + CreateAlignedStore = Method(ptr(StoreInst), ptr(Value), ptr(Value), + cast(int, Unsigned), cast(bool, Bool)) + CreateAlignedStore.require_only(3) + + CreateFence = Method(ptr(FenceInst), + AtomicOrdering, SynchronizationScope).require_only(1) + + CreateAtomicCmpXchg = Method(ptr(AtomicCmpXchgInst), ptr(Value), ptr(Value), + ptr(Value), AtomicOrdering, SynchronizationScope) + CreateAtomicCmpXchg.require_only(4) + + CreateAtomicRMW = Method(ptr(AtomicRMWInst), AtomicRMWInst.BinOp, + ptr(Value), ptr(Value), AtomicOrdering, + SynchronizationScope) + CreateAtomicRMW.require_only(4) + + _CreateGEP = Method(ptr(Value), ptr(Value), ref(SmallVector_Value), + cast(str, StringRef)) + _CreateGEP.require_only(2) + _CreateGEP.realname = 'CreateGEP' + + @CustomPythonMethod + def CreateGEP(self, *args): + import extra + args = list(args) + valuelist = args[1] + args[1] = extra.make_small_vector_from_values(*valuelist) + return self._CreateGEP(*args) + + _CreateInBoundsGEP = Method(ptr(Value), ptr(Value), ref(SmallVector_Value), cast(str, StringRef)) - _CreateCall |= Method(ptr(CallInst), ptr(Value), ref(SmallVector_Value)) + _CreateInBoundsGEP.require_only(2) + _CreateInBoundsGEP.realname = 'CreateInBoundsGEP' + + @CustomPythonMethod + def CreateInBoundsGEP(self, *args): + import extra + args = list(args) + valuelist = args[1] + args[1] = extra.make_small_vector_from_values(*valuelist) + return self._CreateInBoundsGEP(*args) + + CreateStructGEP = Method(ptr(Value), ptr(Value), cast(int, Unsigned), + cast(str, StringRef)).require_only(2) + + CreateGlobalStringPtr = Method(ptr(Value), cast(str, StringRef), + cast(str, StringRef)).require_only(1) + + def _value_type(): + sig = [ptr(Value), ptr(Value), ptr(Type), cast(str, StringRef)] + op = Method(*sig).require_only(2) + return op + + CreateTrunc = _value_type() + CreateZExt = _value_type() + CreateSExt = _value_type() + CreateZExtOrTrunc = Method(ptr(Value), ptr(Value), ptr(IntegerType), + cast(str, StringRef)).require_only(2) + CreateSExtOrTrunc = Method(ptr(Value), ptr(Value), ptr(IntegerType), + cast(str, StringRef)).require_only(2) + CreateFPToUI = _value_type() + CreateFPToSI = _value_type() + CreateUIToFP = _value_type() + CreateSIToFP = _value_type() + CreateFPTrunc = _value_type() + CreateFPExt = _value_type() + CreatePtrToInt = _value_type() + CreateIntToPtr = _value_type() + CreateBitCast = _value_type() + CreateZExtOrBitCast = _value_type() + CreateSExtOrBitCast = _value_type() + # Skip CreateCast + CreateTruncOrBitCast = _value_type() + CreateIntCast = Method(ptr(Value), ptr(Value), ptr(Type), cast(bool, Bool), + cast(str, StringRef)).require_only(3) + CreateFPCast = _value_type() + + _CreateCall = Method(ptr(CallInst), ptr(Value), ref(SmallVector_Value), + cast(str, StringRef)).require_only(2) _CreateCall.realname = 'CreateCall' + # Skip specialized CreateICmp* and CreateFCmp* + + CreateICmp = Method(ptr(Value), CmpInst.Predicate, ptr(Value), ptr(Value), + cast(str, StringRef)).require_only(3) + + CreateFCmp = Method(ptr(Value), CmpInst.Predicate, ptr(Value), ptr(Value), + cast(str, StringRef)).require_only(3) + + CreatePHI = Method(ptr(PHINode), ptr(Type), cast(int, Unsigned), + cast(str, StringRef)).require_only(2) + @CustomPythonMethod def CreateCall(self, *args): import extra args = list(args) valuelist = args[1] args[1] = extra.make_small_vector_from_values(*valuelist) - return IRBuilder._CreateCall(self, *args) + return self._CreateCall(*args) + + CreateSelect = Method(ptr(Value), ptr(Value), ptr(Value), ptr(Value), + cast(str, StringRef)).require_only(3) + + CreateVAArg = Method(ptr(VAArgInst), ptr(Value), ptr(Type), + cast(str, StringRef)).require_only(2) + + CreateExtractElement = _binop_basic() + + CreateInsertElement = Method(ptr(Value), ptr(Value), ptr(Value), ptr(Value), + cast(str, StringRef)).require_only(3) + + CreateShuffleVector = Method(ptr(Value), ptr(Value), ptr(Value), + ptr(Value), cast(str, StringRef)) + CreateShuffleVector.require_only(3) + + CreateExtractValue = Method(ptr(Value), ptr(Value), ref(SmallVector_Unsigned), + cast(str, StringRef)) + CreateExtractValue.require_only(2) + + CreateInsertValue = Method(ptr(Value), ptr(Value), ptr(Value), + ref(SmallVector_Unsigned), cast(str, StringRef)) + CreateInsertValue.require_only(3) + + CreateLandingPad = Method(ptr(LandingPadInst), ptr(Type), ptr(Value), + cast(int, Unsigned), cast(str, StringRef)) + CreateLandingPad.require_only(3) + + CreateIsNull = Method(ptr(Value), ptr(Value), cast(str, StringRef)) + CreateIsNull.require_only(1) + + CreateIsNotNull = Method(ptr(Value), ptr(Value), cast(str, StringRef)) + CreateIsNotNull.require_only(1) + + CreatePtrDiff = _binop_basic() + + # New in llvm 3.3 + #CreateVectorSplat = Method(ptr(Value), cast(int, Unsigned), ptr(Value), + # cast(str, StringRef)) diff --git a/newbinding/src/Instruction.py b/newbinding/src/Instruction.py index 310e19d..dda6b48 100644 --- a/newbinding/src/Instruction.py +++ b/newbinding/src/Instruction.py @@ -26,9 +26,9 @@ IntrinsicInst = llvm.Class(CallInst) FCmpInst = llvm.Class(CmpInst) ICmpInst = llvm.Class(CmpInst) - BranchInst = llvm.Class(TerminatorInst) IndirectBrInst = llvm.Class(TerminatorInst) +InvokeInst = llvm.Class(TerminatorInst) ResumeInst = llvm.Class(TerminatorInst) ReturnInst = llvm.Class(TerminatorInst) SwitchInst = llvm.Class(TerminatorInst) @@ -56,14 +56,14 @@ FPTruncInst = llvm.Class(CastInst) class Instruction: pass - @AtomicCmpXchgInst class AtomicCmpXchgInst: pass @AtomicRMWInst class AtomicRMWInst: - pass + BinOp = Enum('Xchg', 'Add', 'Sub', 'And', 'Nand', 'Or', 'Xor', 'Max', 'Min', + 'UMax', 'UMin', 'FIRST_BINOP', 'LAST_BINOP', 'BAD_BINOP') @BinaryOperator class BinaryOperator: @@ -75,7 +75,17 @@ class CallInst: @CmpInst class CmpInst: - pass + Predicate = Enum('FCMP_FALSE', 'FCMP_OEQ', 'FCMP_OGT', 'FCMP_OGE', + 'FCMP_OLT', 'FCMP_OLE', 'FCMP_ONE', 'FCMP_ORD', 'FCMP_UNO', + 'FCMP_UEQ', 'FCMP_UGT', 'FCMP_UGE', 'FCMP_ULT', 'FCMP_ULE', + 'FCMP_UNE', 'FCMP_TRUE', 'FIRST_FCMP_PREDICATE', + 'LAST_FCMP_PREDICATE', + 'BAD_FCMP_PREDICATE', + 'ICMP_EQ', 'ICMP_NE', 'ICMP_UGT', 'ICMP_UGE', 'ICMP_ULT', + 'ICMP_ULE', 'ICMP_SGT', 'ICMP_SGE', 'ICMP_SLT', 'ICMP_SLE', + 'FIRST_ICMP_PREDICATE', + 'LAST_ICMP_PREDICATE', + 'BAD_ICMP_PREDICATE',) @ExtractElementInst class ExtractElementInst: @@ -146,11 +156,14 @@ class ICmpInst: class BranchInst: pass - @IndirectBrInst class IndirectBrInst: pass +@InvokeInst +class InvokeInst: + pass + @ResumeInst class ResumeInst: pass @@ -228,3 +241,12 @@ class FPToUIInst: @FPTruncInst class FPTruncInst: pass + +AtomicOrdering = llvm.Enum('AtomicOrdering', + 'NotAtomic', 'Unordered', 'Monotonic', 'Acquire', + 'Release', 'AcquireRelease', + 'SequentiallyConsistent') + +SynchronizationScope = llvm.Enum('SynchronizationScope', + 'SingleThread', 'CrossThread') + diff --git a/newbinding/src/JITMemoryManager.py b/newbinding/src/JITMemoryManager.py new file mode 100644 index 0000000..f134735 --- /dev/null +++ b/newbinding/src/JITMemoryManager.py @@ -0,0 +1,7 @@ +from binding import * +from namespace import llvm + +@llvm.Class() +class JITMemoryManager: + pass + diff --git a/newbinding/src/Metadata.py b/newbinding/src/Metadata.py new file mode 100644 index 0000000..78dbe15 --- /dev/null +++ b/newbinding/src/Metadata.py @@ -0,0 +1,7 @@ +from binding import * +from namespace import llvm +from Value import MDNode + +@MDNode +class MDNode: + pass diff --git a/newbinding/src/Module.py b/newbinding/src/Module.py index 730b757..6cd6e2e 100644 --- a/newbinding/src/Module.py +++ b/newbinding/src/Module.py @@ -36,7 +36,8 @@ class Module: appendModuleInlineAsm = Method(Void, cast(str, StringRef)) # Function Accessors - getOrInsertFunction = Method(ptr(Constant), cast(str, StringRef), ptr(FunctionType)) + getOrInsertFunction = Method(ptr(Constant), cast(str, StringRef), + ptr(FunctionType)) # Utilities dump = Method(Void) diff --git a/newbinding/src/SmallVector.py b/newbinding/src/SmallVector.py index 594faf8..5b48aba 100644 --- a/newbinding/src/SmallVector.py +++ b/newbinding/src/SmallVector.py @@ -11,3 +11,7 @@ class SmallVector_Value: _realname_ = 'SmallVector' delete = Destructor() +@llvm.Class() +class SmallVector_Unsigned: + _realname_ = 'SmallVector' + delete = Destructor() diff --git a/newbinding/src/TargetSelect.py b/newbinding/src/TargetSelect.py new file mode 100644 index 0000000..cb2eb96 --- /dev/null +++ b/newbinding/src/TargetSelect.py @@ -0,0 +1,8 @@ +from binding import * +from namespace import llvm + +llvm.includes.add('llvm/Support/TargetSelect.h') + +llvm.Function('InitializeNativeTarget') +#llvm.Function('InitializeAllTargets') + diff --git a/newbinding/src/Type.py b/newbinding/src/Type.py index 45f9444..15b5e31 100644 --- a/newbinding/src/Type.py +++ b/newbinding/src/Type.py @@ -6,6 +6,7 @@ from raw_ostream import raw_ostream Type = llvm.Class() IntegerType = llvm.Class(Type) CompositeType = llvm.Class(Type) +StructType = llvm.Class(CompositeType) SequentialType = llvm.Class(CompositeType) PointerType = llvm.Class(SequentialType) @@ -113,3 +114,6 @@ class SequentialType: class PointerType: pass +@StructType +class StructType: + pass diff --git a/newbinding/src/Value.py b/newbinding/src/Value.py index 5b907bd..7460c90 100644 --- a/newbinding/src/Value.py +++ b/newbinding/src/Value.py @@ -9,6 +9,7 @@ from StringRef import StringRef Value = llvm.Class() # forward declarations Argument = llvm.Class(Value) +MDNode = llvm.Class(Value) User = llvm.Class(Value) BasicBlock = llvm.Class(Value) Constant = llvm.Class(User) diff --git a/newbinding/test2.py b/newbinding/test2.py index a7a4ddd..9492bb6 100644 --- a/newbinding/test2.py +++ b/newbinding/test2.py @@ -1,7 +1,11 @@ import api import extra import _capsule +from StringIO import StringIO api.capsule.set_debug(True) + + +api.InitializeNativeTarget() context = api.getGlobalContext() @@ -71,3 +75,13 @@ builder.CreateRet(ret) print fn +errio = StringIO() +ee = api.ExecutionEngine.createJIT(m) +print ee, errio.getvalue() +print ee.getDataLayout().getStringRepresentation() + +datalayout_str = 'e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64' + +assert datalayout_str == str(api.DataLayout.new(datalayout_str)) +assert datalayout_str == str(api.DataLayout.new(str(api.DataLayout.new(datalayout_str)))) + From 25b498c8fae73fa621179b76398c733b13200871 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 30 Jan 2013 14:44:17 -0600 Subject: [PATCH 236/516] Improve refct and management of capsules --- newbinding/capsule.py | 187 +++++++++++++++++++++++++++--------------- newbinding/extra.py | 18 ---- 2 files changed, 121 insertions(+), 84 deletions(-) diff --git a/newbinding/capsule.py b/newbinding/capsule.py index f489c7f..907fa15 100644 --- a/newbinding/capsule.py +++ b/newbinding/capsule.py @@ -1,5 +1,5 @@ -import _capsule -from weakref import WeakValueDictionary, ref +from weakref import WeakKeyDictionary, WeakValueDictionary, ref +from collections import defaultdict import logging logger = logging.getLogger(__name__) @@ -17,81 +17,106 @@ def set_debug(enabled): else: logger.setLevel(logging.WARNING) +def _capsule_weakref_dtor(item): + addr = item.pointer + _addr2refct[addr] -= 1 + refct = _addr2refct[addr] + assert refct >= 0, "RefCt drop below 0" + if refct == 0: + dtor = _addr2dtor.pop(addr, None) + if dtor is not None: + logger.debug('Destroy %s %s', item.name, hex(item.pointer)) + dtor(item.capsule) + +class Capsule(object): + "Wraps PyCapsule so that we can build weakref of it." + + 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 __ne__(self, other): + return not (self == other) class WeakRef(ref): - __slots__ = 'capsule', 'dtor', 'owning' + pass +_addr2refct = defaultdict(lambda: 0) +_capsule2weak = WeakKeyDictionary() +_addr2dtor = {} _pyclasses = {} -_addr2obj = WeakValueDictionary() -_owners = {} # address to weak reference -def _sentry(ptr): - if not _capsule.check(ptr): - raise ValueError('Must provide a PyCapsule object.') - -def classof(cap): - cls = _capsule.getClassName(cap) - return _pyclasses[cls] - -def _capsule_destructor(weak): - if weak.owning: - cap = weak.capsule - addr = _capsule.getPointer(cap) - cls = _capsule.getClassName(cap) - logger.debug("destroy pointer 0x%08X to %s", addr, cls) -# weak.dtor(cap) - del _owners[addr] +# Cache {cls: {addr: obj}} +# NOTE: The same 'addr' may appear in multiple class bins. +_cache = defaultdict(WeakValueDictionary) def release_ownership(old): - addr = _capsule.getPointer(old) - oldweak = _owners[addr] - oldweak.owning = False # dis-own - del _owners[addr] + logger.debug('Release %s', old) + _addr2dtor[Capsule.getPointer(old)] = None + +def has_ownership(cap): + addr = Capsule.getPointer(cap) + return _addr2dtor.get(addr) is not None def wrap(cap, owned=False): '''Wrap a PyCapsule with the corresponding Wrapper class. If `cap` is not a PyCapsule, returns `cap` ''' - if not _capsule.check(cap): + if not Capsule.valid(cap): if isinstance(cap, list): return map(wrap, cap) return cap # bypass if cap is not a PyCapsule and not a list - addr = _capsule.getPointer(cap) - try: - # find cached object by pointer address - obj = _addr2obj[addr] - except KeyError: - # create new object and cache it - cls = classof(cap) - obj = cls(cap) - _addr2obj[addr] = obj # cache object by address - # set ownership if *cls* defines *_delete_* - if not owned and hasattr(cls, '_delete_'): - assert addr not in _owners, "has existing owner" - weak = WeakRef(obj, _capsule_destructor) - _owners[addr] = weak - weak.capsule = cap - weak.owning = True - weak.dtor = cls._delete_ - else: - oldcls = classof(obj._ptr) - newcls = classof(cap) - if issubclass(oldcls, newcls): - # do auto downcast - pass - else: - assert oldcls is newcls, (cap, obj, oldcls, newcls) - return obj -def downcast(old, new): - assert old is not new - assert _capsule.getPointer(old) not in _owners - oldcls = classof(old) - newcls = classof(new) - assert issubclass(newcls, oldcls) - # release_ownership(old) - del _addr2obj[_capsule.getPointer(old)] # clear cache - return wrap(new) + cap = Capsule(cap) + cls = cap.get_class() + addr = cap.pointer + try: # lookup cached object + return _cache[cls][addr] + except KeyError: + if not owned and hasattr(cls, '_delete_'): + _addr2dtor[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. @@ -112,13 +137,43 @@ def register_class(clsname): class Wrapper(object): - __slots__ = '__ptr' + __slots__ = '__capsule' - def __init__(self, ptr): - _sentry(ptr) - self.__ptr = ptr + def __init__(self, capsule): + self.__capsule = capsule + + @property + def _capsule(self): + return self.__capsule @property def _ptr(self): - return self.__ptr + return self._capsule.capsule + def __eq__(self, other): + return self._capsule == other._capsule + + def __ne__(self, other): + return self._capsule != other._capsule + + def _downcast(self, newcls): + return downcast(self, newcls) + +def downcast(obj, cls): + 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, 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) + return wrap(new, owned=not used_to_own) diff --git a/newbinding/extra.py b/newbinding/extra.py index a613296..d65f84c 100644 --- a/newbinding/extra.py +++ b/newbinding/extra.py @@ -22,22 +22,4 @@ def _init(glob): _init(globals()) -# -# Downcasts -# -def downcast(obj, cls): - if type(obj) is cls: - return obj - fromty = obj._llvm_type_ - toty = cls._llvm_type_ - fname = 'downcast_%s_to_%s' % (fromty, toty) - fname = fname.replace('::', '_') - try: - caster = getattr(_api, fname) - except AttributeError: - fmt = "Downcast from %s to %s is not supported" - raise TypeError(fmt % (fromty, toty)) - old = capsule.unwrap(obj) - new = caster(old) - return capsule.downcast(old, new) \ No newline at end of file From 78f9c9a61087f73e805d32b0a9bbb48ec5026827 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 30 Jan 2013 18:09:22 -0600 Subject: [PATCH 237/516] Completed binding for most of ExecutionEngine --- newbinding/binding.py | 8 ++ newbinding/include/llvm_binding/conversion.h | 117 ++++++++++++++++++- newbinding/include/llvm_binding/extra.h | 106 +++++++++++++++++ newbinding/src/ExecutionEngine.py | 60 ++++++++++ newbinding/src/GenericValue.py | 34 ++++++ newbinding/src/MachineCodeInfo.py | 13 +++ newbinding/src/Module.py | 7 ++ newbinding/src/Type.py | 14 +++ newbinding/test2.py | 41 +++++-- 9 files changed, 391 insertions(+), 9 deletions(-) create mode 100644 newbinding/src/GenericValue.py create mode 100644 newbinding/src/MachineCodeInfo.py diff --git a/newbinding/binding.py b/newbinding/binding.py index f7d5ac4..9ddedf3 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -59,9 +59,17 @@ class BuiltinTypes(_Type): Void = BuiltinTypes('void') Unsigned = BuiltinTypes('unsigned') +UnsignedLongLong = BuiltinTypes('unsigned long long') # used in llvm-3.2 +LongLong = BuiltinTypes('long long') +Float = BuiltinTypes('float') +Double = BuiltinTypes('double') Uint64 = BuiltinTypes('uint64_t') +Size_t = BuiltinTypes('size_t') +VoidPtr = BuiltinTypes('void*') Bool = BuiltinTypes('bool') +StdString = BuiltinTypes('std::string') ConstStdString = BuiltinTypes('const std::string') +ConstCharPtr = BuiltinTypes('const char*') PyObjectPtr = BuiltinTypes('PyObject*') PyObjectPtr.format='O' diff --git a/newbinding/include/llvm_binding/conversion.h b/newbinding/include/llvm_binding/conversion.h index 0e30c60..a1fc87c 100644 --- a/newbinding/include/llvm_binding/conversion.h +++ b/newbinding/include/llvm_binding/conversion.h @@ -25,6 +25,45 @@ int py_str_to(PyObject *strobj, llvm::StringRef &strref){ return 1; } +static +int py_str_to(PyObject *strobj, std::string &strref){ + // type check + if (!PyString_Check(strobj)) { + // raises TypeError + PyErr_SetString(PyExc_TypeError, "Expecting a str"); + return 0; + } + // get len and buffer + const char * buf = PyString_AsString(strobj); + if (!buf) { + // raises TypeError + return 0; + } + // set output + strref = std::string(buf); + // success + return 1; +} + + +static +int py_str_to(PyObject *strobj, const char* &strref){ + // type check + if (!PyString_Check(strobj)) { + // raises TypeError + PyErr_SetString(PyExc_TypeError, "Expecting a str"); + return 0; + } + // get buffer + strref = PyString_AsString(strobj); + if (!strref) { + // raises TypeError + return 0; + } + // success + return 1; +} + static int py_int_to(PyObject *intobj, unsigned & val){ if (!PyInt_Check(intobj)) { @@ -37,6 +76,70 @@ int py_int_to(PyObject *intobj, unsigned & val){ return 1; } +static +int py_int_to(PyObject *intobj, unsigned long long & val){ + if (!PyInt_Check(intobj)) { + // raise TypeError + puts(PyString_AsString(PyObject_Str(PyObject_Type(intobj)))); + PyErr_SetString(PyExc_TypeError, "Expecting an int 2"); + return 0; + } + val = PyInt_AsUnsignedLongLongMask(intobj); + // success + return 1; + +} + +static +int py_int_to(PyObject *intobj, size_t & val){ + unsigned long long ull; + if (py_int_to(intobj, ull)) { + val = (size_t)ull; + return 1; + } else { + return 0; + } +} + + +static +int py_int_to(PyObject *intobj, void* & val){ + if (!PyLong_Check(intobj)) { + // raise TypeError + PyErr_SetString(PyExc_TypeError, "Expecting an int"); + return 0; + } + val = PyLong_FromVoidPtr(intobj); + // success + return 1; +} + +static +int py_float_to(PyObject *floatobj, double & val){ + if (!PyFloat_Check(floatobj)) { + // raise TypeError + PyErr_SetString(PyExc_TypeError, "Expecting a float"); + return 0; + } + val = PyFloat_AsDouble(floatobj); + if (PyErr_Occurred()){ + return 0; + } + // success + return 1; +} + + +static +int py_float_to(PyObject *floatobj, float & val){ + double db; + int status = py_float_to(floatobj, db); + if (status) + val = db; + return status; +} + + static int py_bool_to(PyObject *boolobj, bool & val){ if (!PyBool_Check(boolobj)) { @@ -78,8 +181,18 @@ PyObject* py_bool_from(bool val){ } static -PyObject* py_int_from(int val){ - return PyInt_FromLong(val); +PyObject* py_int_from(const long long & val){ + return PyLong_FromLongLong(val); +} + +static +PyObject* py_int_from(void * addr){ + return PyLong_FromVoidPtr(addr); +} + +static +PyObject* py_float_from(const double& val) { + return PyFloat_FromDouble(val); } // casting diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h index b5edd2c..7aacfde 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/extra.h @@ -4,6 +4,7 @@ #include #include #include +#include namespace extra{ using namespace llvm; @@ -234,3 +235,108 @@ llvm::ExecutionEngine* ExecutionEngine_createJIT( PyFile_WriteString(ErrorStr.c_str(), errout); return ee; } + +static +llvm::GenericValue* GenericValue_CreateInt(llvm::Type* Ty, unsigned long long N, + bool IsSigned) +{ + // Shamelessly copied from LLVM + llvm::GenericValue *GenVal = new llvm::GenericValue(); + GenVal->IntVal = llvm::APInt(Ty->getIntegerBitWidth(), N, IsSigned); + return GenVal; +} + +static +llvm::GenericValue* GenericValue_CreateFloat(float Val) +{ + llvm::GenericValue *GenVal = new llvm::GenericValue(); + GenVal->FloatVal = Val; + return GenVal; +} + +static +llvm::GenericValue* GenericValue_CreateDouble(double Val) +{ + llvm::GenericValue *GenVal = new llvm::GenericValue(); + GenVal->DoubleVal = Val; + return GenVal; +} + +static +llvm::GenericValue* GenericValue_CreatePointer(void * Ptr) +{ + llvm::GenericValue *GenVal = new llvm::GenericValue(); + GenVal->PointerVal = Ptr; + return GenVal; +} + +static +unsigned GenericValue_ValueIntWidth(llvm::GenericValue *GenValRef) +{ + return GenValRef->IntVal.getBitWidth(); +} + +static +unsigned long long GenericValue_ToUnsignedInt(llvm::GenericValue* GenVal) +{ + return GenVal->IntVal.getZExtValue(); +} + + +static +long long GenericValue_ToSignedInt(llvm::GenericValue* GenVal) +{ + return GenVal->IntVal.getSExtValue(); +} + +static +void* GenericValue_ToPointer(llvm::GenericValue* GenVal) +{ + return GenVal->PointerVal; +} + +static +double GenericValue_ToFloat(llvm::GenericValue* GenVal, llvm::Type* Ty) +{ + switch (Ty->getTypeID()) { + case llvm::Type::FloatTyID: + return GenVal->FloatVal; + default: + // Behavior undefined if type is not a float or a double + return GenVal->DoubleVal; + } +} + +static +PyObject* ExecutionEngine_RunFunction(llvm::ExecutionEngine* EE, + llvm::Function* Fn, PyObject* Args) +{ + using namespace llvm; + const char * GVN = "llvm::GenericValue"; + if (!PyTuple_Check(Args)) { + PyErr_SetString(PyExc_TypeError, "Expect a tuple of args."); + return NULL; + } + std::vector vec_args; + Py_ssize_t nargs = PyTuple_Size(Args); + vec_args.reserve(nargs); + for (Py_ssize_t i = 0; i < nargs; ++i) { + PyObject* obj = PyTuple_GetItem(Args, i); + if (!obj) { + PyErr_SetString(PyExc_RuntimeError, "Failed to index into args?"); + return NULL; + } + + GenericValue* gv = static_cast( + PyCapsule_GetPointer(obj, GVN)); + + if (!gv) { + return NULL; + } + vec_args.push_back(*gv); + } + + GenericValue ret = EE->runFunction(Fn, vec_args); + return pycapsule_new(new GenericValue(ret), GVN); +} + diff --git a/newbinding/src/ExecutionEngine.py b/newbinding/src/ExecutionEngine.py index 0fbe387..5a95a16 100644 --- a/newbinding/src/ExecutionEngine.py +++ b/newbinding/src/ExecutionEngine.py @@ -4,6 +4,11 @@ from Module import Module from JITMemoryManager import JITMemoryManager from CodeGen import CodeGenOpt, Reloc, CodeModel from DataLayout import DataLayout +from Value import Function, GlobalValue, BasicBlock, Constant +from GlobalVariable import GlobalVariable +from MachineCodeInfo import MachineCodeInfo +from GenericValue import GenericValue +from Type import Type ExecutionEngine = llvm.Class() @@ -32,3 +37,58 @@ class ExecutionEngine: addModule = Method(Void, ptr(Module)) getDataLayout = Method(const(ownedptr(DataLayout))) removeModule = Method(cast(Bool, bool), ptr(Module)) + + FindFunctionNamed = Method(ptr(Function), cast(str, ConstCharPtr)) + getPointerToNamedFunction = Method(cast(VoidPtr, int), + cast(str, StdString), + cast(bool, Bool)).require_only(1) + + runStaticConstructorsDestructors = Method(Void, cast(Bool, bool)) + runStaticConstructorsDestructors |= Method(Void, ptr(Module), + cast(Bool, bool)) + + addGlobalMapping = Method(Void, ptr(GlobalValue), cast(int, VoidPtr)) + clearAllGlobalMappings = Method() + clearGlobalMappingsFromModule = Method(Void, ptr(Module)) + updateGlobalMapping = Method(cast(VoidPtr, int), + ptr(GlobalValue), cast(int, VoidPtr)) + + getPointerToGlobalIfAvailable = Method(cast(VoidPtr, int), ptr(GlobalValue)) + getPointerToGlobal = Method(cast(VoidPtr, int), ptr(GlobalValue)) + getPointerToFunction = Method(cast(VoidPtr, int), ptr(Function)) + getPointerToBasicBlock = Method(cast(VoidPtr, int), ptr(BasicBlock)) + getPointerToFunctionOrStub = Method(cast(VoidPtr, int), ptr(Function)) + + runJITOnFunction = Method(Void, ptr(Function), ptr(MachineCodeInfo)) + runJITOnFunction.require_only(1) + + getGlobalValueAtAddress = Method(const(ptr(GlobalValue)), cast(int, VoidPtr)) + + StoreValueToMemory = Method(Void, ref(GenericValue), ptr(GenericValue), + ptr(Type)) + + InitializeMemory = Method(Void, ptr(Constant), cast(int, VoidPtr)) + + recompileAndRelinkFunction = Method(cast(int, VoidPtr), ptr(Function)) + + freeMachineCodeForFunction = Method(Void, ptr(Function)) + getOrEmitGlobalVariable = Method(cast(int, VoidPtr), ptr(GlobalVariable)) + + DisableLazyCompilation = Method(Void, cast(bool, Bool)) + isCompilingLazily = Method(cast(Bool, bool)) + isLazyCompilationDisabled = Method(cast(Bool, bool)) + DisableGVCompilation = Method(Void, cast(bool, Bool)) + isSymbolSearchingDisabled = Method(cast(Bool, bool)) + RegisterTable = Method(Void, ptr(Function), cast(int, VoidPtr)) + DeregisterTable = Method(Void, ptr(Function)) + DeregisterAllTables = Method() + + _runFunction = CustomMethod('ExecutionEngine_RunFunction', + PyObjectPtr, ptr(Function), PyObjectPtr) + + @CustomPythonMethod + def runFunction(self, fn, args): + import capsule + unwrapped = map(capsule.unwrap, args) + return self._runFunction(fn, tuple(unwrapped)) + diff --git a/newbinding/src/GenericValue.py b/newbinding/src/GenericValue.py new file mode 100644 index 0000000..74587ba --- /dev/null +++ b/newbinding/src/GenericValue.py @@ -0,0 +1,34 @@ +from binding import * +from namespace import llvm +from Type import Type + +GenericValue = llvm.Class() + +@GenericValue +class GenericValue: + delete = Destructor() + + def _factory(name, *argtys): + return CustomStaticMethod('GenericValue_' + name, + ptr(GenericValue), *argtys) + + CreateFloat = _factory('CreateFloat', cast(float, Float)) + + CreateDouble = _factory('CreateDouble', cast(float, Float)) + + CreateInt = _factory('CreateInt', ptr(Type), + cast(int, UnsignedLongLong), cast(bool, Bool)) + + CreatePointer = _factory('CreatePointer', cast(int, VoidPtr)) + + def _accessor(name, *argtys): + return CustomMethod('GenericValue_' + name, *argtys) + + valueIntWidth = _accessor('ValueIntWidth', cast(Unsigned, int)) + + toSignedInt = _accessor('ToSignedInt', cast(UnsignedLongLong, int)) + toUnsignedInt = _accessor('ToUnsignedInt', cast(LongLong, int)) + + toFloat = _accessor('ToFloat', cast(Double, float), ptr(Type)) + + toPointer = _accessor('ToPointer', cast(VoidPtr, int)) \ No newline at end of file diff --git a/newbinding/src/MachineCodeInfo.py b/newbinding/src/MachineCodeInfo.py new file mode 100644 index 0000000..5d91e3a --- /dev/null +++ b/newbinding/src/MachineCodeInfo.py @@ -0,0 +1,13 @@ +from binding import * +from namespace import llvm + +MachineCodeInfo = llvm.Class() + +@MachineCodeInfo +class MachineCodeInfo: + _include_ = 'llvm/CodeGen/MachineCodeInfo.h' + setSize = Method(Void, cast(int, Size_t)) + setAddress = Method(Void, cast(int, VoidPtr)) + size = Method(cast(Size_t, int)) + address = Method(cast(VoidPtr, int)) + diff --git a/newbinding/src/Module.py b/newbinding/src/Module.py index 6cd6e2e..9b392ca 100644 --- a/newbinding/src/Module.py +++ b/newbinding/src/Module.py @@ -44,4 +44,11 @@ class Module: print_ = Method(Void, ref(raw_ostream), ptr(AssemblyAnnotationWriter)) print_.realname = 'print' + @CustomPythonMethod + def __str__(self): + import extra + os = extra.make_raw_ostream_for_printing() + self.print_(os, None) + return os.str() + dropAllReferences = Method() diff --git a/newbinding/src/Type.py b/newbinding/src/Type.py index 15b5e31..bf51b9d 100644 --- a/newbinding/src/Type.py +++ b/newbinding/src/Type.py @@ -2,6 +2,7 @@ from binding import * from namespace import llvm from LLVMContext import LLVMContext from raw_ostream import raw_ostream +from StringRef import StringRef Type = llvm.Class() IntegerType = llvm.Class(Type) @@ -52,6 +53,19 @@ class Type: isIntegerTy = Method(cast(Bool, bool)) isIntegerTy |= Method(cast(Bool, bool), cast(int, Unsigned)) + getIntegerBitWidth = Method(cast(Unsigned, int)) + getFunctionParamType = Method(ptr(Type), cast(int, Unsigned)) + getFunctionNumParams = Method(cast(int, Unsigned)) + + isFunctionVarArg = type_checker() + + getStructName = Method(cast(StringRef, str)) + getStructNumElements = Method(cast(Unsigned, int)) + getStructElementType = Method(ptr(Type), cast(int, Unsigned)) + getSequentialElementType = Method(ptr(Type)) + + # Factories + def type_factory(): return StaticMethod(ptr(Type), ref(LLVMContext)) diff --git a/newbinding/test2.py b/newbinding/test2.py index 9492bb6..7902df4 100644 --- a/newbinding/test2.py +++ b/newbinding/test2.py @@ -28,25 +28,25 @@ print os.str() int1ty = api.Type.getInt1Ty(context) int1ty.dump() -print int1ty.isIntegerTy(1) +assert int1ty.isIntegerTy(1) fnty = api.FunctionType.get(int1ty, False) fnty.dump() -types = [int1ty, api.Type.getIntNTy(context, 21)] -fnty = api.FunctionType.get(int1ty, types, False) +types = [api.Type.getIntNTy(context, 8), api.Type.getIntNTy(context, 32)] +fnty = api.FunctionType.get(api.Type.getIntNTy(context, 8), types, False) print fnty const = m.getOrInsertFunction("foo", fnty) -fn = extra.downcast(const, api.Function) +fn = const._downcast(api.Function) print fn assert fn.hasName() assert 'foo' == fn.getName() fn.setName('bar') assert 'bar' == fn.getName() -assert fn.getReturnType() is int1ty +assert fn.getReturnType().isIntegerTy(8) assert fnty is fn.getFunctionType() @@ -70,13 +70,19 @@ assert bb.getTerminator() is None arg0, arg1 = fn.getArgumentList() print arg0, arg1 -ret = builder.CreateCall(fn, [arg0, arg1], '') +extended = builder.CreateZExt(arg0, arg1.getType()) +result = builder.CreateAdd(extended, arg1) +ret = builder.CreateTrunc(result, fn.getReturnType()) builder.CreateRet(ret) +print arg0.list_use() + print fn errio = StringIO() -ee = api.ExecutionEngine.createJIT(m) +print m + +ee = api.ExecutionEngine.createJIT(m, errio) print ee, errio.getvalue() print ee.getDataLayout().getStringRepresentation() @@ -85,3 +91,24 @@ datalayout_str = 'e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64- assert datalayout_str == str(api.DataLayout.new(datalayout_str)) assert datalayout_str == str(api.DataLayout.new(str(api.DataLayout.new(datalayout_str)))) +fn2 = ee.FindFunctionNamed(fn.getName()) +assert fn2 is fn + +assert ee.getPointerToFunction(fn) +assert ee.getPointerToNamedFunction('printf') + +gv0 = api.GenericValue.CreateInt(arg0.getType(), 12, False) +gv1 = api.GenericValue.CreateInt(arg1.getType(), -32, True) + +assert gv0.valueIntWidth() == arg0.getType().getIntegerBitWidth() +assert gv1.valueIntWidth() == arg1.getType().getIntegerBitWidth() + +assert gv0.toUnsignedInt() == 12 +assert gv1.toSignedInt() == -32 + +gv1 = api.GenericValue.CreateInt(arg1.getType(), 32, False) + +gvR = ee.runFunction(fn, (gv0, gv1)) + +assert 44 == gvR.toUnsignedInt() + From ca0a2b9fddd9e8224b5a919de6fbccc80492a04c Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 1 Feb 2013 11:45:19 -0600 Subject: [PATCH 238/516] binding for EngineBuilder --- newbinding/binding.py | 3 +- newbinding/capsule.py | 7 +- newbinding/include/llvm_binding/extra.h | 41 ++++++ newbinding/src/EngineBuilder.py | 49 +++++++ newbinding/src/TargetMachine.py | 11 ++ newbinding/test2.py | 170 ++++++++++++++---------- 6 files changed, 206 insertions(+), 75 deletions(-) create mode 100644 newbinding/src/EngineBuilder.py create mode 100644 newbinding/src/TargetMachine.py diff --git a/newbinding/binding.py b/newbinding/binding.py index 9ddedf3..1f980d1 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -358,7 +358,8 @@ class Method(object): argtys = self.signatures[0][1:] for i, ty in enumerate(argtys): if isinstance(ty, ownedptr): - writer.release_ownership('%s[%d]' % (unwrapped, i)) + with writer.block('if len(%s) > %d:' % (unwrapped, i)): + writer.release_ownership('%s[%d]' % (unwrapped, i)) class CustomMethod(Method): def __init__(self, methodname, retty, *argtys): diff --git a/newbinding/capsule.py b/newbinding/capsule.py index 907fa15..8c2f10e 100644 --- a/newbinding/capsule.py +++ b/newbinding/capsule.py @@ -91,7 +91,12 @@ _cache = defaultdict(WeakValueDictionary) def release_ownership(old): logger.debug('Release %s', old) - _addr2dtor[Capsule.getPointer(old)] = None + addr = Capsule.getPointer(old) + if _addr2dtor[addr] is None: + # Guard deduplicated release + raise Exception("Already released") + _addr2dtor[addr] = None + def has_ownership(cap): addr = Capsule.getPointer(cap) diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h index 7aacfde..10a4361 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/extra.h @@ -340,3 +340,44 @@ PyObject* ExecutionEngine_RunFunction(llvm::ExecutionEngine* EE, return pycapsule_new(new GenericValue(ret), GVN); } +static +PyObject* EngineBuilder_setErrorStr(llvm::EngineBuilder* eb, PyObject* fileobj) +{ + + if (!PyFile_Check(fileobj)) { + PyErr_SetString(PyExc_TypeError, "Expecting a file object."); + return NULL; + } + + std::string buffer; + eb->setErrorStr(&buffer); + + if (-1 == PyFile_WriteString(buffer.c_str(), fileobj)) { + return NULL; + } + + return pycapsule_new(eb, "llvm::EngineBuilder"); +} + +static +PyObject* EngineBuilder_setMAttrs(llvm::EngineBuilder* eb, + PyObject* strlist) +{ + if (!PyList_Check(strlist)) { + PyErr_SetString(PyExc_TypeError, "Expecting a list of string."); + return NULL; + } + std::vector tmp; + const int N = PyList_Size(strlist); + tmp.reserve(N); + for (int i = 0; i < N; ++i) { + const char * elem = PyString_AsString(PyList_GetItem(strlist, i)); + if (!elem) { + return NULL; + } + tmp.push_back(elem); + } + eb->setMAttrs(tmp); + return pycapsule_new(eb, "llvm::EngineBuilder"); +} + diff --git a/newbinding/src/EngineBuilder.py b/newbinding/src/EngineBuilder.py new file mode 100644 index 0000000..0e8388e --- /dev/null +++ b/newbinding/src/EngineBuilder.py @@ -0,0 +1,49 @@ +from binding import * +from namespace import llvm +from Module import Module +from JITMemoryManager import JITMemoryManager +from CodeGen import CodeGenOpt, Reloc, CodeModel +from StringRef import StringRef +from ExecutionEngine import ExecutionEngine +from TargetMachine import TargetMachine + +EngineBuilder = llvm.Class() + +@llvm.Class() # a fake class (actually a namespace) +class EngineKind: + Kind = Enum('JIT', 'Interpreter') + +@EngineBuilder +class EngineBuilder: + new = Constructor(ownedptr(Module)) + delete = Destructor() + + def _setter(*args): + return Method(ref(EngineBuilder), *args) + + setEngineKind = _setter(EngineKind.Kind) + setJITMemoryManager = _setter(ptr(JITMemoryManager)) + + setErrorStr = CustomMethod('EngineBuilder_setErrorStr', + PyObjectPtr, PyObjectPtr) + + setOptLevel = _setter(CodeGenOpt.Level) + #setTargetOptions = + setRelocationModel = _setter(Reloc.Model) + setCodeModel = _setter(CodeModel.Model) + setAllocateGVsWithCode = _setter(cast(bool, Bool)) + setMArch = _setter(cast(str, StringRef)) + setMCPU = _setter(cast(str, StringRef)) + setUseMCJIT = _setter(cast(bool, Bool)) + _setMAttrs = CustomMethod('EngineBuilder_setMAttrs', + PyObjectPtr, PyObjectPtr) + @CustomPythonMethod + def setMAttrs(self, attrs): + attrlist = list(str(a) for a in attrs) + return self._setMAttrs(attrlist) + + create = Method(ptr(ExecutionEngine), + ownedptr(TargetMachine)).require_only(0) + + selectTarget = Method(ptr(TargetMachine)) + diff --git a/newbinding/src/TargetMachine.py b/newbinding/src/TargetMachine.py new file mode 100644 index 0000000..e53cd33 --- /dev/null +++ b/newbinding/src/TargetMachine.py @@ -0,0 +1,11 @@ +from binding import * +from namespace import llvm + +TargetMachine = llvm.Class() + +@TargetMachine +class TargetMachine: + _include_ = 'llvm/Target/TargetMachine.h' + delete = Destructor() + + diff --git a/newbinding/test2.py b/newbinding/test2.py index 7902df4..a304426 100644 --- a/newbinding/test2.py +++ b/newbinding/test2.py @@ -4,111 +4,135 @@ import _capsule from StringIO import StringIO api.capsule.set_debug(True) - -api.InitializeNativeTarget() -context = api.getGlobalContext() +def test_basic_jit_use(): + api.InitializeNativeTarget() + context = api.getGlobalContext() -m = api.Module.new("modname", context) -print m.getModuleIdentifier() -m.setModuleIdentifier('modname2') -print m.getModuleIdentifier() -print 'endianness', m.getEndianness() -assert m.getEndianness() == api.Module.Endianness.AnyEndianness -print 'pointer-size', m.getPointerSize() -assert m.getPointerSize() == api.Module.PointerSize.AnyPointerSize -m.dump() + m = api.Module.new("modname", context) + print m.getModuleIdentifier() + m.setModuleIdentifier('modname2') + print m.getModuleIdentifier() + print 'endianness', m.getEndianness() + assert m.getEndianness() == api.Module.Endianness.AnyEndianness + print 'pointer-size', m.getPointerSize() + assert m.getPointerSize() == api.Module.PointerSize.AnyPointerSize + m.dump() -os = extra.make_raw_ostream_for_printing() -m.print_(os, None) -print os.str() + os = extra.make_raw_ostream_for_printing() + m.print_(os, None) + print os.str() -int1ty = api.Type.getInt1Ty(context) -int1ty.dump() + int1ty = api.Type.getInt1Ty(context) + int1ty.dump() -assert int1ty.isIntegerTy(1) + assert int1ty.isIntegerTy(1) -fnty = api.FunctionType.get(int1ty, False) -fnty.dump() + fnty = api.FunctionType.get(int1ty, False) + fnty.dump() -types = [api.Type.getIntNTy(context, 8), api.Type.getIntNTy(context, 32)] -fnty = api.FunctionType.get(api.Type.getIntNTy(context, 8), types, False) + types = [api.Type.getIntNTy(context, 8), api.Type.getIntNTy(context, 32)] + fnty = api.FunctionType.get(api.Type.getIntNTy(context, 8), types, False) -print fnty + print fnty -const = m.getOrInsertFunction("foo", fnty) -fn = const._downcast(api.Function) -print fn -assert fn.hasName() -assert 'foo' == fn.getName() -fn.setName('bar') -assert 'bar' == fn.getName() + const = m.getOrInsertFunction("foo", fnty) + fn = const._downcast(api.Function) + print fn + assert fn.hasName() + assert 'foo' == fn.getName() + fn.setName('bar') + assert 'bar' == fn.getName() -assert fn.getReturnType().isIntegerTy(8) + assert fn.getReturnType().isIntegerTy(8) -assert fnty is fn.getFunctionType() + assert fnty is fn.getFunctionType() -assert fn.isVarArg() == False -assert fn.getIntrinsicID() == 0 -assert not fn.isIntrinsic() + assert fn.isVarArg() == False + assert fn.getIntrinsicID() == 0 + assert not fn.isIntrinsic() -fn_uselist = fn.list_use() -assert isinstance(fn_uselist, list) -assert len(fn_uselist) == 0 + fn_uselist = fn.list_use() + assert isinstance(fn_uselist, list) + assert len(fn_uselist) == 0 -builder = api.IRBuilder.new(context) -print builder + builder = api.IRBuilder.new(context) + print builder -bb = api.BasicBlock.Create(context, "entry", fn, None) -assert bb.empty() -builder.SetInsertPoint(bb) + bb = api.BasicBlock.Create(context, "entry", fn, None) + assert bb.empty() + builder.SetInsertPoint(bb) -assert bb.getTerminator() is None + assert bb.getTerminator() is None -arg0, arg1 = fn.getArgumentList() -print arg0, arg1 + arg0, arg1 = fn.getArgumentList() + print arg0, arg1 -extended = builder.CreateZExt(arg0, arg1.getType()) -result = builder.CreateAdd(extended, arg1) -ret = builder.CreateTrunc(result, fn.getReturnType()) -builder.CreateRet(ret) + extended = builder.CreateZExt(arg0, arg1.getType()) + result = builder.CreateAdd(extended, arg1) + ret = builder.CreateTrunc(result, fn.getReturnType()) + builder.CreateRet(ret) -print arg0.list_use() + print arg0.list_use() -print fn + print fn -errio = StringIO() -print m + errio = StringIO() + print m -ee = api.ExecutionEngine.createJIT(m, errio) -print ee, errio.getvalue() -print ee.getDataLayout().getStringRepresentation() + ee = api.ExecutionEngine.createJIT(m, errio) + print ee, errio.getvalue() + print ee.getDataLayout().getStringRepresentation() -datalayout_str = 'e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64' + datalayout_str = 'e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64' -assert datalayout_str == str(api.DataLayout.new(datalayout_str)) -assert datalayout_str == str(api.DataLayout.new(str(api.DataLayout.new(datalayout_str)))) + assert datalayout_str == str(api.DataLayout.new(datalayout_str)) + assert datalayout_str == str(api.DataLayout.new(str(api.DataLayout.new(datalayout_str)))) -fn2 = ee.FindFunctionNamed(fn.getName()) -assert fn2 is fn + fn2 = ee.FindFunctionNamed(fn.getName()) + assert fn2 is fn -assert ee.getPointerToFunction(fn) -assert ee.getPointerToNamedFunction('printf') + assert ee.getPointerToFunction(fn) + assert ee.getPointerToNamedFunction('printf') -gv0 = api.GenericValue.CreateInt(arg0.getType(), 12, False) -gv1 = api.GenericValue.CreateInt(arg1.getType(), -32, True) + gv0 = api.GenericValue.CreateInt(arg0.getType(), 12, False) + gv1 = api.GenericValue.CreateInt(arg1.getType(), -32, True) -assert gv0.valueIntWidth() == arg0.getType().getIntegerBitWidth() -assert gv1.valueIntWidth() == arg1.getType().getIntegerBitWidth() + assert gv0.valueIntWidth() == arg0.getType().getIntegerBitWidth() + assert gv1.valueIntWidth() == arg1.getType().getIntegerBitWidth() -assert gv0.toUnsignedInt() == 12 -assert gv1.toSignedInt() == -32 + assert gv0.toUnsignedInt() == 12 + assert gv1.toSignedInt() == -32 -gv1 = api.GenericValue.CreateInt(arg1.getType(), 32, False) + gv1 = api.GenericValue.CreateInt(arg1.getType(), 32, False) -gvR = ee.runFunction(fn, (gv0, gv1)) + gvR = ee.runFunction(fn, (gv0, gv1)) -assert 44 == gvR.toUnsignedInt() + assert 44 == gvR.toUnsignedInt() + +def test_engine_builder(): + api.InitializeNativeTarget() + context = api.getGlobalContext() + + m = api.Module.new("modname", context) + + eb = api.EngineBuilder.new(m) + eb2 = eb.setEngineKind(api.EngineKind.Kind.JIT) + assert eb is eb2 + eb.setOptLevel(api.CodeGenOpt.Level.Aggressive).setUseMCJIT(False) + + tm = eb.selectTarget() + ee = eb.create(tm) + + +def main(): + for name, value in globals().items(): + if name.startswith('test_') and callable(value): + print name.center(80, '-') + value() + +if __name__ == '__main__': + main() From 9485d03e18a226303b36bae577da37f994f61776 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 1 Feb 2013 14:19:22 -0600 Subject: [PATCH 239/516] binding for Target, Triple, TargetMachine --- newbinding/binding.py | 19 ++++++--- newbinding/include/llvm_binding/extra.h | 28 ++++++++++++- newbinding/src/CodeGen.py | 1 + newbinding/src/EngineBuilder.py | 15 ++++++- newbinding/src/Target.py | 27 ++++++++++++ newbinding/src/TargetMachine.py | 25 +++++++++++ newbinding/src/TargetTransformInfo.py | 14 +++++++ newbinding/src/Triple.py | 55 +++++++++++++++++++++++++ newbinding/test2.py | 23 +++++++++++ 9 files changed, 199 insertions(+), 8 deletions(-) create mode 100644 newbinding/src/Target.py create mode 100644 newbinding/src/TargetTransformInfo.py create mode 100644 newbinding/src/Triple.py diff --git a/newbinding/binding.py b/newbinding/binding.py index 1f980d1..69267dc 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -185,6 +185,11 @@ class Class(_Type): writer.die_if_false(casted) return casted + def wrap(self, writer, val): + copy = 'new %s(%s)' % (self.fullname, val) + return writer.pycapsule_new(copy, self.capsule_name, self.fullname) + + class Enum(object): format = 'O' @@ -466,13 +471,17 @@ class ref(_Type): def __init__(self, element): assert isinstance(element, Class), type(element) self.element = element + self.const = False def __str__(self): return self.fullname @property def fullname(self): - return '%s&' % self.element.fullname + if self.const: + return 'const %s&' % self.element.fullname + else: + return '%s&' % self.element.fullname @property def capsule_name(self): @@ -483,7 +492,7 @@ class ref(_Type): return self.element.format def wrap(self, writer, val): - p = writer.declare(ptr(self.element).fullname, '&%s' % val) + p = writer.declare(const(ptr(self.element)).fullname, '&%s' % val) return writer.pycapsule_new(p, self.capsule_name, self.element.fullname) def unwrap(self, writer, val): @@ -522,9 +531,9 @@ class ptr(_Type): class ownedptr(ptr): pass -def const(ptr): - ptr.const = True - return ptr +def const(ptr_or_ref): + ptr_or_ref.const = True + return ptr_or_ref class cast(_Type): format = 'O' diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h index 10a4361..46dd42a 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/extra.h @@ -368,9 +368,9 @@ PyObject* EngineBuilder_setMAttrs(llvm::EngineBuilder* eb, return NULL; } std::vector tmp; - const int N = PyList_Size(strlist); + const Py_ssize_t N = PyList_Size(strlist); tmp.reserve(N); - for (int i = 0; i < N; ++i) { + for (Py_ssize_t i = 0; i < N; ++i) { const char * elem = PyString_AsString(PyList_GetItem(strlist, i)); if (!elem) { return NULL; @@ -381,3 +381,27 @@ PyObject* EngineBuilder_setMAttrs(llvm::EngineBuilder* eb, return pycapsule_new(eb, "llvm::EngineBuilder"); } +static +PyObject* EngineBuilder_selectTarget(llvm::EngineBuilder* eb, + const llvm::Triple& TargetTriple, + llvm::StringRef MArch, + llvm::StringRef MCPU, + PyObject* strlist) +{ + const Py_ssize_t N = PySequence_Size(strlist); + llvm::SmallVector MAttrs; + MAttrs.reserve(N); + for (Py_ssize_t i = 0; i < N; ++i) { + PyObject* str = PySequence_GetItem(strlist, i); + const char * cp = PyString_AsString(str); + if (!cp) { + Py_DECREF(str); + return NULL; + } + MAttrs.push_back(cp); + Py_DECREF(str); + } + eb->selectTarget(TargetTriple, MArch, MCPU, MAttrs); + return pycapsule_new(eb, "llvm::EngineBuilder"); +} + diff --git a/newbinding/src/CodeGen.py b/newbinding/src/CodeGen.py index 06821aa..7afcd49 100644 --- a/newbinding/src/CodeGen.py +++ b/newbinding/src/CodeGen.py @@ -17,3 +17,4 @@ class TLSModel: class CodeGenOpt: 'Actually a namespace' Level = Enum('None', 'Less', 'Default', 'Aggressive') + diff --git a/newbinding/src/EngineBuilder.py b/newbinding/src/EngineBuilder.py index 0e8388e..07ffcc0 100644 --- a/newbinding/src/EngineBuilder.py +++ b/newbinding/src/EngineBuilder.py @@ -6,6 +6,7 @@ from CodeGen import CodeGenOpt, Reloc, CodeModel from StringRef import StringRef from ExecutionEngine import ExecutionEngine from TargetMachine import TargetMachine +from Triple import Triple EngineBuilder = llvm.Class() @@ -45,5 +46,17 @@ class EngineBuilder: create = Method(ptr(ExecutionEngine), ownedptr(TargetMachine)).require_only(0) - selectTarget = Method(ptr(TargetMachine)) + _selectTarget0 = Method(ptr(TargetMachine)) + _selectTarget0.realname = 'selectTarget' + + _selectTarget1 = CustomMethod('EngineBuilder_selectTarget', + const(ref(Triple)), cast(str, StringRef), + cast(str, StringRef), PyObjectPtr), + + @CustomPythonMethod + def selectTarget(self, *args): + if not args: + return self._selectTarget0() + else: + return self._selectTarget1(*args) diff --git a/newbinding/src/Target.py b/newbinding/src/Target.py new file mode 100644 index 0000000..3c2a0e1 --- /dev/null +++ b/newbinding/src/Target.py @@ -0,0 +1,27 @@ +from binding import * +from namespace import llvm +from StringRef import StringRef +Target = llvm.Class() + +@Target +class Target: + _include_ = 'llvm/Support/TargetRegistry.h' + + getNext = Method(const(ptr(Target))) + + getName = Method(cast(StringRef, str)) + getShortDescription = Method(cast(StringRef, str)) + + def _has(): + return Method(cast(Bool, bool)) + + hasJIT = _has() + hasTargetMachine = _has() + hasMCAsmBackend = _has() + hasMCAsmParser = _has() + hasAsmPrinter = _has() + hasMCDisassembler = _has() + hasMCInstPrinter = _has() + hasMCCodeEmitter = _has() + hasMCObjectStreamer = _has() + hasAsmStreamer = _has() diff --git a/newbinding/src/TargetMachine.py b/newbinding/src/TargetMachine.py index e53cd33..5910585 100644 --- a/newbinding/src/TargetMachine.py +++ b/newbinding/src/TargetMachine.py @@ -1,5 +1,12 @@ from binding import * from namespace import llvm +from StringRef import StringRef +from CodeGen import CodeModel, TLSModel, CodeGenOpt, Reloc +from GlobalValue import GlobalValue +from Target import Target +from DataLayout import DataLayout +from TargetTransformInfo import (ScalarTargetTransformInfo, + VectorTargetTransformInfo) TargetMachine = llvm.Class() @@ -8,4 +15,22 @@ class TargetMachine: _include_ = 'llvm/Target/TargetMachine.h' delete = Destructor() + getTarget = Method(const(ref(Target))) + getTargetTriple = Method(cast(StringRef, str)) + getTargetCPU = Method(cast(StringRef, str)) + getTargetFeatureString = Method(cast(StringRef, str)) + + getRelocationModel = Method(Reloc.Model) + getCodeModel = Method(CodeModel.Model) + getTLSModel = Method(TLSModel.Model, ptr(GlobalValue)) + getOptLevel = Method(CodeGenOpt.Level) + + hasMCUseDwarfDirectory = Method(cast(Bool, bool)) + setMCUseDwarfDirectory = Method(Void, cast(bool, Bool)) + + getDataLayout = Method(const(ownedptr(DataLayout))) + getScalarTargetTransformInfo = Method(const( + ownedptr(ScalarTargetTransformInfo))) + getVectorTargetTransformInfo = Method(const( + ownedptr(VectorTargetTransformInfo))) diff --git a/newbinding/src/TargetTransformInfo.py b/newbinding/src/TargetTransformInfo.py new file mode 100644 index 0000000..8e3c17e --- /dev/null +++ b/newbinding/src/TargetTransformInfo.py @@ -0,0 +1,14 @@ +from binding import * +from namespace import llvm + +ScalarTargetTransformInfo = llvm.Class() +VectorTargetTransformInfo = llvm.Class() + +@ScalarTargetTransformInfo +class ScalarTargetTransformInfo: + delete = Destructor() + +@VectorTargetTransformInfo +class VectorTargetTransformInfo: + delete = Destructor() + diff --git a/newbinding/src/Triple.py b/newbinding/src/Triple.py new file mode 100644 index 0000000..0fd894e --- /dev/null +++ b/newbinding/src/Triple.py @@ -0,0 +1,55 @@ +from binding import * +from namespace import llvm +from StringRef import StringRef + +Triple = llvm.Class() + +@Triple +class Triple: + _include_ = 'llvm/ADT/Triple.h' + + new = Constructor() + new |= Constructor(cast(str, StringRef)) + new |= Constructor(cast(str, StringRef), + cast(str, StringRef), cast(str, StringRef)) + + def _return_str(): + return Method(cast(StringRef, str)) + + getTriple = _return_str() + getArchName = _return_str() + getVendorName = _return_str() + getOSName = _return_str() + getEnvironmentName = _return_str() + getOSAndEnvironmentName = _return_str() + + @CustomPythonMethod + def __str__(self): + return self.getTriple() + + def _return_bool(*args): + return Method(cast(bool, Bool), *args) + + isArch64Bit = _return_bool() + isArch32Bit = _return_bool() + isArch16Bit = _return_bool() + isOSVersionLT = _return_bool(cast(int, Unsigned), + cast(int, Unsigned), + cast(int, Unsigned)).require_only(1) + + isMacOSXVersionLT = _return_bool(cast(int, Unsigned), + cast(int, Unsigned), + cast(int, Unsigned)).require_only(1) + + isMacOSX = _return_bool() + isOSDarwin = _return_bool() + isOSCygMing = _return_bool() + isOSWindows = _return_bool() + # isOSNaCl = _return_bool() + isOSBinFormatELF = _return_bool() + isOSBinFormatCOFF = _return_bool() + isEnvironmentMachO = _return_bool() + + get32BitArchVariant = Method(Triple) + get64BitArchVariant = Method(Triple) + diff --git a/newbinding/test2.py b/newbinding/test2.py index a304426..93fccb8 100644 --- a/newbinding/test2.py +++ b/newbinding/test2.py @@ -124,8 +124,31 @@ def test_engine_builder(): eb.setOptLevel(api.CodeGenOpt.Level.Aggressive).setUseMCJIT(False) tm = eb.selectTarget() + + print 'target triple:', tm.getTargetTriple() + print 'target cpu:', tm.getTargetCPU() + print 'target feature string:', tm.getTargetFeatureString() + + target = tm.getTarget() + print 'target name:', target.getName() + print 'target short description:', target.getShortDescription() + + assert target.hasJIT() + assert target.hasTargetMachine() + ee = eb.create(tm) + triple = api.Triple.new('x86_64-unknown-linux') + assert triple.getArchName() == 'x86_64' + assert triple.getVendorName() == 'unknown' + assert triple.getOSName() == 'linux' + assert triple.isArch64Bit() + assert not triple.isArch32Bit() + triple_32variant = triple.get32BitArchVariant() + assert triple_32variant.isArch32Bit() + + print tm.getDataLayout() + def main(): for name, value in globals().items(): From 372d6804e4ba2b38cd10172323413b2d48417133 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 1 Feb 2013 17:02:09 -0600 Subject: [PATCH 240/516] Add bindings for Pass, PassManagers, PassManagerBuilder and TargetLibraryInfo. --- newbinding/binding.py | 2 + newbinding/src/DataLayout.py | 5 +- newbinding/src/Pass.py | 35 +++++++++++++ newbinding/src/PassManager.py | 34 +++++++++++++ newbinding/src/PassManagerBuilder.py | 19 +++++++ newbinding/src/TargetLibraryInfo.py | 76 ++++++++++++++++++++++++++++ newbinding/test2.py | 25 ++++++++- 7 files changed, 192 insertions(+), 4 deletions(-) create mode 100644 newbinding/src/Pass.py create mode 100644 newbinding/src/PassManager.py create mode 100644 newbinding/src/PassManagerBuilder.py create mode 100644 newbinding/src/TargetLibraryInfo.py diff --git a/newbinding/binding.py b/newbinding/binding.py index 69267dc..cb40d1e 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -195,6 +195,8 @@ class Enum(object): def __init__(self, *value_names): self.parent = None + if len(value_names) == 1: + value_names = filter(bool, value_names[0].replace(',', ' ').split()) self.value_names = value_names self.includes = set() diff --git a/newbinding/src/DataLayout.py b/newbinding/src/DataLayout.py index a1ef8bc..74d1ad0 100644 --- a/newbinding/src/DataLayout.py +++ b/newbinding/src/DataLayout.py @@ -6,8 +6,9 @@ from Module import Module from Type import Type, IntegerType, StructType from SmallVector import SmallVector_Value from GlobalVariable import GlobalVariable +from Pass import ImmutablePass -DataLayout = llvm.Class() +DataLayout = llvm.Class(ImmutablePass) StructLayout = llvm.Class() @DataLayout @@ -24,8 +25,6 @@ class DataLayout: else: return DataLayout._new_string(arg) - delete = Destructor() - isLittleEndian = Method(cast(Bool, bool)) isBigEndian = Method(cast(Bool, bool)) diff --git a/newbinding/src/Pass.py b/newbinding/src/Pass.py new file mode 100644 index 0000000..5842232 --- /dev/null +++ b/newbinding/src/Pass.py @@ -0,0 +1,35 @@ +from binding import * +from namespace import llvm +from StringRef import StringRef +from Module import Module +from Function import Function + +Pass = llvm.Class() +ModulePass = llvm.Class(Pass) +FunctionPass = llvm.Class(Pass) +ImmutablePass = llvm.Class(ModulePass) + + +@Pass +class Pass: + _include_ = 'llvm/Pass.h' + + delete = Destructor() + getPassName = Method(cast(StringRef, str)) + + +@ModulePass +class ModulePass: + runOnModule = Method(cast(Bool, bool), ref(Module)) + + +@FunctionPass +class FunctionPass: + doInitialization = Method(cast(Bool, bool), ref(Module)) + doFinalization = Method(cast(Bool, bool), ref(Module)) + + +@ImmutablePass +class ImmutablePass: + pass + diff --git a/newbinding/src/PassManager.py b/newbinding/src/PassManager.py new file mode 100644 index 0000000..f969192 --- /dev/null +++ b/newbinding/src/PassManager.py @@ -0,0 +1,34 @@ +from binding import * +from namespace import llvm +from Pass import Pass +from Module import Module +from Function import Function + +PassManagerBase = llvm.Class() +PassManager = llvm.Class(PassManagerBase) +FunctionPassManager = llvm.Class(PassManagerBase) + +@PassManagerBase +class PassManagerBase: + _include_ = 'llvm/PassManager.h' + + delete = Destructor() + + add = Method(Void, ownedptr(Pass)) + +@PassManager +class PassManager: + new = Constructor() + + run = Method(cast(Bool, bool), ref(Module)) + + +@FunctionPassManager +class FunctionPassManager: + new = Constructor(ptr(Module)) + + run = Method(cast(Bool, bool), ref(Function)) + + doInitialization = Method(cast(Bool, bool)) + doFinalization = Method(cast(Bool, bool)) + diff --git a/newbinding/src/PassManagerBuilder.py b/newbinding/src/PassManagerBuilder.py new file mode 100644 index 0000000..2e2ea5e --- /dev/null +++ b/newbinding/src/PassManagerBuilder.py @@ -0,0 +1,19 @@ +from binding import * +from namespace import llvm +from PassManager import PassManagerBase, FunctionPassManager + +@llvm.Class() +class PassManagerBuilder: + _include_ = 'llvm/Transforms/IPO/PassManagerBuilder.h' + + new = Constructor() + delete = Destructor() + + populateFunctionPassManager = Method(Void, ref(FunctionPassManager)) + populateModulePassManager = Method(Void, ref(PassManagerBase)) + populateLTOPassManager = Method(Void, + ref(PassManagerBase), + cast(bool, Bool), + cast(bool, Bool), + cast(bool, Bool)).require_only(3) + diff --git a/newbinding/src/TargetLibraryInfo.py b/newbinding/src/TargetLibraryInfo.py new file mode 100644 index 0000000..a5ba28d --- /dev/null +++ b/newbinding/src/TargetLibraryInfo.py @@ -0,0 +1,76 @@ +from binding import * +from namespace import llvm +from Triple import Triple +from Pass import ImmutablePass +from StringRef import StringRef + +TargetLibraryInfo = llvm.Class(ImmutablePass) + +@llvm.Class() +class LibFunc: + Func = Enum(''' + ZdaPv, ZdlPv, Znaj, ZnajRKSt9nothrow_t, + Znam, ZnamRKSt9nothrow_t, Znwj, ZnwjRKSt9nothrow_t, + Znwm, ZnwmRKSt9nothrow_t, cxa_atexit, cxa_guard_abort, + cxa_guard_acquire, cxa_guard_release, memcpy_chk, + acos, acosf, acosh, acoshf, + acoshl, acosl, asin, asinf, + asinh, asinhf, asinhl, asinl, + atan, atan2, atan2f, atan2l, + atanf, atanh, atanhf, atanhl, + atanl, calloc, cbrt, cbrtf, + cbrtl, ceil, ceilf, ceill, + copysign, copysignf, copysignl, cos, + cosf, cosh, coshf, coshl, + cosl, exp, exp10, exp10f, + exp10l, exp2, exp2f, exp2l, + expf, expl, expm1, expm1f, + expm1l, fabs, fabsf, fabsl, + fiprintf, + floor, floorf, floorl, fmod, + fmodf, fmodl, fputc, + fputs, free, fwrite, iprintf, + log, log10, log10f, log10l, + log1p, log1pf, log1pl, log2, + log2f, log2l, logb, logbf, + logbl, logf, logl, malloc, + memchr, memcmp, memcpy, memmove, + memset, memset_pattern16, nearbyint, nearbyintf, + nearbyintl, posix_memalign, pow, powf, + powl, putchar, puts, + realloc, reallocf, rint, rintf, + rintl, round, roundf, roundl, + sin, sinf, sinh, sinhf, + sinhl, sinl, siprintf, + sqrt, sqrtf, sqrtl, stpcpy, + strcat, strchr, strcmp, strcpy, + strcspn, strdup, strlen, strncat, + strncmp, strncpy, strndup, strnlen, + strpbrk, strrchr, strspn, strstr, + strtod, strtof, strtol, strtold, + strtoll, strtoul, strtoull, tan, + tanf, tanh, tanhf, tanhl, + tanl, trunc, truncf, + truncl, valloc, NumLibFuncs''') + # not in llvm-3.2 abs, ffs, ffsl, ffsll, fprintf, isascii, + # isdigit, labs, llabs, printf, sprintf, toascii + +@TargetLibraryInfo +class TargetLibraryInfo: + _include_ = 'llvm/Target/TargetLibraryInfo.h' + + new = Constructor() + new |= Constructor(ref(Triple)) + + delete = Destructor() + + has = Method(cast(bool, Bool), LibFunc.Func) + hasOptimizedCodeGen = Method(cast(bool, Bool), LibFunc.Func) + + getName = Method(cast(str, StringRef), LibFunc.Func) + + setUnavailable = Method(Void, LibFunc.Func) + setAvailable = Method(Void, LibFunc.Func) + setAvailableWithName = Method(Void, LibFunc.Func, cast(str, StringRef)) + disableAllFunctions = Method() + diff --git a/newbinding/test2.py b/newbinding/test2.py index 93fccb8..e2f8dd2 100644 --- a/newbinding/test2.py +++ b/newbinding/test2.py @@ -8,7 +8,6 @@ def test_basic_jit_use(): api.InitializeNativeTarget() context = api.getGlobalContext() - m = api.Module.new("modname", context) print m.getModuleIdentifier() m.setModuleIdentifier('modname2') @@ -82,6 +81,26 @@ def test_basic_jit_use(): errio = StringIO() print m + # build pass manager + + pmb = api.PassManagerBuilder.new() + + fpm = api.FunctionPassManager.new(m) + pm = api.PassManager.new() + + pmb.populateFunctionPassManager(fpm) + pmb.populateModulePassManager(pm) + + fpm.doInitialization() + fpm.run(fn) + fpm.doFinalization() + + pm.run(m) + + print m + + # build engine + ee = api.ExecutionEngine.createJIT(m, errio) print ee, errio.getvalue() print ee.getDataLayout().getStringRepresentation() @@ -149,6 +168,10 @@ def test_engine_builder(): print tm.getDataLayout() + pm = api.PassManager.new() + pm.add(api.DataLayout.new(str(tm.getDataLayout()))) + pm.add(api.TargetLibraryInfo.new()) + def main(): for name, value in globals().items(): From 7788346152a461142f5256f832d66d2d9347981e Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 1 Feb 2013 17:32:30 -0600 Subject: [PATCH 241/516] Improve enum implementation --- newbinding/binding.py | 48 +++++++++++++++++++------------------------ newbinding/gen.py | 7 +++++++ 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/newbinding/binding.py b/newbinding/binding.py index cb40d1e..4205c64 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -125,6 +125,8 @@ class Class(_Type): # generate methods for meth in self.methods: meth.compile_cpp(writer) + for enum in self.enums: + enum.compile_cpp(writer) # generate method table writer.println('static') @@ -135,6 +137,11 @@ class Class(_Type): name = meth.name func = meth.c_name writer.println(fmt % locals()) + for enumkind in self.enums: + for enum in enumkind.value_names: + name = enum + func = enumkind.c_name(enum) + writer.println(fmt % locals()) writer.println('{ NULL },') writer.println('};') writer.println() @@ -212,38 +219,22 @@ class Enum(object): return self.fullname def wrap(self, writer, val): - ret = writer.declare('PyObject*', 'NULL') - with writer.block('switch(%s) ' % val): - for v in self.value_names: - writer.println('case %s::%s:' % (self.parent, v)) - with writer.indent(): - fmt = '%(ret)s = PyString_FromString("%(v)s");' - writer.println(fmt % locals()) - writer.println('break;') - else: - writer.println('default:') - with writer.indent(): - writer.raises(ValueError, 'Invalid enum %s' % v) + ret = writer.declare('PyObject*', 'PyInt_FromLong(%s)' % val) return ret def unwrap(self, writer, val): - tostring = 'PyString_AsString(%(val)s)' % locals() - string = writer.declare('const char*', tostring) - ret = writer.declare('%s::%s' % (self.parent, self.name)) - parent = self.parent - iffmt = 'if (string_equal(%(string)s, "%(v)s"))' - for i, v in enumerate(self.value_names): - with writer.block(iffmt % locals()): - fmt = '%(ret)s = %(parent)s::%(v)s;' - writer.println(fmt % locals()) - if i == 0: - iffmt = 'else ' + iffmt - with writer.block('else'): - writer.raises(ValueError, 'Invalid enum.') + convert_long_to_enum = '(%s)PyInt_AsLong(%s)' % (self.fullname, val) + ret = writer.declare(self.fullname, convert_long_to_enum) return ret + def c_name(self, enum): + return cg.mangle("%s_%s_%s" % (self.parent, self.name, enum)) + def compile_cpp(self, writer): - pass + for enum in self.value_names: + with writer.py_function(self.c_name(enum)): + ret = self.wrap(writer, '::'.join([self.parent.fullname, enum])) + writer.return_value(ret) def compile_py(self, writer): with writer.block('class %s:' % self.name): @@ -251,9 +242,12 @@ class Enum(object): for v in self.value_names: if v in RESERVED: k = '%s_' % v + fmt = '%(k)s = getattr(%(p)s, "%(v)s")()' else: k = v - writer.println('%(k)s = "%(v)s"' % locals()) + fmt = '%(k)s = %(p)s.%(v)s()' + p = '.'.join(['_api'] + self.parent.fullname.split('::')[1:]) + writer.println(fmt % locals()) writer.println() class Method(object): diff --git a/newbinding/gen.py b/newbinding/gen.py index 47f5655..7c56452 100644 --- a/newbinding/gen.py +++ b/newbinding/gen.py @@ -136,6 +136,13 @@ static name = u.name func = u.c_name writer.println(fmt % locals()) + for u in units: + if isinstance(u, Enum): + for enum in u.value_names: + name = enum + func = u.c_name(enum) + writer.println(fmt % locals()) + writer.println('{ NULL },') writer.println('};') writer.println() From 1f49bb6d7c7e1fcfeb0ab47c3770ec35e65917dc Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sun, 3 Feb 2013 12:57:13 -0600 Subject: [PATCH 242/516] Binding for PassManagerBuilder --- newbinding/binding.py | 92 +++++++++++++++++++++++++ newbinding/include/llvm_binding/extra.h | 14 ++-- newbinding/{src => }/namespace.py | 0 newbinding/src/EngineBuilder.py | 3 +- newbinding/src/PassManagerBuilder.py | 24 +++++++ newbinding/src/Transforms/IPO.py | 9 +++ newbinding/src/Transforms/__init__.py | 10 +++ newbinding/src/__init__.py | 5 +- newbinding/test2.py | 4 ++ 9 files changed, 151 insertions(+), 10 deletions(-) rename newbinding/{src => }/namespace.py (100%) create mode 100644 newbinding/src/Transforms/IPO.py create mode 100644 newbinding/src/Transforms/__init__.py diff --git a/newbinding/binding.py b/newbinding/binding.py index 4205c64..142c8ef 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -83,6 +83,7 @@ class Class(_Type): self.methods = [] self.pymethods = [] self.enums = [] + self.attrs = [] self.includes = set() self.downcastables = set() @@ -103,6 +104,10 @@ class Class(_Type): v.name = k v.parent = self setattr(self, k, v) + elif isinstance(v, Attr): + self.attrs.append(v) + v.name = k + v.parent = self elif isinstance(v, CustomPythonMethod): self.pymethods.append(v) elif k == '_include_': @@ -127,6 +132,8 @@ class Class(_Type): meth.compile_cpp(writer) for enum in self.enums: enum.compile_cpp(writer) + for attr in self.attrs: + attr.compile_cpp(writer) # generate method table writer.println('static') @@ -142,6 +149,16 @@ class Class(_Type): name = enum func = enumkind.c_name(enum) writer.println(fmt % locals()) + for attr in self.attrs: + # getter + name = attr.getter_name + func = attr.getter_c_name + writer.println(fmt % locals()) + # setter + name = attr.setter_name + func = attr.setter_c_name + writer.println(fmt % locals()) + writer.println('{ NULL },') writer.println('};') writer.println() @@ -160,6 +177,8 @@ class Class(_Type): meth.compile_py(writer) for meth in self.pymethods: meth.compile_py(writer) + for attr in self.attrs: + attr.compile_py(writer) writer.println() @property @@ -587,3 +606,76 @@ class CustomPythonStaticMethod(CustomPythonMethod): writer.println('@staticmethod') super(CustomPythonStaticMethod, self).compile_py(writer) + +class Attr(object): + def __init__(self, getter, setter): + self.getter = getter + self.setter = setter + + @property + def fullname(self): + try: + name = self.realname + except AttributeError: + name = self.name + return '::'.join([self.parent.fullname, name]) + + def __str__(self): + return self.fullname + + @property + def getter_name(self): + return '%s_get' % self.name + + @property + def setter_name(self): + return '%s_set' % self.name + + @property + def getter_c_name(self): + return cg.mangle('%s_get' % self.fullname) + + @property + def setter_c_name(self): + return cg.mangle('%s_set' % self.fullname) + + def compile_cpp(self, writer): + # getter + with writer.py_function(self.getter_c_name): + (this,) = writer.parse_arguments('args', ptr(self.parent)) + attr = self.name + ret = writer.declare(self.getter.fullname, + '%(this)s->%(attr)s' % locals()) + writer.return_value(self.getter.wrap(writer, ret)) + # setter + with writer.py_function(self.setter_c_name): + (this, value) = writer.parse_arguments('args', ptr(self.parent), + self.setter) + attr = self.name + writer.println('%(this)s->%(attr)s = %(value)s;' % locals()) + writer.return_value(None) + + def compile_py(self, writer): + name = self.name + parent = '.'.join(self.parent.fullname.split('::')[1:]) + getter = '.'.join([parent, self.getter_name]) + setter = '.'.join([parent, self.setter_name]) + writer.println('@property') + with writer.block('def %(name)s(self):' % locals()): + unself = writer.unwrap('self') + ret = writer.new_symbol('ret') + writer.println('%(ret)s = _api.%(getter)s(%(unself)s)' % locals()) + is_ownedptr = isinstance(self.getter, ownedptr) + writer.return_value(writer.wrap(ret, is_ownedptr)) + writer.println() + writer.println('@%(name)s.setter' % locals()) + with writer.block('def %(name)s(self, value):' % locals()): + unself = writer.unwrap('self') + unvalue = writer.unwrap('value') + if isinstance(self.setter, ownedptr): + writer.release_ownership(unvalue) + writer.println('return _api.%(setter)s(%(unself)s, %(unvalue)s)' % + locals()) + writer.println() + + diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h index 46dd42a..c69f177 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/extra.h @@ -163,13 +163,13 @@ PyObject* iplist_to_pylist(iplist &IPL, const char * capsuleName, className); } -static -bool string_equal(const char *A, const char *B){ - for (; *A and *B; ++A, ++B) { - if (*A != *B) return false; - } - return true; -} +//static +//bool string_equal(const char *A, const char *B){ +// for (; *A and *B; ++A, ++B) { +// if (*A != *B) return false; +// } +// return true; +//} //////////// static diff --git a/newbinding/src/namespace.py b/newbinding/namespace.py similarity index 100% rename from newbinding/src/namespace.py rename to newbinding/namespace.py diff --git a/newbinding/src/EngineBuilder.py b/newbinding/src/EngineBuilder.py index 07ffcc0..d9594f0 100644 --- a/newbinding/src/EngineBuilder.py +++ b/newbinding/src/EngineBuilder.py @@ -50,8 +50,9 @@ class EngineBuilder: _selectTarget0.realname = 'selectTarget' _selectTarget1 = CustomMethod('EngineBuilder_selectTarget', + PyObjectPtr, const(ref(Triple)), cast(str, StringRef), - cast(str, StringRef), PyObjectPtr), + cast(str, StringRef), PyObjectPtr) @CustomPythonMethod def selectTarget(self, *args): diff --git a/newbinding/src/PassManagerBuilder.py b/newbinding/src/PassManagerBuilder.py index 2e2ea5e..11fedfb 100644 --- a/newbinding/src/PassManagerBuilder.py +++ b/newbinding/src/PassManagerBuilder.py @@ -1,6 +1,8 @@ from binding import * from namespace import llvm from PassManager import PassManagerBase, FunctionPassManager +from TargetLibraryInfo import TargetLibraryInfo +from Pass import Pass @llvm.Class() class PassManagerBuilder: @@ -17,3 +19,25 @@ class PassManagerBuilder: cast(bool, Bool), cast(bool, Bool)).require_only(3) + def _attr_int(): + return Attr(getter=cast(Unsigned, int), + setter=cast(int, Unsigned)) + + OptLevel = _attr_int() + SizeLevel = _attr_int() + + def _attr_bool(): + return Attr(getter=cast(Bool, bool), + setter=cast(bool, Bool)) + + DisableSimplifyLibCalls = _attr_bool() + DisableUnitAtATime = _attr_bool() + DisableUnrollLoops = _attr_bool() + Vectorize = _attr_bool() + LoopVectorize = _attr_bool() + + LibraryInfo = Attr(getter=ownedptr(TargetLibraryInfo), + setter=ownedptr(TargetLibraryInfo)) + + Inliner = Attr(getter=ownedptr(Pass), + setter=ownedptr(Pass)) diff --git a/newbinding/src/Transforms/IPO.py b/newbinding/src/Transforms/IPO.py new file mode 100644 index 0000000..6c2fc26 --- /dev/null +++ b/newbinding/src/Transforms/IPO.py @@ -0,0 +1,9 @@ +from binding import * +from namespace import llvm +from ..Pass import Pass + +llvm.includes.add('llvm/Transforms/IPO.h') + +createFunctionInliningPass = llvm.Function('createFunctionInliningPass', + ptr(Pass), + cast(int, Unsigned)).require_only(0) diff --git a/newbinding/src/Transforms/__init__.py b/newbinding/src/Transforms/__init__.py new file mode 100644 index 0000000..da0beed --- /dev/null +++ b/newbinding/src/Transforms/__init__.py @@ -0,0 +1,10 @@ +import os.path, importlib + +def _init(): + for fname in os.listdir(os.path.dirname(__file__)): + if ((fname.endswith('.py') or fname.endswith('.pyc')) and + not fname.startswith('__init__')): + modname = os.path.basename(fname).rsplit('.', 1)[0] + importlib.import_module('.' + modname, __name__) + +_init() diff --git a/newbinding/src/__init__.py b/newbinding/src/__init__.py index 1042826..f67a3c4 100644 --- a/newbinding/src/__init__.py +++ b/newbinding/src/__init__.py @@ -5,7 +5,8 @@ def _init(): if ((fname.endswith('.py') or fname.endswith('.pyc')) and not fname.startswith('__init__')): modname = os.path.basename(fname).rsplit('.', 1)[0] - topname = __name__.rsplit('.', 1)[0] - importlib.import_module('.' + modname, topname) + importlib.import_module('.' + modname, __name__) _init() + +import Transforms \ No newline at end of file diff --git a/newbinding/test2.py b/newbinding/test2.py index e2f8dd2..248e32a 100644 --- a/newbinding/test2.py +++ b/newbinding/test2.py @@ -84,6 +84,10 @@ def test_basic_jit_use(): # build pass manager pmb = api.PassManagerBuilder.new() + pmb.OptLevel = 3 + assert pmb.OptLevel == 3 + pmb.LibraryInfo = api.TargetLibraryInfo.new() + pmb.Inliner = api.createFunctionInliningPass() fpm = api.FunctionPassManager.new(m) pm = api.PassManager.new() From c085bef46e4bd03ca60abff0ba46928ce7f81ad7 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sun, 3 Feb 2013 15:01:57 -0600 Subject: [PATCH 243/516] Rename the tests --- newbinding/Makefile | 4 +-- newbinding/test.py | 32 ------------------------ newbinding/{test2.py => test_binding.py} | 0 3 files changed, 2 insertions(+), 34 deletions(-) delete mode 100644 newbinding/test.py rename newbinding/{test2.py => test_binding.py} (100%) diff --git a/newbinding/Makefile b/newbinding/Makefile index 735d4ff..8573235 100644 --- a/newbinding/Makefile +++ b/newbinding/Makefile @@ -13,10 +13,10 @@ clean: cleantemp cleantemp: rm -f api.cpp api.py - rm -f src/*.pyc + rm -f src/*.pyc src/Transforms/*.pyc check: _api.so api.py - $(PYTHON) test2.py + $(PYTHON) test_binding.py @PHONY: all clean check diff --git a/newbinding/test.py b/newbinding/test.py deleted file mode 100644 index bed9e1a..0000000 --- a/newbinding/test.py +++ /dev/null @@ -1,32 +0,0 @@ -import _api - -context = _api.getGlobalContext() -modname = "modname" -module = _api.Module.new(modname, context) -assert modname == _api.Module.getModuleIdentifier(module) -modname2 = "newmodname" -_api.Module.setModuleIdentifier(module, modname2) -assert modname2 == _api.Module.getModuleIdentifier(module) - -_api.Module.dump(module) - -_api.Module.delete(module) - -voidty = _api.Type.getVoidTy(context) -assert _api.Type.isVoidTy(voidty) -assert not _api.Type.isLabelTy(voidty) - -int21ty = _api.Type.getIntNTy(context, 21) -assert _api.Type.isIntegerTy(int21ty) -assert _api.Type.isIntegerTy(int21ty, 21) -_api.Type.dump(int21ty) - -halfty = _api.Type.getHalfTy(context) -assert _api.Type.isHalfTy(halfty) -_api.Type.dump(halfty) - -fnty = _api.FunctionType.get(halfty, False) -_api.Type.dump(fnty) - - - diff --git a/newbinding/test2.py b/newbinding/test_binding.py similarity index 100% rename from newbinding/test2.py rename to newbinding/test_binding.py From 961c5e99e1191f44fb192d226119877f695a84ce Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sun, 3 Feb 2013 15:09:07 -0600 Subject: [PATCH 244/516] Re-organize --- newbinding/Makefile | 6 +++--- newbinding/{ => gen}/binding.py | 0 newbinding/{ => gen}/codegen.py | 0 newbinding/{ => gen}/gen.py | 4 ++-- newbinding/src/{ => ADT}/SmallVector.py | 2 +- newbinding/src/{ => ADT}/StringRef.py | 2 +- newbinding/src/{ => ADT}/Triple.py | 2 +- newbinding/src/ADT/__init__.py | 10 ++++++++++ .../AssemblyAnnotationWriter.py | 2 +- newbinding/src/Assembly/__init__.py | 10 ++++++++++ newbinding/src/BasicBlock.py | 2 +- .../src/{ => CodeGen}/MachineCodeInfo.py | 2 +- newbinding/src/CodeGen/__init__.py | 10 ++++++++++ newbinding/src/DataLayout.py | 4 ++-- newbinding/src/DerivedTypes.py | 2 +- newbinding/src/EngineBuilder.py | 10 +++++----- .../{ => ExecutionEngine}/ExecutionEngine.py | 20 +++++++++---------- newbinding/src/ExecutionEngine/__init__.py | 10 ++++++++++ newbinding/src/IRBuilder.py | 4 ++-- newbinding/src/Module.py | 6 +++--- newbinding/src/Pass.py | 2 +- newbinding/src/{ => Support}/CodeGen.py | 2 +- newbinding/src/Support/MemoryBuffer.py | 9 +++++++++ newbinding/src/{ => Support}/Target.py | 4 ++-- newbinding/src/{ => Support}/TargetSelect.py | 4 ++-- newbinding/src/Support/__init__.py | 10 ++++++++++ newbinding/src/{ => Support}/raw_ostream.py | 6 +++--- .../src/{ => Target}/TargetLibraryInfo.py | 8 ++++---- newbinding/src/{ => Target}/TargetMachine.py | 16 +++++++-------- newbinding/src/Target/__init__.py | 10 ++++++++++ newbinding/src/TargetTransformInfo.py | 2 ++ newbinding/src/Transforms/IPO.py | 2 +- .../{ => Transforms}/PassManagerBuilder.py | 8 ++++---- newbinding/src/Type.py | 4 ++-- newbinding/src/Value.py | 6 +++--- newbinding/src/__init__.py | 2 +- newbinding/{ => src}/namespace.py | 0 37 files changed, 137 insertions(+), 66 deletions(-) rename newbinding/{ => gen}/binding.py (100%) rename newbinding/{ => gen}/codegen.py (100%) rename newbinding/{ => gen}/gen.py (98%) rename newbinding/src/{ => ADT}/SmallVector.py (92%) rename newbinding/src/{ => ADT}/StringRef.py (76%) rename newbinding/src/{ => ADT}/Triple.py (98%) create mode 100644 newbinding/src/ADT/__init__.py rename newbinding/src/{ => Assembly}/AssemblyAnnotationWriter.py (81%) create mode 100644 newbinding/src/Assembly/__init__.py rename newbinding/src/{ => CodeGen}/MachineCodeInfo.py (91%) create mode 100644 newbinding/src/CodeGen/__init__.py rename newbinding/src/{ => ExecutionEngine}/ExecutionEngine.py (89%) create mode 100644 newbinding/src/ExecutionEngine/__init__.py rename newbinding/src/{ => Support}/CodeGen.py (93%) create mode 100644 newbinding/src/Support/MemoryBuffer.py rename newbinding/src/{ => Support}/Target.py (89%) rename newbinding/src/{ => Support}/TargetSelect.py (54%) create mode 100644 newbinding/src/Support/__init__.py rename newbinding/src/{ => Support}/raw_ostream.py (73%) rename newbinding/src/{ => Target}/TargetLibraryInfo.py (95%) rename newbinding/src/{ => Target}/TargetMachine.py (72%) create mode 100644 newbinding/src/Target/__init__.py rename newbinding/src/{ => Transforms}/PassManagerBuilder.py (88%) rename newbinding/{ => src}/namespace.py (100%) diff --git a/newbinding/Makefile b/newbinding/Makefile index 8573235..0e7924f 100644 --- a/newbinding/Makefile +++ b/newbinding/Makefile @@ -5,15 +5,15 @@ all: _api.so _capsule.so _api.so _capsule.so: api.cpp capsule.cpp $(PYTHON) setup.py build_ext --inplace -api.cpp api.py: src/*.py include/llvm_binding/*.h gen.py binding.py - $(PYTHON) gen.py api src +api.cpp api.py: src/*.py include/llvm_binding/*.h gen/gen.py gen/binding.py + $(PYTHON) gen/gen.py api src clean: cleantemp rm -f _api.so _capsule.so cleantemp: rm -f api.cpp api.py - rm -f src/*.pyc src/Transforms/*.pyc + rm -f src/*.pyc src/Transforms/*.pyc src/ADT/*.pyc src/Assembly/*.pyc src/CodeGen/*.pyc src/ExecutionEngine/*.pyc src/Target/*.pyc src/Transforms/*.pyc check: _api.so api.py diff --git a/newbinding/binding.py b/newbinding/gen/binding.py similarity index 100% rename from newbinding/binding.py rename to newbinding/gen/binding.py diff --git a/newbinding/codegen.py b/newbinding/gen/codegen.py similarity index 100% rename from newbinding/codegen.py rename to newbinding/gen/codegen.py diff --git a/newbinding/gen.py b/newbinding/gen/gen.py similarity index 98% rename from newbinding/gen.py rename to newbinding/gen/gen.py index 7c56452..89399f3 100644 --- a/newbinding/gen.py +++ b/newbinding/gen/gen.py @@ -1,4 +1,4 @@ -import sys +import sys, os from binding import * import codegen @@ -59,7 +59,7 @@ def wrap_println_from_file(file): def main(): outputfilename = sys.argv[1] entry_modname = sys.argv[2] - + sys.path += [os.path.dirname(os.curdir)] entry_module = __import__(entry_modname) units = [] diff --git a/newbinding/src/SmallVector.py b/newbinding/src/ADT/SmallVector.py similarity index 92% rename from newbinding/src/SmallVector.py rename to newbinding/src/ADT/SmallVector.py index 5b48aba..f52ff60 100644 --- a/newbinding/src/SmallVector.py +++ b/newbinding/src/ADT/SmallVector.py @@ -1,5 +1,5 @@ from binding import * -from namespace import llvm +from ..namespace import llvm @llvm.Class() class SmallVector_Type: diff --git a/newbinding/src/StringRef.py b/newbinding/src/ADT/StringRef.py similarity index 76% rename from newbinding/src/StringRef.py rename to newbinding/src/ADT/StringRef.py index fb3b896..e6fc8f2 100644 --- a/newbinding/src/StringRef.py +++ b/newbinding/src/ADT/StringRef.py @@ -1,5 +1,5 @@ from binding import * -from namespace import llvm +from ..namespace import llvm @llvm.Class() class StringRef: diff --git a/newbinding/src/Triple.py b/newbinding/src/ADT/Triple.py similarity index 98% rename from newbinding/src/Triple.py rename to newbinding/src/ADT/Triple.py index 0fd894e..82de57e 100644 --- a/newbinding/src/Triple.py +++ b/newbinding/src/ADT/Triple.py @@ -1,5 +1,5 @@ from binding import * -from namespace import llvm +from ..namespace import llvm from StringRef import StringRef Triple = llvm.Class() diff --git a/newbinding/src/ADT/__init__.py b/newbinding/src/ADT/__init__.py new file mode 100644 index 0000000..da0beed --- /dev/null +++ b/newbinding/src/ADT/__init__.py @@ -0,0 +1,10 @@ +import os.path, importlib + +def _init(): + for fname in os.listdir(os.path.dirname(__file__)): + if ((fname.endswith('.py') or fname.endswith('.pyc')) and + not fname.startswith('__init__')): + modname = os.path.basename(fname).rsplit('.', 1)[0] + importlib.import_module('.' + modname, __name__) + +_init() diff --git a/newbinding/src/AssemblyAnnotationWriter.py b/newbinding/src/Assembly/AssemblyAnnotationWriter.py similarity index 81% rename from newbinding/src/AssemblyAnnotationWriter.py rename to newbinding/src/Assembly/AssemblyAnnotationWriter.py index d2b5a5d..6b4d694 100644 --- a/newbinding/src/AssemblyAnnotationWriter.py +++ b/newbinding/src/Assembly/AssemblyAnnotationWriter.py @@ -1,5 +1,5 @@ from binding import * -from namespace import llvm +from ..namespace import llvm @llvm.Class() class AssemblyAnnotationWriter: diff --git a/newbinding/src/Assembly/__init__.py b/newbinding/src/Assembly/__init__.py new file mode 100644 index 0000000..da0beed --- /dev/null +++ b/newbinding/src/Assembly/__init__.py @@ -0,0 +1,10 @@ +import os.path, importlib + +def _init(): + for fname in os.listdir(os.path.dirname(__file__)): + if ((fname.endswith('.py') or fname.endswith('.pyc')) and + not fname.startswith('__init__')): + modname = os.path.basename(fname).rsplit('.', 1)[0] + importlib.import_module('.' + modname, __name__) + +_init() diff --git a/newbinding/src/BasicBlock.py b/newbinding/src/BasicBlock.py index b0716cd..61a09d7 100644 --- a/newbinding/src/BasicBlock.py +++ b/newbinding/src/BasicBlock.py @@ -3,7 +3,7 @@ from namespace import llvm from Value import Function, BasicBlock from Instruction import Instruction, TerminatorInst from LLVMContext import LLVMContext -from StringRef import StringRef +from ADT.StringRef import StringRef @BasicBlock class BasicBlock: diff --git a/newbinding/src/MachineCodeInfo.py b/newbinding/src/CodeGen/MachineCodeInfo.py similarity index 91% rename from newbinding/src/MachineCodeInfo.py rename to newbinding/src/CodeGen/MachineCodeInfo.py index 5d91e3a..fc3a1b6 100644 --- a/newbinding/src/MachineCodeInfo.py +++ b/newbinding/src/CodeGen/MachineCodeInfo.py @@ -1,5 +1,5 @@ from binding import * -from namespace import llvm +from ..namespace import llvm MachineCodeInfo = llvm.Class() diff --git a/newbinding/src/CodeGen/__init__.py b/newbinding/src/CodeGen/__init__.py new file mode 100644 index 0000000..da0beed --- /dev/null +++ b/newbinding/src/CodeGen/__init__.py @@ -0,0 +1,10 @@ +import os.path, importlib + +def _init(): + for fname in os.listdir(os.path.dirname(__file__)): + if ((fname.endswith('.py') or fname.endswith('.pyc')) and + not fname.startswith('__init__')): + modname = os.path.basename(fname).rsplit('.', 1)[0] + importlib.import_module('.' + modname, __name__) + +_init() diff --git a/newbinding/src/DataLayout.py b/newbinding/src/DataLayout.py index 74d1ad0..704c4b1 100644 --- a/newbinding/src/DataLayout.py +++ b/newbinding/src/DataLayout.py @@ -1,10 +1,10 @@ from binding import * from namespace import llvm from LLVMContext import LLVMContext -from StringRef import StringRef +from ADT.StringRef import StringRef from Module import Module from Type import Type, IntegerType, StructType -from SmallVector import SmallVector_Value +from ADT.SmallVector import SmallVector_Value from GlobalVariable import GlobalVariable from Pass import ImmutablePass diff --git a/newbinding/src/DerivedTypes.py b/newbinding/src/DerivedTypes.py index efce8b8..af9e757 100644 --- a/newbinding/src/DerivedTypes.py +++ b/newbinding/src/DerivedTypes.py @@ -2,7 +2,7 @@ from binding import * from namespace import llvm from LLVMContext import LLVMContext from Type import Type -from SmallVector import SmallVector_Type +from ADT.SmallVector import SmallVector_Type FunctionType = llvm.Class(Type) diff --git a/newbinding/src/EngineBuilder.py b/newbinding/src/EngineBuilder.py index d9594f0..4b68a25 100644 --- a/newbinding/src/EngineBuilder.py +++ b/newbinding/src/EngineBuilder.py @@ -2,11 +2,11 @@ from binding import * from namespace import llvm from Module import Module from JITMemoryManager import JITMemoryManager -from CodeGen import CodeGenOpt, Reloc, CodeModel -from StringRef import StringRef -from ExecutionEngine import ExecutionEngine -from TargetMachine import TargetMachine -from Triple import Triple +from Support.CodeGen import CodeGenOpt, Reloc, CodeModel +from ADT.StringRef import StringRef +from ExecutionEngine.ExecutionEngine import ExecutionEngine +from Target.TargetMachine import TargetMachine +from ADT.Triple import Triple EngineBuilder = llvm.Class() diff --git a/newbinding/src/ExecutionEngine.py b/newbinding/src/ExecutionEngine/ExecutionEngine.py similarity index 89% rename from newbinding/src/ExecutionEngine.py rename to newbinding/src/ExecutionEngine/ExecutionEngine.py index 5a95a16..f4bdb14 100644 --- a/newbinding/src/ExecutionEngine.py +++ b/newbinding/src/ExecutionEngine/ExecutionEngine.py @@ -1,14 +1,14 @@ from binding import * -from namespace import llvm -from Module import Module -from JITMemoryManager import JITMemoryManager -from CodeGen import CodeGenOpt, Reloc, CodeModel -from DataLayout import DataLayout -from Value import Function, GlobalValue, BasicBlock, Constant -from GlobalVariable import GlobalVariable -from MachineCodeInfo import MachineCodeInfo -from GenericValue import GenericValue -from Type import Type +from ..namespace import llvm +from ..Module import Module +from ..JITMemoryManager import JITMemoryManager +from ..Support.CodeGen import CodeGenOpt, Reloc, CodeModel +from ..DataLayout import DataLayout +from ..Value import Function, GlobalValue, BasicBlock, Constant +from ..GlobalVariable import GlobalVariable +from ..CodeGen.MachineCodeInfo import MachineCodeInfo +from ..GenericValue import GenericValue +from ..Type import Type ExecutionEngine = llvm.Class() diff --git a/newbinding/src/ExecutionEngine/__init__.py b/newbinding/src/ExecutionEngine/__init__.py new file mode 100644 index 0000000..da0beed --- /dev/null +++ b/newbinding/src/ExecutionEngine/__init__.py @@ -0,0 +1,10 @@ +import os.path, importlib + +def _init(): + for fname in os.listdir(os.path.dirname(__file__)): + if ((fname.endswith('.py') or fname.endswith('.pyc')) and + not fname.startswith('__init__')): + modname = os.path.basename(fname).rsplit('.', 1)[0] + importlib.import_module('.' + modname, __name__) + +_init() diff --git a/newbinding/src/IRBuilder.py b/newbinding/src/IRBuilder.py index cea94ce..61dd99b 100644 --- a/newbinding/src/IRBuilder.py +++ b/newbinding/src/IRBuilder.py @@ -8,8 +8,8 @@ from Instruction import UnreachableInst, AllocaInst, LoadInst, StoreInst from Instruction import FenceInst, AtomicCmpXchgInst, AtomicRMWInst, CmpInst from Instruction import LandingPadInst, VAArgInst from Instruction import AtomicOrdering, SynchronizationScope -from SmallVector import SmallVector_Value, SmallVector_Unsigned -from StringRef import StringRef +from ADT.SmallVector import SmallVector_Value, SmallVector_Unsigned +from ADT.StringRef import StringRef from Value import Value, MDNode from Type import Type, IntegerType diff --git a/newbinding/src/Module.py b/newbinding/src/Module.py index 9b392ca..539c486 100644 --- a/newbinding/src/Module.py +++ b/newbinding/src/Module.py @@ -1,12 +1,12 @@ from binding import * from namespace import llvm from LLVMContext import LLVMContext -from StringRef import StringRef +from ADT.StringRef import StringRef from Constant import Constant from Function import Function from DerivedTypes import FunctionType -from raw_ostream import raw_ostream -from AssemblyAnnotationWriter import AssemblyAnnotationWriter +from Support.raw_ostream import raw_ostream +from Assembly.AssemblyAnnotationWriter import AssemblyAnnotationWriter @llvm.Class() class Module: diff --git a/newbinding/src/Pass.py b/newbinding/src/Pass.py index 5842232..39e894b 100644 --- a/newbinding/src/Pass.py +++ b/newbinding/src/Pass.py @@ -1,6 +1,6 @@ from binding import * from namespace import llvm -from StringRef import StringRef +from ADT.StringRef import StringRef from Module import Module from Function import Function diff --git a/newbinding/src/CodeGen.py b/newbinding/src/Support/CodeGen.py similarity index 93% rename from newbinding/src/CodeGen.py rename to newbinding/src/Support/CodeGen.py index 7afcd49..013caa1 100644 --- a/newbinding/src/CodeGen.py +++ b/newbinding/src/Support/CodeGen.py @@ -1,5 +1,5 @@ from binding import * -from namespace import llvm +from ..namespace import llvm @llvm.Class() class Reloc: diff --git a/newbinding/src/Support/MemoryBuffer.py b/newbinding/src/Support/MemoryBuffer.py new file mode 100644 index 0000000..b960fe6 --- /dev/null +++ b/newbinding/src/Support/MemoryBuffer.py @@ -0,0 +1,9 @@ +from binding import * +from ..namespace import llvm + +MemoryBuffer = llvm.Class() + +@MemoryBuffer +class MemoryBuffer: + _include_ = 'llvm/Support/MemoryBuffer.h' + diff --git a/newbinding/src/Target.py b/newbinding/src/Support/Target.py similarity index 89% rename from newbinding/src/Target.py rename to newbinding/src/Support/Target.py index 3c2a0e1..bdaeff5 100644 --- a/newbinding/src/Target.py +++ b/newbinding/src/Support/Target.py @@ -1,6 +1,6 @@ from binding import * -from namespace import llvm -from StringRef import StringRef +from ..namespace import llvm +from ..ADT.StringRef import StringRef Target = llvm.Class() @Target diff --git a/newbinding/src/TargetSelect.py b/newbinding/src/Support/TargetSelect.py similarity index 54% rename from newbinding/src/TargetSelect.py rename to newbinding/src/Support/TargetSelect.py index cb2eb96..4a2b171 100644 --- a/newbinding/src/TargetSelect.py +++ b/newbinding/src/Support/TargetSelect.py @@ -1,8 +1,8 @@ from binding import * -from namespace import llvm +from ..namespace import llvm llvm.includes.add('llvm/Support/TargetSelect.h') -llvm.Function('InitializeNativeTarget') +InitializeNativeTarget = llvm.Function('InitializeNativeTarget') #llvm.Function('InitializeAllTargets') diff --git a/newbinding/src/Support/__init__.py b/newbinding/src/Support/__init__.py new file mode 100644 index 0000000..da0beed --- /dev/null +++ b/newbinding/src/Support/__init__.py @@ -0,0 +1,10 @@ +import os.path, importlib + +def _init(): + for fname in os.listdir(os.path.dirname(__file__)): + if ((fname.endswith('.py') or fname.endswith('.pyc')) and + not fname.startswith('__init__')): + modname = os.path.basename(fname).rsplit('.', 1)[0] + importlib.import_module('.' + modname, __name__) + +_init() diff --git a/newbinding/src/raw_ostream.py b/newbinding/src/Support/raw_ostream.py similarity index 73% rename from newbinding/src/raw_ostream.py rename to newbinding/src/Support/raw_ostream.py index 2f5a6f5..ecf3614 100644 --- a/newbinding/src/raw_ostream.py +++ b/newbinding/src/Support/raw_ostream.py @@ -1,7 +1,7 @@ from binding import * -from namespace import llvm -from LLVMContext import LLVMContext -from StringRef import StringRef +from ..namespace import llvm +from ..LLVMContext import LLVMContext +from ..ADT.StringRef import StringRef @llvm.Class() class raw_ostream: diff --git a/newbinding/src/TargetLibraryInfo.py b/newbinding/src/Target/TargetLibraryInfo.py similarity index 95% rename from newbinding/src/TargetLibraryInfo.py rename to newbinding/src/Target/TargetLibraryInfo.py index a5ba28d..b90c619 100644 --- a/newbinding/src/TargetLibraryInfo.py +++ b/newbinding/src/Target/TargetLibraryInfo.py @@ -1,8 +1,8 @@ from binding import * -from namespace import llvm -from Triple import Triple -from Pass import ImmutablePass -from StringRef import StringRef +from ..namespace import llvm +from ..ADT.Triple import Triple +from ..Pass import ImmutablePass +from ..ADT.StringRef import StringRef TargetLibraryInfo = llvm.Class(ImmutablePass) diff --git a/newbinding/src/TargetMachine.py b/newbinding/src/Target/TargetMachine.py similarity index 72% rename from newbinding/src/TargetMachine.py rename to newbinding/src/Target/TargetMachine.py index 5910585..3fc16e2 100644 --- a/newbinding/src/TargetMachine.py +++ b/newbinding/src/Target/TargetMachine.py @@ -1,12 +1,12 @@ from binding import * -from namespace import llvm -from StringRef import StringRef -from CodeGen import CodeModel, TLSModel, CodeGenOpt, Reloc -from GlobalValue import GlobalValue -from Target import Target -from DataLayout import DataLayout -from TargetTransformInfo import (ScalarTargetTransformInfo, - VectorTargetTransformInfo) +from ..namespace import llvm +from ..ADT.StringRef import StringRef +from ..Support.CodeGen import CodeModel, TLSModel, CodeGenOpt, Reloc +from ..GlobalValue import GlobalValue +from ..Support.Target import Target +from ..DataLayout import DataLayout +from ..TargetTransformInfo import (ScalarTargetTransformInfo, + VectorTargetTransformInfo) TargetMachine = llvm.Class() diff --git a/newbinding/src/Target/__init__.py b/newbinding/src/Target/__init__.py new file mode 100644 index 0000000..da0beed --- /dev/null +++ b/newbinding/src/Target/__init__.py @@ -0,0 +1,10 @@ +import os.path, importlib + +def _init(): + for fname in os.listdir(os.path.dirname(__file__)): + if ((fname.endswith('.py') or fname.endswith('.pyc')) and + not fname.startswith('__init__')): + modname = os.path.basename(fname).rsplit('.', 1)[0] + importlib.import_module('.' + modname, __name__) + +_init() diff --git a/newbinding/src/TargetTransformInfo.py b/newbinding/src/TargetTransformInfo.py index 8e3c17e..5761281 100644 --- a/newbinding/src/TargetTransformInfo.py +++ b/newbinding/src/TargetTransformInfo.py @@ -1,6 +1,8 @@ from binding import * from namespace import llvm +llvm.includes.add('llvm/TargetTransformInfo.h') + ScalarTargetTransformInfo = llvm.Class() VectorTargetTransformInfo = llvm.Class() diff --git a/newbinding/src/Transforms/IPO.py b/newbinding/src/Transforms/IPO.py index 6c2fc26..48b34f9 100644 --- a/newbinding/src/Transforms/IPO.py +++ b/newbinding/src/Transforms/IPO.py @@ -1,5 +1,5 @@ from binding import * -from namespace import llvm +from ..namespace import llvm from ..Pass import Pass llvm.includes.add('llvm/Transforms/IPO.h') diff --git a/newbinding/src/PassManagerBuilder.py b/newbinding/src/Transforms/PassManagerBuilder.py similarity index 88% rename from newbinding/src/PassManagerBuilder.py rename to newbinding/src/Transforms/PassManagerBuilder.py index 11fedfb..a95b6df 100644 --- a/newbinding/src/PassManagerBuilder.py +++ b/newbinding/src/Transforms/PassManagerBuilder.py @@ -1,8 +1,8 @@ from binding import * -from namespace import llvm -from PassManager import PassManagerBase, FunctionPassManager -from TargetLibraryInfo import TargetLibraryInfo -from Pass import Pass +from ..namespace import llvm +from ..PassManager import PassManagerBase, FunctionPassManager +from ..Target.TargetLibraryInfo import TargetLibraryInfo +from ..Pass import Pass @llvm.Class() class PassManagerBuilder: diff --git a/newbinding/src/Type.py b/newbinding/src/Type.py index bf51b9d..8e6b381 100644 --- a/newbinding/src/Type.py +++ b/newbinding/src/Type.py @@ -1,8 +1,8 @@ from binding import * from namespace import llvm from LLVMContext import LLVMContext -from raw_ostream import raw_ostream -from StringRef import StringRef +from Support.raw_ostream import raw_ostream +from ADT.StringRef import StringRef Type = llvm.Class() IntegerType = llvm.Class(Type) diff --git a/newbinding/src/Value.py b/newbinding/src/Value.py index 7460c90..5841746 100644 --- a/newbinding/src/Value.py +++ b/newbinding/src/Value.py @@ -1,10 +1,10 @@ from binding import * from namespace import llvm -from raw_ostream import raw_ostream -from AssemblyAnnotationWriter import AssemblyAnnotationWriter +from Support.raw_ostream import raw_ostream +from Assembly.AssemblyAnnotationWriter import AssemblyAnnotationWriter from Type import Type from LLVMContext import LLVMContext -from StringRef import StringRef +from ADT.StringRef import StringRef Value = llvm.Class() # forward declarations diff --git a/newbinding/src/__init__.py b/newbinding/src/__init__.py index f67a3c4..8a1b356 100644 --- a/newbinding/src/__init__.py +++ b/newbinding/src/__init__.py @@ -9,4 +9,4 @@ def _init(): _init() -import Transforms \ No newline at end of file +import Transforms, ADT, Support, Assembly, ExecutionEngine, CodeGen, Target diff --git a/newbinding/namespace.py b/newbinding/src/namespace.py similarity index 100% rename from newbinding/namespace.py rename to newbinding/src/namespace.py From 168510222fc4d0975635d6b76befaff2ed14dd55 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 4 Feb 2013 16:45:49 -0600 Subject: [PATCH 245/516] Add Module bitcode writer/parser --- newbinding/gen/binding.py | 16 ++++++- newbinding/include/llvm_binding/extra.h | 60 +++++++++++++++++++++++++ newbinding/src/Bitcode/ReaderWriter.py | 30 +++++++++++++ newbinding/src/Bitcode/__init__.py | 10 +++++ newbinding/src/Support/MemoryBuffer.py | 9 ---- newbinding/src/__init__.py | 11 +++-- newbinding/test_binding.py | 16 +++++++ 7 files changed, 138 insertions(+), 14 deletions(-) create mode 100644 newbinding/src/Bitcode/ReaderWriter.py create mode 100644 newbinding/src/Bitcode/__init__.py delete mode 100644 newbinding/src/Support/MemoryBuffer.py diff --git a/newbinding/gen/binding.py b/newbinding/gen/binding.py index 142c8ef..d9b44af 100644 --- a/newbinding/gen/binding.py +++ b/newbinding/gen/binding.py @@ -26,6 +26,11 @@ class Namespace(object): self.functions.append(fn) return fn + def CustomFunction(self, *args): + fn = CustomFunction(self, *args) + self.functions.append(fn) + return fn + def Enum(self, name, *value_names): enum = Enum(*value_names) enum.parent = self @@ -444,13 +449,22 @@ class Function(Method): with writer.function(self.name, varargs='args') as varargs: unwrapped = writer.unwrap_many(varargs) self.process_ownedptr_args(writer, unwrapped) - func = self.fullname.split('::', 1)[1].replace('::', '.') + func = self.name ret = writer.call('_api.%s' % func, varargs=unwrapped) wrapped = writer.wrap(ret, self.is_return_ownedptr()) writer.return_value(wrapped) writer.println() +class CustomFunction(Function): + def __init__(self, parent, name, realname, return_type=Void, *args): + super(CustomFunction, self).__init__(parent, name, return_type, *args) + self.realname = realname + + @property + def fullname(self): + return self.realname + class Destructor(Method): _kind_ = 'dtor' diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h index c69f177..e8f39cb 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/extra.h @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include @@ -405,3 +407,61 @@ PyObject* EngineBuilder_selectTarget(llvm::EngineBuilder* eb, return pycapsule_new(eb, "llvm::EngineBuilder"); } + +static +PyObject* llvm_ParseBitCodeFile(llvm::StringRef Buf, llvm::LLVMContext& Ctx, + PyObject* FObj=NULL) +{ + using namespace llvm; + MemoryBuffer* MB = MemoryBuffer::getMemBuffer(Buf); + Module* M; + if (FObj) { + std::string ErrStr; + M = ParseBitcodeFile(MB, Ctx, &ErrStr); + if (-1 == PyFile_WriteString(ErrStr.c_str(), FObj)) { + return NULL; + } + } else { + M = ParseBitcodeFile(MB, Ctx); + } + delete MB; + return pycapsule_new(M, "llvm::Module"); +} + + +static +PyObject* llvm_WriteBitcodeToFile(const llvm::Module *M, PyObject* FObj) +{ + using namespace llvm; + llvm::SmallVector sv; + llvm::raw_svector_ostream rso(sv); + llvm::WriteBitcodeToFile(M, rso); + rso.flush(); + StringRef ref = rso.str(); + PyObject* buf = PyString_FromStringAndSize(ref.data(), ref.size()); + if (-1 == PyFile_WriteObject(buf, FObj, Py_PRINT_RAW)){ + return NULL; + } + Py_RETURN_NONE; +} + +static +PyObject* llvm_getBitcodeTargetTriple(llvm::StringRef Buf, + llvm::LLVMContext& Ctx, + PyObject* FObj = NULL) +{ + using namespace llvm; + MemoryBuffer* MB = MemoryBuffer::getMemBuffer(Buf); + std::string Triple; + if (FObj) { + std::string ErrStr; + Triple = getBitcodeTargetTriple(MB, Ctx, &ErrStr); + if (-1 == PyFile_WriteString(ErrStr.c_str(), FObj)) { + return NULL; + } + } else { + Triple = getBitcodeTargetTriple(MB, Ctx); + } + delete MB; + return PyString_FromString(Triple.c_str()); +} diff --git a/newbinding/src/Bitcode/ReaderWriter.py b/newbinding/src/Bitcode/ReaderWriter.py new file mode 100644 index 0000000..a8e8c43 --- /dev/null +++ b/newbinding/src/Bitcode/ReaderWriter.py @@ -0,0 +1,30 @@ +from binding import * +from ..namespace import llvm +from ..ADT.StringRef import StringRef +from ..Module import Module +from ..LLVMContext import LLVMContext + +llvm.includes.add('llvm/Bitcode/ReaderWriter.h') + +ParseBitCodeFile = llvm.CustomFunction('ParseBitCodeFile', + 'llvm_ParseBitCodeFile', + PyObjectPtr, # returns Module* + cast(str, StringRef), + ref(LLVMContext), + PyObjectPtr, # file-like object + ).require_only(2) + +WriteBitcodeToFile = llvm.CustomFunction('WriteBitcodeToFile', + 'llvm_WriteBitcodeToFile', + PyObjectPtr, # return None + ptr(Module), + PyObjectPtr, # file-like object + ) + +getBitcodeTargetTriple = llvm.CustomFunction('getBitcodeTargetTriple', + 'llvm_getBitcodeTargetTriple', + PyObjectPtr, # return str + cast(str, StringRef), + ref(LLVMContext), + PyObjectPtr, # file-like object + ).require_only(2) diff --git a/newbinding/src/Bitcode/__init__.py b/newbinding/src/Bitcode/__init__.py new file mode 100644 index 0000000..da0beed --- /dev/null +++ b/newbinding/src/Bitcode/__init__.py @@ -0,0 +1,10 @@ +import os.path, importlib + +def _init(): + for fname in os.listdir(os.path.dirname(__file__)): + if ((fname.endswith('.py') or fname.endswith('.pyc')) and + not fname.startswith('__init__')): + modname = os.path.basename(fname).rsplit('.', 1)[0] + importlib.import_module('.' + modname, __name__) + +_init() diff --git a/newbinding/src/Support/MemoryBuffer.py b/newbinding/src/Support/MemoryBuffer.py deleted file mode 100644 index b960fe6..0000000 --- a/newbinding/src/Support/MemoryBuffer.py +++ /dev/null @@ -1,9 +0,0 @@ -from binding import * -from ..namespace import llvm - -MemoryBuffer = llvm.Class() - -@MemoryBuffer -class MemoryBuffer: - _include_ = 'llvm/Support/MemoryBuffer.h' - diff --git a/newbinding/src/__init__.py b/newbinding/src/__init__.py index 8a1b356..98c06fc 100644 --- a/newbinding/src/__init__.py +++ b/newbinding/src/__init__.py @@ -1,12 +1,15 @@ import os.path, importlib def _init(): - for fname in os.listdir(os.path.dirname(__file__)): - if ((fname.endswith('.py') or fname.endswith('.pyc')) and - not fname.startswith('__init__')): + base = os.path.dirname(__file__) + for fname in os.listdir(base): + print fname + is_python_script = fname.endswith('.py') or fname.endswith('.pyc') + is_init_script = fname.startswith('__init__') + is_directory = os.path.isdir(os.path.join(base, fname)) + if (is_directory or is_python_script) and not is_init_script : modname = os.path.basename(fname).rsplit('.', 1)[0] importlib.import_module('.' + modname, __name__) _init() -import Transforms, ADT, Support, Assembly, ExecutionEngine, CodeGen, Target diff --git a/newbinding/test_binding.py b/newbinding/test_binding.py index 248e32a..8a72aef 100644 --- a/newbinding/test_binding.py +++ b/newbinding/test_binding.py @@ -135,6 +135,22 @@ def test_basic_jit_use(): assert 44 == gvR.toUnsignedInt() + # write bitcode + bc_buffer = StringIO() + api.WriteBitcodeToFile(m, bc_buffer) + bc = bc_buffer.getvalue() + bc_buffer.close() + + # read bitcode + errbuf = StringIO() + m2 = api.ParseBitCodeFile(bc, context, errbuf) + if not m2: + raise Exception(errbuf.getvalue()) + else: + m2.setModuleIdentifier(m.getModuleIdentifier()) + assert str(m2) == str(m) + + def test_engine_builder(): api.InitializeNativeTarget() context = api.getGlobalContext() From da85049eb9efbb6174dc73e07914e2060fc50f15 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 5 Feb 2013 13:44:59 -0600 Subject: [PATCH 246/516] Add support to emit assembly. --- newbinding/include/llvm_binding/extra.h | 31 ++++++++++++++++++++ newbinding/src/Support/FormattedStream.py | 9 ++++++ newbinding/src/Support/TargetSelect.py | 9 ++++++ newbinding/src/Support/raw_ostream.py | 1 + newbinding/src/Target/TargetMachine.py | 17 +++++++++++ newbinding/test_binding.py | 35 +++++++++++++++++++++++ 6 files changed, 102 insertions(+) create mode 100644 newbinding/src/Support/FormattedStream.py diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h index e8f39cb..77b399d 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/extra.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -465,3 +466,33 @@ PyObject* llvm_getBitcodeTargetTriple(llvm::StringRef Buf, delete MB; return PyString_FromString(Triple.c_str()); } + +static +PyObject* TargetMachine_addPassesToEmitFile( + llvm::TargetMachine *TM, + llvm::PassManagerBase & PM, + PyObject* Out, + llvm::TargetMachine::CodeGenFileType FTy, + bool disableVerify=true) +{ + using namespace llvm; + llvm::SmallVector sv; + raw_svector_ostream rso(sv); + formatted_raw_ostream fso(rso); + fso.flush(); + bool status = TM->addPassesToEmitFile(PM, fso, FTy, disableVerify); + if (status) { + StringRef sr = rso.str(); + PyObject* buf = PyString_FromStringAndSize(sr.data(), sr.size()); + if (!buf) { + return NULL; + } + if ( -1 == PyFile_WriteObject(buf, Out, Py_PRINT_RAW) ){ + return NULL; + } + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } +} + diff --git a/newbinding/src/Support/FormattedStream.py b/newbinding/src/Support/FormattedStream.py new file mode 100644 index 0000000..17c259b --- /dev/null +++ b/newbinding/src/Support/FormattedStream.py @@ -0,0 +1,9 @@ +from binding import * +from ..namespace import llvm +from raw_ostream import raw_ostream + +@llvm.Class(raw_ostream) +class formatted_raw_ostream: + _include_ = 'llvm/Support/FormattedStream.h' + new = Constructor(ref(raw_ostream), cast(bool, Bool)) + diff --git a/newbinding/src/Support/TargetSelect.py b/newbinding/src/Support/TargetSelect.py index 4a2b171..208ef4b 100644 --- a/newbinding/src/Support/TargetSelect.py +++ b/newbinding/src/Support/TargetSelect.py @@ -6,3 +6,12 @@ llvm.includes.add('llvm/Support/TargetSelect.h') InitializeNativeTarget = llvm.Function('InitializeNativeTarget') #llvm.Function('InitializeAllTargets') +InitializeNativeTargetAsmPrinter = llvm.Function( + 'InitializeNativeTargetAsmPrinter', cast(Bool, bool)) + +InitializeNativeTargetAsmParser = llvm.Function( + 'InitializeNativeTargetAsmParser', cast(Bool, bool)) + +InitializeNativeTargetDisassembler = llvm.Function( + 'InitializeNativeTargetDisassembler', cast(Bool, bool)) + diff --git a/newbinding/src/Support/raw_ostream.py b/newbinding/src/Support/raw_ostream.py index ecf3614..dcce73f 100644 --- a/newbinding/src/Support/raw_ostream.py +++ b/newbinding/src/Support/raw_ostream.py @@ -7,6 +7,7 @@ from ..ADT.StringRef import StringRef class raw_ostream: _include_ = "llvm/Support/raw_ostream.h" delete = Destructor() + flush = Method() @llvm.Class(raw_ostream) class raw_svector_ostream: diff --git a/newbinding/src/Target/TargetMachine.py b/newbinding/src/Target/TargetMachine.py index 3fc16e2..e60ed5c 100644 --- a/newbinding/src/Target/TargetMachine.py +++ b/newbinding/src/Target/TargetMachine.py @@ -7,12 +7,20 @@ from ..Support.Target import Target from ..DataLayout import DataLayout from ..TargetTransformInfo import (ScalarTargetTransformInfo, VectorTargetTransformInfo) +from ..PassManager import PassManagerBase +from ..Support.FormattedStream import formatted_raw_ostream TargetMachine = llvm.Class() @TargetMachine class TargetMachine: _include_ = 'llvm/Target/TargetMachine.h' + + CodeGenFileType = Enum(''' + CGFT_AssemblyFile + CGFT_ObjectFile + CGFT_Null''') + delete = Destructor() getTarget = Method(const(ref(Target))) @@ -34,3 +42,12 @@ class TargetMachine: ownedptr(ScalarTargetTransformInfo))) getVectorTargetTransformInfo = Method(const( ownedptr(VectorTargetTransformInfo))) + + addPassesToEmitFile = Method(cast(bool, Bool), + ref(PassManagerBase), + ref(formatted_raw_ostream), + CodeGenFileType, + cast(bool, Bool) + ).require_only(3) + + diff --git a/newbinding/test_binding.py b/newbinding/test_binding.py index 8a72aef..1321eb6 100644 --- a/newbinding/test_binding.py +++ b/newbinding/test_binding.py @@ -6,6 +6,7 @@ api.capsule.set_debug(True) def test_basic_jit_use(): api.InitializeNativeTarget() + api.InitializeNativeTargetAsmPrinter() context = api.getGlobalContext() m = api.Module.new("modname", context) @@ -157,6 +158,16 @@ def test_engine_builder(): m = api.Module.new("modname", context) + int32ty = api.Type.getIntNTy(context, 32) + fnty = api.FunctionType.get(int32ty, [int32ty], False) + fn = m.getOrInsertFunction("foo", fnty)._downcast(api.Function) + bb = api.BasicBlock.Create(context, "entry", fn, None) + builder = api.IRBuilder.new(context) + builder.SetInsertPoint(bb) + builder.CreateRet(fn.getArgumentList()[0]) + + print fn + eb = api.EngineBuilder.new(m) eb2 = eb.setEngineKind(api.EngineKind.Kind.JIT) assert eb is eb2 @@ -192,6 +203,30 @@ def test_engine_builder(): pm.add(api.DataLayout.new(str(tm.getDataLayout()))) pm.add(api.TargetLibraryInfo.new()) + # write assembly + pm = api.PassManager.new() + pm.add(api.DataLayout.new(str(tm.getDataLayout()))) + + raw = extra.make_raw_ostream_for_printing() + formatted = api.formatted_raw_ostream.new(raw, False) + + cgft = api.TargetMachine.CodeGenFileType.CGFT_AssemblyFile + failed = tm.addPassesToEmitFile(pm, formatted, cgft, False) + assert not failed + + pm.run(m) + + formatted.flush() + raw.flush() + asm = raw.str() + print asm + assert 'foo' in asm + + + + + + def main(): for name, value in globals().items(): From 450c29e0523fbae1b0772147d2490de33affa754 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 5 Feb 2013 15:30:43 -0600 Subject: [PATCH 247/516] Swap out old llvm code --- llvm/2.9_update.diff | 2117 ------------------------------------- llvm/__init__.py | 154 --- llvm/_core.cpp | 2212 --------------------------------------- llvm/_dwarf.cpp | 86 -- llvm/_dwarf.h | 101 -- llvm/_util.py | 108 -- llvm/_version.py | 193 ---- llvm/capsulethunk.h | 134 --- llvm/core.py | 2158 +------------------------------------- llvm/debuginfo.py | 398 ------- llvm/ee.py | 392 ------- llvm/extra.cpp | 1361 ------------------------ llvm/extra.h | 676 ------------ llvm/llvm_c_extra.h | 31 - llvm/passes.py | 417 -------- llvm/py3k_update.diff | 973 ----------------- llvm/py3k_update.output | 62 -- llvm/tbaa.py | 51 - llvm/test_llvmpy.py | 1249 ---------------------- llvm/wrap.cpp | 70 -- llvm/wrap.h | 1277 ---------------------- 21 files changed, 20 insertions(+), 14200 deletions(-) delete mode 100644 llvm/2.9_update.diff delete mode 100644 llvm/_core.cpp delete mode 100644 llvm/_dwarf.cpp delete mode 100644 llvm/_dwarf.h delete mode 100644 llvm/_util.py delete mode 100644 llvm/_version.py delete mode 100644 llvm/capsulethunk.h delete mode 100644 llvm/debuginfo.py delete mode 100644 llvm/extra.cpp delete mode 100644 llvm/extra.h delete mode 100644 llvm/llvm_c_extra.h delete mode 100644 llvm/py3k_update.diff delete mode 100644 llvm/py3k_update.output delete mode 100644 llvm/tbaa.py delete mode 100644 llvm/test_llvmpy.py delete mode 100644 llvm/wrap.cpp delete mode 100644 llvm/wrap.h diff --git a/llvm/2.9_update.diff b/llvm/2.9_update.diff deleted file mode 100644 index 5572286..0000000 --- a/llvm/2.9_update.diff +++ /dev/null @@ -1,2117 +0,0 @@ -Index: core.py -=================================================================== ---- core.py (revision 105) -+++ core.py (working copy) -@@ -51,14 +51,15 @@ - TYPE_FP128 = 4 - TYPE_PPC_FP128 = 5 - TYPE_LABEL = 6 --TYPE_INTEGER = 7 --TYPE_FUNCTION = 8 --TYPE_STRUCT = 9 --TYPE_ARRAY = 10 --TYPE_POINTER = 11 --TYPE_OPAQUE = 12 --TYPE_VECTOR = 13 --TYPE_METADATA = 14 -+TYPE_METADATA = 7 -+TYPE_X86_MMX = 8 -+TYPE_INTEGER = 9 -+TYPE_FUNCTION = 10 -+TYPE_STRUCT = 11 -+TYPE_ARRAY = 12 -+TYPE_POINTER = 13 -+TYPE_OPAQUE = 14 -+TYPE_VECTOR = 15 - - # value IDs (llvm::Value::ValueTy enum) - VALUE_ARGUMENT = 0 -@@ -140,11 +141,21 @@ - OPCODE_INSERTVALUE = 54 - - # calling conventions --CC_C = 0 --CC_FASTCALL = 8 --CC_COLDCALL = 9 --CC_X86_STDCALL = 64 --CC_X86_FASTCALL = 65 -+CC_C = 0 -+CC_FASTCALL = 8 -+CC_COLDCALL = 9 -+CC_GHC = 10 -+CC_X86_STDCALL = 64 -+CC_X86_FASTCALL = 65 -+CC_ARM_APCS = 66 -+CC_ARM_AAPCS = 67 -+CC_ARM_AAPCS_VFP = 68 -+CC_MSP430_INTR = 69 -+CC_X86_THISCALL = 70 -+CC_PTX_KERNEL = 71 -+CC_PTX_DEVICE = 72 -+CC_MBLAZE_INTR = 73 -+CC_MBLAZE_SVOL = 74 - - # int predicates - ICMP_EQ = 32 -@@ -248,11 +259,14 @@ - ATTR_OPTIMIZE_FOR_SIZE = 1<<13 - ATTR_STACK_PROTECT = 1<<14 - ATTR_STACK_PROTECT_REQ = 1<<15 -+ATTR_ALIGNMENT = 1<<16 - ATTR_NO_CAPTURE = 1<<21 - ATTR_NO_REDZONE = 1<<22 - ATTR_NO_IMPLICIT_FLOAT = 1<<23 - ATTR_NAKED = 1<<24 - ATTR_INLINE_HINT = 1<<25 -+ATTR_STACK_ALIGNMENT = 7<<26 -+ATTR_HOTPATCH = 1<<29 - - # intrinsic IDs - from llvm._intrinsic_ids import * -Index: extra.cpp -=================================================================== ---- extra.cpp (revision 105) -+++ extra.cpp (working copy) -@@ -54,7 +54,7 @@ - #include "llvm/IntrinsicInst.h" - #include "llvm/Analysis/Verifier.h" - #include "llvm/Assembly/Parser.h" --#include "llvm/System/DynamicLibrary.h" -+#include "llvm/Support/DynamicLibrary.h" - #include "llvm/PassManager.h" - #include "llvm/ExecutionEngine/ExecutionEngine.h" - #include "llvm/Analysis/LoopPass.h" -@@ -452,12 +452,19 @@ - return eep->getPointerToFunction(fnp); - } - -+ - int LLVMInlineFunction(LLVMValueRef call) - { - llvm::Value *callp = llvm::unwrap(call); - assert(callp); - -- llvm::CallSite cs = llvm::CallSite::get(callp); -+// llvm::CallSite cs = llvm::CallSite::get(callp); -+ llvm::CallSite cs; -+ llvm::Instruction *II = llvm::dyn_cast(callp); -+ if (II->getOpcode() == llvm::Instruction::Call) -+ cs = llvm::CallSite(static_cast(II)); -+ else if (II->getOpcode() == llvm::Instruction::Invoke) -+ cs = llvm::CallSite(static_cast(II)); - - llvm::InlineFunctionInfo unused; - return llvm::InlineFunction(cs, unused); -@@ -501,13 +508,13 @@ - define_pass( DomPrinter ) - define_pass( DomViewer ) - define_pass( EdgeProfiler ) --define_pass( GEPSplitter ) -+//define_pass( GEPSplitter ) - define_pass( GlobalsModRef ) - define_pass( InstCount ) - define_pass( InstructionNamer ) - define_pass( LazyValueInfo ) - define_pass( LCSSA ) --define_pass( LiveValues ) -+//define_pass( LiveValues ) - define_pass( LoopDependenceAnalysis ) - define_pass( LoopExtractor ) - define_pass( LoopSimplify ) -@@ -519,7 +526,7 @@ - define_pass( NoProfileInfo ) - define_pass( OptimalEdgeProfiler ) - define_pass( PartialInlining ) --define_pass( PartialSpecialization ) -+//define_pass( PartialSpecialization ) - define_pass( PostDomOnlyPrinter ) - define_pass( PostDomOnlyViewer ) - define_pass( PostDomPrinter ) -@@ -528,7 +535,7 @@ - define_pass( ProfileLoader ) - define_pass( ProfileVerifier ) - define_pass( ScalarEvolutionAliasAnalysis ) --define_pass( SimplifyHalfPowrLibCalls ) -+//define_pass( SimplifyHalfPowrLibCalls ) - define_pass( SingleLoopExtractor ) - define_pass( StripNonDebugSymbols ) - define_pass( StructRetPromotion ) -Index: passes.py -=================================================================== ---- passes.py (revision 105) -+++ passes.py (working copy) -@@ -68,7 +68,7 @@ - PASS_EDGE_PROFILER = 25 - PASS_FUNCTION_ATTRS = 26 - PASS_FUNCTION_INLINING = 27 --PASS_GEP_SPLITTER = 28 -+#PASS_GEP_SPLITTER = 28 - PASS_GLOBAL_DCE = 29 - PASS_GLOBAL_OPTIMIZER = 30 - PASS_GLOBALS_MOD_REF = 31 -@@ -83,11 +83,11 @@ - PASS_LAZY_VALUE_INFO = 40 - PASS_LCSSA = 41 - PASS_LICM = 42 --PASS_LIVE_VALUES = 43 -+#PASS_LIVE_VALUES = 43 - PASS_LOOP_DELETION = 44 - PASS_LOOP_DEPENDENCE_ANALYSIS = 45 - PASS_LOOP_EXTRACTOR = 46 --PASS_LOOP_INDEX_SPLIT = 47 -+#PASS_LOOP_INDEX_SPLIT = 47 - PASS_LOOP_ROTATE = 48 - PASS_LOOP_SIMPLIFY = 49 - PASS_LOOP_STRENGTH_REDUCE = 50 -@@ -102,11 +102,11 @@ - PASS_NO_PROFILE_INFO = 59 - PASS_OPTIMAL_EDGE_PROFILER = 60 - PASS_PARTIAL_INLINING = 61 --PASS_PARTIAL_SPECIALIZATION = 62 --PASS_POST_DOM_ONLY_PRINTER = 63 --PASS_POST_DOM_ONLY_VIEWER = 64 --PASS_POST_DOM_PRINTER = 65 --PASS_POST_DOM_VIEWER = 66 -+#PASS_PARTIAL_SPECIALIZATION = 62 -+#PASS_POST_DOM_ONLY_PRINTER = 63 -+#PASS_POST_DOM_ONLY_VIEWER = 64 -+#PASS_POST_DOM_PRINTER = 65 -+#PASS_POST_DOM_VIEWER = 66 - PASS_PROFILE_ESTIMATOR = 67 - PASS_PROFILE_LOADER = 68 - PASS_PROFILE_VERIFIER = 69 -@@ -116,7 +116,7 @@ - PASS_SCALAR_EVOLUTION_ALIAS_ANALYSIS = 73 - PASS_SCALAR_REPL_AGGREGATES = 74 - PASS_SCCP = 76 --PASS_SIMPLIFY_HALF_POWR_LIB_CALLS = 77 -+#PASS_SIMPLIFY_HALF_POWR_LIB_CALLS = 77 - PASS_SIMPLIFY_LIB_CALLS = 78 - PASS_SINGLE_LOOP_EXTRACTOR = 79 - PASS_STRIP_DEAD_PROTOTYPES = 82 -@@ -161,7 +161,7 @@ - PASS_EDGE_PROFILER : _core.LLVMAddEdgeProfilerPass, - PASS_FUNCTION_ATTRS : _core.LLVMAddFunctionAttrsPass, - PASS_FUNCTION_INLINING : _core.LLVMAddFunctionInliningPass, -- PASS_GEP_SPLITTER : _core.LLVMAddGEPSplitterPass, -+ #PASS_GEP_SPLITTER : _core.LLVMAddGEPSplitterPass, - PASS_GLOBAL_DCE : _core.LLVMAddGlobalDCEPass, - PASS_GLOBAL_OPTIMIZER : _core.LLVMAddGlobalOptimizerPass, - PASS_GLOBALS_MOD_REF : _core.LLVMAddGlobalsModRefPass, -@@ -176,11 +176,11 @@ - PASS_LAZY_VALUE_INFO : _core.LLVMAddLazyValueInfoPass, - PASS_LCSSA : _core.LLVMAddLCSSAPass, - PASS_LICM : _core.LLVMAddLICMPass, -- PASS_LIVE_VALUES : _core.LLVMAddLiveValuesPass, -+ #PASS_LIVE_VALUES : _core.LLVMAddLiveValuesPass, - PASS_LOOP_DELETION : _core.LLVMAddLoopDeletionPass, - PASS_LOOP_DEPENDENCE_ANALYSIS : _core.LLVMAddLoopDependenceAnalysisPass, - PASS_LOOP_EXTRACTOR : _core.LLVMAddLoopExtractorPass, -- PASS_LOOP_INDEX_SPLIT : _core.LLVMAddLoopIndexSplitPass, -+ #PASS_LOOP_INDEX_SPLIT : _core.LLVMAddLoopIndexSplitPass, - PASS_LOOP_ROTATE : _core.LLVMAddLoopRotatePass, - PASS_LOOP_SIMPLIFY : _core.LLVMAddLoopSimplifyPass, - PASS_LOOP_STRENGTH_REDUCE : _core.LLVMAddLoopStrengthReducePass, -@@ -195,11 +195,11 @@ - PASS_NO_PROFILE_INFO : _core.LLVMAddNoProfileInfoPass, - PASS_OPTIMAL_EDGE_PROFILER : _core.LLVMAddOptimalEdgeProfilerPass, - PASS_PARTIAL_INLINING : _core.LLVMAddPartialInliningPass, -- PASS_PARTIAL_SPECIALIZATION : _core.LLVMAddPartialSpecializationPass, -- PASS_POST_DOM_ONLY_PRINTER : _core.LLVMAddPostDomOnlyPrinterPass, -- PASS_POST_DOM_ONLY_VIEWER : _core.LLVMAddPostDomOnlyViewerPass, -- PASS_POST_DOM_PRINTER : _core.LLVMAddPostDomPrinterPass, -- PASS_POST_DOM_VIEWER : _core.LLVMAddPostDomViewerPass, -+ #PASS_PARTIAL_SPECIALIZATION : _core.LLVMAddPartialSpecializationPass, -+ #PASS_POST_DOM_ONLY_PRINTER : _core.LLVMAddPostDomOnlyPrinterPass, -+ #PASS_POST_DOM_ONLY_VIEWER : _core.LLVMAddPostDomOnlyViewerPass, -+ #PASS_POST_DOM_PRINTER : _core.LLVMAddPostDomPrinterPass, -+ #PASS_POST_DOM_VIEWER : _core.LLVMAddPostDomViewerPass, - PASS_PROFILE_ESTIMATOR : _core.LLVMAddProfileEstimatorPass, - PASS_PROFILE_LOADER : _core.LLVMAddProfileLoaderPass, - PASS_PROFILE_VERIFIER : _core.LLVMAddProfileVerifierPass, -@@ -209,7 +209,7 @@ - PASS_SCALAR_EVOLUTION_ALIAS_ANALYSIS : _core.LLVMAddScalarEvolutionAliasAnalysisPass, - PASS_SCALAR_REPL_AGGREGATES : _core.LLVMAddScalarReplAggregatesPass, - PASS_SCCP : _core.LLVMAddSCCPPass, -- PASS_SIMPLIFY_HALF_POWR_LIB_CALLS : _core.LLVMAddSimplifyHalfPowrLibCallsPass, -+ #PASS_SIMPLIFY_HALF_POWR_LIB_CALLS : _core.LLVMAddSimplifyHalfPowrLibCallsPass, - PASS_SIMPLIFY_LIB_CALLS : _core.LLVMAddSimplifyLibCallsPass, - PASS_SINGLE_LOOP_EXTRACTOR : _core.LLVMAddSingleLoopExtractorPass, - PASS_STRIP_DEAD_PROTOTYPES : _core.LLVMAddStripDeadPrototypesPass, -Index: _intrinsic_ids.py -=================================================================== ---- _intrinsic_ids.py (revision 105) -+++ _intrinsic_ids.py (working copy) -@@ -49,854 +49,879 @@ - INTR_ARM_NEON_VCNT = 14 - INTR_ARM_NEON_VCVTFP2FXS = 15 - INTR_ARM_NEON_VCVTFP2FXU = 16 --INTR_ARM_NEON_VCVTFXS2FP = 17 --INTR_ARM_NEON_VCVTFXU2FP = 18 --INTR_ARM_NEON_VHADDS = 19 --INTR_ARM_NEON_VHADDU = 20 --INTR_ARM_NEON_VHSUBS = 21 --INTR_ARM_NEON_VHSUBU = 22 --INTR_ARM_NEON_VLD1 = 23 --INTR_ARM_NEON_VLD2 = 24 --INTR_ARM_NEON_VLD2LANE = 25 --INTR_ARM_NEON_VLD3 = 26 --INTR_ARM_NEON_VLD3LANE = 27 --INTR_ARM_NEON_VLD4 = 28 --INTR_ARM_NEON_VLD4LANE = 29 --INTR_ARM_NEON_VMAXS = 30 --INTR_ARM_NEON_VMAXU = 31 --INTR_ARM_NEON_VMINS = 32 --INTR_ARM_NEON_VMINU = 33 --INTR_ARM_NEON_VMULLP = 34 --INTR_ARM_NEON_VMULP = 35 --INTR_ARM_NEON_VPADALS = 36 --INTR_ARM_NEON_VPADALU = 37 --INTR_ARM_NEON_VPADD = 38 --INTR_ARM_NEON_VPADDLS = 39 --INTR_ARM_NEON_VPADDLU = 40 --INTR_ARM_NEON_VPMAXS = 41 --INTR_ARM_NEON_VPMAXU = 42 --INTR_ARM_NEON_VPMINS = 43 --INTR_ARM_NEON_VPMINU = 44 --INTR_ARM_NEON_VQABS = 45 --INTR_ARM_NEON_VQADDS = 46 --INTR_ARM_NEON_VQADDU = 47 --INTR_ARM_NEON_VQDMLAL = 48 --INTR_ARM_NEON_VQDMLSL = 49 --INTR_ARM_NEON_VQDMULH = 50 --INTR_ARM_NEON_VQDMULL = 51 --INTR_ARM_NEON_VQMOVNS = 52 --INTR_ARM_NEON_VQMOVNSU = 53 --INTR_ARM_NEON_VQMOVNU = 54 --INTR_ARM_NEON_VQNEG = 55 --INTR_ARM_NEON_VQRDMULH = 56 --INTR_ARM_NEON_VQRSHIFTNS = 57 --INTR_ARM_NEON_VQRSHIFTNSU = 58 --INTR_ARM_NEON_VQRSHIFTNU = 59 --INTR_ARM_NEON_VQRSHIFTS = 60 --INTR_ARM_NEON_VQRSHIFTU = 61 --INTR_ARM_NEON_VQSHIFTNS = 62 --INTR_ARM_NEON_VQSHIFTNSU = 63 --INTR_ARM_NEON_VQSHIFTNU = 64 --INTR_ARM_NEON_VQSHIFTS = 65 --INTR_ARM_NEON_VQSHIFTSU = 66 --INTR_ARM_NEON_VQSHIFTU = 67 --INTR_ARM_NEON_VQSUBS = 68 --INTR_ARM_NEON_VQSUBU = 69 --INTR_ARM_NEON_VRADDHN = 70 --INTR_ARM_NEON_VRECPE = 71 --INTR_ARM_NEON_VRECPS = 72 --INTR_ARM_NEON_VRHADDS = 73 --INTR_ARM_NEON_VRHADDU = 74 --INTR_ARM_NEON_VRSHIFTN = 75 --INTR_ARM_NEON_VRSHIFTS = 76 --INTR_ARM_NEON_VRSHIFTU = 77 --INTR_ARM_NEON_VRSQRTE = 78 --INTR_ARM_NEON_VRSQRTS = 79 --INTR_ARM_NEON_VRSUBHN = 80 --INTR_ARM_NEON_VSHIFTINS = 81 --INTR_ARM_NEON_VSHIFTLS = 82 --INTR_ARM_NEON_VSHIFTLU = 83 --INTR_ARM_NEON_VSHIFTN = 84 --INTR_ARM_NEON_VSHIFTS = 85 --INTR_ARM_NEON_VSHIFTU = 86 --INTR_ARM_NEON_VST1 = 87 --INTR_ARM_NEON_VST2 = 88 --INTR_ARM_NEON_VST2LANE = 89 --INTR_ARM_NEON_VST3 = 90 --INTR_ARM_NEON_VST3LANE = 91 --INTR_ARM_NEON_VST4 = 92 --INTR_ARM_NEON_VST4LANE = 93 --INTR_ARM_NEON_VSUBHN = 94 --INTR_ARM_NEON_VTBL1 = 95 --INTR_ARM_NEON_VTBL2 = 96 --INTR_ARM_NEON_VTBL3 = 97 --INTR_ARM_NEON_VTBL4 = 98 --INTR_ARM_NEON_VTBX1 = 99 --INTR_ARM_NEON_VTBX2 = 100 --INTR_ARM_NEON_VTBX3 = 101 --INTR_ARM_NEON_VTBX4 = 102 --INTR_ARM_QADD = 103 --INTR_ARM_QSUB = 104 --INTR_ARM_SET_FPSCR = 105 --INTR_ARM_SSAT = 106 --INTR_ARM_THREAD_POINTER = 107 --INTR_ARM_USAT = 108 --INTR_ARM_VCVTR = 109 --INTR_ARM_VCVTRU = 110 --INTR_ATOMIC_CMP_SWAP = 111 --INTR_ATOMIC_LOAD_ADD = 112 --INTR_ATOMIC_LOAD_AND = 113 --INTR_ATOMIC_LOAD_MAX = 114 --INTR_ATOMIC_LOAD_MIN = 115 --INTR_ATOMIC_LOAD_NAND = 116 --INTR_ATOMIC_LOAD_OR = 117 --INTR_ATOMIC_LOAD_SUB = 118 --INTR_ATOMIC_LOAD_UMAX = 119 --INTR_ATOMIC_LOAD_UMIN = 120 --INTR_ATOMIC_LOAD_XOR = 121 --INTR_ATOMIC_SWAP = 122 --INTR_BSWAP = 123 --INTR_CONVERT_FROM_FP16 = 124 --INTR_CONVERT_TO_FP16 = 125 --INTR_CONVERTFF = 126 --INTR_CONVERTFSI = 127 --INTR_CONVERTFUI = 128 --INTR_CONVERTSIF = 129 --INTR_CONVERTSS = 130 --INTR_CONVERTSU = 131 --INTR_CONVERTUIF = 132 --INTR_CONVERTUS = 133 --INTR_CONVERTUU = 134 --INTR_COS = 135 --INTR_CTLZ = 136 --INTR_CTPOP = 137 --INTR_CTTZ = 138 --INTR_DBG_DECLARE = 139 --INTR_DBG_VALUE = 140 --INTR_EH_DWARF_CFA = 141 --INTR_EH_EXCEPTION = 142 --INTR_EH_RETURN_I32 = 143 --INTR_EH_RETURN_I64 = 144 --INTR_EH_SELECTOR = 145 --INTR_EH_SJLJ_CALLSITE = 146 --INTR_EH_SJLJ_LONGJMP = 147 --INTR_EH_SJLJ_LSDA = 148 --INTR_EH_SJLJ_SETJMP = 149 --INTR_EH_TYPEID_FOR = 150 --INTR_EH_UNWIND_INIT = 151 --INTR_EXP = 152 --INTR_EXP2 = 153 --INTR_FLT_ROUNDS = 154 --INTR_FRAMEADDRESS = 155 --INTR_GCREAD = 156 --INTR_GCROOT = 157 --INTR_GCWRITE = 158 --INTR_INIT_TRAMPOLINE = 159 --INTR_INVARIANT_END = 160 --INTR_INVARIANT_START = 161 --INTR_LIFETIME_END = 162 --INTR_LIFETIME_START = 163 --INTR_LOG = 164 --INTR_LOG10 = 165 --INTR_LOG2 = 166 --INTR_LONGJMP = 167 --INTR_MEMCPY = 168 --INTR_MEMMOVE = 169 --INTR_MEMORY_BARRIER = 170 --INTR_MEMSET = 171 --INTR_OBJECTSIZE = 172 --INTR_PCMARKER = 173 --INTR_POW = 174 --INTR_POWI = 175 --INTR_PPC_ALTIVEC_DSS = 176 --INTR_PPC_ALTIVEC_DSSALL = 177 --INTR_PPC_ALTIVEC_DST = 178 --INTR_PPC_ALTIVEC_DSTST = 179 --INTR_PPC_ALTIVEC_DSTSTT = 180 --INTR_PPC_ALTIVEC_DSTT = 181 --INTR_PPC_ALTIVEC_LVEBX = 182 --INTR_PPC_ALTIVEC_LVEHX = 183 --INTR_PPC_ALTIVEC_LVEWX = 184 --INTR_PPC_ALTIVEC_LVSL = 185 --INTR_PPC_ALTIVEC_LVSR = 186 --INTR_PPC_ALTIVEC_LVX = 187 --INTR_PPC_ALTIVEC_LVXL = 188 --INTR_PPC_ALTIVEC_MFVSCR = 189 --INTR_PPC_ALTIVEC_MTVSCR = 190 --INTR_PPC_ALTIVEC_STVEBX = 191 --INTR_PPC_ALTIVEC_STVEHX = 192 --INTR_PPC_ALTIVEC_STVEWX = 193 --INTR_PPC_ALTIVEC_STVX = 194 --INTR_PPC_ALTIVEC_STVXL = 195 --INTR_PPC_ALTIVEC_VADDCUW = 196 --INTR_PPC_ALTIVEC_VADDSBS = 197 --INTR_PPC_ALTIVEC_VADDSHS = 198 --INTR_PPC_ALTIVEC_VADDSWS = 199 --INTR_PPC_ALTIVEC_VADDUBS = 200 --INTR_PPC_ALTIVEC_VADDUHS = 201 --INTR_PPC_ALTIVEC_VADDUWS = 202 --INTR_PPC_ALTIVEC_VAVGSB = 203 --INTR_PPC_ALTIVEC_VAVGSH = 204 --INTR_PPC_ALTIVEC_VAVGSW = 205 --INTR_PPC_ALTIVEC_VAVGUB = 206 --INTR_PPC_ALTIVEC_VAVGUH = 207 --INTR_PPC_ALTIVEC_VAVGUW = 208 --INTR_PPC_ALTIVEC_VCFSX = 209 --INTR_PPC_ALTIVEC_VCFUX = 210 --INTR_PPC_ALTIVEC_VCMPBFP = 211 --INTR_PPC_ALTIVEC_VCMPBFP_P = 212 --INTR_PPC_ALTIVEC_VCMPEQFP = 213 --INTR_PPC_ALTIVEC_VCMPEQFP_P = 214 --INTR_PPC_ALTIVEC_VCMPEQUB = 215 --INTR_PPC_ALTIVEC_VCMPEQUB_P = 216 --INTR_PPC_ALTIVEC_VCMPEQUH = 217 --INTR_PPC_ALTIVEC_VCMPEQUH_P = 218 --INTR_PPC_ALTIVEC_VCMPEQUW = 219 --INTR_PPC_ALTIVEC_VCMPEQUW_P = 220 --INTR_PPC_ALTIVEC_VCMPGEFP = 221 --INTR_PPC_ALTIVEC_VCMPGEFP_P = 222 --INTR_PPC_ALTIVEC_VCMPGTFP = 223 --INTR_PPC_ALTIVEC_VCMPGTFP_P = 224 --INTR_PPC_ALTIVEC_VCMPGTSB = 225 --INTR_PPC_ALTIVEC_VCMPGTSB_P = 226 --INTR_PPC_ALTIVEC_VCMPGTSH = 227 --INTR_PPC_ALTIVEC_VCMPGTSH_P = 228 --INTR_PPC_ALTIVEC_VCMPGTSW = 229 --INTR_PPC_ALTIVEC_VCMPGTSW_P = 230 --INTR_PPC_ALTIVEC_VCMPGTUB = 231 --INTR_PPC_ALTIVEC_VCMPGTUB_P = 232 --INTR_PPC_ALTIVEC_VCMPGTUH = 233 --INTR_PPC_ALTIVEC_VCMPGTUH_P = 234 --INTR_PPC_ALTIVEC_VCMPGTUW = 235 --INTR_PPC_ALTIVEC_VCMPGTUW_P = 236 --INTR_PPC_ALTIVEC_VCTSXS = 237 --INTR_PPC_ALTIVEC_VCTUXS = 238 --INTR_PPC_ALTIVEC_VEXPTEFP = 239 --INTR_PPC_ALTIVEC_VLOGEFP = 240 --INTR_PPC_ALTIVEC_VMADDFP = 241 --INTR_PPC_ALTIVEC_VMAXFP = 242 --INTR_PPC_ALTIVEC_VMAXSB = 243 --INTR_PPC_ALTIVEC_VMAXSH = 244 --INTR_PPC_ALTIVEC_VMAXSW = 245 --INTR_PPC_ALTIVEC_VMAXUB = 246 --INTR_PPC_ALTIVEC_VMAXUH = 247 --INTR_PPC_ALTIVEC_VMAXUW = 248 --INTR_PPC_ALTIVEC_VMHADDSHS = 249 --INTR_PPC_ALTIVEC_VMHRADDSHS = 250 --INTR_PPC_ALTIVEC_VMINFP = 251 --INTR_PPC_ALTIVEC_VMINSB = 252 --INTR_PPC_ALTIVEC_VMINSH = 253 --INTR_PPC_ALTIVEC_VMINSW = 254 --INTR_PPC_ALTIVEC_VMINUB = 255 --INTR_PPC_ALTIVEC_VMINUH = 256 --INTR_PPC_ALTIVEC_VMINUW = 257 --INTR_PPC_ALTIVEC_VMLADDUHM = 258 --INTR_PPC_ALTIVEC_VMSUMMBM = 259 --INTR_PPC_ALTIVEC_VMSUMSHM = 260 --INTR_PPC_ALTIVEC_VMSUMSHS = 261 --INTR_PPC_ALTIVEC_VMSUMUBM = 262 --INTR_PPC_ALTIVEC_VMSUMUHM = 263 --INTR_PPC_ALTIVEC_VMSUMUHS = 264 --INTR_PPC_ALTIVEC_VMULESB = 265 --INTR_PPC_ALTIVEC_VMULESH = 266 --INTR_PPC_ALTIVEC_VMULEUB = 267 --INTR_PPC_ALTIVEC_VMULEUH = 268 --INTR_PPC_ALTIVEC_VMULOSB = 269 --INTR_PPC_ALTIVEC_VMULOSH = 270 --INTR_PPC_ALTIVEC_VMULOUB = 271 --INTR_PPC_ALTIVEC_VMULOUH = 272 --INTR_PPC_ALTIVEC_VNMSUBFP = 273 --INTR_PPC_ALTIVEC_VPERM = 274 --INTR_PPC_ALTIVEC_VPKPX = 275 --INTR_PPC_ALTIVEC_VPKSHSS = 276 --INTR_PPC_ALTIVEC_VPKSHUS = 277 --INTR_PPC_ALTIVEC_VPKSWSS = 278 --INTR_PPC_ALTIVEC_VPKSWUS = 279 --INTR_PPC_ALTIVEC_VPKUHUS = 280 --INTR_PPC_ALTIVEC_VPKUWUS = 281 --INTR_PPC_ALTIVEC_VREFP = 282 --INTR_PPC_ALTIVEC_VRFIM = 283 --INTR_PPC_ALTIVEC_VRFIN = 284 --INTR_PPC_ALTIVEC_VRFIP = 285 --INTR_PPC_ALTIVEC_VRFIZ = 286 --INTR_PPC_ALTIVEC_VRLB = 287 --INTR_PPC_ALTIVEC_VRLH = 288 --INTR_PPC_ALTIVEC_VRLW = 289 --INTR_PPC_ALTIVEC_VRSQRTEFP = 290 --INTR_PPC_ALTIVEC_VSEL = 291 --INTR_PPC_ALTIVEC_VSL = 292 --INTR_PPC_ALTIVEC_VSLB = 293 --INTR_PPC_ALTIVEC_VSLH = 294 --INTR_PPC_ALTIVEC_VSLO = 295 --INTR_PPC_ALTIVEC_VSLW = 296 --INTR_PPC_ALTIVEC_VSR = 297 --INTR_PPC_ALTIVEC_VSRAB = 298 --INTR_PPC_ALTIVEC_VSRAH = 299 --INTR_PPC_ALTIVEC_VSRAW = 300 --INTR_PPC_ALTIVEC_VSRB = 301 --INTR_PPC_ALTIVEC_VSRH = 302 --INTR_PPC_ALTIVEC_VSRO = 303 --INTR_PPC_ALTIVEC_VSRW = 304 --INTR_PPC_ALTIVEC_VSUBCUW = 305 --INTR_PPC_ALTIVEC_VSUBSBS = 306 --INTR_PPC_ALTIVEC_VSUBSHS = 307 --INTR_PPC_ALTIVEC_VSUBSWS = 308 --INTR_PPC_ALTIVEC_VSUBUBS = 309 --INTR_PPC_ALTIVEC_VSUBUHS = 310 --INTR_PPC_ALTIVEC_VSUBUWS = 311 --INTR_PPC_ALTIVEC_VSUM2SWS = 312 --INTR_PPC_ALTIVEC_VSUM4SBS = 313 --INTR_PPC_ALTIVEC_VSUM4SHS = 314 --INTR_PPC_ALTIVEC_VSUM4UBS = 315 --INTR_PPC_ALTIVEC_VSUMSWS = 316 --INTR_PPC_ALTIVEC_VUPKHPX = 317 --INTR_PPC_ALTIVEC_VUPKHSB = 318 --INTR_PPC_ALTIVEC_VUPKHSH = 319 --INTR_PPC_ALTIVEC_VUPKLPX = 320 --INTR_PPC_ALTIVEC_VUPKLSB = 321 --INTR_PPC_ALTIVEC_VUPKLSH = 322 --INTR_PPC_DCBA = 323 --INTR_PPC_DCBF = 324 --INTR_PPC_DCBI = 325 --INTR_PPC_DCBST = 326 --INTR_PPC_DCBT = 327 --INTR_PPC_DCBTST = 328 --INTR_PPC_DCBZ = 329 --INTR_PPC_DCBZL = 330 --INTR_PPC_SYNC = 331 --INTR_PREFETCH = 332 --INTR_PTR_ANNOTATION = 333 --INTR_READCYCLECOUNTER = 334 --INTR_RETURNADDRESS = 335 --INTR_SADD_WITH_OVERFLOW = 336 --INTR_SETJMP = 337 --INTR_SIGLONGJMP = 338 --INTR_SIGSETJMP = 339 --INTR_SIN = 340 --INTR_SMUL_WITH_OVERFLOW = 341 --INTR_SPU_SI_A = 342 --INTR_SPU_SI_ADDX = 343 --INTR_SPU_SI_AH = 344 --INTR_SPU_SI_AHI = 345 --INTR_SPU_SI_AI = 346 --INTR_SPU_SI_AND = 347 --INTR_SPU_SI_ANDBI = 348 --INTR_SPU_SI_ANDC = 349 --INTR_SPU_SI_ANDHI = 350 --INTR_SPU_SI_ANDI = 351 --INTR_SPU_SI_BG = 352 --INTR_SPU_SI_BGX = 353 --INTR_SPU_SI_CEQ = 354 --INTR_SPU_SI_CEQB = 355 --INTR_SPU_SI_CEQBI = 356 --INTR_SPU_SI_CEQH = 357 --INTR_SPU_SI_CEQHI = 358 --INTR_SPU_SI_CEQI = 359 --INTR_SPU_SI_CG = 360 --INTR_SPU_SI_CGT = 361 --INTR_SPU_SI_CGTB = 362 --INTR_SPU_SI_CGTBI = 363 --INTR_SPU_SI_CGTH = 364 --INTR_SPU_SI_CGTHI = 365 --INTR_SPU_SI_CGTI = 366 --INTR_SPU_SI_CGX = 367 --INTR_SPU_SI_CLGT = 368 --INTR_SPU_SI_CLGTB = 369 --INTR_SPU_SI_CLGTBI = 370 --INTR_SPU_SI_CLGTH = 371 --INTR_SPU_SI_CLGTHI = 372 --INTR_SPU_SI_CLGTI = 373 --INTR_SPU_SI_DFA = 374 --INTR_SPU_SI_DFM = 375 --INTR_SPU_SI_DFMA = 376 --INTR_SPU_SI_DFMS = 377 --INTR_SPU_SI_DFNMA = 378 --INTR_SPU_SI_DFNMS = 379 --INTR_SPU_SI_DFS = 380 --INTR_SPU_SI_FA = 381 --INTR_SPU_SI_FCEQ = 382 --INTR_SPU_SI_FCGT = 383 --INTR_SPU_SI_FCMEQ = 384 --INTR_SPU_SI_FCMGT = 385 --INTR_SPU_SI_FM = 386 --INTR_SPU_SI_FMA = 387 --INTR_SPU_SI_FMS = 388 --INTR_SPU_SI_FNMS = 389 --INTR_SPU_SI_FS = 390 --INTR_SPU_SI_FSMBI = 391 --INTR_SPU_SI_MPY = 392 --INTR_SPU_SI_MPYA = 393 --INTR_SPU_SI_MPYH = 394 --INTR_SPU_SI_MPYHH = 395 --INTR_SPU_SI_MPYHHA = 396 --INTR_SPU_SI_MPYHHAU = 397 --INTR_SPU_SI_MPYHHU = 398 --INTR_SPU_SI_MPYI = 399 --INTR_SPU_SI_MPYS = 400 --INTR_SPU_SI_MPYU = 401 --INTR_SPU_SI_MPYUI = 402 --INTR_SPU_SI_NAND = 403 --INTR_SPU_SI_NOR = 404 --INTR_SPU_SI_OR = 405 --INTR_SPU_SI_ORBI = 406 --INTR_SPU_SI_ORC = 407 --INTR_SPU_SI_ORHI = 408 --INTR_SPU_SI_ORI = 409 --INTR_SPU_SI_SF = 410 --INTR_SPU_SI_SFH = 411 --INTR_SPU_SI_SFHI = 412 --INTR_SPU_SI_SFI = 413 --INTR_SPU_SI_SFX = 414 --INTR_SPU_SI_SHLI = 415 --INTR_SPU_SI_SHLQBI = 416 --INTR_SPU_SI_SHLQBII = 417 --INTR_SPU_SI_SHLQBY = 418 --INTR_SPU_SI_SHLQBYI = 419 --INTR_SPU_SI_XOR = 420 --INTR_SPU_SI_XORBI = 421 --INTR_SPU_SI_XORHI = 422 --INTR_SPU_SI_XORI = 423 --INTR_SQRT = 424 --INTR_SSUB_WITH_OVERFLOW = 425 --INTR_STACKPROTECTOR = 426 --INTR_STACKRESTORE = 427 --INTR_STACKSAVE = 428 --INTR_TRAP = 429 --INTR_UADD_WITH_OVERFLOW = 430 --INTR_UMUL_WITH_OVERFLOW = 431 --INTR_USUB_WITH_OVERFLOW = 432 --INTR_VACOPY = 433 --INTR_VAEND = 434 --INTR_VAR_ANNOTATION = 435 --INTR_VASTART = 436 --INTR_X86_AESNI_AESDEC = 437 --INTR_X86_AESNI_AESDECLAST = 438 --INTR_X86_AESNI_AESENC = 439 --INTR_X86_AESNI_AESENCLAST = 440 --INTR_X86_AESNI_AESIMC = 441 --INTR_X86_AESNI_AESKEYGENASSIST = 442 --INTR_X86_AVX_ADDSUB_PD_256 = 443 --INTR_X86_AVX_ADDSUB_PS_256 = 444 --INTR_X86_AVX_BLEND_PD_256 = 445 --INTR_X86_AVX_BLEND_PS_256 = 446 --INTR_X86_AVX_BLENDV_PD_256 = 447 --INTR_X86_AVX_BLENDV_PS_256 = 448 --INTR_X86_AVX_CMP_PD_256 = 449 --INTR_X86_AVX_CMP_PS_256 = 450 --INTR_X86_AVX_CVT_PD2_PS_256 = 451 --INTR_X86_AVX_CVT_PD2DQ_256 = 452 --INTR_X86_AVX_CVT_PS2_PD_256 = 453 --INTR_X86_AVX_CVT_PS2DQ_256 = 454 --INTR_X86_AVX_CVTDQ2_PD_256 = 455 --INTR_X86_AVX_CVTDQ2_PS_256 = 456 --INTR_X86_AVX_CVTT_PD2DQ_256 = 457 --INTR_X86_AVX_CVTT_PS2DQ_256 = 458 --INTR_X86_AVX_DP_PS_256 = 459 --INTR_X86_AVX_HADD_PD_256 = 460 --INTR_X86_AVX_HADD_PS_256 = 461 --INTR_X86_AVX_HSUB_PD_256 = 462 --INTR_X86_AVX_HSUB_PS_256 = 463 --INTR_X86_AVX_LDU_DQ_256 = 464 --INTR_X86_AVX_LOADU_DQ_256 = 465 --INTR_X86_AVX_LOADU_PD_256 = 466 --INTR_X86_AVX_LOADU_PS_256 = 467 --INTR_X86_AVX_MASKLOAD_PD = 468 --INTR_X86_AVX_MASKLOAD_PD_256 = 469 --INTR_X86_AVX_MASKLOAD_PS = 470 --INTR_X86_AVX_MASKLOAD_PS_256 = 471 --INTR_X86_AVX_MASKSTORE_PD = 472 --INTR_X86_AVX_MASKSTORE_PD_256 = 473 --INTR_X86_AVX_MASKSTORE_PS = 474 --INTR_X86_AVX_MASKSTORE_PS_256 = 475 --INTR_X86_AVX_MAX_PD_256 = 476 --INTR_X86_AVX_MAX_PS_256 = 477 --INTR_X86_AVX_MIN_PD_256 = 478 --INTR_X86_AVX_MIN_PS_256 = 479 --INTR_X86_AVX_MOVMSK_PD_256 = 480 --INTR_X86_AVX_MOVMSK_PS_256 = 481 --INTR_X86_AVX_MOVNT_DQ_256 = 482 --INTR_X86_AVX_MOVNT_PD_256 = 483 --INTR_X86_AVX_MOVNT_PS_256 = 484 --INTR_X86_AVX_PTESTC_256 = 485 --INTR_X86_AVX_PTESTNZC_256 = 486 --INTR_X86_AVX_PTESTZ_256 = 487 --INTR_X86_AVX_RCP_PS_256 = 488 --INTR_X86_AVX_ROUND_PD_256 = 489 --INTR_X86_AVX_ROUND_PS_256 = 490 --INTR_X86_AVX_RSQRT_PS_256 = 491 --INTR_X86_AVX_SQRT_PD_256 = 492 --INTR_X86_AVX_SQRT_PS_256 = 493 --INTR_X86_AVX_STOREU_DQ_256 = 494 --INTR_X86_AVX_STOREU_PD_256 = 495 --INTR_X86_AVX_STOREU_PS_256 = 496 --INTR_X86_AVX_VBROADCAST_SD_256 = 497 --INTR_X86_AVX_VBROADCASTF128_PD_256 = 498 --INTR_X86_AVX_VBROADCASTF128_PS_256 = 499 --INTR_X86_AVX_VBROADCASTSS = 500 --INTR_X86_AVX_VBROADCASTSS_256 = 501 --INTR_X86_AVX_VEXTRACTF128_PD_256 = 502 --INTR_X86_AVX_VEXTRACTF128_PS_256 = 503 --INTR_X86_AVX_VEXTRACTF128_SI_256 = 504 --INTR_X86_AVX_VINSERTF128_PD_256 = 505 --INTR_X86_AVX_VINSERTF128_PS_256 = 506 --INTR_X86_AVX_VINSERTF128_SI_256 = 507 --INTR_X86_AVX_VPERM2F128_PD_256 = 508 --INTR_X86_AVX_VPERM2F128_PS_256 = 509 --INTR_X86_AVX_VPERM2F128_SI_256 = 510 --INTR_X86_AVX_VPERMIL_PD = 511 --INTR_X86_AVX_VPERMIL_PD_256 = 512 --INTR_X86_AVX_VPERMIL_PS = 513 --INTR_X86_AVX_VPERMIL_PS_256 = 514 --INTR_X86_AVX_VPERMILVAR_PD = 515 --INTR_X86_AVX_VPERMILVAR_PD_256 = 516 --INTR_X86_AVX_VPERMILVAR_PS = 517 --INTR_X86_AVX_VPERMILVAR_PS_256 = 518 --INTR_X86_AVX_VTESTC_PD = 519 --INTR_X86_AVX_VTESTC_PD_256 = 520 --INTR_X86_AVX_VTESTC_PS = 521 --INTR_X86_AVX_VTESTC_PS_256 = 522 --INTR_X86_AVX_VTESTNZC_PD = 523 --INTR_X86_AVX_VTESTNZC_PD_256 = 524 --INTR_X86_AVX_VTESTNZC_PS = 525 --INTR_X86_AVX_VTESTNZC_PS_256 = 526 --INTR_X86_AVX_VTESTZ_PD = 527 --INTR_X86_AVX_VTESTZ_PD_256 = 528 --INTR_X86_AVX_VTESTZ_PS = 529 --INTR_X86_AVX_VTESTZ_PS_256 = 530 --INTR_X86_AVX_VZEROALL = 531 --INTR_X86_AVX_VZEROUPPER = 532 --INTR_X86_INT = 533 --INTR_X86_MMX_CVTSI32_SI64 = 534 --INTR_X86_MMX_CVTSI64_SI32 = 535 --INTR_X86_MMX_EMMS = 536 --INTR_X86_MMX_FEMMS = 537 --INTR_X86_MMX_MASKMOVQ = 538 --INTR_X86_MMX_MOVNT_DQ = 539 --INTR_X86_MMX_PACKSSDW = 540 --INTR_X86_MMX_PACKSSWB = 541 --INTR_X86_MMX_PACKUSWB = 542 --INTR_X86_MMX_PADD_B = 543 --INTR_X86_MMX_PADD_D = 544 --INTR_X86_MMX_PADD_Q = 545 --INTR_X86_MMX_PADD_W = 546 --INTR_X86_MMX_PADDS_B = 547 --INTR_X86_MMX_PADDS_W = 548 --INTR_X86_MMX_PADDUS_B = 549 --INTR_X86_MMX_PADDUS_W = 550 --INTR_X86_MMX_PAND = 551 --INTR_X86_MMX_PANDN = 552 --INTR_X86_MMX_PAVG_B = 553 --INTR_X86_MMX_PAVG_W = 554 --INTR_X86_MMX_PCMPEQ_B = 555 --INTR_X86_MMX_PCMPEQ_D = 556 --INTR_X86_MMX_PCMPEQ_W = 557 --INTR_X86_MMX_PCMPGT_B = 558 --INTR_X86_MMX_PCMPGT_D = 559 --INTR_X86_MMX_PCMPGT_W = 560 --INTR_X86_MMX_PEXTR_W = 561 --INTR_X86_MMX_PINSR_W = 562 --INTR_X86_MMX_PMADD_WD = 563 --INTR_X86_MMX_PMAXS_W = 564 --INTR_X86_MMX_PMAXU_B = 565 --INTR_X86_MMX_PMINS_W = 566 --INTR_X86_MMX_PMINU_B = 567 --INTR_X86_MMX_PMOVMSKB = 568 --INTR_X86_MMX_PMULH_W = 569 --INTR_X86_MMX_PMULHU_W = 570 --INTR_X86_MMX_PMULL_W = 571 --INTR_X86_MMX_PMULU_DQ = 572 --INTR_X86_MMX_POR = 573 --INTR_X86_MMX_PSAD_BW = 574 --INTR_X86_MMX_PSLL_D = 575 --INTR_X86_MMX_PSLL_Q = 576 --INTR_X86_MMX_PSLL_W = 577 --INTR_X86_MMX_PSLLI_D = 578 --INTR_X86_MMX_PSLLI_Q = 579 --INTR_X86_MMX_PSLLI_W = 580 --INTR_X86_MMX_PSRA_D = 581 --INTR_X86_MMX_PSRA_W = 582 --INTR_X86_MMX_PSRAI_D = 583 --INTR_X86_MMX_PSRAI_W = 584 --INTR_X86_MMX_PSRL_D = 585 --INTR_X86_MMX_PSRL_Q = 586 --INTR_X86_MMX_PSRL_W = 587 --INTR_X86_MMX_PSRLI_D = 588 --INTR_X86_MMX_PSRLI_Q = 589 --INTR_X86_MMX_PSRLI_W = 590 --INTR_X86_MMX_PSUB_B = 591 --INTR_X86_MMX_PSUB_D = 592 --INTR_X86_MMX_PSUB_Q = 593 --INTR_X86_MMX_PSUB_W = 594 --INTR_X86_MMX_PSUBS_B = 595 --INTR_X86_MMX_PSUBS_W = 596 --INTR_X86_MMX_PSUBUS_B = 597 --INTR_X86_MMX_PSUBUS_W = 598 --INTR_X86_MMX_PUNPCKHBW = 599 --INTR_X86_MMX_PUNPCKHDQ = 600 --INTR_X86_MMX_PUNPCKHWD = 601 --INTR_X86_MMX_PUNPCKLBW = 602 --INTR_X86_MMX_PUNPCKLDQ = 603 --INTR_X86_MMX_PUNPCKLWD = 604 --INTR_X86_MMX_PXOR = 605 --INTR_X86_MMX_VEC_EXT_D = 606 --INTR_X86_MMX_VEC_INIT_B = 607 --INTR_X86_MMX_VEC_INIT_D = 608 --INTR_X86_MMX_VEC_INIT_W = 609 --INTR_X86_SSE2_ADD_SD = 610 --INTR_X86_SSE2_CLFLUSH = 611 --INTR_X86_SSE2_CMP_PD = 612 --INTR_X86_SSE2_CMP_SD = 613 --INTR_X86_SSE2_COMIEQ_SD = 614 --INTR_X86_SSE2_COMIGE_SD = 615 --INTR_X86_SSE2_COMIGT_SD = 616 --INTR_X86_SSE2_COMILE_SD = 617 --INTR_X86_SSE2_COMILT_SD = 618 --INTR_X86_SSE2_COMINEQ_SD = 619 --INTR_X86_SSE2_CVTDQ2PD = 620 --INTR_X86_SSE2_CVTDQ2PS = 621 --INTR_X86_SSE2_CVTPD2DQ = 622 --INTR_X86_SSE2_CVTPD2PS = 623 --INTR_X86_SSE2_CVTPS2DQ = 624 --INTR_X86_SSE2_CVTPS2PD = 625 --INTR_X86_SSE2_CVTSD2SI = 626 --INTR_X86_SSE2_CVTSD2SI64 = 627 --INTR_X86_SSE2_CVTSD2SS = 628 --INTR_X86_SSE2_CVTSI2SD = 629 --INTR_X86_SSE2_CVTSI642SD = 630 --INTR_X86_SSE2_CVTSS2SD = 631 --INTR_X86_SSE2_CVTTPD2DQ = 632 --INTR_X86_SSE2_CVTTPS2DQ = 633 --INTR_X86_SSE2_CVTTSD2SI = 634 --INTR_X86_SSE2_CVTTSD2SI64 = 635 --INTR_X86_SSE2_DIV_SD = 636 --INTR_X86_SSE2_LFENCE = 637 --INTR_X86_SSE2_LOADU_DQ = 638 --INTR_X86_SSE2_LOADU_PD = 639 --INTR_X86_SSE2_MASKMOV_DQU = 640 --INTR_X86_SSE2_MAX_PD = 641 --INTR_X86_SSE2_MAX_SD = 642 --INTR_X86_SSE2_MFENCE = 643 --INTR_X86_SSE2_MIN_PD = 644 --INTR_X86_SSE2_MIN_SD = 645 --INTR_X86_SSE2_MOVMSK_PD = 646 --INTR_X86_SSE2_MOVNT_DQ = 647 --INTR_X86_SSE2_MOVNT_I = 648 --INTR_X86_SSE2_MOVNT_PD = 649 --INTR_X86_SSE2_MUL_SD = 650 --INTR_X86_SSE2_PACKSSDW_128 = 651 --INTR_X86_SSE2_PACKSSWB_128 = 652 --INTR_X86_SSE2_PACKUSWB_128 = 653 --INTR_X86_SSE2_PADDS_B = 654 --INTR_X86_SSE2_PADDS_W = 655 --INTR_X86_SSE2_PADDUS_B = 656 --INTR_X86_SSE2_PADDUS_W = 657 --INTR_X86_SSE2_PAVG_B = 658 --INTR_X86_SSE2_PAVG_W = 659 --INTR_X86_SSE2_PCMPEQ_B = 660 --INTR_X86_SSE2_PCMPEQ_D = 661 --INTR_X86_SSE2_PCMPEQ_W = 662 --INTR_X86_SSE2_PCMPGT_B = 663 --INTR_X86_SSE2_PCMPGT_D = 664 --INTR_X86_SSE2_PCMPGT_W = 665 --INTR_X86_SSE2_PMADD_WD = 666 --INTR_X86_SSE2_PMAXS_W = 667 --INTR_X86_SSE2_PMAXU_B = 668 --INTR_X86_SSE2_PMINS_W = 669 --INTR_X86_SSE2_PMINU_B = 670 --INTR_X86_SSE2_PMOVMSKB_128 = 671 --INTR_X86_SSE2_PMULH_W = 672 --INTR_X86_SSE2_PMULHU_W = 673 --INTR_X86_SSE2_PMULU_DQ = 674 --INTR_X86_SSE2_PSAD_BW = 675 --INTR_X86_SSE2_PSLL_D = 676 --INTR_X86_SSE2_PSLL_DQ = 677 --INTR_X86_SSE2_PSLL_DQ_BS = 678 --INTR_X86_SSE2_PSLL_Q = 679 --INTR_X86_SSE2_PSLL_W = 680 --INTR_X86_SSE2_PSLLI_D = 681 --INTR_X86_SSE2_PSLLI_Q = 682 --INTR_X86_SSE2_PSLLI_W = 683 --INTR_X86_SSE2_PSRA_D = 684 --INTR_X86_SSE2_PSRA_W = 685 --INTR_X86_SSE2_PSRAI_D = 686 --INTR_X86_SSE2_PSRAI_W = 687 --INTR_X86_SSE2_PSRL_D = 688 --INTR_X86_SSE2_PSRL_DQ = 689 --INTR_X86_SSE2_PSRL_DQ_BS = 690 --INTR_X86_SSE2_PSRL_Q = 691 --INTR_X86_SSE2_PSRL_W = 692 --INTR_X86_SSE2_PSRLI_D = 693 --INTR_X86_SSE2_PSRLI_Q = 694 --INTR_X86_SSE2_PSRLI_W = 695 --INTR_X86_SSE2_PSUBS_B = 696 --INTR_X86_SSE2_PSUBS_W = 697 --INTR_X86_SSE2_PSUBUS_B = 698 --INTR_X86_SSE2_PSUBUS_W = 699 --INTR_X86_SSE2_SQRT_PD = 700 --INTR_X86_SSE2_SQRT_SD = 701 --INTR_X86_SSE2_STOREL_DQ = 702 --INTR_X86_SSE2_STOREU_DQ = 703 --INTR_X86_SSE2_STOREU_PD = 704 --INTR_X86_SSE2_SUB_SD = 705 --INTR_X86_SSE2_UCOMIEQ_SD = 706 --INTR_X86_SSE2_UCOMIGE_SD = 707 --INTR_X86_SSE2_UCOMIGT_SD = 708 --INTR_X86_SSE2_UCOMILE_SD = 709 --INTR_X86_SSE2_UCOMILT_SD = 710 --INTR_X86_SSE2_UCOMINEQ_SD = 711 --INTR_X86_SSE3_ADDSUB_PD = 712 --INTR_X86_SSE3_ADDSUB_PS = 713 --INTR_X86_SSE3_HADD_PD = 714 --INTR_X86_SSE3_HADD_PS = 715 --INTR_X86_SSE3_HSUB_PD = 716 --INTR_X86_SSE3_HSUB_PS = 717 --INTR_X86_SSE3_LDU_DQ = 718 --INTR_X86_SSE3_MONITOR = 719 --INTR_X86_SSE3_MWAIT = 720 --INTR_X86_SSE41_BLENDPD = 721 --INTR_X86_SSE41_BLENDPS = 722 --INTR_X86_SSE41_BLENDVPD = 723 --INTR_X86_SSE41_BLENDVPS = 724 --INTR_X86_SSE41_DPPD = 725 --INTR_X86_SSE41_DPPS = 726 --INTR_X86_SSE41_EXTRACTPS = 727 --INTR_X86_SSE41_INSERTPS = 728 --INTR_X86_SSE41_MOVNTDQA = 729 --INTR_X86_SSE41_MPSADBW = 730 --INTR_X86_SSE41_PACKUSDW = 731 --INTR_X86_SSE41_PBLENDVB = 732 --INTR_X86_SSE41_PBLENDW = 733 --INTR_X86_SSE41_PCMPEQQ = 734 --INTR_X86_SSE41_PEXTRB = 735 --INTR_X86_SSE41_PEXTRD = 736 --INTR_X86_SSE41_PEXTRQ = 737 --INTR_X86_SSE41_PHMINPOSUW = 738 --INTR_X86_SSE41_PMAXSB = 739 --INTR_X86_SSE41_PMAXSD = 740 --INTR_X86_SSE41_PMAXUD = 741 --INTR_X86_SSE41_PMAXUW = 742 --INTR_X86_SSE41_PMINSB = 743 --INTR_X86_SSE41_PMINSD = 744 --INTR_X86_SSE41_PMINUD = 745 --INTR_X86_SSE41_PMINUW = 746 --INTR_X86_SSE41_PMOVSXBD = 747 --INTR_X86_SSE41_PMOVSXBQ = 748 --INTR_X86_SSE41_PMOVSXBW = 749 --INTR_X86_SSE41_PMOVSXDQ = 750 --INTR_X86_SSE41_PMOVSXWD = 751 --INTR_X86_SSE41_PMOVSXWQ = 752 --INTR_X86_SSE41_PMOVZXBD = 753 --INTR_X86_SSE41_PMOVZXBQ = 754 --INTR_X86_SSE41_PMOVZXBW = 755 --INTR_X86_SSE41_PMOVZXDQ = 756 --INTR_X86_SSE41_PMOVZXWD = 757 --INTR_X86_SSE41_PMOVZXWQ = 758 --INTR_X86_SSE41_PMULDQ = 759 --INTR_X86_SSE41_PTESTC = 760 --INTR_X86_SSE41_PTESTNZC = 761 --INTR_X86_SSE41_PTESTZ = 762 --INTR_X86_SSE41_ROUND_PD = 763 --INTR_X86_SSE41_ROUND_PS = 764 --INTR_X86_SSE41_ROUND_SD = 765 --INTR_X86_SSE41_ROUND_SS = 766 --INTR_X86_SSE42_CRC32_16 = 767 --INTR_X86_SSE42_CRC32_32 = 768 --INTR_X86_SSE42_CRC32_8 = 769 --INTR_X86_SSE42_CRC64_64 = 770 --INTR_X86_SSE42_CRC64_8 = 771 --INTR_X86_SSE42_PCMPESTRI128 = 772 --INTR_X86_SSE42_PCMPESTRIA128 = 773 --INTR_X86_SSE42_PCMPESTRIC128 = 774 --INTR_X86_SSE42_PCMPESTRIO128 = 775 --INTR_X86_SSE42_PCMPESTRIS128 = 776 --INTR_X86_SSE42_PCMPESTRIZ128 = 777 --INTR_X86_SSE42_PCMPESTRM128 = 778 --INTR_X86_SSE42_PCMPGTQ = 779 --INTR_X86_SSE42_PCMPISTRI128 = 780 --INTR_X86_SSE42_PCMPISTRIA128 = 781 --INTR_X86_SSE42_PCMPISTRIC128 = 782 --INTR_X86_SSE42_PCMPISTRIO128 = 783 --INTR_X86_SSE42_PCMPISTRIS128 = 784 --INTR_X86_SSE42_PCMPISTRIZ128 = 785 --INTR_X86_SSE42_PCMPISTRM128 = 786 --INTR_X86_SSE_ADD_SS = 787 --INTR_X86_SSE_CMP_PS = 788 --INTR_X86_SSE_CMP_SS = 789 --INTR_X86_SSE_COMIEQ_SS = 790 --INTR_X86_SSE_COMIGE_SS = 791 --INTR_X86_SSE_COMIGT_SS = 792 --INTR_X86_SSE_COMILE_SS = 793 --INTR_X86_SSE_COMILT_SS = 794 --INTR_X86_SSE_COMINEQ_SS = 795 --INTR_X86_SSE_CVTPD2PI = 796 --INTR_X86_SSE_CVTPI2PD = 797 --INTR_X86_SSE_CVTPI2PS = 798 --INTR_X86_SSE_CVTPS2PI = 799 --INTR_X86_SSE_CVTSI2SS = 800 --INTR_X86_SSE_CVTSI642SS = 801 --INTR_X86_SSE_CVTSS2SI = 802 --INTR_X86_SSE_CVTSS2SI64 = 803 --INTR_X86_SSE_CVTTPD2PI = 804 --INTR_X86_SSE_CVTTPS2PI = 805 --INTR_X86_SSE_CVTTSS2SI = 806 --INTR_X86_SSE_CVTTSS2SI64 = 807 --INTR_X86_SSE_DIV_SS = 808 --INTR_X86_SSE_LDMXCSR = 809 --INTR_X86_SSE_LOADU_PS = 810 --INTR_X86_SSE_MAX_PS = 811 --INTR_X86_SSE_MAX_SS = 812 --INTR_X86_SSE_MIN_PS = 813 --INTR_X86_SSE_MIN_SS = 814 --INTR_X86_SSE_MOVMSK_PS = 815 --INTR_X86_SSE_MOVNT_PS = 816 --INTR_X86_SSE_MUL_SS = 817 --INTR_X86_SSE_RCP_PS = 818 --INTR_X86_SSE_RCP_SS = 819 --INTR_X86_SSE_RSQRT_PS = 820 --INTR_X86_SSE_RSQRT_SS = 821 --INTR_X86_SSE_SFENCE = 822 --INTR_X86_SSE_SQRT_PS = 823 --INTR_X86_SSE_SQRT_SS = 824 --INTR_X86_SSE_STMXCSR = 825 --INTR_X86_SSE_STOREU_PS = 826 --INTR_X86_SSE_SUB_SS = 827 --INTR_X86_SSE_UCOMIEQ_SS = 828 --INTR_X86_SSE_UCOMIGE_SS = 829 --INTR_X86_SSE_UCOMIGT_SS = 830 --INTR_X86_SSE_UCOMILE_SS = 831 --INTR_X86_SSE_UCOMILT_SS = 832 --INTR_X86_SSE_UCOMINEQ_SS = 833 --INTR_X86_SSSE3_PABS_B = 834 --INTR_X86_SSSE3_PABS_B_128 = 835 --INTR_X86_SSSE3_PABS_D = 836 --INTR_X86_SSSE3_PABS_D_128 = 837 --INTR_X86_SSSE3_PABS_W = 838 --INTR_X86_SSSE3_PABS_W_128 = 839 --INTR_X86_SSSE3_PHADD_D = 840 --INTR_X86_SSSE3_PHADD_D_128 = 841 --INTR_X86_SSSE3_PHADD_SW = 842 --INTR_X86_SSSE3_PHADD_SW_128 = 843 --INTR_X86_SSSE3_PHADD_W = 844 --INTR_X86_SSSE3_PHADD_W_128 = 845 --INTR_X86_SSSE3_PHSUB_D = 846 --INTR_X86_SSSE3_PHSUB_D_128 = 847 --INTR_X86_SSSE3_PHSUB_SW = 848 --INTR_X86_SSSE3_PHSUB_SW_128 = 849 --INTR_X86_SSSE3_PHSUB_W = 850 --INTR_X86_SSSE3_PHSUB_W_128 = 851 --INTR_X86_SSSE3_PMADD_UB_SW = 852 --INTR_X86_SSSE3_PMADD_UB_SW_128 = 853 --INTR_X86_SSSE3_PMUL_HR_SW = 854 --INTR_X86_SSSE3_PMUL_HR_SW_128 = 855 --INTR_X86_SSSE3_PSHUF_B = 856 --INTR_X86_SSSE3_PSHUF_B_128 = 857 --INTR_X86_SSSE3_PSHUF_W = 858 --INTR_X86_SSSE3_PSIGN_B = 859 --INTR_X86_SSSE3_PSIGN_B_128 = 860 --INTR_X86_SSSE3_PSIGN_D = 861 --INTR_X86_SSSE3_PSIGN_D_128 = 862 --INTR_X86_SSSE3_PSIGN_W = 863 --INTR_X86_SSSE3_PSIGN_W_128 = 864 --INTR_XCORE_BITREV = 865 --INTR_XCORE_GETID = 866 -- -+INTR_ARM_NEON_VCVTFP2HF = 17 -+INTR_ARM_NEON_VCVTFXS2FP = 18 -+INTR_ARM_NEON_VCVTFXU2FP = 19 -+INTR_ARM_NEON_VCVTHF2FP = 20 -+INTR_ARM_NEON_VHADDS = 21 -+INTR_ARM_NEON_VHADDU = 22 -+INTR_ARM_NEON_VHSUBS = 23 -+INTR_ARM_NEON_VHSUBU = 24 -+INTR_ARM_NEON_VLD1 = 25 -+INTR_ARM_NEON_VLD2 = 26 -+INTR_ARM_NEON_VLD2LANE = 27 -+INTR_ARM_NEON_VLD3 = 28 -+INTR_ARM_NEON_VLD3LANE = 29 -+INTR_ARM_NEON_VLD4 = 30 -+INTR_ARM_NEON_VLD4LANE = 31 -+INTR_ARM_NEON_VMAXS = 32 -+INTR_ARM_NEON_VMAXU = 33 -+INTR_ARM_NEON_VMINS = 34 -+INTR_ARM_NEON_VMINU = 35 -+INTR_ARM_NEON_VMULLP = 36 -+INTR_ARM_NEON_VMULP = 37 -+INTR_ARM_NEON_VPADALS = 38 -+INTR_ARM_NEON_VPADALU = 39 -+INTR_ARM_NEON_VPADD = 40 -+INTR_ARM_NEON_VPADDLS = 41 -+INTR_ARM_NEON_VPADDLU = 42 -+INTR_ARM_NEON_VPMAXS = 43 -+INTR_ARM_NEON_VPMAXU = 44 -+INTR_ARM_NEON_VPMINS = 45 -+INTR_ARM_NEON_VPMINU = 46 -+INTR_ARM_NEON_VQABS = 47 -+INTR_ARM_NEON_VQADDS = 48 -+INTR_ARM_NEON_VQADDU = 49 -+INTR_ARM_NEON_VQDMLAL = 50 -+INTR_ARM_NEON_VQDMLSL = 51 -+INTR_ARM_NEON_VQDMULH = 52 -+INTR_ARM_NEON_VQDMULL = 53 -+INTR_ARM_NEON_VQMOVNS = 54 -+INTR_ARM_NEON_VQMOVNSU = 55 -+INTR_ARM_NEON_VQMOVNU = 56 -+INTR_ARM_NEON_VQNEG = 57 -+INTR_ARM_NEON_VQRDMULH = 58 -+INTR_ARM_NEON_VQRSHIFTNS = 59 -+INTR_ARM_NEON_VQRSHIFTNSU = 60 -+INTR_ARM_NEON_VQRSHIFTNU = 61 -+INTR_ARM_NEON_VQRSHIFTS = 62 -+INTR_ARM_NEON_VQRSHIFTU = 63 -+INTR_ARM_NEON_VQSHIFTNS = 64 -+INTR_ARM_NEON_VQSHIFTNSU = 65 -+INTR_ARM_NEON_VQSHIFTNU = 66 -+INTR_ARM_NEON_VQSHIFTS = 67 -+INTR_ARM_NEON_VQSHIFTSU = 68 -+INTR_ARM_NEON_VQSHIFTU = 69 -+INTR_ARM_NEON_VQSUBS = 70 -+INTR_ARM_NEON_VQSUBU = 71 -+INTR_ARM_NEON_VRADDHN = 72 -+INTR_ARM_NEON_VRECPE = 73 -+INTR_ARM_NEON_VRECPS = 74 -+INTR_ARM_NEON_VRHADDS = 75 -+INTR_ARM_NEON_VRHADDU = 76 -+INTR_ARM_NEON_VRSHIFTN = 77 -+INTR_ARM_NEON_VRSHIFTS = 78 -+INTR_ARM_NEON_VRSHIFTU = 79 -+INTR_ARM_NEON_VRSQRTE = 80 -+INTR_ARM_NEON_VRSQRTS = 81 -+INTR_ARM_NEON_VRSUBHN = 82 -+INTR_ARM_NEON_VSHIFTINS = 83 -+INTR_ARM_NEON_VSHIFTLS = 84 -+INTR_ARM_NEON_VSHIFTLU = 85 -+INTR_ARM_NEON_VSHIFTN = 86 -+INTR_ARM_NEON_VSHIFTS = 87 -+INTR_ARM_NEON_VSHIFTU = 88 -+INTR_ARM_NEON_VST1 = 89 -+INTR_ARM_NEON_VST2 = 90 -+INTR_ARM_NEON_VST2LANE = 91 -+INTR_ARM_NEON_VST3 = 92 -+INTR_ARM_NEON_VST3LANE = 93 -+INTR_ARM_NEON_VST4 = 94 -+INTR_ARM_NEON_VST4LANE = 95 -+INTR_ARM_NEON_VSUBHN = 96 -+INTR_ARM_NEON_VTBL1 = 97 -+INTR_ARM_NEON_VTBL2 = 98 -+INTR_ARM_NEON_VTBL3 = 99 -+INTR_ARM_NEON_VTBL4 = 100 -+INTR_ARM_NEON_VTBX1 = 101 -+INTR_ARM_NEON_VTBX2 = 102 -+INTR_ARM_NEON_VTBX3 = 103 -+INTR_ARM_NEON_VTBX4 = 104 -+INTR_ARM_QADD = 105 -+INTR_ARM_QSUB = 106 -+INTR_ARM_SET_FPSCR = 107 -+INTR_ARM_SSAT = 108 -+INTR_ARM_THREAD_POINTER = 109 -+INTR_ARM_USAT = 110 -+INTR_ARM_VCVTR = 111 -+INTR_ARM_VCVTRU = 112 -+INTR_ATOMIC_CMP_SWAP = 113 -+INTR_ATOMIC_LOAD_ADD = 114 -+INTR_ATOMIC_LOAD_AND = 115 -+INTR_ATOMIC_LOAD_MAX = 116 -+INTR_ATOMIC_LOAD_MIN = 117 -+INTR_ATOMIC_LOAD_NAND = 118 -+INTR_ATOMIC_LOAD_OR = 119 -+INTR_ATOMIC_LOAD_SUB = 120 -+INTR_ATOMIC_LOAD_UMAX = 121 -+INTR_ATOMIC_LOAD_UMIN = 122 -+INTR_ATOMIC_LOAD_XOR = 123 -+INTR_ATOMIC_SWAP = 124 -+INTR_BSWAP = 125 -+INTR_CONVERT_FROM_FP16 = 126 -+INTR_CONVERT_TO_FP16 = 127 -+INTR_CONVERTFF = 128 -+INTR_CONVERTFSI = 129 -+INTR_CONVERTFUI = 130 -+INTR_CONVERTSIF = 131 -+INTR_CONVERTSS = 132 -+INTR_CONVERTSU = 133 -+INTR_CONVERTUIF = 134 -+INTR_CONVERTUS = 135 -+INTR_CONVERTUU = 136 -+INTR_COS = 137 -+INTR_CTLZ = 138 -+INTR_CTPOP = 139 -+INTR_CTTZ = 140 -+INTR_DBG_DECLARE = 141 -+INTR_DBG_VALUE = 142 -+INTR_EH_DWARF_CFA = 143 -+INTR_EH_EXCEPTION = 144 -+INTR_EH_RETURN_I32 = 145 -+INTR_EH_RETURN_I64 = 146 -+INTR_EH_SELECTOR = 147 -+INTR_EH_SJLJ_CALLSITE = 148 -+INTR_EH_SJLJ_DISPATCH_SETUP = 149 -+INTR_EH_SJLJ_LONGJMP = 150 -+INTR_EH_SJLJ_LSDA = 151 -+INTR_EH_SJLJ_SETJMP = 152 -+INTR_EH_TYPEID_FOR = 153 -+INTR_EH_UNWIND_INIT = 154 -+INTR_EXP = 155 -+INTR_EXP2 = 156 -+INTR_FLT_ROUNDS = 157 -+INTR_FRAMEADDRESS = 158 -+INTR_GCREAD = 159 -+INTR_GCROOT = 160 -+INTR_GCWRITE = 161 -+INTR_INIT_TRAMPOLINE = 162 -+INTR_INVARIANT_END = 163 -+INTR_INVARIANT_START = 164 -+INTR_LIFETIME_END = 165 -+INTR_LIFETIME_START = 166 -+INTR_LOG = 167 -+INTR_LOG10 = 168 -+INTR_LOG2 = 169 -+INTR_LONGJMP = 170 -+INTR_MEMCPY = 171 -+INTR_MEMMOVE = 172 -+INTR_MEMORY_BARRIER = 173 -+INTR_MEMSET = 174 -+INTR_OBJECTSIZE = 175 -+INTR_PCMARKER = 176 -+INTR_POW = 177 -+INTR_POWI = 178 -+INTR_PPC_ALTIVEC_DSS = 179 -+INTR_PPC_ALTIVEC_DSSALL = 180 -+INTR_PPC_ALTIVEC_DST = 181 -+INTR_PPC_ALTIVEC_DSTST = 182 -+INTR_PPC_ALTIVEC_DSTSTT = 183 -+INTR_PPC_ALTIVEC_DSTT = 184 -+INTR_PPC_ALTIVEC_LVEBX = 185 -+INTR_PPC_ALTIVEC_LVEHX = 186 -+INTR_PPC_ALTIVEC_LVEWX = 187 -+INTR_PPC_ALTIVEC_LVSL = 188 -+INTR_PPC_ALTIVEC_LVSR = 189 -+INTR_PPC_ALTIVEC_LVX = 190 -+INTR_PPC_ALTIVEC_LVXL = 191 -+INTR_PPC_ALTIVEC_MFVSCR = 192 -+INTR_PPC_ALTIVEC_MTVSCR = 193 -+INTR_PPC_ALTIVEC_STVEBX = 194 -+INTR_PPC_ALTIVEC_STVEHX = 195 -+INTR_PPC_ALTIVEC_STVEWX = 196 -+INTR_PPC_ALTIVEC_STVX = 197 -+INTR_PPC_ALTIVEC_STVXL = 198 -+INTR_PPC_ALTIVEC_VADDCUW = 199 -+INTR_PPC_ALTIVEC_VADDSBS = 200 -+INTR_PPC_ALTIVEC_VADDSHS = 201 -+INTR_PPC_ALTIVEC_VADDSWS = 202 -+INTR_PPC_ALTIVEC_VADDUBS = 203 -+INTR_PPC_ALTIVEC_VADDUHS = 204 -+INTR_PPC_ALTIVEC_VADDUWS = 205 -+INTR_PPC_ALTIVEC_VAVGSB = 206 -+INTR_PPC_ALTIVEC_VAVGSH = 207 -+INTR_PPC_ALTIVEC_VAVGSW = 208 -+INTR_PPC_ALTIVEC_VAVGUB = 209 -+INTR_PPC_ALTIVEC_VAVGUH = 210 -+INTR_PPC_ALTIVEC_VAVGUW = 211 -+INTR_PPC_ALTIVEC_VCFSX = 212 -+INTR_PPC_ALTIVEC_VCFUX = 213 -+INTR_PPC_ALTIVEC_VCMPBFP = 214 -+INTR_PPC_ALTIVEC_VCMPBFP_P = 215 -+INTR_PPC_ALTIVEC_VCMPEQFP = 216 -+INTR_PPC_ALTIVEC_VCMPEQFP_P = 217 -+INTR_PPC_ALTIVEC_VCMPEQUB = 218 -+INTR_PPC_ALTIVEC_VCMPEQUB_P = 219 -+INTR_PPC_ALTIVEC_VCMPEQUH = 220 -+INTR_PPC_ALTIVEC_VCMPEQUH_P = 221 -+INTR_PPC_ALTIVEC_VCMPEQUW = 222 -+INTR_PPC_ALTIVEC_VCMPEQUW_P = 223 -+INTR_PPC_ALTIVEC_VCMPGEFP = 224 -+INTR_PPC_ALTIVEC_VCMPGEFP_P = 225 -+INTR_PPC_ALTIVEC_VCMPGTFP = 226 -+INTR_PPC_ALTIVEC_VCMPGTFP_P = 227 -+INTR_PPC_ALTIVEC_VCMPGTSB = 228 -+INTR_PPC_ALTIVEC_VCMPGTSB_P = 229 -+INTR_PPC_ALTIVEC_VCMPGTSH = 230 -+INTR_PPC_ALTIVEC_VCMPGTSH_P = 231 -+INTR_PPC_ALTIVEC_VCMPGTSW = 232 -+INTR_PPC_ALTIVEC_VCMPGTSW_P = 233 -+INTR_PPC_ALTIVEC_VCMPGTUB = 234 -+INTR_PPC_ALTIVEC_VCMPGTUB_P = 235 -+INTR_PPC_ALTIVEC_VCMPGTUH = 236 -+INTR_PPC_ALTIVEC_VCMPGTUH_P = 237 -+INTR_PPC_ALTIVEC_VCMPGTUW = 238 -+INTR_PPC_ALTIVEC_VCMPGTUW_P = 239 -+INTR_PPC_ALTIVEC_VCTSXS = 240 -+INTR_PPC_ALTIVEC_VCTUXS = 241 -+INTR_PPC_ALTIVEC_VEXPTEFP = 242 -+INTR_PPC_ALTIVEC_VLOGEFP = 243 -+INTR_PPC_ALTIVEC_VMADDFP = 244 -+INTR_PPC_ALTIVEC_VMAXFP = 245 -+INTR_PPC_ALTIVEC_VMAXSB = 246 -+INTR_PPC_ALTIVEC_VMAXSH = 247 -+INTR_PPC_ALTIVEC_VMAXSW = 248 -+INTR_PPC_ALTIVEC_VMAXUB = 249 -+INTR_PPC_ALTIVEC_VMAXUH = 250 -+INTR_PPC_ALTIVEC_VMAXUW = 251 -+INTR_PPC_ALTIVEC_VMHADDSHS = 252 -+INTR_PPC_ALTIVEC_VMHRADDSHS = 253 -+INTR_PPC_ALTIVEC_VMINFP = 254 -+INTR_PPC_ALTIVEC_VMINSB = 255 -+INTR_PPC_ALTIVEC_VMINSH = 256 -+INTR_PPC_ALTIVEC_VMINSW = 257 -+INTR_PPC_ALTIVEC_VMINUB = 258 -+INTR_PPC_ALTIVEC_VMINUH = 259 -+INTR_PPC_ALTIVEC_VMINUW = 260 -+INTR_PPC_ALTIVEC_VMLADDUHM = 261 -+INTR_PPC_ALTIVEC_VMSUMMBM = 262 -+INTR_PPC_ALTIVEC_VMSUMSHM = 263 -+INTR_PPC_ALTIVEC_VMSUMSHS = 264 -+INTR_PPC_ALTIVEC_VMSUMUBM = 265 -+INTR_PPC_ALTIVEC_VMSUMUHM = 266 -+INTR_PPC_ALTIVEC_VMSUMUHS = 267 -+INTR_PPC_ALTIVEC_VMULESB = 268 -+INTR_PPC_ALTIVEC_VMULESH = 269 -+INTR_PPC_ALTIVEC_VMULEUB = 270 -+INTR_PPC_ALTIVEC_VMULEUH = 271 -+INTR_PPC_ALTIVEC_VMULOSB = 272 -+INTR_PPC_ALTIVEC_VMULOSH = 273 -+INTR_PPC_ALTIVEC_VMULOUB = 274 -+INTR_PPC_ALTIVEC_VMULOUH = 275 -+INTR_PPC_ALTIVEC_VNMSUBFP = 276 -+INTR_PPC_ALTIVEC_VPERM = 277 -+INTR_PPC_ALTIVEC_VPKPX = 278 -+INTR_PPC_ALTIVEC_VPKSHSS = 279 -+INTR_PPC_ALTIVEC_VPKSHUS = 280 -+INTR_PPC_ALTIVEC_VPKSWSS = 281 -+INTR_PPC_ALTIVEC_VPKSWUS = 282 -+INTR_PPC_ALTIVEC_VPKUHUS = 283 -+INTR_PPC_ALTIVEC_VPKUWUS = 284 -+INTR_PPC_ALTIVEC_VREFP = 285 -+INTR_PPC_ALTIVEC_VRFIM = 286 -+INTR_PPC_ALTIVEC_VRFIN = 287 -+INTR_PPC_ALTIVEC_VRFIP = 288 -+INTR_PPC_ALTIVEC_VRFIZ = 289 -+INTR_PPC_ALTIVEC_VRLB = 290 -+INTR_PPC_ALTIVEC_VRLH = 291 -+INTR_PPC_ALTIVEC_VRLW = 292 -+INTR_PPC_ALTIVEC_VRSQRTEFP = 293 -+INTR_PPC_ALTIVEC_VSEL = 294 -+INTR_PPC_ALTIVEC_VSL = 295 -+INTR_PPC_ALTIVEC_VSLB = 296 -+INTR_PPC_ALTIVEC_VSLH = 297 -+INTR_PPC_ALTIVEC_VSLO = 298 -+INTR_PPC_ALTIVEC_VSLW = 299 -+INTR_PPC_ALTIVEC_VSR = 300 -+INTR_PPC_ALTIVEC_VSRAB = 301 -+INTR_PPC_ALTIVEC_VSRAH = 302 -+INTR_PPC_ALTIVEC_VSRAW = 303 -+INTR_PPC_ALTIVEC_VSRB = 304 -+INTR_PPC_ALTIVEC_VSRH = 305 -+INTR_PPC_ALTIVEC_VSRO = 306 -+INTR_PPC_ALTIVEC_VSRW = 307 -+INTR_PPC_ALTIVEC_VSUBCUW = 308 -+INTR_PPC_ALTIVEC_VSUBSBS = 309 -+INTR_PPC_ALTIVEC_VSUBSHS = 310 -+INTR_PPC_ALTIVEC_VSUBSWS = 311 -+INTR_PPC_ALTIVEC_VSUBUBS = 312 -+INTR_PPC_ALTIVEC_VSUBUHS = 313 -+INTR_PPC_ALTIVEC_VSUBUWS = 314 -+INTR_PPC_ALTIVEC_VSUM2SWS = 315 -+INTR_PPC_ALTIVEC_VSUM4SBS = 316 -+INTR_PPC_ALTIVEC_VSUM4SHS = 317 -+INTR_PPC_ALTIVEC_VSUM4UBS = 318 -+INTR_PPC_ALTIVEC_VSUMSWS = 319 -+INTR_PPC_ALTIVEC_VUPKHPX = 320 -+INTR_PPC_ALTIVEC_VUPKHSB = 321 -+INTR_PPC_ALTIVEC_VUPKHSH = 322 -+INTR_PPC_ALTIVEC_VUPKLPX = 323 -+INTR_PPC_ALTIVEC_VUPKLSB = 324 -+INTR_PPC_ALTIVEC_VUPKLSH = 325 -+INTR_PPC_DCBA = 326 -+INTR_PPC_DCBF = 327 -+INTR_PPC_DCBI = 328 -+INTR_PPC_DCBST = 329 -+INTR_PPC_DCBT = 330 -+INTR_PPC_DCBTST = 331 -+INTR_PPC_DCBZ = 332 -+INTR_PPC_DCBZL = 333 -+INTR_PPC_SYNC = 334 -+INTR_PREFETCH = 335 -+INTR_PTR_ANNOTATION = 336 -+INTR_PTX_BAR_SYNC = 337 -+INTR_PTX_READ_TID_R64 = 338 -+INTR_PTX_READ_TID_V4I16 = 339 -+INTR_PTX_READ_TID_W = 340 -+INTR_PTX_READ_TID_X = 341 -+INTR_PTX_READ_TID_Y = 342 -+INTR_PTX_READ_TID_Z = 343 -+INTR_READCYCLECOUNTER = 344 -+INTR_RETURNADDRESS = 345 -+INTR_SADD_WITH_OVERFLOW = 346 -+INTR_SETJMP = 347 -+INTR_SIGLONGJMP = 348 -+INTR_SIGSETJMP = 349 -+INTR_SIN = 350 -+INTR_SMUL_WITH_OVERFLOW = 351 -+INTR_SPU_SI_A = 352 -+INTR_SPU_SI_ADDX = 353 -+INTR_SPU_SI_AH = 354 -+INTR_SPU_SI_AHI = 355 -+INTR_SPU_SI_AI = 356 -+INTR_SPU_SI_AND = 357 -+INTR_SPU_SI_ANDBI = 358 -+INTR_SPU_SI_ANDC = 359 -+INTR_SPU_SI_ANDHI = 360 -+INTR_SPU_SI_ANDI = 361 -+INTR_SPU_SI_BG = 362 -+INTR_SPU_SI_BGX = 363 -+INTR_SPU_SI_CEQ = 364 -+INTR_SPU_SI_CEQB = 365 -+INTR_SPU_SI_CEQBI = 366 -+INTR_SPU_SI_CEQH = 367 -+INTR_SPU_SI_CEQHI = 368 -+INTR_SPU_SI_CEQI = 369 -+INTR_SPU_SI_CG = 370 -+INTR_SPU_SI_CGT = 371 -+INTR_SPU_SI_CGTB = 372 -+INTR_SPU_SI_CGTBI = 373 -+INTR_SPU_SI_CGTH = 374 -+INTR_SPU_SI_CGTHI = 375 -+INTR_SPU_SI_CGTI = 376 -+INTR_SPU_SI_CGX = 377 -+INTR_SPU_SI_CLGT = 378 -+INTR_SPU_SI_CLGTB = 379 -+INTR_SPU_SI_CLGTBI = 380 -+INTR_SPU_SI_CLGTH = 381 -+INTR_SPU_SI_CLGTHI = 382 -+INTR_SPU_SI_CLGTI = 383 -+INTR_SPU_SI_DFA = 384 -+INTR_SPU_SI_DFM = 385 -+INTR_SPU_SI_DFMA = 386 -+INTR_SPU_SI_DFMS = 387 -+INTR_SPU_SI_DFNMA = 388 -+INTR_SPU_SI_DFNMS = 389 -+INTR_SPU_SI_DFS = 390 -+INTR_SPU_SI_FA = 391 -+INTR_SPU_SI_FCEQ = 392 -+INTR_SPU_SI_FCGT = 393 -+INTR_SPU_SI_FCMEQ = 394 -+INTR_SPU_SI_FCMGT = 395 -+INTR_SPU_SI_FM = 396 -+INTR_SPU_SI_FMA = 397 -+INTR_SPU_SI_FMS = 398 -+INTR_SPU_SI_FNMS = 399 -+INTR_SPU_SI_FS = 400 -+INTR_SPU_SI_FSMBI = 401 -+INTR_SPU_SI_MPY = 402 -+INTR_SPU_SI_MPYA = 403 -+INTR_SPU_SI_MPYH = 404 -+INTR_SPU_SI_MPYHH = 405 -+INTR_SPU_SI_MPYHHA = 406 -+INTR_SPU_SI_MPYHHAU = 407 -+INTR_SPU_SI_MPYHHU = 408 -+INTR_SPU_SI_MPYI = 409 -+INTR_SPU_SI_MPYS = 410 -+INTR_SPU_SI_MPYU = 411 -+INTR_SPU_SI_MPYUI = 412 -+INTR_SPU_SI_NAND = 413 -+INTR_SPU_SI_NOR = 414 -+INTR_SPU_SI_OR = 415 -+INTR_SPU_SI_ORBI = 416 -+INTR_SPU_SI_ORC = 417 -+INTR_SPU_SI_ORHI = 418 -+INTR_SPU_SI_ORI = 419 -+INTR_SPU_SI_SF = 420 -+INTR_SPU_SI_SFH = 421 -+INTR_SPU_SI_SFHI = 422 -+INTR_SPU_SI_SFI = 423 -+INTR_SPU_SI_SFX = 424 -+INTR_SPU_SI_SHLI = 425 -+INTR_SPU_SI_SHLQBI = 426 -+INTR_SPU_SI_SHLQBII = 427 -+INTR_SPU_SI_SHLQBY = 428 -+INTR_SPU_SI_SHLQBYI = 429 -+INTR_SPU_SI_XOR = 430 -+INTR_SPU_SI_XORBI = 431 -+INTR_SPU_SI_XORHI = 432 -+INTR_SPU_SI_XORI = 433 -+INTR_SQRT = 434 -+INTR_SSUB_WITH_OVERFLOW = 435 -+INTR_STACKPROTECTOR = 436 -+INTR_STACKRESTORE = 437 -+INTR_STACKSAVE = 438 -+INTR_TRAP = 439 -+INTR_UADD_WITH_OVERFLOW = 440 -+INTR_UMUL_WITH_OVERFLOW = 441 -+INTR_USUB_WITH_OVERFLOW = 442 -+INTR_VACOPY = 443 -+INTR_VAEND = 444 -+INTR_VAR_ANNOTATION = 445 -+INTR_VASTART = 446 -+INTR_X86_AESNI_AESDEC = 447 -+INTR_X86_AESNI_AESDECLAST = 448 -+INTR_X86_AESNI_AESENC = 449 -+INTR_X86_AESNI_AESENCLAST = 450 -+INTR_X86_AESNI_AESIMC = 451 -+INTR_X86_AESNI_AESKEYGENASSIST = 452 -+INTR_X86_AVX_ADDSUB_PD_256 = 453 -+INTR_X86_AVX_ADDSUB_PS_256 = 454 -+INTR_X86_AVX_BLEND_PD_256 = 455 -+INTR_X86_AVX_BLEND_PS_256 = 456 -+INTR_X86_AVX_BLENDV_PD_256 = 457 -+INTR_X86_AVX_BLENDV_PS_256 = 458 -+INTR_X86_AVX_CMP_PD_256 = 459 -+INTR_X86_AVX_CMP_PS_256 = 460 -+INTR_X86_AVX_CVT_PD2_PS_256 = 461 -+INTR_X86_AVX_CVT_PD2DQ_256 = 462 -+INTR_X86_AVX_CVT_PS2_PD_256 = 463 -+INTR_X86_AVX_CVT_PS2DQ_256 = 464 -+INTR_X86_AVX_CVTDQ2_PD_256 = 465 -+INTR_X86_AVX_CVTDQ2_PS_256 = 466 -+INTR_X86_AVX_CVTT_PD2DQ_256 = 467 -+INTR_X86_AVX_CVTT_PS2DQ_256 = 468 -+INTR_X86_AVX_DP_PS_256 = 469 -+INTR_X86_AVX_HADD_PD_256 = 470 -+INTR_X86_AVX_HADD_PS_256 = 471 -+INTR_X86_AVX_HSUB_PD_256 = 472 -+INTR_X86_AVX_HSUB_PS_256 = 473 -+INTR_X86_AVX_LDU_DQ_256 = 474 -+INTR_X86_AVX_LOADU_DQ_256 = 475 -+INTR_X86_AVX_LOADU_PD_256 = 476 -+INTR_X86_AVX_LOADU_PS_256 = 477 -+INTR_X86_AVX_MASKLOAD_PD = 478 -+INTR_X86_AVX_MASKLOAD_PD_256 = 479 -+INTR_X86_AVX_MASKLOAD_PS = 480 -+INTR_X86_AVX_MASKLOAD_PS_256 = 481 -+INTR_X86_AVX_MASKSTORE_PD = 482 -+INTR_X86_AVX_MASKSTORE_PD_256 = 483 -+INTR_X86_AVX_MASKSTORE_PS = 484 -+INTR_X86_AVX_MASKSTORE_PS_256 = 485 -+INTR_X86_AVX_MAX_PD_256 = 486 -+INTR_X86_AVX_MAX_PS_256 = 487 -+INTR_X86_AVX_MIN_PD_256 = 488 -+INTR_X86_AVX_MIN_PS_256 = 489 -+INTR_X86_AVX_MOVMSK_PD_256 = 490 -+INTR_X86_AVX_MOVMSK_PS_256 = 491 -+INTR_X86_AVX_MOVNT_DQ_256 = 492 -+INTR_X86_AVX_MOVNT_PD_256 = 493 -+INTR_X86_AVX_MOVNT_PS_256 = 494 -+INTR_X86_AVX_PTESTC_256 = 495 -+INTR_X86_AVX_PTESTNZC_256 = 496 -+INTR_X86_AVX_PTESTZ_256 = 497 -+INTR_X86_AVX_RCP_PS_256 = 498 -+INTR_X86_AVX_ROUND_PD_256 = 499 -+INTR_X86_AVX_ROUND_PS_256 = 500 -+INTR_X86_AVX_RSQRT_PS_256 = 501 -+INTR_X86_AVX_SQRT_PD_256 = 502 -+INTR_X86_AVX_SQRT_PS_256 = 503 -+INTR_X86_AVX_STOREU_DQ_256 = 504 -+INTR_X86_AVX_STOREU_PD_256 = 505 -+INTR_X86_AVX_STOREU_PS_256 = 506 -+INTR_X86_AVX_VBROADCAST_SD_256 = 507 -+INTR_X86_AVX_VBROADCASTF128_PD_256 = 508 -+INTR_X86_AVX_VBROADCASTF128_PS_256 = 509 -+INTR_X86_AVX_VBROADCASTSS = 510 -+INTR_X86_AVX_VBROADCASTSS_256 = 511 -+INTR_X86_AVX_VEXTRACTF128_PD_256 = 512 -+INTR_X86_AVX_VEXTRACTF128_PS_256 = 513 -+INTR_X86_AVX_VEXTRACTF128_SI_256 = 514 -+INTR_X86_AVX_VINSERTF128_PD_256 = 515 -+INTR_X86_AVX_VINSERTF128_PS_256 = 516 -+INTR_X86_AVX_VINSERTF128_SI_256 = 517 -+INTR_X86_AVX_VPERM2F128_PD_256 = 518 -+INTR_X86_AVX_VPERM2F128_PS_256 = 519 -+INTR_X86_AVX_VPERM2F128_SI_256 = 520 -+INTR_X86_AVX_VPERMIL_PD = 521 -+INTR_X86_AVX_VPERMIL_PD_256 = 522 -+INTR_X86_AVX_VPERMIL_PS = 523 -+INTR_X86_AVX_VPERMIL_PS_256 = 524 -+INTR_X86_AVX_VPERMILVAR_PD = 525 -+INTR_X86_AVX_VPERMILVAR_PD_256 = 526 -+INTR_X86_AVX_VPERMILVAR_PS = 527 -+INTR_X86_AVX_VPERMILVAR_PS_256 = 528 -+INTR_X86_AVX_VTESTC_PD = 529 -+INTR_X86_AVX_VTESTC_PD_256 = 530 -+INTR_X86_AVX_VTESTC_PS = 531 -+INTR_X86_AVX_VTESTC_PS_256 = 532 -+INTR_X86_AVX_VTESTNZC_PD = 533 -+INTR_X86_AVX_VTESTNZC_PD_256 = 534 -+INTR_X86_AVX_VTESTNZC_PS = 535 -+INTR_X86_AVX_VTESTNZC_PS_256 = 536 -+INTR_X86_AVX_VTESTZ_PD = 537 -+INTR_X86_AVX_VTESTZ_PD_256 = 538 -+INTR_X86_AVX_VTESTZ_PS = 539 -+INTR_X86_AVX_VTESTZ_PS_256 = 540 -+INTR_X86_AVX_VZEROALL = 541 -+INTR_X86_AVX_VZEROUPPER = 542 -+INTR_X86_INT = 543 -+INTR_X86_MMX_EMMS = 544 -+INTR_X86_MMX_FEMMS = 545 -+INTR_X86_MMX_MASKMOVQ = 546 -+INTR_X86_MMX_MOVNT_DQ = 547 -+INTR_X86_MMX_PACKSSDW = 548 -+INTR_X86_MMX_PACKSSWB = 549 -+INTR_X86_MMX_PACKUSWB = 550 -+INTR_X86_MMX_PADD_B = 551 -+INTR_X86_MMX_PADD_D = 552 -+INTR_X86_MMX_PADD_Q = 553 -+INTR_X86_MMX_PADD_W = 554 -+INTR_X86_MMX_PADDS_B = 555 -+INTR_X86_MMX_PADDS_W = 556 -+INTR_X86_MMX_PADDUS_B = 557 -+INTR_X86_MMX_PADDUS_W = 558 -+INTR_X86_MMX_PALIGNR_B = 559 -+INTR_X86_MMX_PAND = 560 -+INTR_X86_MMX_PANDN = 561 -+INTR_X86_MMX_PAVG_B = 562 -+INTR_X86_MMX_PAVG_W = 563 -+INTR_X86_MMX_PCMPEQ_B = 564 -+INTR_X86_MMX_PCMPEQ_D = 565 -+INTR_X86_MMX_PCMPEQ_W = 566 -+INTR_X86_MMX_PCMPGT_B = 567 -+INTR_X86_MMX_PCMPGT_D = 568 -+INTR_X86_MMX_PCMPGT_W = 569 -+INTR_X86_MMX_PEXTR_W = 570 -+INTR_X86_MMX_PINSR_W = 571 -+INTR_X86_MMX_PMADD_WD = 572 -+INTR_X86_MMX_PMAXS_W = 573 -+INTR_X86_MMX_PMAXU_B = 574 -+INTR_X86_MMX_PMINS_W = 575 -+INTR_X86_MMX_PMINU_B = 576 -+INTR_X86_MMX_PMOVMSKB = 577 -+INTR_X86_MMX_PMULH_W = 578 -+INTR_X86_MMX_PMULHU_W = 579 -+INTR_X86_MMX_PMULL_W = 580 -+INTR_X86_MMX_PMULU_DQ = 581 -+INTR_X86_MMX_POR = 582 -+INTR_X86_MMX_PSAD_BW = 583 -+INTR_X86_MMX_PSLL_D = 584 -+INTR_X86_MMX_PSLL_Q = 585 -+INTR_X86_MMX_PSLL_W = 586 -+INTR_X86_MMX_PSLLI_D = 587 -+INTR_X86_MMX_PSLLI_Q = 588 -+INTR_X86_MMX_PSLLI_W = 589 -+INTR_X86_MMX_PSRA_D = 590 -+INTR_X86_MMX_PSRA_W = 591 -+INTR_X86_MMX_PSRAI_D = 592 -+INTR_X86_MMX_PSRAI_W = 593 -+INTR_X86_MMX_PSRL_D = 594 -+INTR_X86_MMX_PSRL_Q = 595 -+INTR_X86_MMX_PSRL_W = 596 -+INTR_X86_MMX_PSRLI_D = 597 -+INTR_X86_MMX_PSRLI_Q = 598 -+INTR_X86_MMX_PSRLI_W = 599 -+INTR_X86_MMX_PSUB_B = 600 -+INTR_X86_MMX_PSUB_D = 601 -+INTR_X86_MMX_PSUB_Q = 602 -+INTR_X86_MMX_PSUB_W = 603 -+INTR_X86_MMX_PSUBS_B = 604 -+INTR_X86_MMX_PSUBS_W = 605 -+INTR_X86_MMX_PSUBUS_B = 606 -+INTR_X86_MMX_PSUBUS_W = 607 -+INTR_X86_MMX_PUNPCKHBW = 608 -+INTR_X86_MMX_PUNPCKHDQ = 609 -+INTR_X86_MMX_PUNPCKHWD = 610 -+INTR_X86_MMX_PUNPCKLBW = 611 -+INTR_X86_MMX_PUNPCKLDQ = 612 -+INTR_X86_MMX_PUNPCKLWD = 613 -+INTR_X86_MMX_PXOR = 614 -+INTR_X86_SSE2_ADD_SD = 615 -+INTR_X86_SSE2_CLFLUSH = 616 -+INTR_X86_SSE2_CMP_PD = 617 -+INTR_X86_SSE2_CMP_SD = 618 -+INTR_X86_SSE2_COMIEQ_SD = 619 -+INTR_X86_SSE2_COMIGE_SD = 620 -+INTR_X86_SSE2_COMIGT_SD = 621 -+INTR_X86_SSE2_COMILE_SD = 622 -+INTR_X86_SSE2_COMILT_SD = 623 -+INTR_X86_SSE2_COMINEQ_SD = 624 -+INTR_X86_SSE2_CVTDQ2PD = 625 -+INTR_X86_SSE2_CVTDQ2PS = 626 -+INTR_X86_SSE2_CVTPD2DQ = 627 -+INTR_X86_SSE2_CVTPD2PS = 628 -+INTR_X86_SSE2_CVTPS2DQ = 629 -+INTR_X86_SSE2_CVTPS2PD = 630 -+INTR_X86_SSE2_CVTSD2SI = 631 -+INTR_X86_SSE2_CVTSD2SI64 = 632 -+INTR_X86_SSE2_CVTSD2SS = 633 -+INTR_X86_SSE2_CVTSI2SD = 634 -+INTR_X86_SSE2_CVTSI642SD = 635 -+INTR_X86_SSE2_CVTSS2SD = 636 -+INTR_X86_SSE2_CVTTPD2DQ = 637 -+INTR_X86_SSE2_CVTTPS2DQ = 638 -+INTR_X86_SSE2_CVTTSD2SI = 639 -+INTR_X86_SSE2_CVTTSD2SI64 = 640 -+INTR_X86_SSE2_DIV_SD = 641 -+INTR_X86_SSE2_LFENCE = 642 -+INTR_X86_SSE2_LOADU_DQ = 643 -+INTR_X86_SSE2_LOADU_PD = 644 -+INTR_X86_SSE2_MASKMOV_DQU = 645 -+INTR_X86_SSE2_MAX_PD = 646 -+INTR_X86_SSE2_MAX_SD = 647 -+INTR_X86_SSE2_MFENCE = 648 -+INTR_X86_SSE2_MIN_PD = 649 -+INTR_X86_SSE2_MIN_SD = 650 -+INTR_X86_SSE2_MOVMSK_PD = 651 -+INTR_X86_SSE2_MOVNT_DQ = 652 -+INTR_X86_SSE2_MOVNT_I = 653 -+INTR_X86_SSE2_MOVNT_PD = 654 -+INTR_X86_SSE2_MUL_SD = 655 -+INTR_X86_SSE2_PACKSSDW_128 = 656 -+INTR_X86_SSE2_PACKSSWB_128 = 657 -+INTR_X86_SSE2_PACKUSWB_128 = 658 -+INTR_X86_SSE2_PADDS_B = 659 -+INTR_X86_SSE2_PADDS_W = 660 -+INTR_X86_SSE2_PADDUS_B = 661 -+INTR_X86_SSE2_PADDUS_W = 662 -+INTR_X86_SSE2_PAVG_B = 663 -+INTR_X86_SSE2_PAVG_W = 664 -+INTR_X86_SSE2_PCMPEQ_B = 665 -+INTR_X86_SSE2_PCMPEQ_D = 666 -+INTR_X86_SSE2_PCMPEQ_W = 667 -+INTR_X86_SSE2_PCMPGT_B = 668 -+INTR_X86_SSE2_PCMPGT_D = 669 -+INTR_X86_SSE2_PCMPGT_W = 670 -+INTR_X86_SSE2_PMADD_WD = 671 -+INTR_X86_SSE2_PMAXS_W = 672 -+INTR_X86_SSE2_PMAXU_B = 673 -+INTR_X86_SSE2_PMINS_W = 674 -+INTR_X86_SSE2_PMINU_B = 675 -+INTR_X86_SSE2_PMOVMSKB_128 = 676 -+INTR_X86_SSE2_PMULH_W = 677 -+INTR_X86_SSE2_PMULHU_W = 678 -+INTR_X86_SSE2_PMULU_DQ = 679 -+INTR_X86_SSE2_PSAD_BW = 680 -+INTR_X86_SSE2_PSLL_D = 681 -+INTR_X86_SSE2_PSLL_DQ = 682 -+INTR_X86_SSE2_PSLL_DQ_BS = 683 -+INTR_X86_SSE2_PSLL_Q = 684 -+INTR_X86_SSE2_PSLL_W = 685 -+INTR_X86_SSE2_PSLLI_D = 686 -+INTR_X86_SSE2_PSLLI_Q = 687 -+INTR_X86_SSE2_PSLLI_W = 688 -+INTR_X86_SSE2_PSRA_D = 689 -+INTR_X86_SSE2_PSRA_W = 690 -+INTR_X86_SSE2_PSRAI_D = 691 -+INTR_X86_SSE2_PSRAI_W = 692 -+INTR_X86_SSE2_PSRL_D = 693 -+INTR_X86_SSE2_PSRL_DQ = 694 -+INTR_X86_SSE2_PSRL_DQ_BS = 695 -+INTR_X86_SSE2_PSRL_Q = 696 -+INTR_X86_SSE2_PSRL_W = 697 -+INTR_X86_SSE2_PSRLI_D = 698 -+INTR_X86_SSE2_PSRLI_Q = 699 -+INTR_X86_SSE2_PSRLI_W = 700 -+INTR_X86_SSE2_PSUBS_B = 701 -+INTR_X86_SSE2_PSUBS_W = 702 -+INTR_X86_SSE2_PSUBUS_B = 703 -+INTR_X86_SSE2_PSUBUS_W = 704 -+INTR_X86_SSE2_SQRT_PD = 705 -+INTR_X86_SSE2_SQRT_SD = 706 -+INTR_X86_SSE2_STOREL_DQ = 707 -+INTR_X86_SSE2_STOREU_DQ = 708 -+INTR_X86_SSE2_STOREU_PD = 709 -+INTR_X86_SSE2_SUB_SD = 710 -+INTR_X86_SSE2_UCOMIEQ_SD = 711 -+INTR_X86_SSE2_UCOMIGE_SD = 712 -+INTR_X86_SSE2_UCOMIGT_SD = 713 -+INTR_X86_SSE2_UCOMILE_SD = 714 -+INTR_X86_SSE2_UCOMILT_SD = 715 -+INTR_X86_SSE2_UCOMINEQ_SD = 716 -+INTR_X86_SSE3_ADDSUB_PD = 717 -+INTR_X86_SSE3_ADDSUB_PS = 718 -+INTR_X86_SSE3_HADD_PD = 719 -+INTR_X86_SSE3_HADD_PS = 720 -+INTR_X86_SSE3_HSUB_PD = 721 -+INTR_X86_SSE3_HSUB_PS = 722 -+INTR_X86_SSE3_LDU_DQ = 723 -+INTR_X86_SSE3_MONITOR = 724 -+INTR_X86_SSE3_MWAIT = 725 -+INTR_X86_SSE41_BLENDPD = 726 -+INTR_X86_SSE41_BLENDPS = 727 -+INTR_X86_SSE41_BLENDVPD = 728 -+INTR_X86_SSE41_BLENDVPS = 729 -+INTR_X86_SSE41_DPPD = 730 -+INTR_X86_SSE41_DPPS = 731 -+INTR_X86_SSE41_EXTRACTPS = 732 -+INTR_X86_SSE41_INSERTPS = 733 -+INTR_X86_SSE41_MOVNTDQA = 734 -+INTR_X86_SSE41_MPSADBW = 735 -+INTR_X86_SSE41_PACKUSDW = 736 -+INTR_X86_SSE41_PBLENDVB = 737 -+INTR_X86_SSE41_PBLENDW = 738 -+INTR_X86_SSE41_PCMPEQQ = 739 -+INTR_X86_SSE41_PEXTRB = 740 -+INTR_X86_SSE41_PEXTRD = 741 -+INTR_X86_SSE41_PEXTRQ = 742 -+INTR_X86_SSE41_PHMINPOSUW = 743 -+INTR_X86_SSE41_PMAXSB = 744 -+INTR_X86_SSE41_PMAXSD = 745 -+INTR_X86_SSE41_PMAXUD = 746 -+INTR_X86_SSE41_PMAXUW = 747 -+INTR_X86_SSE41_PMINSB = 748 -+INTR_X86_SSE41_PMINSD = 749 -+INTR_X86_SSE41_PMINUD = 750 -+INTR_X86_SSE41_PMINUW = 751 -+INTR_X86_SSE41_PMOVSXBD = 752 -+INTR_X86_SSE41_PMOVSXBQ = 753 -+INTR_X86_SSE41_PMOVSXBW = 754 -+INTR_X86_SSE41_PMOVSXDQ = 755 -+INTR_X86_SSE41_PMOVSXWD = 756 -+INTR_X86_SSE41_PMOVSXWQ = 757 -+INTR_X86_SSE41_PMOVZXBD = 758 -+INTR_X86_SSE41_PMOVZXBQ = 759 -+INTR_X86_SSE41_PMOVZXBW = 760 -+INTR_X86_SSE41_PMOVZXDQ = 761 -+INTR_X86_SSE41_PMOVZXWD = 762 -+INTR_X86_SSE41_PMOVZXWQ = 763 -+INTR_X86_SSE41_PMULDQ = 764 -+INTR_X86_SSE41_PTESTC = 765 -+INTR_X86_SSE41_PTESTNZC = 766 -+INTR_X86_SSE41_PTESTZ = 767 -+INTR_X86_SSE41_ROUND_PD = 768 -+INTR_X86_SSE41_ROUND_PS = 769 -+INTR_X86_SSE41_ROUND_SD = 770 -+INTR_X86_SSE41_ROUND_SS = 771 -+INTR_X86_SSE42_CRC32_16 = 772 -+INTR_X86_SSE42_CRC32_32 = 773 -+INTR_X86_SSE42_CRC32_8 = 774 -+INTR_X86_SSE42_CRC64_64 = 775 -+INTR_X86_SSE42_CRC64_8 = 776 -+INTR_X86_SSE42_PCMPESTRI128 = 777 -+INTR_X86_SSE42_PCMPESTRIA128 = 778 -+INTR_X86_SSE42_PCMPESTRIC128 = 779 -+INTR_X86_SSE42_PCMPESTRIO128 = 780 -+INTR_X86_SSE42_PCMPESTRIS128 = 781 -+INTR_X86_SSE42_PCMPESTRIZ128 = 782 -+INTR_X86_SSE42_PCMPESTRM128 = 783 -+INTR_X86_SSE42_PCMPGTQ = 784 -+INTR_X86_SSE42_PCMPISTRI128 = 785 -+INTR_X86_SSE42_PCMPISTRIA128 = 786 -+INTR_X86_SSE42_PCMPISTRIC128 = 787 -+INTR_X86_SSE42_PCMPISTRIO128 = 788 -+INTR_X86_SSE42_PCMPISTRIS128 = 789 -+INTR_X86_SSE42_PCMPISTRIZ128 = 790 -+INTR_X86_SSE42_PCMPISTRM128 = 791 -+INTR_X86_SSE_ADD_SS = 792 -+INTR_X86_SSE_CMP_PS = 793 -+INTR_X86_SSE_CMP_SS = 794 -+INTR_X86_SSE_COMIEQ_SS = 795 -+INTR_X86_SSE_COMIGE_SS = 796 -+INTR_X86_SSE_COMIGT_SS = 797 -+INTR_X86_SSE_COMILE_SS = 798 -+INTR_X86_SSE_COMILT_SS = 799 -+INTR_X86_SSE_COMINEQ_SS = 800 -+INTR_X86_SSE_CVTPD2PI = 801 -+INTR_X86_SSE_CVTPI2PD = 802 -+INTR_X86_SSE_CVTPI2PS = 803 -+INTR_X86_SSE_CVTPS2PI = 804 -+INTR_X86_SSE_CVTSI2SS = 805 -+INTR_X86_SSE_CVTSI642SS = 806 -+INTR_X86_SSE_CVTSS2SI = 807 -+INTR_X86_SSE_CVTSS2SI64 = 808 -+INTR_X86_SSE_CVTTPD2PI = 809 -+INTR_X86_SSE_CVTTPS2PI = 810 -+INTR_X86_SSE_CVTTSS2SI = 811 -+INTR_X86_SSE_CVTTSS2SI64 = 812 -+INTR_X86_SSE_DIV_SS = 813 -+INTR_X86_SSE_LDMXCSR = 814 -+INTR_X86_SSE_LOADU_PS = 815 -+INTR_X86_SSE_MAX_PS = 816 -+INTR_X86_SSE_MAX_SS = 817 -+INTR_X86_SSE_MIN_PS = 818 -+INTR_X86_SSE_MIN_SS = 819 -+INTR_X86_SSE_MOVMSK_PS = 820 -+INTR_X86_SSE_MOVNT_PS = 821 -+INTR_X86_SSE_MUL_SS = 822 -+INTR_X86_SSE_PSHUF_W = 823 -+INTR_X86_SSE_RCP_PS = 824 -+INTR_X86_SSE_RCP_SS = 825 -+INTR_X86_SSE_RSQRT_PS = 826 -+INTR_X86_SSE_RSQRT_SS = 827 -+INTR_X86_SSE_SFENCE = 828 -+INTR_X86_SSE_SQRT_PS = 829 -+INTR_X86_SSE_SQRT_SS = 830 -+INTR_X86_SSE_STMXCSR = 831 -+INTR_X86_SSE_STOREU_PS = 832 -+INTR_X86_SSE_SUB_SS = 833 -+INTR_X86_SSE_UCOMIEQ_SS = 834 -+INTR_X86_SSE_UCOMIGE_SS = 835 -+INTR_X86_SSE_UCOMIGT_SS = 836 -+INTR_X86_SSE_UCOMILE_SS = 837 -+INTR_X86_SSE_UCOMILT_SS = 838 -+INTR_X86_SSE_UCOMINEQ_SS = 839 -+INTR_X86_SSSE3_PABS_B = 840 -+INTR_X86_SSSE3_PABS_B_128 = 841 -+INTR_X86_SSSE3_PABS_D = 842 -+INTR_X86_SSSE3_PABS_D_128 = 843 -+INTR_X86_SSSE3_PABS_W = 844 -+INTR_X86_SSSE3_PABS_W_128 = 845 -+INTR_X86_SSSE3_PHADD_D = 846 -+INTR_X86_SSSE3_PHADD_D_128 = 847 -+INTR_X86_SSSE3_PHADD_SW = 848 -+INTR_X86_SSSE3_PHADD_SW_128 = 849 -+INTR_X86_SSSE3_PHADD_W = 850 -+INTR_X86_SSSE3_PHADD_W_128 = 851 -+INTR_X86_SSSE3_PHSUB_D = 852 -+INTR_X86_SSSE3_PHSUB_D_128 = 853 -+INTR_X86_SSSE3_PHSUB_SW = 854 -+INTR_X86_SSSE3_PHSUB_SW_128 = 855 -+INTR_X86_SSSE3_PHSUB_W = 856 -+INTR_X86_SSSE3_PHSUB_W_128 = 857 -+INTR_X86_SSSE3_PMADD_UB_SW = 858 -+INTR_X86_SSSE3_PMADD_UB_SW_128 = 859 -+INTR_X86_SSSE3_PMUL_HR_SW = 860 -+INTR_X86_SSSE3_PMUL_HR_SW_128 = 861 -+INTR_X86_SSSE3_PSHUF_B = 862 -+INTR_X86_SSSE3_PSHUF_B_128 = 863 -+INTR_X86_SSSE3_PSIGN_B = 864 -+INTR_X86_SSSE3_PSIGN_B_128 = 865 -+INTR_X86_SSSE3_PSIGN_D = 866 -+INTR_X86_SSSE3_PSIGN_D_128 = 867 -+INTR_X86_SSSE3_PSIGN_W = 868 -+INTR_X86_SSSE3_PSIGN_W_128 = 869 -+INTR_XCORE_BITREV = 870 -+INTR_XCORE_CHKCT = 871 -+INTR_XCORE_CLRE = 872 -+INTR_XCORE_EEU = 873 -+INTR_XCORE_FREER = 874 -+INTR_XCORE_GETID = 875 -+INTR_XCORE_GETR = 876 -+INTR_XCORE_GETTS = 877 -+INTR_XCORE_IN = 878 -+INTR_XCORE_INCT = 879 -+INTR_XCORE_INSHR = 880 -+INTR_XCORE_INT = 881 -+INTR_XCORE_OUT = 882 -+INTR_XCORE_OUTCT = 883 -+INTR_XCORE_OUTSHR = 884 -+INTR_XCORE_OUTT = 885 -+INTR_XCORE_SETC = 886 -+INTR_XCORE_SETD = 887 -+INTR_XCORE_SETPT = 888 -+INTR_XCORE_SETTW = 889 -+INTR_XCORE_SETV = 890 -+INTR_XCORE_SYNCR = 891 -+INTR_XCORE_WAITEVENT = 892 -Index: _core.c -=================================================================== ---- _core.c (revision 105) -+++ _core.c (working copy) -@@ -807,7 +807,7 @@ - _wrap_pass( EdgeProfiler ) - _wrap_pass( FunctionAttrs ) - _wrap_pass( FunctionInlining ) --_wrap_pass( GEPSplitter ) -+//_wrap_pass( GEPSplitter ) - _wrap_pass( GlobalDCE ) - _wrap_pass( GlobalOptimizer ) - _wrap_pass( GlobalsModRef ) -@@ -822,11 +822,11 @@ - _wrap_pass( LazyValueInfo ) - _wrap_pass( LCSSA ) - _wrap_pass( LICM ) --_wrap_pass( LiveValues ) -+//_wrap_pass( LiveValues ) - _wrap_pass( LoopDeletion ) - _wrap_pass( LoopDependenceAnalysis ) - _wrap_pass( LoopExtractor ) --_wrap_pass( LoopIndexSplit ) -+//_wrap_pass( LoopIndexSplit ) - _wrap_pass( LoopRotate ) - _wrap_pass( LoopSimplify ) - _wrap_pass( LoopStrengthReduce ) -@@ -841,7 +841,7 @@ - _wrap_pass( NoProfileInfo ) - _wrap_pass( OptimalEdgeProfiler ) - _wrap_pass( PartialInlining ) --_wrap_pass( PartialSpecialization ) -+//_wrap_pass( PartialSpecialization ) - _wrap_pass( PostDomOnlyPrinter ) - _wrap_pass( PostDomOnlyViewer ) - _wrap_pass( PostDomPrinter ) -@@ -855,7 +855,7 @@ - _wrap_pass( ScalarEvolutionAliasAnalysis ) - _wrap_pass( ScalarReplAggregates ) - _wrap_pass( SCCP ) --_wrap_pass( SimplifyHalfPowrLibCalls ) -+//_wrap_pass( SimplifyHalfPowrLibCalls ) - _wrap_pass( SimplifyLibCalls ) - _wrap_pass( SingleLoopExtractor ) - _wrap_pass( StripDeadPrototypes ) -@@ -1162,7 +1162,7 @@ - Py_RETURN_NONE; - } - --_wrap_obj2obj(LLVMInlineFunction, LLVMValueRef, int) -+//_wrap_obj2obj(LLVMInlineFunction, LLVMValueRef, int) - - /* Expose the void* inside a PyCObject as a PyLong. This allows us to - * use it as a unique ID. */ -@@ -1569,7 +1569,7 @@ - _pass( EdgeProfiler ) - _pass( FunctionAttrs ) - _pass( FunctionInlining ) -- _pass( GEPSplitter ) -+ //_pass( GEPSplitter ) - _pass( GlobalDCE ) - _pass( GlobalOptimizer ) - _pass( GlobalsModRef ) -@@ -1584,11 +1584,11 @@ - _pass( LazyValueInfo ) - _pass( LCSSA ) - _pass( LICM ) -- _pass( LiveValues ) -+ //_pass( LiveValues ) - _pass( LoopDeletion ) - _pass( LoopDependenceAnalysis ) - _pass( LoopExtractor ) -- _pass( LoopIndexSplit ) -+ //_pass( LoopIndexSplit ) - _pass( LoopRotate ) - _pass( LoopSimplify ) - _pass( LoopStrengthReduce ) -@@ -1603,7 +1603,7 @@ - _pass( NoProfileInfo ) - _pass( OptimalEdgeProfiler ) - _pass( PartialInlining ) -- _pass( PartialSpecialization ) -+ //_pass( PartialSpecialization ) - _pass( PostDomOnlyPrinter ) - _pass( PostDomOnlyViewer ) - _pass( PostDomPrinter ) -@@ -1617,7 +1617,7 @@ - _pass( ScalarEvolutionAliasAnalysis ) - _pass( ScalarReplAggregates ) - _pass( SCCP ) -- _pass( SimplifyHalfPowrLibCalls ) -+ //_pass( SimplifyHalfPowrLibCalls ) - _pass( SimplifyLibCalls ) - _pass( SingleLoopExtractor ) - _pass( StripDeadPrototypes ) -@@ -1672,7 +1672,7 @@ - /* Misc */ - _method( LLVMGetIntrinsic ) - _method( LLVMLoadLibraryPermanently ) -- _method( LLVMInlineFunction ) -+ //_method( LLVMInlineFunction ) - _method( PyCObjectVoidPtrToPyLong ) - - { NULL } -Index: extra.h -=================================================================== ---- extra.h (revision 105) -+++ extra.h (working copy) -@@ -181,7 +181,7 @@ - /* Wraps llvm::InlineFunction(). Inlines a function. C is the call - * instruction, created by LLVMBuildCall. Even if it fails, the Function - * containing the call is still in a proper state (not changed). */ --int LLVMInlineFunction(LLVMValueRef call); -+//int LLVMInlineFunction(LLVMValueRef call); - - /* Wraps llvm::getAlignmentFromAttrs from Attributes.h. Compliments the - * already available LLVMSetParamAlignment(). */ -@@ -209,13 +209,13 @@ - declare_pass( DomPrinter ) - declare_pass( DomViewer ) - declare_pass( EdgeProfiler ) --declare_pass( GEPSplitter ) -+//declare_pass( GEPSplitter ) - declare_pass( GlobalsModRef ) - declare_pass( InstCount ) - declare_pass( InstructionNamer ) - declare_pass( LazyValueInfo ) - declare_pass( LCSSA ) --declare_pass( LiveValues ) -+//declare_pass( LiveValues ) - declare_pass( LoopDependenceAnalysis ) - declare_pass( LoopExtractor ) - declare_pass( LoopSimplify ) -@@ -227,7 +227,7 @@ - declare_pass( NoProfileInfo ) - declare_pass( OptimalEdgeProfiler ) - declare_pass( PartialInlining ) --declare_pass( PartialSpecialization ) -+//declare_pass( PartialSpecialization ) - declare_pass( PostDomOnlyPrinter ) - declare_pass( PostDomOnlyViewer ) - declare_pass( PostDomPrinter ) diff --git a/llvm/__init__.py b/llvm/__init__.py index 8f61f35..e69de29 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -1,154 +0,0 @@ -""" -Common classes related to LLVM. -""" - -from ._version import get_versions -__version__ = get_versions()['version'] -del get_versions - - -from weakref import WeakValueDictionary -from . import _core - -#===----------------------------------------------------------------------=== -# LLVM Version -#===----------------------------------------------------------------------=== - -version = _core.LLVMGetVersion() - -def require_version_at_least(major, minor): - '''Sentry to guard version requirement - ''' - if version < (major, minor): - raise Exception(major, minor) - -#===----------------------------------------------------------------------=== -# Exceptions -#===----------------------------------------------------------------------=== - -class LLVMException(Exception): - """Generic LLVM exception.""" - - def __init__(self, msg=""): - Exception.__init__(self, msg) - - -#===----------------------------------------------------------------------=== -# Ownables -#===----------------------------------------------------------------------=== - -class Ownable(object): - """Objects that can be owned. - - Modules and Module Providers can be owned, i.e., the responsibility of - destruction of ownable objects can be handed over to other objects. The - llvm.Ownable class represents objects that can be so owned. This class - is NOT intended for public use. - """ - - def __init__(self, ptr, del_fn): - self.ptr = ptr - self.owner = None - self.del_fn = del_fn - - def _own(self, owner): - if self.owner: - raise LLVMException("object already owned") - self.owner = owner - - def _disown(self): - if not self.owner: - raise LLVMException("not owned") - self.owner = None - - def __del__(self): - if not self.owner: - self.del_fn(self.ptr) - - -#===----------------------------------------------------------------------=== -# Dummy owner, will not delete ownee. Be careful. -#===----------------------------------------------------------------------=== - -class DummyOwner(object): - pass - - -#===----------------------------------------------------------------------=== -# A metaclass to prevent aliasing. It stores a (weak) reference to objects -# constructed based on a PyCObject. If an object is constructed based on a -# PyCObject with the same underlying pointer as a previous object, a reference -# to the previous object is returned rather than a new one. -#===----------------------------------------------------------------------=== - -class _ObjectCache(type): - """A metaclass to prevent aliasing. - - Classes using 'ObjectCache' as a metaclass must have constructors - that take a PyCObject as their first argument. When the class is - called (to create a new instance of the class), the value of the - pointer wrapped by the PyCObj is checked: - - If no previous object has been created based on the same - underlying pointer (note that different PyCObject objects can - wrap the same pointer), the object will be initialized as - usual and returned. - - If a previous has been created based on the same pointer, - then a reference to that object will be returned, and no - object initialization is performed. - """ - - __instances = WeakValueDictionary() - - def __call__(cls, ptr, *args, **kwargs): - objid = _core.PyCObjectVoidPtrToPyLong(ptr) - key = "%s:%d" % (cls.__name__, objid) - obj = _ObjectCache.__instances.get(key) - if obj is None: - obj = super(_ObjectCache, cls).__call__(ptr, *args, **kwargs) - _ObjectCache.__instances[key] = obj - return obj - - @staticmethod - def forget(obj): - objid = _core.PyCObjectVoidPtrToPyLong(obj.ptr) - key = "%s:%d" % (type(obj).__name__, objid) - if key in _ObjectCache.__instances: - del _ObjectCache.__instances[key] - - -#===----------------------------------------------------------------------=== -# Cacheables -#===----------------------------------------------------------------------=== - -# version 2/3 compatibility help -# version 2 metaclass -# class Cacheable(object): -# __metaclass__ = _ObjectCache # Doing nothing for version 3 -# -# version 3 metaclass -# class Cacheable(metaclass=_ObjectCache): -# -# Reference: http://mikewatkins.ca/2008/11/29/python-2-and-3-metaclasses/#using-the-metaclass-in-python-3-x -ObjectCache = _ObjectCache('ObjectCache', (object, ), {}) - -class Cacheable(ObjectCache): - """Objects that can be cached. - - Objects that wrap a PyCObject are cached to avoid "aliasing", i.e., - two Python objects each containing a PyCObject which internally points - to the same C pointer.""" - - def forget(self): - ObjectCache.forget(self) - - -def test(verbosity=1): - """test(verbosity=1) -> TextTestResult - - Run self-test, and return unittest.runner.TextTestResult object. - """ - from llvm.test_llvmpy import run - - return run(verbosity=verbosity) diff --git a/llvm/_core.cpp b/llvm/_core.cpp deleted file mode 100644 index db5287e..0000000 --- a/llvm/_core.cpp +++ /dev/null @@ -1,2212 +0,0 @@ -/* - * Copyright (c) 2008-10, Mahadevan R All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of this software, nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* our includes */ -#include "wrap.h" -#include "extra.h" - - - -// Python include -#include "Python.h" - -/* LLVM includes */ -#include "llvm-c/Analysis.h" -#include "llvm-c/Transforms/Scalar.h" -#include "llvm-c/ExecutionEngine.h" -#include "llvm-c/Target.h" -#include "llvm-c/Transforms/IPO.h" - -#include "llvm/Support/CommandLine.h" -#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 2 - #include "llvm-c/Linker.h" -#else - typedef unsigned int LLVMLinkerMode; -#endif - -/* Compatibility with Python 2.4: Py_ssize_t is not available. */ -#ifndef PY_SSIZE_T_MAX -typedef int Py_ssize_t; -#endif - - -// explicit specializations -template <> PyObject* pycap_new(int i) -{ - return PyLong_FromLong(static_cast(i)); -} - -template <> PyObject* pycap_new(unsigned long i) -{ - return PyLong_FromLong(static_cast(i)); -} - -template <> PyObject* pycap_new(LLVMTypeKind i) -{ - return PyLong_FromLong(static_cast(i)); -} - -template <> PyObject* pycap_new(LLVMLinkage i) -{ - return PyLong_FromLong(static_cast(i)); -} - -template <> PyObject* pycap_new(LLVMVisibility i) -{ - return PyLong_FromLong(static_cast(i)); -} - -template <> PyObject* pycap_new(LLVMByteOrdering i) -{ - return PyLong_FromLong(static_cast(i)); -} - -template <> PyObject* pycap_new(unsigned PY_LONG_LONG ull) -{ - return PyLong_FromUnsignedLongLong(ull); -} - -template <> PyObject* pycap_new(PY_LONG_LONG ll) -{ - return PyLong_FromLongLong(ll); -} - -/*===----------------------------------------------------------------------===*/ -/* Modules */ -/*===----------------------------------------------------------------------===*/ - -static PyObject * -_wLLVMModuleCreateWithName(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - const char *s; - - if (!PyArg_ParseTuple(args, "s:LLVMModuleCreateWithName", &s)) { - return NULL; - } - - const LLVMModuleRef module = LLVMModuleCreateWithName(s); - return pycap_new(module); - LLVMPY_CATCH_ALL -} - -_wrap_obj2str(LLVMGetDataLayout, LLVMModuleRef) -_wrap_objstr2none(LLVMSetDataLayout, LLVMModuleRef) -_wrap_obj2str(LLVMGetModuleIdentifier, LLVMModuleRef) -_wrap_objstr2none(LLVMSetModuleIdentifier, LLVMModuleRef) -_wrap_obj2str(LLVMGetTarget, LLVMModuleRef) -_wrap_objstr2none(LLVMSetTarget, LLVMModuleRef) -_wrap_objstr2none(LLVMModuleAddLibrary, LLVMModuleRef) -_wrap_objstr2obj(LLVMGetTypeByName, LLVMModuleRef, LLVMTypeRef) -_wrap_obj2none(LLVMDumpModule, LLVMModuleRef) -_wrap_obj2none(LLVMDisposeModule, LLVMModuleRef) -_wrap_dumper(LLVMDumpModuleToString, LLVMModuleRef) - _wrap_obj2obj( LLVMModuleGetPointerSize, LLVMModuleRef, int) -_wrap_objstrobj2obj(LLVMModuleGetOrInsertFunction, LLVMModuleRef, - LLVMTypeRef, LLVMValueRef) - -static PyObject * -_wLLVMVerifyModule(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - const LLVMModuleRef m = get_object_arg(args) ; - if (!m) return NULL; - - char *outmsg = 0; - (void) LLVMVerifyModule(m, LLVMReturnStatusAction, &outmsg); - - PyObject *ret; - if (outmsg) { - ret = PyUnicode_FromString(outmsg); - LLVMDisposeMessage(outmsg); - } else { - ret = PyUnicode_FromString(""); - } - - return ret; - LLVMPY_CATCH_ALL -} - -///// unused -// typedef LLVMModuleRef (*asm_or_bc_fn_t)(const char *A, unsigned Len, char **OutMessage); - - -static PyObject* -_wLLVMGetModuleFromAssembly(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - const char * str; -#if (PY_MAJOR_VERSION >= 3) - if ( !PyArg_ParseTuple(args, "y", &str) ){ -#else - if ( !PyArg_ParseTuple(args, "s", &str) ){ -#endif - return NULL; - } - - char * outmsg = 0; - const LLVMModuleRef mod = LLVMGetModuleFromAssembly(str, &outmsg); - - if ( !mod ){ - if ( outmsg ){ - PyObject * ret = PyUnicode_FromString(outmsg); - LLVMDisposeMessage(outmsg); - return ret; - } else { - Py_RETURN_NONE; - } - } - - return pycap_new(mod); - LLVMPY_CATCH_ALL -} - -static PyObject * -_wLLVMGetModuleFromBitcode(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - PyObject *obj ; - - if (!PyArg_ParseTuple(args, "S", &obj)) - return NULL; - - const char *start = PyBytes_AsString(obj); - const Py_ssize_t len = PyBytes_Size(obj); - - char *outmsg = 0; - LLVMModuleRef m = LLVMGetModuleFromBitcode(start, len, &outmsg); - - PyObject *ret; - if (!m) { - if (outmsg) { - ret = PyUnicode_FromString(outmsg); - LLVMDisposeMessage(outmsg); - return ret; - } else { - Py_RETURN_NONE; - } - } - - return pycap_new(m); - LLVMPY_CATCH_ALL -} - -static PyObject * -_wLLVMGetBitcodeFromModule(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - const LLVMModuleRef m = get_object_arg(args) ; - if (!m ) return NULL; - - size_t len; - const unsigned char *ubytes = LLVMGetBitcodeFromModule(m, &len) ; - if ( !ubytes ) Py_RETURN_NONE; - - const char *chars = reinterpret_cast(ubytes) ; - PyObject *ret = PyBytes_FromStringAndSize(chars, len); - delete [] ubytes; - return ret; - LLVMPY_CATCH_ALL -} - -static PyObject * -_wLLVMGetNativeCodeFromModule(PyObject * self, PyObject * args) -{ - LLVMPY_TRY - PyObject * arg_m; - int arg_use_asm; - - if (!PyArg_ParseTuple(args, "Oi", &arg_m, &arg_use_asm)) - return NULL; - - const LLVMModuleRef m = pycap_get( arg_m ) ; - - std::string error; - size_t len; - unsigned const char * ubytes - = LLVMGetNativeCodeFromModule(m, arg_use_asm, &len, error); - if ( !error.empty() ){ - PyErr_SetString(PyExc_RuntimeError, error.c_str()); - } - - const char *chars = reinterpret_cast(ubytes) ; - PyObject * ret = PyBytes_FromStringAndSize(chars, len); - - delete [] ubytes; - - return ret; - LLVMPY_CATCH_ALL -} - -static PyObject * -_wLLVMLinkModules(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - size_t mode = 0; - - PyObject *dest_obj, *src_obj ; - if (!PyArg_ParseTuple(args, "OO|I", &dest_obj, &src_obj, &mode)) - return NULL; - - const LLVMModuleRef dest = pycap_get(dest_obj ) ; - const LLVMModuleRef src = pycap_get(src_obj) ; - - PyObject *ret = NULL; - char *errmsg = NULL; - if (LLVMLinkModules(dest, src, (LLVMLinkerMode)mode, &errmsg)) { - if (errmsg) { - ret = PyUnicode_FromString(errmsg); - LLVMDisposeMessage(errmsg); - } else { - ret = PyUnicode_FromString("Link error"); - } - return ret; - } - - /* note: success => None, failure => string with error message */ - Py_RETURN_NONE; - LLVMPY_CATCH_ALL -} - -_wrap_objstr2obj(LLVMModuleGetOrInsertNamedMetaData, LLVMModuleRef, LLVMNamedMDRef) -_wrap_objstr2obj(LLVMModuleGetNamedMetaData, LLVMModuleRef, LLVMNamedMDRef) -_wrap_obj2obj(LLVMCloneModule, LLVMModuleRef, LLVMModuleRef) - -/*===----------------------------------------------------------------------===*/ -/* Types */ -/*===----------------------------------------------------------------------===*/ - -/*===-- General ----------------------------------------------------------===*/ - -_wrap_obj2obj(LLVMGetTypeKind, LLVMTypeRef, int) -_wrap_dumper(LLVMDumpTypeToString, LLVMTypeRef) - -/*===-- Integer types ----------------------------------------------------===*/ - -_wrap_none2obj(LLVMInt1Type, LLVMTypeRef) -_wrap_none2obj(LLVMInt8Type, LLVMTypeRef) -_wrap_none2obj(LLVMInt16Type, LLVMTypeRef) -_wrap_none2obj(LLVMInt32Type, LLVMTypeRef) -_wrap_none2obj(LLVMInt64Type, LLVMTypeRef) -_wrap_int2obj(LLVMIntType, LLVMTypeRef) -_wrap_obj2obj(LLVMGetIntTypeWidth, LLVMTypeRef, int) - -/*===-- Floating-point types ---------------------------------------------===*/ - -_wrap_none2obj(LLVMFloatType, LLVMTypeRef) -_wrap_none2obj(LLVMDoubleType, LLVMTypeRef) -_wrap_none2obj(LLVMX86FP80Type, LLVMTypeRef) -_wrap_none2obj(LLVMFP128Type, LLVMTypeRef) -_wrap_none2obj(LLVMPPCFP128Type, LLVMTypeRef) - -/*===-- Function types ---------------------------------------------------===*/ - -_wrap_objlistint2obj(LLVMFunctionType, LLVMTypeRef, LLVMTypeRef, LLVMTypeRef) -_wrap_obj2obj(LLVMIsFunctionVarArg, LLVMTypeRef, int) -_wrap_obj2obj(LLVMGetReturnType, LLVMTypeRef, LLVMTypeRef) -_wrap_obj2obj(LLVMCountParamTypes, LLVMTypeRef, int) - -/* The LLVMGetParamTypes and LLVMGetStructElementTypes functions both - * have the same signatures. The following implementation takes advantage - * of this. - */ - -typedef void (*obj2arr_fn_t)(LLVMTypeRef ty, LLVMTypeRef *outv); -typedef unsigned (*arrcnt_fn_t)(LLVMTypeRef ty); - -static PyObject * -obj2arr(PyObject *self, PyObject *args, arrcnt_fn_t cntfunc, obj2arr_fn_t arrfunc) -{ - size_t param_count; - - /* get the function object ptr */ - const LLVMTypeRef type = get_object_arg(args) ; - - /* get param count */ - param_count = cntfunc(type); - - /* alloc enough space for all of them */ - LLVMTypeRef* param_types = new LLVMTypeRef[param_count] ; - - /* call LLVM func */ - arrfunc(type, param_types); - - /* create a list from the array */ - PyObject *list = make_list(param_types, param_count); - - /* free temp storage */ - delete [] param_types ; - - return list; -} - -static PyObject * -_wLLVMGetFunctionTypeParams(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - return obj2arr(self, args, LLVMCountParamTypes, LLVMGetParamTypes); - LLVMPY_CATCH_ALL -} - -/*===-- Struct types -----------------------------------------------------===*/ - -_wrap_listint2obj(LLVMStructType, LLVMTypeRef, LLVMTypeRef) -_wrap_str2obj(LLVMStructTypeIdentified, LLVMTypeRef) -_wrap_objlistint2none(LLVMSetStructBody, LLVMTypeRef, LLVMTypeRef) -_wrap_obj2obj(LLVMCountStructElementTypes, LLVMTypeRef, int) -_wrap_obj2str(LLVMGetStructName, LLVMTypeRef) -_wrap_objstr2none(LLVMSetStructName, LLVMTypeRef) - - -static PyObject * -_wLLVMGetStructElementTypes(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - return obj2arr(self, args, LLVMCountStructElementTypes, - LLVMGetStructElementTypes); - LLVMPY_CATCH_ALL -} - - -_wrap_obj2obj(LLVMIsPackedStruct, LLVMTypeRef, int) -_wrap_obj2obj(LLVMIsOpaqueStruct, LLVMTypeRef, int) -_wrap_obj2obj(LLVMIsLiteralStruct, LLVMTypeRef, int) - -/*===-- Array types ------------------------------------------------------===*/ - -_wrap_objint2obj(LLVMArrayType, LLVMTypeRef, LLVMTypeRef) -_wrap_obj2obj(LLVMGetElementType, LLVMTypeRef, LLVMTypeRef) -_wrap_obj2obj(LLVMGetArrayLength, LLVMTypeRef, int) - -/*===-- Pointer types ----------------------------------------------------===*/ - -_wrap_objint2obj(LLVMPointerType, LLVMTypeRef, LLVMTypeRef) -_wrap_obj2obj(LLVMGetPointerAddressSpace, LLVMTypeRef, int) - -/*===-- Vector type ------------------------------------------------------===*/ - -_wrap_objint2obj(LLVMVectorType, LLVMTypeRef, LLVMTypeRef) -_wrap_obj2obj(LLVMGetVectorSize, LLVMTypeRef, int) - -/*===-- Other types ------------------------------------------------------===*/ - -_wrap_none2obj(LLVMVoidType, LLVMTypeRef) -_wrap_none2obj(LLVMLabelType, LLVMTypeRef) - -/*===-- Type handles -----------------------------------------------------===*/ - -/* -_wrap_obj2obj(LLVMCreateTypeHandle, LLVMTypeRef, LLVMTypeHandleRef) -_wrap_obj2obj(LLVMResolveTypeHandle, LLVMTypeHandleRef, LLVMTypeRef) -_wrap_obj2none(LLVMDisposeTypeHandle, LLVMTypeHandleRef) -*/ - - -/*===----------------------------------------------------------------------===*/ -/* Values */ -/*===----------------------------------------------------------------------===*/ - -/* Operations on all values */ - -_wrap_obj2obj(LLVMTypeOf, LLVMValueRef, LLVMTypeRef) -_wrap_obj2str(LLVMGetValueName, LLVMValueRef) -_wrap_objstr2none(LLVMSetValueName, LLVMValueRef) -_wrap_obj2none(LLVMDumpValue, LLVMValueRef) -_wrap_dumper(LLVMDumpValueToString, LLVMValueRef) -_wrap_obj2obj(LLVMValueGetID, LLVMValueRef, int) -_wrap_obj2obj(LLVMValueGetNumUses, LLVMValueRef, int) - -static PyObject * -_wLLVMValueGetUses(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - const LLVMValueRef value = get_object_arg(args) ; - - LLVMValueRef *uses = 0; - size_t n = LLVMValueGetUses(value, &uses); - - PyObject *list = make_list(uses, n); - if (n > 0) - LLVMDisposeValueRefArray(uses); - - return list; - LLVMPY_CATCH_ALL -} - -/*===-- Users ------------------------------------------------------------===*/ - -_wrap_obj2obj(LLVMUserGetNumOperands, LLVMValueRef, int) -_wrap_objint2obj(LLVMUserGetOperand, LLVMValueRef, LLVMValueRef) - -/*===-- Constant Values --------------------------------------------------===*/ - -/* Operations on constants of any type */ - -_wrap_obj2obj(LLVMConstNull, LLVMTypeRef, LLVMValueRef) -_wrap_obj2obj(LLVMConstAllOnes, LLVMTypeRef, LLVMValueRef) -_wrap_obj2obj(LLVMGetUndef, LLVMTypeRef, LLVMValueRef) -_wrap_obj2obj(LLVMIsConstant, LLVMValueRef, int) -_wrap_obj2obj(LLVMIsNull, LLVMValueRef, int) -_wrap_obj2obj(LLVMIsUndef, LLVMValueRef, int) - -/* Operations on scalar constants */ - -static PyObject * -_wLLVMConstInt(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - PyObject *obj; - unsigned PY_LONG_LONG n; - int sign_extend; - - if (!PyArg_ParseTuple(args, "OKi", &obj, &n, &sign_extend)) - return NULL; - - const LLVMTypeRef ty = pycap_get( obj ) ; - - const LLVMValueRef val = LLVMConstInt(ty, n, sign_extend); - - return pycap_new(val); - LLVMPY_CATCH_ALL -} - -static PyObject * -_wLLVMConstReal(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - PyObject *obj; - double d; - - if (!PyArg_ParseTuple(args, "Od", &obj, &d)) - return NULL; - - const LLVMTypeRef ty = pycap_get( obj ) ; - - const LLVMValueRef val = LLVMConstReal(ty, d); - return pycap_new(val); - LLVMPY_CATCH_ALL -} - -_wrap_objstr2obj(LLVMConstRealOfString, LLVMTypeRef, LLVMValueRef) -_wrap_obj2obj(LLVMConstIntGetZExtValue, LLVMValueRef, llvmwrap_ull) -_wrap_obj2obj(LLVMConstIntGetSExtValue, LLVMValueRef, llvmwrap_ll) - -/* Operations on composite constants */ - -static PyObject * -_wLLVMConstString(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - const char *s; - int dont_null_terminate; - - if (!PyArg_ParseTuple(args, "si:LLVMConstString", &s, &dont_null_terminate)) { - return NULL; - } - - LLVMValueRef val = LLVMConstString(s, strlen(s), dont_null_terminate); - return pycap_new(val); - LLVMPY_CATCH_ALL -} - -_wrap_objlist2obj(LLVMConstArray, LLVMTypeRef, LLVMValueRef, LLVMValueRef) -_wrap_listint2obj(LLVMConstStruct, LLVMValueRef, LLVMValueRef) -_wrap_list2obj(LLVMConstVector, LLVMValueRef, LLVMValueRef) - -/* Constant expressions */ - -_wrap_obj2obj(LLVMGetConstExprOpcode, LLVMValueRef, int) -_wrap_obj2str(LLVMGetConstExprOpcodeName, LLVMValueRef) -_wrap_obj2obj(LLVMSizeOf, LLVMTypeRef, LLVMValueRef) -_wrap_obj2obj(LLVMConstNeg, LLVMValueRef, LLVMValueRef) -_wrap_obj2obj(LLVMConstNot, LLVMValueRef, LLVMValueRef) - -_wrap_objobj2obj(LLVMConstAdd, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstFAdd, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstSub, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstFSub, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstMul, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstFMul, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstUDiv, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstSDiv, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstFDiv, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstURem, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstSRem, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstFRem, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstAnd, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstOr, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstXor, LLVMValueRef, LLVMValueRef, LLVMValueRef) - -_wrap_enumobjobj2obj(LLVMConstICmp, LLVMIntPredicate, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_enumobjobj2obj(LLVMConstFCmp, LLVMRealPredicate, LLVMValueRef, LLVMValueRef, LLVMValueRef) - -_wrap_objobj2obj(LLVMConstShl, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstLShr, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstAShr, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objlist2obj(LLVMConstGEP, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstTrunc, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstSExt, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstZExt, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstFPTrunc, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstFPExt, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstUIToFP, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstSIToFP, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstFPToUI, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstFPToSI, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstPtrToInt, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstIntToPtr, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstBitCast, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobj2obj(LLVMConstSelect, LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMConstExtractElement, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobj2obj(LLVMConstInsertElement, LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobj2obj(LLVMConstShuffleVector, LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) - - -/*===----------------------------------------------------------------------===*/ -/* Globals */ -/*===----------------------------------------------------------------------===*/ - -/*===-- Globals ----------------------------------------------------------===*/ - -_wrap_obj2obj(LLVMGetGlobalParent, LLVMValueRef, LLVMModuleRef) -_wrap_obj2obj(LLVMIsDeclaration, LLVMValueRef, int) -_wrap_obj2obj(LLVMGetLinkage, LLVMValueRef, int) -_wrap_objenum2none(LLVMSetLinkage, LLVMValueRef, LLVMLinkage) -_wrap_obj2str(LLVMGetSection, LLVMValueRef) -_wrap_objstr2none(LLVMSetSection, LLVMValueRef) -_wrap_obj2obj(LLVMGetVisibility, LLVMValueRef, int) -_wrap_objenum2none(LLVMSetVisibility, LLVMValueRef, LLVMVisibility) -_wrap_obj2obj(LLVMGetAlignment, LLVMValueRef, int) -_wrap_objint2none(LLVMSetAlignment, LLVMValueRef) - -/*===-- Global Variables -------------------------------------------------===*/ - -_wrap_objobjstr2obj(LLVMAddGlobal, LLVMModuleRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjstrint2obj(LLVMAddGlobalInAddressSpace, LLVMModuleRef, LLVMTypeRef, LLVMValueRef) -_wrap_objstr2obj(LLVMGetNamedGlobal, LLVMModuleRef, LLVMValueRef) -_wrap_obj2obj(LLVMGetFirstGlobal, LLVMModuleRef, LLVMValueRef) -_wrap_obj2obj(LLVMGetNextGlobal, LLVMValueRef, LLVMValueRef) -_wrap_obj2none(LLVMDeleteGlobal, LLVMValueRef) -_wrap_obj2obj(LLVMHasInitializer, LLVMValueRef, int) -_wrap_obj2obj(LLVMGetInitializer, LLVMValueRef, LLVMValueRef) -_wrap_objobj2none(LLVMSetInitializer, LLVMValueRef, LLVMValueRef) -_wrap_objint2none(LLVMSetGlobalConstant, LLVMValueRef) -_wrap_obj2obj(LLVMIsGlobalConstant, LLVMValueRef, int) -_wrap_objint2none(LLVMSetThreadLocal, LLVMValueRef) -_wrap_obj2obj(LLVMIsThreadLocal, LLVMValueRef, int) - - -/*===-- Functions --------------------------------------------------------===*/ - -_wrap_objstrobj2obj(LLVMAddFunction, LLVMModuleRef, LLVMTypeRef, LLVMValueRef) -_wrap_objstr2obj(LLVMGetNamedFunction, LLVMModuleRef, LLVMValueRef) -_wrap_obj2obj(LLVMGetFirstFunction, LLVMModuleRef, LLVMValueRef) -_wrap_obj2obj(LLVMGetNextFunction, LLVMValueRef, LLVMValueRef) -_wrap_obj2none(LLVMDeleteFunction, LLVMValueRef) -_wrap_obj2obj(LLVMGetIntrinsicID, LLVMValueRef, int) -_wrap_obj2obj(LLVMGetFunctionCallConv, LLVMValueRef, int) -_wrap_objint2none(LLVMSetFunctionCallConv, LLVMValueRef) -_wrap_obj2str(LLVMGetGC, LLVMValueRef) -_wrap_objstr2none(LLVMSetGC, LLVMValueRef) -_wrap_obj2obj(LLVMGetDoesNotThrow, LLVMValueRef, int) -_wrap_objint2none(LLVMSetDoesNotThrow, LLVMValueRef) -_wrap_obj2none(LLVMViewFunctionCFG, LLVMValueRef) -_wrap_obj2none(LLVMViewFunctionCFGOnly, LLVMValueRef) -_wrap_objenum2none(LLVMAddFunctionAttr, LLVMValueRef, LLVMAttribute) -_wrap_objenum2none(LLVMRemoveFunctionAttr, LLVMValueRef, LLVMAttribute) - -static PyObject * -_wLLVMVerifyFunction(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - const LLVMValueRef fn = get_object_arg(args); - if (!fn) return NULL; - - return pycap_new(LLVMVerifyFunction(fn, LLVMReturnStatusAction)); - LLVMPY_CATCH_ALL -} - -static PyObject * -_wLLVMGetFunctionFromInlineAsm(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - PyObject *pycapFuncType; - const char *inlineAsm = NULL; - const char *constrains = NULL; - int hasSideEffect; - int isAlignStack; - int asmDialect; - - if (!PyArg_ParseTuple(args, "Ossiii", &pycapFuncType, &inlineAsm, - &constrains, &hasSideEffect, - &isAlignStack, &asmDialect)) - return NULL; - - - LLVMTypeRef funcType = pycap_get(pycapFuncType); - LLVMValueRef inlineAsmRef; - inlineAsmRef = LLVMGetFunctionFromInlineAsm(funcType, inlineAsm, constrains, - hasSideEffect, isAlignStack, - asmDialect); - - return pycap_new(inlineAsmRef); - LLVMPY_CATCH_ALL -} - - -/*===-- Arguments --------------------------------------------------------===*/ - -_wrap_obj2obj(LLVMCountParams, LLVMValueRef, int) -_wrap_obj2obj(LLVMGetFirstParam, LLVMValueRef, LLVMValueRef) -_wrap_obj2obj(LLVMGetNextParam, LLVMValueRef, LLVMValueRef) -_wrap_obj2obj(LLVMGetParamParent, LLVMValueRef, LLVMValueRef) -_wrap_objenum2none(LLVMAddAttribute, LLVMValueRef, LLVMAttribute) -_wrap_objenum2none(LLVMRemoveAttribute, LLVMValueRef, LLVMAttribute) -_wrap_objenum2none(LLVMSetParamAlignment, LLVMValueRef, LLVMAttribute) -_wrap_obj2obj(LLVMGetParamAlignment, LLVMValueRef, int) - -/*===-- Basic Blocks -----------------------------------------------------===*/ - -_wrap_obj2obj(LLVMGetBasicBlockParent, LLVMBasicBlockRef, LLVMValueRef) -_wrap_obj2obj(LLVMCountBasicBlocks, LLVMValueRef, int) -_wrap_obj2obj(LLVMGetFirstBasicBlock, LLVMValueRef, LLVMBasicBlockRef) -_wrap_obj2obj(LLVMGetNextBasicBlock, LLVMBasicBlockRef, LLVMBasicBlockRef) -_wrap_obj2obj(LLVMGetEntryBasicBlock, LLVMValueRef, LLVMBasicBlockRef) -_wrap_objstr2obj(LLVMAppendBasicBlock, LLVMValueRef, LLVMBasicBlockRef) -_wrap_objstr2obj(LLVMInsertBasicBlock, LLVMBasicBlockRef, LLVMBasicBlockRef) -_wrap_obj2none(LLVMDeleteBasicBlock, LLVMBasicBlockRef) - - -/*===-- MetaData -----------------------------------------------------===*/ - -_wrap_objlist2obj(LLVMMetaDataGet, LLVMModuleRef, LLVMValueRef, LLVMValueRef) -_wrap_objstrobj2none(LLVMAddNamedMetadataOperand, LLVMModuleRef, LLVMValueRef) -_wrap_objint2obj(LLVMMetaDataGetOperand, LLVMValueRef, LLVMValueRef) -_wrap_obj2obj(LLVMMetaDataGetNumOperands, LLVMValueRef, int) -_wrap_objstr2obj(LLVMMetaDataStringGet, LLVMModuleRef, LLVMValueRef) - -static PyObject * -_wLLVMGetNamedMetadataOperands(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - PyObject *obj_module; - const char *name; - - if (!PyArg_ParseTuple(args, "Os", &obj_module, &name)) - return NULL; - - LLVMModuleRef module = pycap_get(obj_module); - unsigned num_operands = LLVMGetNamedMetadataNumOperands(module, name); - LLVMValueRef *operands = new LLVMValueRef[num_operands]; - LLVMGetNamedMetadataOperands(module, name, operands); - - PyObject *list = make_list(operands, num_operands); - delete [] operands; - - return list; - LLVMPY_CATCH_ALL -} - - -/*===-- NamedMetaData -----------------------------------------------------===*/ - -_wrap_obj2str( LLVMNamedMetaDataGetName, LLVMNamedMDRef ) -_wrap_objobj2none( LLVMNamedMetaDataAddOperand, LLVMNamedMDRef, LLVMValueRef ) -_wrap_obj2none( LLVMEraseNamedMetaData, LLVMNamedMDRef ) -_wrap_dumper(LLVMDumpNamedMDToString, LLVMNamedMDRef) - -/*===-- Instructions -----------------------------------------------------===*/ - -_wrap_obj2obj(LLVMGetInstructionParent, LLVMValueRef, LLVMBasicBlockRef) -_wrap_obj2obj(LLVMGetFirstInstruction, LLVMBasicBlockRef, LLVMValueRef) -_wrap_obj2obj(LLVMGetNextInstruction, LLVMValueRef, LLVMValueRef) -_wrap_obj2obj(LLVMInstIsTerminator, LLVMValueRef, int) -_wrap_obj2obj(LLVMInstIsBinaryOp, LLVMValueRef, int) -_wrap_obj2obj(LLVMInstIsShift, LLVMValueRef, int) -_wrap_obj2obj(LLVMInstIsCast, LLVMValueRef, int) -_wrap_obj2obj(LLVMInstIsLogicalShift, LLVMValueRef, int) -_wrap_obj2obj(LLVMInstIsArithmeticShift, LLVMValueRef, int) -_wrap_obj2obj(LLVMInstIsAssociative, LLVMValueRef, int) -_wrap_obj2obj(LLVMInstIsCommutative, LLVMValueRef, int) -_wrap_obj2obj(LLVMInstIsVolatile, LLVMValueRef, int) -_wrap_objint2none(LLVMSetVolatile, LLVMValueRef) -_wrap_obj2obj(LLVMInstGetOpcode, LLVMValueRef, int) -_wrap_obj2str(LLVMInstGetOpcodeName, LLVMValueRef) - -_wrap_objstrobj2none(LLVMInstSetMetaData, LLVMValueRef, LLVMValueRef) -_wrap_obj2none(LLVMInstructionEraseFromParent, LLVMValueRef) - -/*===-- Call Sites (Call or Invoke) --------------------------------------===*/ - -_wrap_objint2none(LLVMSetInstructionCallConv, LLVMValueRef) -_wrap_obj2obj(LLVMGetInstructionCallConv, LLVMValueRef, int) -_wrap_objintenum2none(LLVMAddInstrAttribute, LLVMValueRef, LLVMAttribute) -_wrap_objintenum2none(LLVMRemoveInstrAttribute, LLVMValueRef, LLVMAttribute) -_wrap_objintint2none(LLVMSetInstrParamAlignment, LLVMValueRef) -_wrap_obj2obj(LLVMIsTailCall, LLVMValueRef, int) -_wrap_objint2none(LLVMSetTailCall, LLVMValueRef) -_wrap_obj2obj(LLVMInstGetCalledFunction, LLVMValueRef, LLVMValueRef) -_wrap_objobj2none(LLVMInstSetCalledFunction, LLVMValueRef, LLVMValueRef) - -/*===-- PHI Nodes --------------------------------------------------------===*/ - -static void LLVMAddIncoming1(LLVMValueRef PhiNode, LLVMValueRef IncomingValue, LLVMBasicBlockRef IncomingBlock) -{ - LLVMAddIncoming(PhiNode, &IncomingValue, &IncomingBlock, 1); -} - -_wrap_objobjobj2none(LLVMAddIncoming1, LLVMValueRef, LLVMValueRef, LLVMBasicBlockRef) -_wrap_obj2obj(LLVMCountIncoming, LLVMValueRef, int) -_wrap_objint2obj(LLVMGetIncomingValue, LLVMValueRef, LLVMValueRef) -_wrap_objint2obj(LLVMGetIncomingBlock, LLVMValueRef, LLVMBasicBlockRef) - -/*===-- Compare Instructions ---------------------------------------------===*/ - -_wrap_obj2obj(LLVMCmpInstGetPredicate, LLVMValueRef, int) - -/*===-- Instruction builders ----------------------------------------------===*/ - -_wrap_none2obj(LLVMCreateBuilder, LLVMBuilderRef) -_wrap_objobj2none(LLVMPositionBuilderBefore, LLVMBuilderRef, LLVMValueRef) -_wrap_objobj2none(LLVMPositionBuilderAtEnd, LLVMBuilderRef, LLVMBasicBlockRef) -_wrap_obj2obj(LLVMGetInsertBlock, LLVMBuilderRef, LLVMBasicBlockRef) -_wrap_obj2none(LLVMDisposeBuilder, LLVMBuilderRef) - -/* Terminators */ - -_wrap_obj2obj(LLVMBuildRetVoid, LLVMBuilderRef, LLVMValueRef) -_wrap_objobj2obj(LLVMBuildRet, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) -_wrap_objlist2obj(LLVMBuildRetMultiple, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMBuildBr, LLVMBuilderRef, LLVMBasicBlockRef, LLVMValueRef) -_wrap_objobjobjobj2obj(LLVMBuildCondBr, LLVMBuilderRef, LLVMValueRef, LLVMBasicBlockRef, LLVMBasicBlockRef, LLVMValueRef) -_wrap_objobjobjint2obj(LLVMBuildSwitch, LLVMBuilderRef, LLVMValueRef, LLVMBasicBlockRef, LLVMValueRef) - -static PyObject * -_wLLVMBuildInvoke(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - PyObject *obj1, *obj2, *obj3, *obj4, *obj5; - const char *name; - - if (!PyArg_ParseTuple(args, "OOOOOs:LLVMBuildInvoke", &obj1, &obj2, &obj3, &obj4, &obj5, &name)) { - return NULL; - } - - const LLVMBuilderRef builder = pycap_get( obj1); - const LLVMValueRef func = pycap_get( obj2 ) ; - - size_t fnarg_count = PyList_Size(obj3); - LLVMValueRef *fnargs - = make_array_from_list(obj3, fnarg_count); - - const LLVMBasicBlockRef then_blk = pycap_get ( obj4 ) ; - const LLVMBasicBlockRef catch_blk = pycap_get ( obj5 ) ; - - const LLVMValueRef inst - = LLVMBuildInvoke(builder, func, fnargs, fnarg_count, then_blk, - catch_blk, name); - - delete [] fnargs; - - return pycap_new(inst); - LLVMPY_CATCH_ALL -} - -_wrap_obj2obj(LLVMBuildUnreachable, LLVMBuilderRef, LLVMValueRef) - -/* Add a case to the switch instruction */ - -_wrap_objobjobj2none(LLVMAddCase, LLVMValueRef, LLVMValueRef, LLVMBasicBlockRef) - -/* Arithmetic */ - -_wrap_objobjobjstr2obj(LLVMBuildAdd, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildFAdd, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildSub, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildFSub, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildMul, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildFMul, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildUDiv, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildSDiv, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildFDiv, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildURem, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildSRem, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildFRem, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildShl, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildLShr, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildAShr, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildAnd, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildOr, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildXor, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjstr2obj(LLVMBuildNeg, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjstr2obj(LLVMBuildNot, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) - -/* Memory */ - -_wrap_objobjstr2obj(LLVMBuildMalloc, LLVMBuilderRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildArrayMalloc, LLVMBuilderRef, LLVMTypeRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjstr2obj(LLVMBuildAlloca, LLVMBuilderRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildArrayAlloca, LLVMBuilderRef, LLVMTypeRef, LLVMValueRef, LLVMValueRef) -_wrap_objobj2obj(LLVMBuildFree, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjstr2obj(LLVMBuildLoad, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobj2obj(LLVMBuildStore, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjliststr2obj(LLVMBuildGEP, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjliststr2obj(LLVMBuildInBoundsGEP, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) - - - -_wrap_objint2none(LLVMLdSetAlignment, LLVMValueRef) -_wrap_objint2none(LLVMStSetAlignment, LLVMValueRef) - -/* Casts */ - -_wrap_objobjobjstr2obj(LLVMBuildTrunc, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildZExt, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildSExt, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildFPToUI, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildFPToSI, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildUIToFP, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildSIToFP, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildFPTrunc, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildFPExt, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildPtrToInt, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildIntToPtr, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildBitCast, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) - -/* Comparisons */ - -_wrap_objenumobjobjstr2obj(LLVMBuildICmp, LLVMBuilderRef, LLVMIntPredicate, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objenumobjobjstr2obj(LLVMBuildFCmp, LLVMBuilderRef, LLVMRealPredicate, LLVMValueRef, LLVMValueRef, LLVMValueRef) - - -/* Atomics */ -_wrap_objobjobjobjstrint2obj(LLVMBuildAtomicCmpXchg, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objstrobjobjstrint2obj(LLVMBuildAtomicRMW, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjintstrint2obj(LLVMBuildAtomicLoad, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjintstrint2obj(LLVMBuildAtomicStore, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objstrint2obj(LLVMBuildFence, LLVMBuilderRef, LLVMValueRef) - -/* Miscellaneous instructions */ - -_wrap_objobjintstr2obj(LLVMBuildGetResult, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjintstr2obj(LLVMBuildInsertValue, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjstr2obj(LLVMBuildPhi, LLVMBuilderRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjliststr2obj(LLVMBuildCall, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjobjstr2obj(LLVMBuildSelect, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildVAArg, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef, LLVMValueRef) -_wrap_objobjobjstr2obj(LLVMBuildExtractElement, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjobjstr2obj(LLVMBuildInsertElement, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjobjstr2obj(LLVMBuildShuffleVector, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) - - -/*===----------------------------------------------------------------------===*/ -/* Memory Buffer */ -/*===----------------------------------------------------------------------===*/ - -static PyObject * -_wLLVMCreateMemoryBufferWithContentsOfFile(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - const char *path; - LLVMMemoryBufferRef ref; - PyObject *ret; - - if (!PyArg_ParseTuple(args, "s:LLVMCreateMemoryBufferWithContentsOfFile", &path)) { - return NULL; - } - - char *outmsg; - if (!LLVMCreateMemoryBufferWithContentsOfFile(path, &ref, &outmsg)) { - ret = pycap_new(ref); - } else { - ret = PyUnicode_FromString(outmsg); - LLVMDisposeMessage(outmsg); - } - - return ret; - LLVMPY_CATCH_ALL -} - -static PyObject * -_wLLVMCreateMemoryBufferWithSTDIN(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - PyObject *ret; - LLVMMemoryBufferRef ref; - char *outmsg; - if (!LLVMCreateMemoryBufferWithSTDIN(&ref, &outmsg)) { - ret = pycap_new(ref); - } else { - ret = PyUnicode_FromString(outmsg); - LLVMDisposeMessage(outmsg); - } - - return ret; - LLVMPY_CATCH_ALL -} - -_wrap_obj2none(LLVMDisposeMemoryBuffer, LLVMMemoryBufferRef) - - -/*===----------------------------------------------------------------------===*/ -/* Pass Manager Builder */ -/*===----------------------------------------------------------------------===*/ - -_wrap_none2obj(LLVMPassManagerBuilderCreate, LLVMPassManagerBuilderRef) -_wrap_obj2none(LLVMPassManagerBuilderDispose, LLVMPassManagerBuilderRef) - -_wrap_objint2none(LLVMPassManagerBuilderSetOptLevel, LLVMPassManagerBuilderRef) -_wrap_obj2obj(LLVMPassManagerBuilderGetOptLevel, LLVMPassManagerBuilderRef, int) - -_wrap_objint2none(LLVMPassManagerBuilderSetSizeLevel, LLVMPassManagerBuilderRef) -_wrap_obj2obj(LLVMPassManagerBuilderGetSizeLevel, LLVMPassManagerBuilderRef, int) - -_wrap_objint2none(LLVMPassManagerBuilderSetVectorize, LLVMPassManagerBuilderRef) -_wrap_obj2obj(LLVMPassManagerBuilderGetVectorize, LLVMPassManagerBuilderRef, int) - -#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 2 -_wrap_objint2none(LLVMPassManagerBuilderSetLoopVectorize, LLVMPassManagerBuilderRef) -_wrap_obj2obj(LLVMPassManagerBuilderGetLoopVectorize, LLVMPassManagerBuilderRef, int) -#endif //llvm-3.2 - -_wrap_objint2none(LLVMPassManagerBuilderSetDisableUnitAtATime, - LLVMPassManagerBuilderRef) -_wrap_obj2obj(LLVMPassManagerBuilderGetDisableUnitAtATime, - LLVMPassManagerBuilderRef, int) - -_wrap_objint2none(LLVMPassManagerBuilderSetDisableUnrollLoops, - LLVMPassManagerBuilderRef) -_wrap_obj2obj(LLVMPassManagerBuilderGetDisableUnrollLoops, - LLVMPassManagerBuilderRef, int) - -_wrap_objint2none(LLVMPassManagerBuilderSetDisableSimplifyLibCalls, - LLVMPassManagerBuilderRef) -_wrap_obj2obj(LLVMPassManagerBuilderGetDisableSimplifyLibCalls, - LLVMPassManagerBuilderRef, int) - -_wrap_objint2none(LLVMPassManagerBuilderUseInlinerWithThreshold, - LLVMPassManagerBuilderRef) - - -_wrap_objobj2none(LLVMPassManagerBuilderPopulateFunctionPassManager, - LLVMPassManagerBuilderRef, - LLVMPassManagerRef) - -_wrap_objobj2none(LLVMPassManagerBuilderPopulateModulePassManager, - LLVMPassManagerBuilderRef, - LLVMPassManagerRef) - - -/*===----------------------------------------------------------------------===*/ -/* Pass Manager */ -/*===----------------------------------------------------------------------===*/ - -_wrap_none2obj(LLVMCreatePassManager, LLVMPassManagerRef) -_wrap_obj2obj(LLVMCreateFunctionPassManagerForModule, LLVMModuleRef, LLVMPassManagerRef) -_wrap_objobj2obj(LLVMRunPassManager, LLVMPassManagerRef, LLVMModuleRef, int) -_wrap_obj2obj(LLVMInitializeFunctionPassManager, LLVMPassManagerRef, int) -_wrap_objobj2obj(LLVMRunFunctionPassManager, LLVMPassManagerRef, LLVMValueRef, int) -_wrap_obj2obj(LLVMFinalizeFunctionPassManager, LLVMPassManagerRef, int) -_wrap_obj2none(LLVMDisposePassManager, LLVMPassManagerRef) -_wrap_none2str(LLVMDumpPasses) -_wrap_objstr2obj(LLVMAddPassByName, LLVMPassManagerRef, int) - - -_wrap_objobj2none(LLVMAddPass, LLVMPassManagerRef, LLVMPassRef) -_wrap_none2none(LLVMInitializePasses) - -_wrap_none2obj(LLVMInitializeNativeTarget, int) -_wrap_none2obj(LLVMInitializeNativeTargetAsmPrinter, int) -#if !defined(LLVM_DISABLE_PTX) -# if LLVM_HAS_NVPTX -_wrap_none2none(LLVMInitializeNVPTXTarget) -_wrap_none2none(LLVMInitializeNVPTXTargetInfo) -_wrap_none2none( LLVMInitializeNVPTXTargetMC ) -_wrap_none2none(LLVMInitializeNVPTXAsmPrinter) -# else -_wrap_none2none(LLVMInitializePTXTarget) -_wrap_none2none(LLVMInitializePTXTargetInfo) -_wrap_none2none( LLVMInitializePTXTargetMC ) -_wrap_none2none(LLVMInitializePTXAsmPrinter) -# endif -#endif - -/*===----------------------------------------------------------------------===*/ -/* Passes */ -/*===----------------------------------------------------------------------===*/ - -_wrap_str2obj(LLVMCreatePassByName, LLVMPassRef) -_wrap_obj2none(LLVMDisposePass, LLVMPassRef) -_wrap_obj2str(LLVMGetPassName, LLVMPassRef) -_wrap_obj2none(LLVMPassDump, LLVMPassRef) - -_wrap_str2obj(LLVMCreateTargetLibraryInfo, LLVMPassRef) - -#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 2 -_wrap_obj2obj(LLVMCreateTargetTransformInfo, LLVMTargetMachineRef, LLVMPassRef) -#endif - - -/*===----------------------------------------------------------------------===*/ -/* Target Machine */ -/*===----------------------------------------------------------------------===*/ - -_wrap_none2str(LLVMGetHostCPUName); - -_wrap_obj2obj(LLVMTargetMachineFromEngineBuilder, LLVMEngineBuilderRef, - LLVMTargetMachineRef) -_wrap_obj2none(LLVMDisposeTargetMachine, LLVMTargetMachineRef) - -static PyObject * -_wLLVMTargetMachineLookup(PyObject * self, PyObject * args) -{ - LLVMPY_TRY - const char *triple; - const char *cpu; - const char *features; - int opt, codemodel; - - if (!PyArg_ParseTuple(args, "sssii", &triple, &cpu, &features, - &opt, &codemodel)) - return NULL; - - std::string error; - LLVMTargetMachineRef tm = LLVMTargetMachineLookup(triple, cpu, features, - opt, codemodel, error); - if(!error.empty()){ - PyErr_SetString(PyExc_RuntimeError, error.c_str()); - return NULL; - } - return pycap_new(tm); - LLVMPY_CATCH_ALL -} - - -static PyObject * -_wLLVMCreateTargetMachine(PyObject * self, PyObject * args) -{ - LLVMPY_TRY - const char *triple; - const char *cpu; - const char *features; - int opt, codemodel; - - if (!PyArg_ParseTuple(args, "sssii", &triple, &cpu, &features, - &opt, &codemodel)) - return NULL; - - std::string error; - LLVMTargetMachineRef tm = LLVMCreateTargetMachine(triple, cpu, features, - opt, codemodel, error); - if(!error.empty()){ - PyErr_SetString(PyExc_RuntimeError, error.c_str()); - return NULL; - } - return pycap_new(tm); - LLVMPY_CATCH_ALL -} - -static PyObject * -_wLLVMTargetMachineEmitFile(PyObject * self, PyObject * args) -{ - LLVMPY_TRY - PyObject *arg_tm, *arg_m; - int arg_use_asm; - - if (!PyArg_ParseTuple(args, "OOi", &arg_tm, &arg_m, &arg_use_asm)) - return NULL; - - const LLVMTargetMachineRef tm - = pycap_get( arg_tm ) ; - const LLVMModuleRef m = pycap_get( arg_m ) ; - - std::string error; - size_t len; - unsigned const char * ubytes - = LLVMTargetMachineEmitFile(tm, m, arg_use_asm, &len, error); - if ( !error.empty() ){ - PyErr_SetString(PyExc_RuntimeError, error.c_str()); - return NULL; - } - - const char *chars = reinterpret_cast(ubytes) ; - PyObject * ret = PyBytes_FromStringAndSize(chars, len); - delete [] ubytes; - return ret; - LLVMPY_CATCH_ALL -} - -_wrap_obj2obj(LLVMTargetMachineGetTargetData, LLVMTargetMachineRef, - LLVMTargetDataRef) -_wrap_obj2str(LLVMTargetMachineGetTargetName, LLVMTargetMachineRef) -_wrap_obj2str(LLVMTargetMachineGetTargetShortDescription, LLVMTargetMachineRef) -_wrap_obj2str(LLVMTargetMachineGetTriple, LLVMTargetMachineRef) -_wrap_obj2str(LLVMTargetMachineGetCPU, LLVMTargetMachineRef) -_wrap_obj2str(LLVMTargetMachineGetFS, LLVMTargetMachineRef) -_wrap_none2none(LLVMPrintRegisteredTargetsForVersion) - - -/*===----------------------------------------------------------------------===*/ -/* Target Data */ -/*===----------------------------------------------------------------------===*/ - -_wrap_str2obj(LLVMCreateTargetData, LLVMTargetDataRef) -_wrap_obj2none(LLVMDisposeTargetData, LLVMTargetDataRef) - -static PyObject * -_wLLVMTargetDataAsString(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - const LLVMTargetDataRef td = get_object_arg(args); - - char *tdrep = LLVMCopyStringRepOfTargetData(td); - PyObject *ret = PyUnicode_FromString(tdrep); - LLVMDisposeMessage(tdrep); - return ret; - LLVMPY_CATCH_ALL -} - -_wrap_objobj2none(LLVMAddTargetData, LLVMTargetDataRef, LLVMPassManagerRef) -_wrap_obj2obj(LLVMByteOrder, LLVMTargetDataRef, int) -_wrap_obj2obj(LLVMPointerSize, LLVMTargetDataRef, int) -_wrap_obj2obj(LLVMIntPtrType, LLVMTargetDataRef, LLVMTypeRef) -_wrap_objobj2obj(LLVMSizeOfTypeInBits, LLVMTargetDataRef, LLVMTypeRef, - llvmwrap_ull) -_wrap_objobj2obj(LLVMStoreSizeOfType, LLVMTargetDataRef, LLVMTypeRef, - llvmwrap_ull) -_wrap_objobj2obj(LLVMABISizeOfType, LLVMTargetDataRef, LLVMTypeRef, - llvmwrap_ull) -_wrap_objobj2obj(LLVMABIAlignmentOfType, LLVMTargetDataRef, LLVMTypeRef, - int) -_wrap_objobj2obj(LLVMCallFrameAlignmentOfType, LLVMTargetDataRef, LLVMTypeRef, - int) -_wrap_objobj2obj(LLVMPreferredAlignmentOfType, LLVMTargetDataRef, LLVMTypeRef, - int) -_wrap_objobj2obj(LLVMPreferredAlignmentOfGlobal, LLVMTargetDataRef, - LLVMValueRef, int) -_wrap_objobjull2obj(LLVMElementAtOffset, LLVMTargetDataRef, LLVMTypeRef, int) -_wrap_objobjint2obj(LLVMOffsetOfElement, LLVMTargetDataRef, LLVMTypeRef, - llvmwrap_ull) - - -/*===----------------------------------------------------------------------===*/ -/* Engine Builder */ -/*===----------------------------------------------------------------------===*/ - -_wrap_obj2obj(LLVMCreateEngineBuilder, LLVMModuleRef, LLVMEngineBuilderRef) -_wrap_obj2none(LLVMDisposeEngineBuilder, LLVMEngineBuilderRef) -_wrap_obj2none(LLVMEngineBuilderForceJIT, LLVMEngineBuilderRef) -_wrap_obj2none(LLVMEngineBuilderForceInterpreter, LLVMEngineBuilderRef) -_wrap_objint2none(LLVMEngineBuilderSetOptLevel, LLVMEngineBuilderRef) -_wrap_objstr2none(LLVMEngineBuilderSetMCPU, LLVMEngineBuilderRef) -_wrap_objstr2none(LLVMEngineBuilderSetMAttrs, LLVMEngineBuilderRef) - -static PyObject * -_wLLVMEngineBuilderCreate(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - const LLVMEngineBuilderRef obj - = get_object_arg(args) ; - - std::string outmsg; - const LLVMExecutionEngineRef ee = LLVMEngineBuilderCreate(obj, outmsg); - - PyObject * ret; - if( !ee ){ // check if error message is set. - ret = PyUnicode_FromString(outmsg.c_str()); - }else{ - ret = pycap_new(ee); - } - - return ret; - LLVMPY_CATCH_ALL -} - -static PyObject * -_wLLVMEngineBuilderCreateTM(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - PyObject *obj, *tm; - if (!PyArg_ParseTuple(args, "OO", &obj, &tm)) - return NULL; - - const LLVMEngineBuilderRef objref = pycap_get( obj ); - const LLVMTargetMachineRef tmref = pycap_get( tm ); - std::string outmsg; - - const LLVMExecutionEngineRef ee = LLVMEngineBuilderCreateTM(objref, tmref, - outmsg); - - PyObject * ret; - if( !ee ){ // check if error message is set. - ret = PyUnicode_FromString(outmsg.c_str()); - }else{ - ret = pycap_new(ee); - } - - return ret; - LLVMPY_CATCH_ALL -} - -/*===----------------------------------------------------------------------===*/ -/* Execution Engine */ -/*===----------------------------------------------------------------------===*/ - -// Use EngineBuilder -//static PyObject * -//_wLLVMCreateExecutionEngine(PyObject *self, PyObject *args) -//{ -// LLVMPY_TRY -// PyObject *obj; -// int force_interpreter; -// char *outmsg = 0; -// int error; -// -// if (!PyArg_ParseTuple(args, "Oi", &obj, &force_interpreter)) -// return NULL; -// -// const LLVMModuleRef mod = pycap_get( obj ) ; -// -// LLVMExecutionEngineRef ee; -// if (force_interpreter) -// error = LLVMCreateInterpreterForModule(&ee, mod, &outmsg); -// else -// error = LLVMCreateJITCompilerForModule(&ee, mod, 1 /*fast*/, &outmsg); -// -// PyObject *ret; -// if (error) { -// ret = PyUnicode_FromString(outmsg); -// LLVMDisposeMessage(outmsg); -// } else { -// ret = pycap_new(ee); -// } -// -// return ret; -// LLVMPY_CATCH_ALL -//} - -static PyObject * -_wLLVMGetPointerToFunction(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - PyObject *obj_ee; - PyObject *obj_fn; - - if (!PyArg_ParseTuple(args, "OO", &obj_ee, &obj_fn)) - return NULL; - - const LLVMExecutionEngineRef ee = pycap_get(obj_ee ) ; - const LLVMValueRef fn = pycap_get( obj_fn ) ; - - return PyLong_FromVoidPtr(LLVMGetPointerToFunction(ee,fn)); - LLVMPY_CATCH_ALL -} - -static PyObject * -_wLLVMGetPointerToGlobal(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - PyObject *obj_ee; - PyObject *obj_val; - - if (!PyArg_ParseTuple(args, "OO", &obj_ee, &obj_val)) - return NULL; - - const LLVMExecutionEngineRef ee = pycap_get( obj_ee ) ; - const LLVMValueRef val = pycap_get( obj_val ) ; - - return PyLong_FromVoidPtr(LLVMGetPointerToGlobal(ee, val)); - LLVMPY_CATCH_ALL -} - -static PyObject * -_wLLVMAddGlobalMapping(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - PyObject *obj_ee; - PyObject *obj_val; - PyObject *obj_long; - void* address; - - if (!PyArg_ParseTuple(args, "OOO", &obj_ee, &obj_val, &obj_long)) - return NULL; - - address = PyLong_AsVoidPtr(obj_long); - if (PyErr_Occurred()) return NULL; - - const LLVMExecutionEngineRef ee = pycap_get( obj_ee ); - const LLVMValueRef val = pycap_get( obj_val ); - - LLVMAddGlobalMapping(ee, val, address); - - Py_RETURN_NONE; - - LLVMPY_CATCH_ALL -} - -/* the args should have been ptr, num */ -LLVMGenericValueRef LLVMRunFunction2(LLVMExecutionEngineRef EE, - LLVMValueRef F, LLVMGenericValueRef *Args, unsigned NumArgs) -{ - return LLVMRunFunction(EE, F, NumArgs, Args); -} - -static PyObject * -_wLLVMRemoveModule2(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - PyObject *obj_ee; - PyObject *obj_mod; - if (!PyArg_ParseTuple(args, "OO", &obj_ee, &obj_mod)) - return NULL; - - const LLVMExecutionEngineRef ee = pycap_get( obj_ee ) ; - const LLVMModuleRef mod = pycap_get(obj_mod) ; - - char *outmsg = 0; - LLVMModuleRef mod_new = 0; - LLVMRemoveModule(ee, mod, &mod_new, &outmsg); - PyObject *ret; - if (mod_new) { - ret = pycap_new(mod_new); - } else { - if (outmsg) { - ret = PyUnicode_FromString(outmsg); - LLVMDisposeMessage(outmsg); - } else { - ret = PyUnicode_FromString("error"); - } - } - - return ret; - LLVMPY_CATCH_ALL -} - -_wrap_obj2none(LLVMDisposeExecutionEngine, LLVMExecutionEngineRef) -_wrap_objint2none(LLVMExecutionEngineDisableLazyCompilation, - LLVMExecutionEngineRef) -_wrap_objobjlist2obj(LLVMRunFunction2, LLVMExecutionEngineRef, - LLVMValueRef, LLVMGenericValueRef, LLVMGenericValueRef) -_wrap_obj2obj(LLVMGetExecutionEngineTargetData, LLVMExecutionEngineRef, - LLVMTargetDataRef) -_wrap_obj2none(LLVMRunStaticConstructors, LLVMExecutionEngineRef) -_wrap_obj2none(LLVMRunStaticDestructors, LLVMExecutionEngineRef) -_wrap_objobj2none(LLVMFreeMachineCodeForFunction, LLVMExecutionEngineRef, - LLVMValueRef) -_wrap_objobj2none(LLVMAddModule, LLVMExecutionEngineRef, - LLVMModuleRef) - - -/*===----------------------------------------------------------------------===*/ -/* Generic Value */ -/*===----------------------------------------------------------------------===*/ - -static PyObject * -_wLLVMCreateGenericValueOfInt(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - PyObject *obj1; - unsigned PY_LONG_LONG n; - int is_signed; - LLVMGenericValueRef gv; - - if (!PyArg_ParseTuple(args, "OKi", &obj1, &n, &is_signed)) - return NULL; - - const LLVMTypeRef ty = pycap_get( obj1 ) ; - - gv = LLVMCreateGenericValueOfInt(ty, n, is_signed); - return pycap_new(gv); - LLVMPY_CATCH_ALL -} - -static PyObject * -_wLLVMCreateGenericValueOfFloat(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - PyObject *obj1; - double d; - LLVMGenericValueRef gv; - - if (!PyArg_ParseTuple(args, "Od", &obj1, &d)) - return NULL; - - const LLVMTypeRef ty = pycap_get( obj1 ) ; - - gv = LLVMCreateGenericValueOfFloat(ty, d); - return pycap_new(gv); - LLVMPY_CATCH_ALL -} - -static PyObject * -_wLLVMCreateGenericValueOfPointer(PyObject *self, PyObject *args) -{ - LLVMPY_TRY -// PyObject *obj1; -// LLVMTypeRef ty; //unused? - unsigned PY_LONG_LONG n_; - size_t n; - - if (!PyArg_ParseTuple(args, "K", &n_)) - return NULL; - - n=n_; - - const LLVMGenericValueRef gv = LLVMCreateGenericValueOfPointer((void*)n); - return pycap_new(gv); - LLVMPY_CATCH_ALL -} - -static PyObject * -_wLLVMGenericValueToInt(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - PyObject *obj1; - int is_signed; - unsigned PY_LONG_LONG val; - - if (!PyArg_ParseTuple(args, "Oi", &obj1, &is_signed)) - return NULL; - - LLVMGenericValueRef gv = pycap_get(obj1); - - val = LLVMGenericValueToInt(gv, is_signed); - return is_signed ? - PyLong_FromLongLong((PY_LONG_LONG)val) : - PyLong_FromUnsignedLongLong(val); - LLVMPY_CATCH_ALL -} - -static PyObject * -_wLLVMGenericValueToFloat(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - PyObject *obj1, *obj2; - - if (!PyArg_ParseTuple(args, "OO", &obj1, &obj2)) - return NULL; - - const LLVMTypeRef ty = pycap_get( obj1 ) ; - const LLVMGenericValueRef gv = pycap_get( obj2 ) ; - - double val = LLVMGenericValueToFloat(ty, gv); - return PyFloat_FromDouble(val); - LLVMPY_CATCH_ALL -} - -static PyObject * -_wLLVMGenericValueToPointer(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - PyObject *obj1; - - if (!PyArg_ParseTuple(args, "O", &obj1)) - return NULL; - - const LLVMGenericValueRef gv = pycap_get( obj1 ) ; - - void * val = LLVMGenericValueToPointer(gv); - return PyLong_FromVoidPtr(val); - LLVMPY_CATCH_ALL -} - -_wrap_obj2none(LLVMDisposeGenericValue, LLVMGenericValueRef) - - -/*===----------------------------------------------------------------------===*/ -/* Misc */ -/*===----------------------------------------------------------------------===*/ - -static PyObject * -_wLLVMGetVersion(PyObject *self, PyObject *args) -{ - int major = LLVM_VERSION_MAJOR; - int minor = LLVM_VERSION_MINOR; - return Py_BuildValue("(i,i)", major, minor); -} - -_wrap_objintlist2obj(LLVMGetIntrinsic, LLVMModuleRef, LLVMTypeRef, - LLVMValueRef) - -static PyObject * -_wLLVMLoadLibraryPermanently(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - const char *filename; - PyObject *ret; - - if (!PyArg_ParseTuple(args, "s:LLVMLoadLibraryPermanently", &filename)) { - return NULL; - } - - char *outmsg = 0; - if (!LLVMLoadLibraryPermanently(filename, &outmsg)) { - if (outmsg) { - ret = PyUnicode_FromString(outmsg); - LLVMDisposeMessage(outmsg); - return ret; - } - } - - /* note: success => None, failure => string with error message */ - Py_RETURN_NONE; - LLVMPY_CATCH_ALL -} - -static PyObject * -_wLLVMParseEnvOpts(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - const char * progname; - const char * envname; - if(!PyArg_ParseTuple(args, "ss", &progname, &envname)) { - return NULL; - } - - llvm::cl::ParseEnvironmentOptions(progname, envname); - - Py_RETURN_NONE; - LLVMPY_CATCH_ALL -} - -_wrap_obj2obj(LLVMInlineFunction, LLVMValueRef, int) - -_wrap_none2str(LLVMDefaultTargetTriple) - - -/* Expose the void* inside a PyCObject as a PyLong. This allows us to - * use it as a unique ID. */ -static PyObject * -_wPyCObjectVoidPtrToPyLong(PyObject *self, PyObject *args) -{ - LLVMPY_TRY - void *p = get_object_arg(args); - return PyLong_FromVoidPtr(p); - LLVMPY_CATCH_ALL -} - - -/*===----------------------------------------------------------------------===*/ -/* Python member method table */ -/*===----------------------------------------------------------------------===*/ - -#define _method( func ) { # func , ( PyCFunction )_w ## func , METH_VARARGS , NULL }, -#define _pass( P ) _method( LLVMAdd ## P ## Pass ) - -static PyMethodDef core_methods[] = { - - /* Modules */ - _method( LLVMModuleCreateWithName ) - _method( LLVMGetDataLayout ) - _method( LLVMSetDataLayout ) - _method( LLVMGetModuleIdentifier ) - _method( LLVMSetModuleIdentifier ) - _method( LLVMGetTarget ) - _method( LLVMSetTarget ) - _method( LLVMModuleAddLibrary ) - _method( LLVMGetTypeByName ) - _method( LLVMDumpModule ) - _method( LLVMDisposeModule ) - _method( LLVMDumpModuleToString ) - _method( LLVMVerifyModule ) - _method( LLVMGetModuleFromAssembly ) - _method( LLVMGetModuleFromBitcode ) - _method( LLVMGetBitcodeFromModule ) - _method( LLVMGetNativeCodeFromModule ) - _method( LLVMModuleGetPointerSize ) - _method( LLVMModuleGetOrInsertFunction ) - _method( LLVMLinkModules ) - _method( LLVMModuleGetOrInsertNamedMetaData ) - _method( LLVMModuleGetNamedMetaData ) - _method( LLVMCloneModule ) - - /* Types */ - - /* General */ - _method( LLVMGetTypeKind ) - _method( LLVMDumpTypeToString ) - - /* Integer types */ - _method( LLVMInt1Type ) - _method( LLVMInt8Type ) - _method( LLVMInt16Type ) - _method( LLVMInt32Type ) - _method( LLVMInt64Type ) - _method( LLVMIntType ) - _method( LLVMGetIntTypeWidth ) - - /* Floating-point types */ - _method( LLVMFloatType ) - _method( LLVMDoubleType ) - _method( LLVMX86FP80Type ) - _method( LLVMFP128Type ) - _method( LLVMPPCFP128Type ) - - /* Function types */ - _method( LLVMFunctionType ) - _method( LLVMIsFunctionVarArg ) - _method( LLVMGetReturnType ) - _method( LLVMCountParamTypes ) - _method( LLVMGetFunctionTypeParams ) - - /* Struct types */ - _method( LLVMStructType ) - _method( LLVMStructTypeIdentified ) - _method( LLVMSetStructBody ) - _method( LLVMCountStructElementTypes ) - _method( LLVMGetStructElementTypes ) - _method( LLVMIsPackedStruct ) - _method( LLVMIsOpaqueStruct ) - _method( LLVMIsLiteralStruct ) - _method( LLVMGetStructName ) - _method( LLVMSetStructName ) - - /* Array types */ - _method( LLVMArrayType ) - _method( LLVMGetElementType ) - _method( LLVMGetArrayLength ) - - /* Pointer types */ - _method( LLVMPointerType ) - _method( LLVMGetPointerAddressSpace ) - - /* Vector type */ - _method( LLVMVectorType ) - _method( LLVMGetVectorSize ) - - /* Other types */ - _method( LLVMVoidType ) - _method( LLVMLabelType ) - - /* Type handles */ - /* - _method( LLVMResolveTypeHandle ) - _method( LLVMDisposeTypeHandle ) - */ - - /* Values */ - - /* Operations on all values */ - _method( LLVMTypeOf ) - _method( LLVMGetValueName ) - _method( LLVMSetValueName ) - _method( LLVMDumpValue ) - _method( LLVMDumpValueToString ) - _method( LLVMValueGetID ) - _method( LLVMValueGetNumUses ) - _method( LLVMValueGetUses ) - - /* Users */ - - _method( LLVMUserGetNumOperands ) - _method( LLVMUserGetOperand ) - - /* Constant Values */ - - /* Operations on constants of any type */ - _method( LLVMConstNull ) - _method( LLVMConstAllOnes ) - _method( LLVMGetUndef ) - _method( LLVMIsConstant ) - _method( LLVMIsNull ) - _method( LLVMIsUndef ) - - /* Operations on scalar constants */ - _method( LLVMConstInt ) - _method( LLVMConstReal ) - _method( LLVMConstRealOfString ) - _method( LLVMConstIntGetZExtValue ) - _method( LLVMConstIntGetSExtValue ) - - /* Operations on composite constants */ - _method( LLVMConstString ) - _method( LLVMConstArray ) - _method( LLVMConstStruct ) - _method( LLVMConstVector ) - - /* Constant expressions */ - _method( LLVMGetConstExprOpcode ) - _method( LLVMGetConstExprOpcodeName ) - _method( LLVMSizeOf ) - _method( LLVMConstNeg ) - _method( LLVMConstNot ) - _method( LLVMConstAdd ) - _method( LLVMConstFAdd ) - _method( LLVMConstSub ) - _method( LLVMConstFSub ) - _method( LLVMConstMul ) - _method( LLVMConstFMul ) - _method( LLVMConstUDiv ) - _method( LLVMConstSDiv ) - _method( LLVMConstFDiv ) - _method( LLVMConstURem ) - _method( LLVMConstSRem ) - _method( LLVMConstFRem ) - _method( LLVMConstAnd ) - _method( LLVMConstOr ) - _method( LLVMConstXor ) - _method( LLVMConstICmp ) - _method( LLVMConstFCmp ) - _method( LLVMConstShl ) - _method( LLVMConstLShr ) - _method( LLVMConstAShr ) - _method( LLVMConstGEP ) - _method( LLVMConstTrunc ) - _method( LLVMConstSExt ) - _method( LLVMConstZExt ) - _method( LLVMConstFPTrunc ) - _method( LLVMConstFPExt ) - _method( LLVMConstUIToFP ) - _method( LLVMConstSIToFP ) - _method( LLVMConstFPToUI ) - _method( LLVMConstFPToSI ) - _method( LLVMConstPtrToInt ) - _method( LLVMConstIntToPtr ) - _method( LLVMConstBitCast ) - _method( LLVMConstSelect ) - _method( LLVMConstExtractElement ) - _method( LLVMConstInsertElement ) - _method( LLVMConstShuffleVector ) - - /* Globals */ - - /* Globals (general) */ - _method( LLVMGetGlobalParent ) - _method( LLVMIsDeclaration ) - _method( LLVMGetLinkage ) - _method( LLVMSetLinkage ) - _method( LLVMGetSection ) - _method( LLVMSetSection ) - _method( LLVMGetVisibility ) - _method( LLVMSetVisibility ) - _method( LLVMGetAlignment ) - _method( LLVMSetAlignment ) - - /* Global Variables */ - _method( LLVMAddGlobal ) - _method( LLVMAddGlobalInAddressSpace ) - _method( LLVMGetNamedGlobal ) - _method( LLVMGetFirstGlobal ) - _method( LLVMGetNextGlobal ) - _method( LLVMDeleteGlobal ) - _method( LLVMHasInitializer ) - _method( LLVMGetInitializer ) - _method( LLVMSetInitializer ) - _method( LLVMSetThreadLocal ) - _method( LLVMIsThreadLocal ) - _method( LLVMSetGlobalConstant ) - _method( LLVMIsGlobalConstant ) - - /* Functions */ - _method( LLVMAddFunction ) - _method( LLVMGetNamedFunction ) - _method( LLVMGetFirstFunction ) - _method( LLVMGetNextFunction ) - _method( LLVMDeleteFunction ) - _method( LLVMGetIntrinsicID ) - _method( LLVMGetFunctionCallConv ) - _method( LLVMSetFunctionCallConv ) - _method( LLVMGetGC ) - _method( LLVMSetGC ) - _method( LLVMGetDoesNotThrow ) - _method( LLVMSetDoesNotThrow ) - _method( LLVMVerifyFunction ) - _method( LLVMViewFunctionCFG ) - _method( LLVMViewFunctionCFGOnly ) - _method( LLVMAddFunctionAttr ) - _method( LLVMRemoveFunctionAttr ) - _method( LLVMGetFunctionFromInlineAsm ) - - /* Arguments */ - _method( LLVMCountParams ) - _method( LLVMGetFirstParam ) - _method( LLVMGetNextParam ) - _method( LLVMGetParamParent ) - _method( LLVMAddAttribute ) - _method( LLVMRemoveAttribute ) - _method( LLVMSetParamAlignment ) - _method( LLVMGetParamAlignment ) - - /* Basic Blocks */ - _method( LLVMGetBasicBlockParent ) - _method( LLVMCountBasicBlocks ) - _method( LLVMGetFirstBasicBlock ) - _method( LLVMGetNextBasicBlock ) - _method( LLVMGetEntryBasicBlock ) - _method( LLVMAppendBasicBlock ) - _method( LLVMInsertBasicBlock ) - _method( LLVMDeleteBasicBlock ) - - /* MetaData */ - _method( LLVMMetaDataGet ) - _method( LLVMGetNamedMetadataOperands ) - _method( LLVMAddNamedMetadataOperand ) - _method( LLVMMetaDataGetOperand ) - _method( LLVMMetaDataGetNumOperands ) - _method( LLVMMetaDataStringGet ) - - /* NamedMetaData */ - _method( LLVMNamedMetaDataGetName ) - _method( LLVMNamedMetaDataAddOperand ) - _method( LLVMEraseNamedMetaData ) - _method( LLVMDumpNamedMDToString ) - - /* Instructions */ - _method( LLVMGetInstructionParent ) - _method( LLVMGetFirstInstruction ) - _method( LLVMGetNextInstruction ) - _method( LLVMInstIsTerminator ) - _method( LLVMInstIsBinaryOp ) - _method( LLVMInstIsShift ) - _method( LLVMInstIsCast ) - _method( LLVMInstIsLogicalShift ) - _method( LLVMInstIsArithmeticShift ) - _method( LLVMInstIsAssociative ) - _method( LLVMInstIsCommutative ) - _method( LLVMInstIsVolatile ) - _method( LLVMSetVolatile ) - _method( LLVMInstGetOpcode ) - _method( LLVMInstGetOpcodeName ) - - _method( LLVMInstSetMetaData ) - _method( LLVMInstructionEraseFromParent ) - - /* Call Sites (Call or Invoke) */ - _method( LLVMSetInstructionCallConv ) - _method( LLVMGetInstructionCallConv ) - _method( LLVMIsTailCall ) - _method( LLVMSetTailCall ) - _method( LLVMAddInstrAttribute ) - _method( LLVMRemoveInstrAttribute ) - _method( LLVMSetInstrParamAlignment ) - _method( LLVMInstGetCalledFunction ) - _method( LLVMInstSetCalledFunction ) - - /* PHI Nodes */ - _method( LLVMAddIncoming1 ) - _method( LLVMCountIncoming ) - _method( LLVMGetIncomingValue ) - _method( LLVMGetIncomingBlock ) - - /* Comparison Instructions */ - _method( LLVMCmpInstGetPredicate ) - - /* Instruction builders */ - _method( LLVMCreateBuilder ) - _method( LLVMPositionBuilderBefore ) - _method( LLVMPositionBuilderAtEnd ) - _method( LLVMGetInsertBlock ) - _method( LLVMDisposeBuilder ) - - /* Terminators */ - _method( LLVMBuildRetVoid ) - _method( LLVMBuildRet ) - _method( LLVMBuildRetMultiple ) - _method( LLVMBuildBr ) - _method( LLVMBuildCondBr ) - _method( LLVMBuildSwitch ) - _method( LLVMBuildInvoke ) - _method( LLVMBuildUnreachable ) - - /* Add a case to the switch instruction */ - _method( LLVMAddCase ) - - /* Arithmetic */ - _method( LLVMBuildAdd ) - _method( LLVMBuildFAdd) - _method( LLVMBuildSub ) - _method( LLVMBuildFSub) - _method( LLVMBuildMul ) - _method( LLVMBuildFMul) - _method( LLVMBuildUDiv ) - _method( LLVMBuildSDiv ) - _method( LLVMBuildFDiv ) - _method( LLVMBuildURem ) - _method( LLVMBuildSRem ) - _method( LLVMBuildFRem ) - _method( LLVMBuildShl ) - _method( LLVMBuildLShr ) - _method( LLVMBuildAShr ) - _method( LLVMBuildAnd ) - _method( LLVMBuildOr ) - _method( LLVMBuildXor ) - _method( LLVMBuildNeg ) - _method( LLVMBuildNot ) - - /* Memory */ - _method( LLVMBuildMalloc ) - _method( LLVMBuildArrayMalloc ) - _method( LLVMBuildAlloca ) - _method( LLVMBuildArrayAlloca ) - _method( LLVMBuildFree ) - _method( LLVMBuildLoad ) - _method( LLVMBuildStore ) - _method( LLVMBuildGEP ) - _method( LLVMBuildInBoundsGEP ) - - _method( LLVMLdSetAlignment ) - _method( LLVMStSetAlignment ) - - /* Casts */ - _method( LLVMBuildTrunc ) - _method( LLVMBuildZExt ) - _method( LLVMBuildSExt ) - _method( LLVMBuildFPToUI ) - _method( LLVMBuildFPToSI ) - _method( LLVMBuildUIToFP ) - _method( LLVMBuildSIToFP ) - _method( LLVMBuildFPTrunc ) - _method( LLVMBuildFPExt ) - _method( LLVMBuildPtrToInt ) - _method( LLVMBuildIntToPtr ) - _method( LLVMBuildBitCast ) - - /* Comparisons */ - _method( LLVMBuildICmp ) - _method( LLVMBuildFCmp ) - - /* Atomics */ - _method( LLVMBuildAtomicCmpXchg ) - _method( LLVMBuildAtomicRMW ) - _method( LLVMBuildAtomicLoad ) - _method( LLVMBuildAtomicStore ) - _method( LLVMBuildFence ) - - /* Miscellaneous instructions */ - _method( LLVMBuildGetResult ) - _method( LLVMBuildInsertValue ) - _method( LLVMBuildPhi ) - _method( LLVMBuildCall ) - _method( LLVMBuildSelect ) - _method( LLVMBuildVAArg ) - _method( LLVMBuildExtractElement ) - _method( LLVMBuildInsertElement ) - _method( LLVMBuildShuffleVector ) - - /* Memory Buffer */ - _method( LLVMCreateMemoryBufferWithContentsOfFile ) - _method( LLVMCreateMemoryBufferWithSTDIN ) - _method( LLVMDisposeMemoryBuffer ) - - /* Pass Manager Builder */ - - _method( LLVMPassManagerBuilderCreate ) - _method( LLVMPassManagerBuilderDispose ) - - _method( LLVMPassManagerBuilderSetOptLevel ) - _method( LLVMPassManagerBuilderGetOptLevel ) - - _method( LLVMPassManagerBuilderSetSizeLevel ) - _method( LLVMPassManagerBuilderGetSizeLevel ) - - _method( LLVMPassManagerBuilderSetVectorize ) - _method( LLVMPassManagerBuilderGetVectorize ) -#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 2 - _method( LLVMPassManagerBuilderSetLoopVectorize ) - _method( LLVMPassManagerBuilderGetLoopVectorize ) -#endif // llvm-3.2 - - _method( LLVMPassManagerBuilderSetDisableUnitAtATime ) - _method( LLVMPassManagerBuilderGetDisableUnitAtATime ) - - _method( LLVMPassManagerBuilderSetDisableUnrollLoops ) - _method( LLVMPassManagerBuilderGetDisableUnrollLoops ) - - _method( LLVMPassManagerBuilderSetDisableSimplifyLibCalls ) - _method( LLVMPassManagerBuilderGetDisableSimplifyLibCalls ) - - _method( LLVMPassManagerBuilderUseInlinerWithThreshold ) - - _method( LLVMPassManagerBuilderPopulateFunctionPassManager ) - _method( LLVMPassManagerBuilderPopulateModulePassManager ) - - /* Pass Manager */ - _method( LLVMCreatePassManager ) - _method( LLVMCreateFunctionPassManagerForModule ) - _method( LLVMRunPassManager ) - _method( LLVMInitializeFunctionPassManager ) - _method( LLVMRunFunctionPassManager ) - _method( LLVMFinalizeFunctionPassManager ) - _method( LLVMDisposePassManager ) - _method( LLVMDumpPasses ) - _method( LLVMAddPassByName ) - _method( LLVMAddPass ) - _method( LLVMInitializePasses ) - - _method( LLVMInitializeNativeTarget ) - _method( LLVMInitializeNativeTargetAsmPrinter ) -#if !defined(LLVM_DISABLE_PTX) -# if LLVM_HAS_NVPTX - _method( LLVMInitializeNVPTXTarget ) - _method( LLVMInitializeNVPTXTargetInfo ) - _method( LLVMInitializeNVPTXTargetMC ) - _method( LLVMInitializeNVPTXAsmPrinter ) -# else - _method( LLVMInitializePTXTarget ) - _method( LLVMInitializePTXTargetInfo ) - _method( LLVMInitializePTXTargetMC ) - _method( LLVMInitializePTXAsmPrinter ) -# endif -#endif - - /* Target Machine */ - _method( LLVMTargetMachineFromEngineBuilder ) - _method( LLVMDisposeTargetMachine ) - _method( LLVMCreateTargetMachine ) - _method( LLVMTargetMachineLookup ) - _method( LLVMTargetMachineEmitFile ) - _method( LLVMTargetMachineGetTargetData ) - _method( LLVMTargetMachineGetTargetName ) - _method( LLVMTargetMachineGetTargetShortDescription ) - _method( LLVMTargetMachineGetTriple ) - _method( LLVMTargetMachineGetCPU ) - _method( LLVMTargetMachineGetFS ) - - _method( LLVMPrintRegisteredTargetsForVersion ) - _method( LLVMGetHostCPUName ) - - /* Target Data */ - _method( LLVMCreateTargetData ) - _method( LLVMDisposeTargetData ) - _method( LLVMTargetDataAsString ) - _method( LLVMAddTargetData ) - _method( LLVMByteOrder ) - _method( LLVMPointerSize ) - _method( LLVMIntPtrType ) - _method( LLVMSizeOfTypeInBits ) - _method( LLVMStoreSizeOfType ) - _method( LLVMABISizeOfType ) - _method( LLVMABIAlignmentOfType ) - _method( LLVMCallFrameAlignmentOfType ) - _method( LLVMPreferredAlignmentOfType ) - _method( LLVMPreferredAlignmentOfGlobal ) - _method( LLVMElementAtOffset ) - _method( LLVMOffsetOfElement ) - - /* Engine Builder */ - - _method( LLVMCreateEngineBuilder ) - _method( LLVMDisposeEngineBuilder ) - _method( LLVMEngineBuilderForceJIT ) - _method( LLVMEngineBuilderForceInterpreter ) - _method( LLVMEngineBuilderSetOptLevel ) - _method( LLVMEngineBuilderSetMCPU ) - _method( LLVMEngineBuilderSetMAttrs ) - _method( LLVMEngineBuilderCreate ) - _method( LLVMEngineBuilderCreateTM ) - - /* Execution Engine */ -// Use EngineBuilder instead -// _method( LLVMCreateExecutionEngine ) - _method( LLVMDisposeExecutionEngine ) - _method( LLVMExecutionEngineDisableLazyCompilation ) - _method( LLVMRunFunction2 ) - _method( LLVMGetPointerToFunction ) - _method( LLVMGetPointerToGlobal ) - _method( LLVMAddGlobalMapping ) - _method( LLVMGetExecutionEngineTargetData ) - _method( LLVMRunStaticConstructors ) - _method( LLVMRunStaticDestructors ) - _method( LLVMFreeMachineCodeForFunction ) - _method( LLVMAddModule ) - _method( LLVMRemoveModule2 ) - - /* Generic Value */ - _method( LLVMCreateGenericValueOfInt ) - _method( LLVMCreateGenericValueOfFloat ) - _method( LLVMCreateGenericValueOfPointer ) - _method( LLVMGenericValueToInt ) - _method( LLVMGenericValueToFloat ) - _method( LLVMGenericValueToPointer ) - _method( LLVMDisposeGenericValue ) - - /* Passes */ - _method( LLVMCreatePassByName ) - _method( LLVMDisposePass ) - _method( LLVMGetPassName ) - _method( LLVMPassDump ) - - _method( LLVMCreateTargetLibraryInfo ) - -#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 2 - _method( LLVMCreateTargetTransformInfo ) -#endif - - /* Misc */ - _method( LLVMGetVersion ) - _method( LLVMGetIntrinsic ) - _method( LLVMLoadLibraryPermanently ) - _method( LLVMParseEnvOpts ) - _method( LLVMDefaultTargetTriple ) - _method( LLVMInlineFunction ) - _method( PyCObjectVoidPtrToPyLong ) - { NULL } -}; - - - -// Module main function, hairy because of py3k port -extern "C" { - -#if (PY_MAJOR_VERSION >= 3) -struct PyModuleDef module_def = { - PyModuleDef_HEAD_INIT, - "_core", - NULL, - -1, - core_methods, - NULL, NULL, NULL, NULL -}; -#define INITERROR return NULL -PyObject * -PyInit__core(void) -#else -#define INITERROR return -PyMODINIT_FUNC -init_core(void) -#endif -{ - LLVMLinkInJIT(); - LLVMLinkInInterpreter(); - LLVMInitializeNativeTarget(); -#if PY_MAJOR_VERSION >= 3 - PyObject *module = PyModule_Create( &module_def ); -#else - PyObject *module = Py_InitModule("_core", core_methods); -#endif - if (module == NULL) - INITERROR; -#if PY_MAJOR_VERSION >= 3 - - return module; -#endif -} - -} // end extern C diff --git a/llvm/_dwarf.cpp b/llvm/_dwarf.cpp deleted file mode 100644 index 43f75aa..0000000 --- a/llvm/_dwarf.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include -#include - -namespace llvmpy { -namespace dwarf { - -using namespace llvm::dwarf; - -const char *constant_names[] = { - "LLVMDebugVersion", - - #define define(x) #x, - #include "_dwarf.h" - #undef define -}; - -int constant_values[] = { - llvm::LLVMDebugVersion, - - #define define(x) x, - #include "_dwarf.h" - #undef define -}; - -enum enum_values { - __llvmpy_LLVMDebugVersion, - - #define define(x) __llvmpy_##x, - #include "_dwarf.h" - #undef define - - NVALUES /* Get the number of constants */ -}; - -} // End namespace dwarf - -int -set_dwarf_constants(PyObject *module) -{ - int i; - for (i = 0; i < dwarf::NVALUES; i++) { - if (PyModule_AddIntConstant(module, dwarf::constant_names[i], - dwarf::constant_values[i]) > 0) - return -1; - } - - return 0; -} - -} // End namespace llvmpy - -#if (PY_MAJOR_VERSION >= 3) - struct PyModuleDef module_def = { - PyModuleDef_HEAD_INIT, - "_dwarf", - NULL, - -1, - NULL, /* m_methods */ - NULL, /* m_reload */ - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL, /* m_free */ - }; - - #define INITERROR return NULL - PyObject *PyInit__dwarf(void) -#else - #define INITERROR return - PyMODINIT_FUNC init_dwarf(void) -#endif -{ -#if PY_MAJOR_VERSION >= 3 - PyObject *module = PyModule_Create( &module_def ); -#else - PyObject *module = Py_InitModule("_dwarf", NULL); -#endif - if (module == NULL) - INITERROR; - - if (llvmpy::set_dwarf_constants(module) < 0) - INITERROR; - -#if PY_MAJOR_VERSION >= 3 - return module; -#endif -} diff --git a/llvm/_dwarf.h b/llvm/_dwarf.h deleted file mode 100644 index 78eada0..0000000 --- a/llvm/_dwarf.h +++ /dev/null @@ -1,101 +0,0 @@ -/* Dwarf constant wrapping. See include/llvm/Support/Dwarf.h */ - -define(DWARF_VERSION) - -/* Dwarf tags */ -define(DW_TAG_array_type) -define(DW_TAG_class_type) -define(DW_TAG_entry_point) -define(DW_TAG_enumeration_type) -define(DW_TAG_formal_parameter) -define(DW_TAG_imported_declaration) -define(DW_TAG_label) -define(DW_TAG_lexical_block) -define(DW_TAG_member) -define(DW_TAG_pointer_type) -define(DW_TAG_reference_type) -define(DW_TAG_compile_unit) -define(DW_TAG_string_type) -define(DW_TAG_structure_type) -define(DW_TAG_subroutine_type) -define(DW_TAG_typedef) -define(DW_TAG_union_type) -define(DW_TAG_unspecified_parameters) -define(DW_TAG_variant) -define(DW_TAG_common_block) -define(DW_TAG_common_inclusion) -define(DW_TAG_inheritance) -define(DW_TAG_inlined_subroutine) -define(DW_TAG_module) -define(DW_TAG_ptr_to_member_type) -define(DW_TAG_set_type) -define(DW_TAG_subrange_type) -define(DW_TAG_with_stmt) -define(DW_TAG_access_declaration) -define(DW_TAG_base_type) -define(DW_TAG_catch_block) -define(DW_TAG_const_type) -define(DW_TAG_constant) -define(DW_TAG_enumerator) -define(DW_TAG_file_type) -define(DW_TAG_friend) -define(DW_TAG_namelist) -define(DW_TAG_namelist_item) -define(DW_TAG_packed_type) -define(DW_TAG_subprogram) -define(DW_TAG_template_type_parameter) -define(DW_TAG_template_value_parameter) -define(DW_TAG_thrown_type) -define(DW_TAG_try_block) -define(DW_TAG_variant_part) -define(DW_TAG_variable) -define(DW_TAG_volatile_type) -define(DW_TAG_dwarf_procedure) -define(DW_TAG_restrict_type) -define(DW_TAG_interface_type) -define(DW_TAG_namespace) -define(DW_TAG_imported_module) -define(DW_TAG_unspecified_type) -define(DW_TAG_partial_unit) -define(DW_TAG_imported_unit) -define(DW_TAG_condition) -define(DW_TAG_shared_type) -define(DW_TAG_type_unit) -define(DW_TAG_rvalue_reference_type) -define(DW_TAG_template_alias) -define(DW_TAG_MIPS_loop) -define(DW_TAG_format_label) -define(DW_TAG_function_template) -define(DW_TAG_class_template) -define(DW_TAG_GNU_template_template_param) -define(DW_TAG_GNU_template_parameter_pack) -define(DW_TAG_GNU_formal_parameter_pack) -define(DW_TAG_lo_user) -define(DW_TAG_APPLE_property) -define(DW_TAG_hi_user) - -/* Dwarf language constants */ -define(DW_LANG_C89) -define(DW_LANG_C) -define(DW_LANG_Ada83) -define(DW_LANG_C_plus_plus) -define(DW_LANG_Cobol74) -define(DW_LANG_Cobol85) -define(DW_LANG_Fortran77) -define(DW_LANG_Fortran90) -define(DW_LANG_Pascal83) -define(DW_LANG_Modula2) -define(DW_LANG_Java) -define(DW_LANG_C99) -define(DW_LANG_Ada95) -define(DW_LANG_Fortran95) -define(DW_LANG_PLI) -define(DW_LANG_ObjC) -define(DW_LANG_ObjC_plus_plus) -define(DW_LANG_UPC) -define(DW_LANG_D) -define(DW_LANG_Python) -define(DW_LANG_lo_user) -define(DW_LANG_Mips_Assembler) -define(DW_LANG_hi_user) - diff --git a/llvm/_util.py b/llvm/_util.py deleted file mode 100644 index da003b0..0000000 --- a/llvm/_util.py +++ /dev/null @@ -1,108 +0,0 @@ -# -# Copyright (c) 2008-10, Mahadevan R All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of this software, nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - -"""Utility functions and classes. - -Used only in other modules, not for public use.""" - -import llvm -import llvm._core as _core # for PyCObjectVoidPtrToPyLong - - -#===----------------------------------------------------------------------=== -# A set of helpers to check various things. Raises exceptions on -# failures. -#===----------------------------------------------------------------------=== - -def check_gen(obj, typ): - if not isinstance(obj, typ): - typ_str = typ.__name__ - msg = "argument not an instance of llvm.core.%s" % typ_str - raise TypeError(msg) - -def check_is_unowned(ownable): - if ownable.owner: - raise llvm.LLVMException("object is already owned") - - -#===----------------------------------------------------------------------=== -# A set of helpers to unpack a list of Python wrapper objects -# into a list of PyCObject wrapped objects, checking types along -# the way. -#===----------------------------------------------------------------------=== - -def unpack_gen(objlist, check_fn): - for obj in objlist: check_fn(obj) - return [ obj.ptr for obj in objlist ] - -def unpack_gen_allow_none(objlist, check_fn): - for obj in objlist: - if obj is not None: - check_fn(obj) - return [ (obj.ptr if obj is not None else None) for obj in objlist ] - -#===----------------------------------------------------------------------=== -# Helper to wrap over iterables (LLVMFirstXXX, LLVMNextXXX). This used -# to be a generator, but that loses subscriptability of the result, so -# we now return a list. -#===----------------------------------------------------------------------=== - -def wrapiter(first, next, container, wrapper): - ret = [] - ptr = first(container) - while ptr: - ret.append(wrapper(ptr)) - ptr = next(ptr) - return ret - - -#===----------------------------------------------------------------------=== -# Py2/3 compatibility string check -#===----------------------------------------------------------------------=== -def _isstring_py2(x): - return isinstance(x, basestring) - -def _isstring_py3(x): - return isinstance(x, str) - -def _isstring_choose(): - try: - basestring - return _isstring_py2 - except: - return _isstring_py3 - -isstring = _isstring_choose() - -try: - unicode_type = unicode -except NameError: # Py3 - unicode_type = str - diff --git a/llvm/_version.py b/llvm/_version.py deleted file mode 100644 index a90c5b8..0000000 --- a/llvm/_version.py +++ /dev/null @@ -1,193 +0,0 @@ - -IN_LONG_VERSION_PY = True -# This file helps to compute a version number in source trees obtained from -# git-archive tarball (such as those provided by github's download-from-tag -# feature). Distribution tarballs (build by setup.py sdist) and build -# directories (produced by setup.py build) will contain a much shorter file -# that just contains the computed version number. - -# This file is released into the public domain. Generated by -# versioneer-0.7+ (https://github.com/warner/python-versioneer) - -# these strings will be replaced by git during git-archive -git_refnames = "$Format:%d$" -git_full = "$Format:%H$" -GIT = "git" - -import subprocess -import sys - -def run_command(args, cwd=None, verbose=False): - try: - # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd) - except EnvironmentError: - e = sys.exc_info()[1] - if verbose: - print("unable to run %s" % args[0]) - print(e) - return None - stdout = p.communicate()[0].strip() - if sys.version >= '3': - stdout = stdout.decode() - if p.returncode != 0: - if verbose: - print("unable to run %s (error)" % args[0]) - return None - return stdout - - -import sys -import re -import os.path - -def get_expanded_variables(versionfile_source): - # the code embedded in _version.py can just fetch the value of these - # variables. When used from setup.py, we don't want to import - # _version.py, so we do it with a regexp instead. This function is not - # used from _version.py. - variables = {} - try: - for line in open(versionfile_source,"r").readlines(): - if line.strip().startswith("git_refnames ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - variables["refnames"] = mo.group(1) - if line.strip().startswith("git_full ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - variables["full"] = mo.group(1) - except EnvironmentError: - pass - return variables - -def versions_from_expanded_variables(variables, tag_prefix, verbose=False): - refnames = variables["refnames"].strip() - if refnames.startswith("$Format"): - if verbose: - print("variables are unexpanded, not using") - return {} # unexpanded, so not in an unpacked git-archive tarball - refs = set([r.strip() for r in refnames.strip("()").split(",")]) - for ref in list(refs): - if not re.search(r'\d', ref): - if verbose: - print("discarding '%s', no digits" % ref) - refs.discard(ref) - # Assume all version tags have a digit. git's %d expansion - # behaves like git log --decorate=short and strips out the - # refs/heads/ and refs/tags/ prefixes that would let us - # distinguish between branches and tags. By ignoring refnames - # without digits, we filter out many common branch names like - # "release" and "stabilization", as well as "HEAD" and "master". - if verbose: - print("remaining refs: %s" % ",".join(sorted(refs))) - for ref in sorted(refs): - # sorting will prefer e.g. "2.0" over "2.0rc1" - if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] - if verbose: - print("picking %s" % r) - return { "version": r, - "full": variables["full"].strip() } - # no suitable tags, so we use the full revision id - if verbose: - print("no suitable tags, using full revision id") - return { "version": variables["full"].strip(), - "full": variables["full"].strip() } - -def versions_from_vcs(tag_prefix, versionfile_source, verbose=False): - # this runs 'git' from the root of the source tree. That either means - # someone ran a setup.py command (and this code is in versioneer.py, so - # IN_LONG_VERSION_PY=False, thus the containing directory is the root of - # the source tree), or someone ran a project-specific entry point (and - # this code is in _version.py, so IN_LONG_VERSION_PY=True, thus the - # containing directory is somewhere deeper in the source tree). This only - # gets called if the git-archive 'subst' variables were *not* expanded, - # and _version.py hasn't already been rewritten with a short version - # string, meaning we're inside a checked out source tree. - - try: - here = os.path.abspath(__file__) - except NameError: - # some py2exe/bbfreeze/non-CPython implementations don't do __file__ - return {} # not always correct - - # versionfile_source is the relative path from the top of the source tree - # (where the .git directory might live) to this file. Invert this to find - # the root from __file__. - root = here - if IN_LONG_VERSION_PY: - for i in range(len(versionfile_source.split("/"))): - root = os.path.dirname(root) - else: - root = os.path.dirname(here) - if not os.path.exists(os.path.join(root, ".git")): - if verbose: - print("no .git in %s" % root) - return {} - - stdout = run_command([GIT, "describe", "--tags", "--dirty", "--always"], - cwd=root) - if stdout is None: - return {} - if not stdout.startswith(tag_prefix): - if verbose: - print("tag '%s' doesn't start with prefix '%s'" % (stdout, tag_prefix)) - return {} - tag = stdout[len(tag_prefix):] - stdout = run_command([GIT, "rev-parse", "HEAD"], cwd=root) - if stdout is None: - return {} - full = stdout.strip() - if tag.endswith("-dirty"): - full += "-dirty" - return {"version": tag, "full": full} - - -def versions_from_parentdir(parentdir_prefix, versionfile_source, verbose=False): - if IN_LONG_VERSION_PY: - # We're running from _version.py. If it's from a source tree - # (execute-in-place), we can work upwards to find the root of the - # tree, and then check the parent directory for a version string. If - # it's in an installed application, there's no hope. - try: - here = os.path.abspath(__file__) - except NameError: - # py2exe/bbfreeze/non-CPython don't have __file__ - return {} # without __file__, we have no hope - # versionfile_source is the relative path from the top of the source - # tree to _version.py. Invert this to find the root from __file__. - root = here - for i in range(len(versionfile_source.split("/"))): - root = os.path.dirname(root) - else: - # we're running from versioneer.py, which means we're running from - # the setup.py in a source tree. sys.argv[0] is setup.py in the root. - here = os.path.abspath(sys.argv[0]) - root = os.path.dirname(here) - - # Source tarballs conventionally unpack into a directory that includes - # both the project name and a version string. - dirname = os.path.basename(root) - if not dirname.startswith(parentdir_prefix): - if verbose: - print("guessing rootdir is '%s', but '%s' doesn't start with prefix '%s'" % - (root, dirname, parentdir_prefix)) - return None - return {"version": dirname[len(parentdir_prefix):], "full": ""} - -tag_prefix = "" -parentdir_prefix = "llvmpy-" -versionfile_source = "llvm/_version.py" - -def get_versions(default={"version": "unknown", "full": ""}, verbose=False): - variables = { "refnames": git_refnames, "full": git_full } - ver = versions_from_expanded_variables(variables, tag_prefix, verbose) - if not ver: - ver = versions_from_vcs(tag_prefix, versionfile_source, verbose) - if not ver: - ver = versions_from_parentdir(parentdir_prefix, versionfile_source, - verbose) - if not ver: - ver = default - return ver diff --git a/llvm/capsulethunk.h b/llvm/capsulethunk.h deleted file mode 100644 index 6b20564..0000000 --- a/llvm/capsulethunk.h +++ /dev/null @@ -1,134 +0,0 @@ -#ifndef __CAPSULETHUNK_H -#define __CAPSULETHUNK_H - -#if ( (PY_VERSION_HEX < 0x02070000) \ - || ((PY_VERSION_HEX >= 0x03000000) \ - && (PY_VERSION_HEX < 0x03010000)) ) - -#define __PyCapsule_GetField(capsule, field, default_value) \ - ( PyCapsule_CheckExact(capsule) \ - ? (((PyCObject *)capsule)->field) \ - : (default_value) \ - ) \ - -#define __PyCapsule_SetField(capsule, field, value) \ - ( PyCapsule_CheckExact(capsule) \ - ? (((PyCObject *)capsule)->field = value), 1 \ - : 0 \ - ) \ - - -#define PyCapsule_Type PyCObject_Type - -#define PyCapsule_CheckExact(capsule) (PyCObject_Check(capsule)) -#define PyCapsule_IsValid(capsule, name) (PyCObject_Check(capsule)) - - -#define PyCapsule_New(pointer, name, destructor) \ - (PyCObject_FromVoidPtr(pointer, destructor)) - - -#define PyCapsule_GetPointer(capsule, name) \ - (PyCObject_AsVoidPtr(capsule)) - -/* Don't call PyCObject_SetPointer here, it fails if there's a destructor */ -#define PyCapsule_SetPointer(capsule, pointer) \ - __PyCapsule_SetField(capsule, cobject, pointer) - - -#define PyCapsule_GetDestructor(capsule) \ - __PyCapsule_GetField(capsule, destructor) - -#define PyCapsule_SetDestructor(capsule, dtor) \ - __PyCapsule_SetField(capsule, destructor, dtor) - - -/* - * Sorry, there's simply no place - * to store a Capsule "name" in a CObject. - */ -#define PyCapsule_GetName(capsule) NULL - -static int -PyCapsule_SetName(PyObject *capsule, const char *unused) -{ - unused = unused; - PyErr_SetString(PyExc_NotImplementedError, - "can't use PyCapsule_SetName with CObjects"); - return 1; -} - - - -#define PyCapsule_GetContext(capsule) \ - __PyCapsule_GetField(capsule, descr) - -#define PyCapsule_SetContext(capsule, context) \ - __PyCapsule_SetField(capsule, descr, context) - - -static void * -PyCapsule_Import(const char *name, int no_block) -{ - PyObject *object = NULL; - void *return_value = NULL; - char *trace; - size_t name_length = (strlen(name) + 1) * sizeof(char); - char *name_dup = (char *)PyMem_MALLOC(name_length); - - if (!name_dup) { - return NULL; - } - - memcpy(name_dup, name, name_length); - - trace = name_dup; - while (trace) { - char *dot = strchr(trace, '.'); - if (dot) { - *dot++ = '\0'; - } - - if (object == NULL) { - if (no_block) { - object = PyImport_ImportModuleNoBlock(trace); - } else { - object = PyImport_ImportModule(trace); - if (!object) { - PyErr_Format(PyExc_ImportError, - "PyCapsule_Import could not " - "import module \"%s\"", trace); - } - } - } else { - PyObject *object2 = PyObject_GetAttrString(object, trace); - Py_DECREF(object); - object = object2; - } - if (!object) { - goto EXIT; - } - - trace = dot; - } - - if (PyCObject_Check(object)) { - PyCObject *cobject = (PyCObject *)object; - return_value = cobject->cobject; - } else { - PyErr_Format(PyExc_AttributeError, - "PyCapsule_Import \"%s\" is not valid", - name); - } - -EXIT: - Py_XDECREF(object); - if (name_dup) { - PyMem_FREE(name_dup); - } - return return_value; -} - -#endif /* #if PY_VERSION_HEX < 0x02070000 */ - -#endif /* __CAPSULETHUNK_H */ diff --git a/llvm/core.py b/llvm/core.py index fa9dc77..0bf99fd 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -1,43 +1,9 @@ -# -# Copyright (c) 2008-10, Mahadevan R All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of this software, nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - -"""Core classes of LLVM. - -The llvm.core module contains classes and constants required to build the -in-memory intermediate representation (IR) data structures.""" - - -import llvm # top-level, for common stuff -import llvm._core as _core # C wrappers -import llvm._util as _util # utility functions +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO +import api #===----------------------------------------------------------------------=== # Enumerations @@ -276,72 +242,16 @@ ATTR_INLINE_HINT = 1<<25 ATTR_STACK_ALIGNMENT = 7<<26 ATTR_HOTPATCH = 1<<29 -# intrinsic IDs -from llvm._intrinsic_ids import * - - -#===----------------------------------------------------------------------=== -# Helpers (for internal use) -#===----------------------------------------------------------------------=== - -def check_is_type(obj): _util.check_gen(obj, Type) -def check_is_type_struct(obj): _util.check_gen(obj, StructType) -def check_is_value(obj): _util.check_gen(obj, Value) -def check_is_constant(obj): _util.check_gen(obj, Constant) -def check_is_function(obj): _util.check_gen(obj, Function) -def check_is_global_value(obj): _util.check_gen(obj, GlobalValue) -def check_is_basic_block(obj): _util.check_gen(obj, BasicBlock) -def check_is_module(obj): _util.check_gen(obj, Module) - -def unpack_types(objlst): return _util.unpack_gen(objlst, check_is_type) -def unpack_values(objlst): return _util.unpack_gen(objlst, check_is_value) -def unpack_constants(objlst): return _util.unpack_gen(objlst, check_is_constant) - -def unpack_values_or_none(objlst): - return _util.unpack_gen_allow_none(objlst, check_is_value) - -def check_is_callable(obj): - if isinstance(obj, Function): - return - typ = obj.type - if isinstance(typ, PointerType) and \ - isinstance(typ.pointee, FunctionType): - return - raise TypeError("argument is neither a function nor a function pointer") - -def _to_int(v): - if v: - return 1 - else: - return 0 - - -#===----------------------------------------------------------------------=== -# Module -#===----------------------------------------------------------------------=== - -class Module(llvm.Ownable, llvm.Cacheable): - """A Module instance stores all the information related to an LLVM module. - - Modules are the top level container of all other LLVM Intermediate - Representation (IR) objects. Each module directly contains a list of - globals variables, a list of functions, a list of libraries (or - other modules) this module depends on, a symbol table, and various - data about the target's characteristics. - - Construct a Module only using the static methods defined below, *NOT* - using the constructor. A correct usage is: - - module_obj = Module.new('my_module') - """ - +class Module(object): @staticmethod def new(id): """Create a new Module instance. Creates an instance of Module, having the id `id'. """ - return Module(_core.LLVMModuleCreateWithName(id)) + context = api.getGlobalContext() + m = api.Module.new(id, context) + return Module(m) @staticmethod def from_bitcode(fileobj_or_str): @@ -349,2049 +259,21 @@ class Module(llvm.Ownable, llvm.Cacheable): file. fileobj_or_str -- takes a file-like object or string that contains - a module represented in bitcode. + a module represented in bitcode. """ - - if isinstance(fileobj_or_str, _util.unicode_type): - data = fileobj_or_str.encode('utf-8') - elif isinstance(fileobj_or_str, bytes): - data = fileobj_or_str + if isinstance(fileobj_or_str, str): + bc = fileobj_or_str else: - data = fileobj_or_str.read() - ret = _core.LLVMGetModuleFromBitcode(data) - if not ret: - raise llvm.LLVMException("Unable to create module from bitcode") - elif _util.isstring(ret): - raise llvm.LLVMException(ret) - else: - return Module(ret) - - @staticmethod - def from_assembly(fileobj_or_str): - """Create a Module instance from the contents of an LLVM - assembly (.ll) file. - - - fileobj_or_str -- takes a file-like object or string that contains - a module represented in llvm-ir assembly. - """ - - if isinstance(fileobj_or_str, _util.unicode_type): - data = fileobj_or_str.encode('utf-8') - elif isinstance(fileobj_or_str, bytes): - data = fileobj_or_str - else: - data = fileobj_or_str.read() - if isinstance(data, _util.unicode_type): - data = data.encode() - ret = _core.LLVMGetModuleFromAssembly(data) - if not ret: - raise llvm.LLVMException("Unable to create module from assembly") - elif isinstance(ret, str): - raise llvm.LLVMException(ret) - else: - return Module(ret) - - def __init__(self, ptr): - """DO NOT CALL DIRECTLY. - - Use the static method `Module.new' instead. - """ - llvm.Ownable.__init__(self, ptr, _core.LLVMDisposeModule) - - def __str__(self): - """Text representation of a module. - - Returns the textual representation (`llvm assembly') of the - module. Use it like this: - - ll = str(module_obj) - print module_obj # same as `print ll' - """ - return _core.LLVMDumpModuleToString(self.ptr) - - def __eq__(self, rhs): - if isinstance(rhs, Module): - return str(self) == str(rhs) - else: - return False - - def __ne__(self, rhs): - return not self == rhs - - def _get_target(self): - return _core.LLVMGetTarget(self.ptr) - - def _set_target(self, value): - return _core.LLVMSetTarget(self.ptr, value) - - target = property(_get_target, _set_target, - """The target triple string describing the target host.""" - ) - - def _get_data_layout(self): - return _core.LLVMGetDataLayout(self.ptr) - - def _set_data_layout(self, value): - _core.LLVMSetDataLayout(self.ptr, value) - - data_layout = property(_get_data_layout, _set_data_layout, - """The data layout string for the module's target platform. - - The data layout strings is an encoded representation of - the type sizes and alignments expected by this module. - """ - ) - - @property - def pointer_size(self): - """Pointer size of target platform. - - Can be 0, 32 or 64. Zero represents - llvm::Module::AnyPointerSize.""" - return _core.LLVMModuleGetPointerSize(self.ptr) - - def link_in(self, other, preserve=False): - """Link the `other' module into this one. - - The `other' module is linked into this one such that types, - global variables, function, etc. are matched and resolved. - - The `other' module is no longer valid after this method is - invoked, all refs to it should be dropped. - - In the future, this API might be replaced with a full-fledged - Linker class. - """ - check_is_module(other) - if not preserve: - other.forget() # remove it from object cache - result = _core.LLVMLinkModules(self.ptr, other.ptr, int(bool(preserve))) - if result is not None: - raise llvm.LLVMException(result) - if not preserve: - # Prevent user from using the other module - other.ptr = None - # Use a dummy owner to prevent other.ptr to be deleted - other._own(llvm.DummyOwner()) - - def get_type_named(self, name): - """Return a Type object with the given name.""" - ptr = _core.LLVMGetTypeByName(self.ptr, name) - if ptr: - kind = _core.LLVMGetTypeKind(ptr) - return _make_type(ptr, kind) - return None - - def add_global_variable(self, ty, name, addrspace=0): - """Add a global variable of given type with given name.""" - return GlobalVariable.new(self, ty, name, addrspace) - - def get_global_variable_named(self, name): - """Return a GlobalVariable object for the given name.""" - return GlobalVariable.get(self, name) - - @property - def global_variables(self): - """All global variables in this module.""" - return _util.wrapiter(_core.LLVMGetFirstGlobal, - _core.LLVMGetNextGlobal, self.ptr, _make_value) - - def add_function(self, ty, name): - """Add a function of given type with given name.""" - return Function.new(self, ty, name) - - def get_function_named(self, name): - """Return a Function object representing function with given name.""" - return Function.get(self, name) - - def get_or_insert_function(self, ty, name): - """Like get_function_named(), but does add_function() first, if - function is not present.""" - return Function.get_or_insert(self, ty, name) - - @property - def functions(self): - """All functions in this module.""" - return _util.wrapiter(_core.LLVMGetFirstFunction, - _core.LLVMGetNextFunction, self.ptr, _make_value) - - def verify(self): - """Verify module. - - Checks module for errors. Raises `llvm.LLVMException' on any - error.""" - ret = _core.LLVMVerifyModule(self.ptr) - # Note: LLVM has a bug in preverifier that will always abort - # the process upon failure. - if ret != "": - raise llvm.LLVMException(ret) - - def to_bitcode(self, fileobj=None): - """Write bitcode representation of module to given file-like - object. - - fileobj -- A file-like object to where the bitcode is written. - If it is None, the bitcode is returned. - - Return value -- Returns None if fileobj is not None. - Otherwise, return the bitcode as a bytestring. - """ - - data = _core.LLVMGetBitcodeFromModule(self.ptr) - if not data: - raise llvm.LLVMException("Unable to create bitcode") - if fileobj is not None: - fileobj.write(data) - else: - return data - - def add_library(self, name): - return _core.LLVMModuleAddLibrary(self.ptr, name) - - def _get_id(self): - return _core.LLVMGetModuleIdentifier(self.ptr) - - def _set_id(self, string): - _core.LLVMSetModuleIdentifier(self.ptr, string) - - id = property(_get_id, _set_id) - - def to_native_object(self, fileobj=None): - '''Outputs the byte string of the module as native object code - - If a fileobj is given, the output is written to it; - Otherwise, the output is returned - ''' - data = _core.LLVMGetNativeCodeFromModule(self.ptr, 0) - if fileobj is not None: - fileobj.write(data) - else: - return data - - def to_native_assembly(self, fileobj=None): - '''Outputs the byte string of the module as native assembly code - - If a fileobj is given, the output is written to it; - Otherwise, the output is returned - ''' - data = _core.LLVMGetNativeCodeFromModule(self.ptr, 1) - if fileobj is not None: - fileobj.write(data) - else: - return data - - def get_or_insert_named_metadata(self, name): - ptr = _core.LLVMModuleGetOrInsertNamedMetaData(self.ptr, name) - return NamedMetaData(ptr) - - def get_named_metadata(self, name): - ptr = _core.LLVMModuleGetNamedMetaData(self.ptr, name) - return NamedMetaData(ptr) - - def clone(self): - return Module(_core.LLVMCloneModule(self.ptr)) - -#===----------------------------------------------------------------------=== -# Types -#===----------------------------------------------------------------------=== - -class Type(object): - """Represents a type, like a 32-bit integer or an 80-bit x86 float. - - Use one of the static methods to create an instance. Example: - ty = Type.double() - """ - - @staticmethod - def int(bits=32): - """Create an integer type having the given bit width.""" - if bits == 1: - return _make_type(_core.LLVMInt1Type(), TYPE_INTEGER) - elif bits == 8: - return _make_type(_core.LLVMInt8Type(), TYPE_INTEGER) - elif bits == 16: - return _make_type(_core.LLVMInt16Type(), TYPE_INTEGER) - elif bits == 32: - return _make_type(_core.LLVMInt32Type(), TYPE_INTEGER) - elif bits == 64: - return _make_type(_core.LLVMInt64Type(), TYPE_INTEGER) - else: - bits = int(bits) # bits must be an int - return _make_type(_core.LLVMIntType(bits), TYPE_INTEGER) - - @staticmethod - def float(): - """Create a 32-bit floating point type.""" - return _make_type(_core.LLVMFloatType(), TYPE_FLOAT) - - @staticmethod - def double(): - """Create a 64-bit floating point type.""" - return _make_type(_core.LLVMDoubleType(), TYPE_DOUBLE) - - @staticmethod - def x86_fp80(): - """Create a 80-bit x86 floating point type.""" - return _make_type(_core.LLVMX86FP80Type(), TYPE_X86_FP80) - - @staticmethod - def fp128(): - """Create a 128-bit floating point type (with 112-bit - mantissa).""" - return _make_type(_core.LLVMFP128Type(), TYPE_FP128) - - @staticmethod - def ppc_fp128(): - """Create a 128-bit floating point type (two 64-bits).""" - return _make_type(_core.LLVMPPCFP128Type(), TYPE_PPC_FP128) - - @staticmethod - def function(return_ty, param_tys, var_arg=False): - """Create a function type. - - Creates a function type that returns a value of type - `return_ty', takes arguments of types as given in the iterable - `param_tys'. Set `var_arg' to True (default is False) for a - variadic function.""" - check_is_type(return_ty) - var_arg = _to_int(var_arg) # ensure int - params = unpack_types(param_tys) - return _make_type(_core.LLVMFunctionType(return_ty.ptr, params, - var_arg), TYPE_FUNCTION) - - @staticmethod - def opaque(name): - """Create a opaque StructType""" - if not name: - raise llvm.LLVMException("Must specify a name") - - objptr = _core.LLVMStructTypeIdentified(name) - return _make_type(objptr, TYPE_STRUCT) - - @staticmethod - def struct(element_tys, name=''): # not packed - """Create a (unpacked) structure type. - - Creates a structure type with elements of types as given in the - iterable `element_tys'. This method creates a unpacked - structure. For a packed one, use the packed_struct() method. - - If name is not '', creates a identified type; - otherwise, creates a literal type.""" - return Type.__struct(element_tys, packed=False, name=name) - - @staticmethod - def packed_struct(element_tys, name=''): - """Create a (packed) structure type. - - Creates a structure type with elements of types as given in the - iterable `element_tys'. This method creates a packed - structure. For an unpacked one, use the struct() method. - - If name is not '', creates a identified type; - otherwise, creates a literal type.""" - return Type.__struct(element_tys, packed=True, name=name) - - @staticmethod - def __struct(element_tys, packed, name): - elems = unpack_types(element_tys) - packed = int(bool(packed)) - - if name: # create Identified StructType - objptr = _core.LLVMStructTypeIdentified(name) - _core.LLVMSetStructBody(objptr, elems, packed) - else: # create Literal StructType - objptr = _core.LLVMStructType(elems, packed) - - return _make_type(objptr, TYPE_STRUCT) - - - @staticmethod - def array(element_ty, count): - """Create an array type. - - Creates a type for an array of elements of type `element_ty', - having 'count' elements.""" - check_is_type(element_ty) - count = int(count) # must be an int - return _make_type(_core.LLVMArrayType(element_ty.ptr, count), - TYPE_ARRAY) - - @staticmethod - def pointer(pointee_ty, addr_space=0): - """Create a pointer type. - - Creates a pointer type, which can point to values of type - `pointee_ty', in the address space `addr_space'.""" - check_is_type(pointee_ty) - addr_space = int(addr_space) # must be an int - return _make_type(_core.LLVMPointerType(pointee_ty.ptr, - addr_space), TYPE_POINTER) - - @staticmethod - def vector(element_ty, count): - """Create a vector type. - - Creates a type for a vector of elements of type `element_ty', - having `count' elements.""" - check_is_type(element_ty) - count = int(count) # must be an int - return _make_type(_core.LLVMVectorType(element_ty.ptr, count), - TYPE_VECTOR) - - @staticmethod - def void(): - """Create a void type. - - Represents the `void' type.""" - return _make_type(_core.LLVMVoidType(), TYPE_VOID) - - @staticmethod - def label(): - """Create a label type.""" - return _make_type(_core.LLVMLabelType(), TYPE_LABEL) - - def __init__(self, ptr, kind): - """DO NOT CALL DIRECTLY. - - Use one of the static methods instead.""" - self.ptr = ptr - self.kind = kind - """An enum (int) value denoting which type this is. - - Use the symbolic constants TYPE_* defined in llvm.core - module.""" - - def __str__(self): - """Text representation of a type. - - Returns the textual representation (`llvm assembly') of the type.""" - return _core.LLVMDumpTypeToString(self.ptr) - - def __eq__(self, rhs): - if isinstance(rhs, Type): - return str(self) == str(rhs) - else: - return False - - def __ne__(self, rhs): - return not self == rhs - - -class IntegerType(Type): - """Represents an integer type.""" - - @property - def width(self): - """The width of the integer type, in bits.""" - return _core.LLVMGetIntTypeWidth(self.ptr) - - -class FunctionType(Type): - """Represents a function type.""" - - @property - def return_type(self): - """The type of the value returned by this function.""" - ptr = _core.LLVMGetReturnType(self.ptr) - kind = _core.LLVMGetTypeKind(ptr) - return _make_type(ptr, kind) - - @property - def vararg(self): - """True if this function is variadic.""" - return _core.LLVMIsFunctionVarArg(self.ptr) != 0 - - @property - def args(self): - """An iterable that yields Type objects, representing the types of the - arguments accepted by this function, in order.""" - pp = _core.LLVMGetFunctionTypeParams(self.ptr) - return [ _make_type(p, _core.LLVMGetTypeKind(p)) for p in pp ] - - @property - def arg_count(self): - """Number of arguments accepted by this function. - - Same as len(obj.args), but faster.""" - return _core.LLVMCountParamTypes(self.ptr) - - -class StructType(Type): - """Represents a structure type.""" - - @property - def element_count(self): - """Number of elements (members) in the structure. - - Same as len(obj.elements), but faster.""" - return _core.LLVMCountStructElementTypes(self.ptr) - - @property - def elements(self): - """An iterable that yieldsd Type objects, representing the types of the - elements (members) of the structure, in order.""" - pp = _core.LLVMGetStructElementTypes(self.ptr) - return [ _make_type(p, _core.LLVMGetTypeKind(p)) for p in pp ] - - def set_body(self, elems, packed=False): - """Filled the body of a opaque type. - """ - # check - if not self.is_opaque: - raise llvm.LLVMException("Body is already defined.") - - # prepare arguments - elems = unpack_types(elems) - if packed: - packed = 1 - else: - packed = 0 - - # call c API - _core.LLVMSetStructBody(self.ptr, elems, packed) - - @property - def packed(self): - """True if the structure is packed, False otherwise.""" - return _core.LLVMIsPackedStruct(self.ptr) != 0 - - def _set_name(self, name): - _core.LLVMSetStructName(self.ptr, name) - - def _get_name(self): - return _core.LLVMGetStructName(self.ptr) - - name = property(_get_name, _set_name) - - @property - def is_literal(self): - return bool(_core.LLVMIsLiteralStruct(self.ptr)) - - @property - def is_identified(self): - return not _core.LLVMIsLiteralStruct(self.ptr) - - @property - def is_opaque(self): - return bool(_core.LLVMIsOpaqueStruct(self.ptr)) - -class ArrayType(Type): - """Represents an array type.""" - - @property - def element(self): - ptr = _core.LLVMGetElementType(self.ptr) - kind = _core.LLVMGetTypeKind(ptr) - return _make_type(ptr, kind) - - @property - def count(self): - return _core.LLVMGetArrayLength(self.ptr) - - -class PointerType(Type): - - @property - def pointee(self): - ptr = _core.LLVMGetElementType(self.ptr) - kind = _core.LLVMGetTypeKind(ptr) - return _make_type(ptr, kind) - - @property - def address_space(self): - return _core.LLVMGetPointerAddressSpace(self.ptr) - - -class VectorType(Type): - - @property - def element(self): - ptr = _core.LLVMGetElementType(self.ptr) - kind = _core.LLVMGetTypeKind(ptr) - return _make_type(ptr, kind) - - @property - def count(self): - return _core.LLVMGetVectorSize(self.ptr) - - -#===----------------------------------------------------------------------=== -# Type factory method -#===----------------------------------------------------------------------=== - -# type ID -> class map -__class_for_typeid = { - TYPE_INTEGER : IntegerType, - TYPE_FUNCTION : FunctionType, - TYPE_STRUCT : StructType, - TYPE_ARRAY : ArrayType, - TYPE_POINTER : PointerType, - TYPE_VECTOR : VectorType, -} - -def _make_type(ptr, kind): - class_obj = __class_for_typeid.get(kind) - if class_obj: - return class_obj(ptr, kind) - else: - # "generic" type - return Type(ptr, kind) - - -#===----------------------------------------------------------------------=== -# Values -#===----------------------------------------------------------------------=== - -class Value(llvm.Cacheable): + bc = fileobj_or_str.read() + errbuf = StringIO() + m = api.ParseBitCodeFile(bc, context, errbuf) + if not m: + raise Exception(errbuf.getvalue()) + errbuf.close() + return Module(m) def __init__(self, ptr): self.ptr = ptr - def __str__(self): - return _core.LLVMDumpValueToString(self.ptr) - - def __eq__(self, rhs): - if isinstance(rhs, Value): - return str(self) == str(rhs) - else: - return False - - def __ne__(self, rhs): - return not self == rhs - - def _get_name(self): - return _core.LLVMGetValueName(self.ptr) - - def _set_name(self, value): - return _core.LLVMSetValueName(self.ptr, value) - - name = property(_get_name, _set_name) - - @property - def value_id(self): - return _core.LLVMValueGetID(self.ptr) - - @property - def type(self): - ptr = _core.LLVMTypeOf(self.ptr) - kind = _core.LLVMGetTypeKind(ptr) - return _make_type(ptr, kind) - - @property - def use_count(self): - return _core.LLVMValueGetNumUses(self.ptr) - - @property - def uses(self): - return [ _make_value(v) for v in _core.LLVMValueGetUses(self.ptr) ] - - -class User(Value): - - @property - def operand_count(self): - return _core.LLVMUserGetNumOperands(self.ptr) - - @property - def operands(self): - """Yields operands of this instruction.""" - return [self._get_operand(i) for i in range(self.operand_count)] - - def _get_operand(self, i): - return _make_value(_core.LLVMUserGetOperand(self.ptr, i)) - - -class Constant(User): - - @staticmethod - def null(ty): - check_is_type(ty) - return _make_value(_core.LLVMConstNull(ty.ptr)) - - @staticmethod - def all_ones(ty): - check_is_type(ty) - return _make_value(_core.LLVMConstAllOnes(ty.ptr)) - - @staticmethod - def undef(ty): - check_is_type(ty) - return _make_value(_core.LLVMGetUndef(ty.ptr)) - - @staticmethod - def int(ty, value): - check_is_type(ty) - return _make_value(_core.LLVMConstInt(ty.ptr, value, 0)) - - @staticmethod - def int_signextend(ty, value): - check_is_type(ty) - return _make_value(_core.LLVMConstInt(ty.ptr, value, 1)) - - @staticmethod - def real(ty, value): - check_is_type(ty) - if isinstance(value, str): - return _make_value(_core.LLVMConstRealOfString(ty.ptr, value)) - else: - return _make_value(_core.LLVMConstReal(ty.ptr, value)) - - @staticmethod - def string(strval): # dont_null_terminate=True - return _make_value(_core.LLVMConstString(strval, 1)) - - @staticmethod - def stringz(strval): # dont_null_terminate=False - return _make_value(_core.LLVMConstString(strval, 0)) - - @staticmethod - def array(ty, consts): - check_is_type(ty) - const_ptrs = unpack_constants(consts) - return _make_value(_core.LLVMConstArray(ty.ptr, const_ptrs)) - - @staticmethod - def struct(consts): # not packed - const_ptrs = unpack_constants(consts) - return _make_value(_core.LLVMConstStruct(const_ptrs, 0)) - - @staticmethod - def packed_struct(consts): - const_ptrs = unpack_constants(consts) - return _make_value(_core.LLVMConstStruct(const_ptrs, 1)) - - @staticmethod - def vector(consts): - const_ptrs = unpack_constants(consts) - return _make_value(_core.LLVMConstVector(const_ptrs)) - - @staticmethod - def sizeof(ty): - check_is_type(ty) - return _make_value(_core.LLVMSizeOf(ty.ptr)) - - def neg(self): - return _make_value(_core.LLVMConstNeg(self.ptr)) - - def not_(self): - return _make_value(_core.LLVMConstNot(self.ptr)) - - def add(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstAdd(self.ptr, rhs.ptr)) - - def fadd(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstFAdd(self.ptr, rhs.ptr)) - - def sub(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstSub(self.ptr, rhs.ptr)) - - def fsub(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstFSub(self.ptr, rhs.ptr)) - - def mul(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstMul(self.ptr, rhs.ptr)) - - def fmul(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstFMul(self.ptr, rhs.ptr)) - - def udiv(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstUDiv(self.ptr, rhs.ptr)) - - def sdiv(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstSDiv(self.ptr, rhs.ptr)) - - def fdiv(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstFDiv(self.ptr, rhs.ptr)) - - def urem(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstURem(self.ptr, rhs.ptr)) - - def srem(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstSRem(self.ptr, rhs.ptr)) - - def frem(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstFRem(self.ptr, rhs.ptr)) - - def and_(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstAnd(self.ptr, rhs.ptr)) - - def or_(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstOr(self.ptr, rhs.ptr)) - - def xor(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstXor(self.ptr, rhs.ptr)) - - def icmp(self, int_pred, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstICmp(int_pred, self.ptr, rhs.ptr)) - - def fcmp(self, real_pred, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstFCmp(real_pred, self.ptr, rhs.ptr)) - - def shl(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstShl(self.ptr, rhs.ptr)) - - def lshr(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstLShr(self.ptr, rhs.ptr)) - - def ashr(self, rhs): - check_is_constant(rhs) - return _make_value(_core.LLVMConstAShr(self.ptr, rhs.ptr)) - - def gep(self, indices): - index_ptrs = unpack_constants(indices) - return _make_value(_core.LLVMConstGEP(self.ptr, index_ptrs)) - - def trunc(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstTrunc(self.ptr, ty.ptr)) - - def sext(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstSExt(self.ptr, ty.ptr)) - - def zext(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstZExt(self.ptr, ty.ptr)) - - def fptrunc(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstFPTrunc(self.ptr, ty.ptr)) - - def fpext(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstFPExt(self.ptr, ty.ptr)) - - def uitofp(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstUIToFP(self.ptr, ty.ptr)) - - def sitofp(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstSIToFP(self.ptr, ty.ptr)) - - def fptoui(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstFPToUI(self.ptr, ty.ptr)) - - def fptosi(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstFPToSI(self.ptr, ty.ptr)) - - def ptrtoint(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstPtrToInt(self.ptr, ty.ptr)) - - def inttoptr(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstIntToPtr(self.ptr, ty.ptr)) - - def bitcast(self, ty): - check_is_type(ty) - return _make_value(_core.LLVMConstBitCast(self.ptr, ty.ptr)) - - def select(self, true_const, false_const): - check_is_constant(true_const) - check_is_constant(false_const) - return _make_value( - _core.LLVMConstSelect(self.ptr, true_const.ptr, false_const.ptr)) - - def extract_element(self, index): # note: self must be a _vector_ constant - check_is_constant(index) - return _make_value( - _core.LLVMConstExtractElement(self.ptr, index.ptr)) - - def insert_element(self, value, index): - # note: self must be a _vector_ constant - check_is_constant(value) - check_is_constant(index) - return _make_value( - _core.LLVMConstInsertElement(self.ptr, value.ptr, index.ptr)) - - def shuffle_vector(self, vector_b, mask): - # note: self must be a _vector_ constant - check_is_constant(vector_b) - # note: vector_b must be a _vector_ constant - check_is_constant(mask) - return _make_value( - _core.LLVMConstShuffleVector(self.ptr, vector_b.ptr, mask.ptr)) - - -class ConstantExpr(Constant): - @property - def opcode(self): - return _core.LLVMGetConstExprOpcode(self.ptr) - - @property - def opcode_name(self): - return _core.LLVMGetConstExprOpcodeName(self.ptr) - - -class ConstantAggregateZero(Constant): - pass - - -class ConstantDataArray(Constant): - pass - - -class ConstantDataVector(Constant): - pass - -class ConstantInt(Constant): - @property - def z_ext_value(self): - '''Obtain the zero extended value for an integer constant value.''' - # Warning: assertion failure when value does not fit in 64 bits - return _core.LLVMConstIntGetZExtValue(self.ptr) - - @property - def s_ext_value(self): - '''Obtain the sign extended value for an integer constant value.''' - # Warning: assertion failure when value does not fit in 64 bits - return _core.LLVMConstIntGetSExtValue(self.ptr) - - -class ConstantFP(Constant): - pass - - -class ConstantArray(Constant): - pass - - -class ConstantStruct(Constant): - pass - - -class ConstantVector(Constant): - pass - - -class ConstantPointerNull(Constant): - pass - - -class UndefValue(Constant): - pass - - -class GlobalValue(Constant): - - def __init__(self, ptr): - Constant.__init__(self, ptr) - # Hang on to the module, don't let it die before we do. - # It is nice to have just a map of functions without - # retaining a ref to the owning module. - self._module_obj = self.module - - def _delete(self): - # Called in subclass delete() methods. - self._module_obj = None - - def _get_linkage(self): - return _core.LLVMGetLinkage(self.ptr) - def _set_linkage(self, value): - _core.LLVMSetLinkage(self.ptr, value) - linkage = property(_get_linkage, _set_linkage) - - def _get_section(self): - return _core.LLVMGetSection(self.ptr) - def _set_section(self, value): - return _core.LLVMSetSection(self.ptr, value) - section = property(_get_section, _set_section) - - def _get_visibility(self): - return _core.LLVMGetVisibility(self.ptr) - def _set_visibility(self, value): - return _core.LLVMSetVisibility(self.ptr, value) - visibility = property(_get_visibility, _set_visibility) - - def _get_alignment(self): - return _core.LLVMGetAlignment(self.ptr) - def _set_alignment(self, value): - return _core.LLVMSetAlignment(self.ptr, value) - alignment = property(_get_alignment, _set_alignment) - - @property - def is_declaration(self): - return _core.LLVMIsDeclaration(self.ptr) != 0 - - @property - def module(self): - return Module(_core.LLVMGetGlobalParent(self.ptr)) - -class GlobalVariable(GlobalValue): - - @staticmethod - def new(module, ty, name, addrspace=0): - check_is_module(module) - check_is_type(ty) - return _make_value(_core.LLVMAddGlobalInAddressSpace(module.ptr, ty.ptr, name, addrspace)) - - @staticmethod - def get(module, name): - check_is_module(module) - ptr = _core.LLVMGetNamedGlobal(module.ptr, name) - if not ptr: - raise llvm.LLVMException("no global named `%s`" % name) - return _make_value(ptr) - - def delete(self): - self._delete() - _core.LLVMDeleteGlobal(self.ptr) - self.forget() - self.ptr = None - - def _get_initializer(self): - if _core.LLVMHasInitializer(self.ptr): - return _make_value(_core.LLVMGetInitializer(self.ptr)) - else: - return None - - def _set_initializer(self, const): - check_is_constant(const) - _core.LLVMSetInitializer(self.ptr, const.ptr) - - def _del_initializer(self): - check_is_constant(const) - - initializer = property(_get_initializer, _set_initializer) - - def _get_is_global_constant(self): - return _core.LLVMIsGlobalConstant(self.ptr) - - def _set_is_global_constant(self, value): - value = _to_int(value) - _core.LLVMSetGlobalConstant(self.ptr, value) - - global_constant = \ - property(_get_is_global_constant, _set_is_global_constant) - - def _get_thread_local(self): - return bool(_core.LLVMIsThreadLocal(self.ptr)) - def _set_thread_local(self, value): - value = _to_int(value) - _core.LLVMSetThreadLocal(self.ptr, value) - - thread_local = property(_get_thread_local, _set_thread_local) - -class Argument(Value): - - def add_attribute(self, attr): - _core.LLVMAddAttribute(self.ptr, attr) - - def remove_attribute(self, attr): - _core.LLVMRemoveAttribute(self.ptr, attr) - - def _set_alignment(self, align): - _core.LLVMSetParamAlignment(self.ptr, align) - - def _get_alignment(self): - return _core.LLVMGetParamAlignment(self.ptr) - - alignment = \ - property(_get_alignment, _set_alignment) - - -class Function(GlobalValue): - - @staticmethod - def new(module, func_ty, name): - check_is_module(module) - check_is_type(func_ty) - return _make_value(_core.LLVMAddFunction(module.ptr, name, - func_ty.ptr)) - - @staticmethod - def get_or_insert(module, func_ty, name): - check_is_module(module) - check_is_type(func_ty) - return _make_value(_core.LLVMModuleGetOrInsertFunction(module.ptr, - name, func_ty.ptr)) - - @staticmethod - def get(module, name): - check_is_module(module) - ptr = _core.LLVMGetNamedFunction(module.ptr, name) - if not ptr: - raise llvm.LLVMException("no function named `%s`" % name) - return _make_value(ptr) - - @staticmethod - def intrinsic(module, intrinsic_id, types): - check_is_module(module) - ptrs = unpack_types(types) - return _make_value( - _core.LLVMGetIntrinsic(module.ptr, intrinsic_id, ptrs)) - - def delete(self): - self._delete() - _core.LLVMDeleteFunction(self.ptr) - self.forget() - self.ptr = None - - @property - def intrinsic_id(self): - return _core.LLVMGetIntrinsicID(self.ptr) - - def _get_cc(self): return _core.LLVMGetFunctionCallConv(self.ptr) - def _set_cc(self, value): _core.LLVMSetFunctionCallConv(self.ptr, value) - calling_convention = property(_get_cc, _set_cc) - - def _get_coll(self): return _core.LLVMGetGC(self.ptr) - def _set_coll(self, value): _core.LLVMSetGC(self.ptr, value) - collector = property(_get_coll, _set_coll) - - # the nounwind attribute: - def _get_does_not_throw(self): return _core.LLVMGetDoesNotThrow(self.ptr) - def _set_does_not_throw(self,value): _core.LLVMSetDoesNotThrow(self.ptr, value) - does_not_throw = property(_get_does_not_throw, _set_does_not_throw) - - @property - def args(self): - return _util.wrapiter(_core.LLVMGetFirstParam, - _core.LLVMGetNextParam, self.ptr, _make_value) - - @property - def basic_block_count(self): - return _core.LLVMCountBasicBlocks(self.ptr) - - @property - def entry_basic_block(self): - if self.basic_block_count == 0: - return None - return _make_value(_core.LLVMGetEntryBasicBlock(self.ptr)) - - def get_entry_basic_block(self): - """Deprecated, use entry_basic_block property.""" - return self.entry_basic_block - - def append_basic_block(self, name): - return _make_value(_core.LLVMAppendBasicBlock(self.ptr, name)) - - @property - def basic_blocks(self): - return _util.wrapiter(_core.LLVMGetFirstBasicBlock, - _core.LLVMGetNextBasicBlock, self.ptr, _make_value) - - def viewCFG(self): - return _core.LLVMViewFunctionCFG(self.ptr) - - def add_attribute(self, attr): - _core.LLVMAddFunctionAttr(self.ptr, attr) - - def remove_attribute(self, attr): - _core.LLVMRemoveFunctionAttr(self.ptr, attr) - - def viewCFGOnly(self): - return _core.LLVMViewFunctionCFGOnly(self.ptr) - - def verify(self): - # Although we're just asking LLVM to return the success or - # failure, it appears to print result to stderr and abort. - - # Note: LLVM has a bug in preverifier that will always abort - # the process upon failure. - return _core.LLVMVerifyFunction(self.ptr) != 0 - -#===----------------------------------------------------------------------=== -# InlineAsm -#===----------------------------------------------------------------------=== - -class InlineAsm(Value): - @staticmethod - def get(functype, asm, constrains, side_effect=False, - align_stack=False, dialect=0): - assert dialect == 0, "LLVM 3.1 does not implement dialect selection" - check_is_type(functype) - pycap = _core.LLVMGetFunctionFromInlineAsm(functype.ptr, asm, - constrains, int(side_effect), - int(align_stack), dialect) - return _make_value(pycap) - -#===----------------------------------------------------------------------=== -# MetaData -#===----------------------------------------------------------------------=== - -class MetaData(Value): - @staticmethod - def get(module, values): - ''' - values -- must be an iterable of Constant or None. None is treated as "null". - ''' - vs = unpack_values_or_none(values) - ptr = _core.LLVMMetaDataGet(module.ptr, vs) - return MetaData(ptr) - - @staticmethod - def get_named_operands(module, name): - lst = _core.LLVMGetNamedMetadataOperands(module.ptr, name) - return [MetaData(ptr) for ptr in lst] - - @staticmethod - def add_named_operand(module, name, operand): - _core.LLVMAddNamedMetadataOperand(module.ptr, name, operand.ptr) - - @property - def operand_count(self): - return _core.LLVMMetaDataGetNumOperands(self.ptr) - - @property - def operands(self): - """Yields operands of this metadata.""" - return [self._get_operand(i) for i in range(self.operand_count)] - - def _get_operand(self, i): - val = _core.LLVMMetaDataGetOperand(self.ptr, i) - if val: # metadata operands can be None - return _make_value(val) - -class MetaDataString(Value): - @staticmethod - def get(module, s): - ptr = _core.LLVMMetaDataStringGet(module.ptr, s) - return MetaDataString(ptr) - - @property - def string(self): - '''Same as MDString::getString''' - return self.name - -class NamedMetaData(llvm.Cacheable): - @staticmethod - def get_or_insert(mod, name): - return mod.get_or_insert_named_metadata(name) - - @staticmethod - def get(mod, name): - return mod.get_named_metadata(name) - - def __init__(self, ptr): - self.ptr = ptr - - def delete(self): - _core.LLVMEraseNamedMetaData(self.ptr) - - @property - def name(self): - return _core.LLVMNamedMetaDataGetName(self.ptr) - - def __str__(self): - return _core.LLVMDumpNamedMDToString(self.ptr) - - def add(self, operand): - _core.LLVMNamedMetaDataAddOperand(self.ptr, operand.ptr) - -#===----------------------------------------------------------------------=== -# Instruction -#===----------------------------------------------------------------------=== - -class Instruction(User): - - @property - def basic_block(self): - return _make_value(_core.LLVMGetInstructionParent(self.ptr)) - - @property - def is_terminator(self): - return _core.LLVMInstIsTerminator(self.ptr) != 0 - - @property - def is_binary_op(self): - return _core.LLVMInstIsBinaryOp(self.ptr) != 0 - - @property - def is_shift(self): - return _core.LLVMInstIsShift(self.ptr) != 0 - - @property - def is_cast(self): - return _core.LLVMInstIsCast(self.ptr) != 0 - - @property - def is_logical_shift(self): - return _core.LLVMInstIsLogicalShift(self.ptr) != 0 - - @property - def is_arithmetic_shift(self): - return _core.LLVMInstIsArithmeticShift(self.ptr) != 0 - - @property - def is_associative(self): - return _core.LLVMInstIsAssociative(self.ptr) != 0 - - @property - def is_commutative(self): - return _core.LLVMInstIsCommutative(self.ptr) != 0 - - @property - def is_volatile(self): - """True if this is a volatile load or store.""" - return _core.LLVMInstIsVolatile(self.ptr) != 0 - - def set_volatile(self, flag): - return _core.LLVMSetVolatile(self.ptr, int(bool(flag))) - - def set_metadata(self, kind, metadata): - return _core.LLVMInstSetMetaData(self.ptr, kind, metadata.ptr) - - @property - def opcode(self): - return _core.LLVMInstGetOpcode(self.ptr) - - @property - def opcode_name(self): - return _core.LLVMInstGetOpcodeName(self.ptr) - - def erase_from_parent(self): - return _core.LLVMInstructionEraseFromParent(self.ptr) - -class CallOrInvokeInstruction(Instruction): - - def _get_cc(self): return _core.LLVMGetInstructionCallConv(self.ptr) - def _set_cc(self, value): _core.LLVMSetInstructionCallConv(self.ptr, value) - calling_convention = property(_get_cc, _set_cc) - - def add_parameter_attribute(self, idx, attr): - _core.LLVMAddInstrAttribute(self.ptr, idx, attr) - - def remove_parameter_attribute(self, idx, attr): - _core.LLVMRemoveInstrAttribute(self.ptr, idx, attr) - - def set_parameter_alignment(self, idx, align): - _core.LLVMSetInstrParamAlignment(self.ptr, idx, align) - - def _get_called_function(self): - function = _core.LLVMInstGetCalledFunction(self.ptr) - if function: # Return value can be None on indirect call/invoke - return _make_value(function) - - def _set_called_function(self, function): - _core.LLVMInstSetCalledFunction(self.ptr, function.ptr) - - called_function = property(_get_called_function, _set_called_function) - - # tail call is valid only for 'call', not 'invoke' - # disabled for now - #def _get_tc(self): return _core.LLVMIsTailCall(self.ptr) - #def _set_tc(self, value): _core.LLVMSetTailCall(self.ptr, value) - #tail_call = property(_get_tc, _set_tc) - - -class PHINode(Instruction): - - @property - def incoming_count(self): - return _core.LLVMCountIncoming(self.ptr) - - def add_incoming(self, value, block): - check_is_value(value) - check_is_basic_block(block) - _core.LLVMAddIncoming1(self.ptr, value.ptr, block.ptr) - - def get_incoming_value(self, idx): - return _make_value(_core.LLVMGetIncomingValue(self.ptr, idx)) - - def get_incoming_block(self, idx): - return _make_value(_core.LLVMGetIncomingBlock(self.ptr, idx)) - - -class SwitchInstruction(Instruction): - - def add_case(self, const, bblk): - check_is_constant(const) # and has to be an int too - check_is_basic_block(bblk) - _core.LLVMAddCase(self.ptr, const.ptr, bblk.ptr) - - -class CompareInstruction(Instruction): - - @property - def predicate(self): - return _core.LLVMCmpInstGetPredicate(self.ptr) - - -#===----------------------------------------------------------------------=== -# Basic block -#===----------------------------------------------------------------------=== - -class BasicBlock(Value): - - def insert_before(self, name): - return _make_value(_core.LLVMInsertBasicBlock(self.ptr, name)) - - def delete(self): - _core.LLVMDeleteBasicBlock(self.ptr) - self.forget() - self.ptr = None - - @property - def function(self): - func_ptr = _core.LLVMGetBasicBlockParent(self.ptr) - return _make_value(func_ptr) - - @property - def instructions(self): - return _util.wrapiter(_core.LLVMGetFirstInstruction, - _core.LLVMGetNextInstruction, self.ptr, _make_value) - - -#===----------------------------------------------------------------------=== -# Value factory method -#===----------------------------------------------------------------------=== - -# value ID -> class map -__class_for_valueid = { - VALUE_ARGUMENT : Argument, - VALUE_BASIC_BLOCK : BasicBlock, - VALUE_FUNCTION : Function, - VALUE_GLOBAL_ALIAS : GlobalValue, - VALUE_GLOBAL_VARIABLE : GlobalVariable, - VALUE_UNDEF_VALUE : UndefValue, - VALUE_CONSTANT_EXPR : ConstantExpr, - VALUE_CONSTANT_AGGREGATE_ZERO : ConstantAggregateZero, - VALUE_CONSTANT_DATA_ARRAY : ConstantDataArray, - VALUE_CONSTANT_DATA_VECTOR : ConstantDataVector, - VALUE_CONSTANT_INT : ConstantInt, - VALUE_CONSTANT_FP : ConstantFP, - VALUE_CONSTANT_ARRAY : ConstantArray, - VALUE_CONSTANT_STRUCT : ConstantStruct, - VALUE_CONSTANT_VECTOR : ConstantVector, - VALUE_CONSTANT_POINTER_NULL : ConstantPointerNull, - VALUE_MD_NODE : MetaData, - VALUE_MD_STRING : MetaDataString, - VALUE_INLINE_ASM : InlineAsm, - VALUE_INSTRUCTION + OPCODE_PHI : PHINode, - VALUE_INSTRUCTION + OPCODE_CALL : CallOrInvokeInstruction, - VALUE_INSTRUCTION + OPCODE_INVOKE : CallOrInvokeInstruction, - VALUE_INSTRUCTION + OPCODE_SWITCH : SwitchInstruction, - VALUE_INSTRUCTION + OPCODE_ICMP : CompareInstruction, - VALUE_INSTRUCTION + OPCODE_FCMP : CompareInstruction -} - -def _make_value(ptr): - kind = _core.LLVMValueGetID(ptr) - # based on kind, create one of the Value subclasses - class_obj = __class_for_valueid.get(kind) - if class_obj: - return class_obj(ptr) - elif kind > VALUE_INSTRUCTION: - # "generic" instruction - return Instruction(ptr) - else: - # "generic" value - return Value(ptr) - - -#===----------------------------------------------------------------------=== -# Builder -#===----------------------------------------------------------------------=== - -class Builder(object): - - @staticmethod - def new(basic_block): - check_is_basic_block(basic_block) - b = Builder(_core.LLVMCreateBuilder()) - b.position_at_end(basic_block) - return b - - def __init__(self, ptr): - self.ptr = ptr - - def __del__(self): - _core.LLVMDisposeBuilder(self.ptr) - - def position_at_beginning(self, bblk): - """Position the builder at the beginning of the given block. - - Next instruction inserted will be first one in the block.""" - check_is_basic_block(bblk) - # Avoids using "blk.instructions", which will fetch all the - # instructions into a list. Don't try this at home, though. - inst_ptr = _core.LLVMGetFirstInstruction(bblk.ptr) - if inst_ptr: - # Issue #10: inst_ptr can be None if b/b has no insts. - inst = _make_value(inst_ptr) - self.position_before(inst) - - def position_at_end(self, bblk): - """Position the builder at the end of the given block. - - Next instruction inserted will be last one in the block.""" - _core.LLVMPositionBuilderAtEnd(self.ptr, bblk.ptr) - - def position_before(self, instr): - """Position the builder before the given instruction. - - The instruction can belong to a basic block other than the - current one.""" - _core.LLVMPositionBuilderBefore(self.ptr, instr.ptr) - - @property - def block(self): - """Deprecated, use basic_block property instead.""" - return _make_value(_core.LLVMGetInsertBlock(self.ptr)) - - @property - def basic_block(self): - """The basic block where the builder is positioned.""" - return _make_value(_core.LLVMGetInsertBlock(self.ptr)) - - # terminator instructions - - def ret_void(self): - return _make_value(_core.LLVMBuildRetVoid(self.ptr)) - - def ret(self, value): - check_is_value(value) - return _make_value(_core.LLVMBuildRet(self.ptr, value.ptr)) - - def ret_many(self, values): - vs = unpack_values(values) - return _make_value(_core.LLVMBuildRetMultiple(self.ptr, vs)) - - def branch(self, bblk): - check_is_basic_block(bblk) - if __debug__: - for instr in self.basic_block.instructions: - assert not instr.is_terminator, "BasicBlock can only have one terminator" - return _make_value(_core.LLVMBuildBr(self.ptr, bblk.ptr)) - - def cbranch(self, if_value, then_blk, else_blk): - check_is_value(if_value) - check_is_basic_block(then_blk) - check_is_basic_block(else_blk) - return _make_value( - _core.LLVMBuildCondBr(self.ptr, - if_value.ptr, then_blk.ptr, else_blk.ptr)) - - def switch(self, value, else_blk, n=10): - check_is_value(value) # value has to be of any 'int' type - check_is_basic_block(else_blk) - return _make_value( - _core.LLVMBuildSwitch(self.ptr, value.ptr, else_blk.ptr, n)) - - def invoke(self, func, args, then_blk, catch_blk, name=""): - check_is_callable(func) - check_is_basic_block(then_blk) - check_is_basic_block(catch_blk) - args2 = unpack_values(args) - return _make_value( - _core.LLVMBuildInvoke(self.ptr, func.ptr, args2, - then_blk.ptr, catch_blk.ptr, name)) - - def unreachable(self): - return _make_value(_core.LLVMBuildUnreachable(self.ptr)) - - # arithmethic, bitwise and logical - - def add(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value(_core.LLVMBuildAdd(self.ptr, lhs.ptr, rhs.ptr, name)) - - def fadd(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value(_core.LLVMBuildFAdd(self.ptr, lhs.ptr, rhs.ptr, name)) - - def sub(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value(_core.LLVMBuildSub(self.ptr, lhs.ptr, rhs.ptr, name)) - - def fsub(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value(_core.LLVMBuildFSub(self.ptr, lhs.ptr, rhs.ptr, name)) - - def mul(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value(_core.LLVMBuildMul(self.ptr, lhs.ptr, rhs.ptr, name)) - - def fmul(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value(_core.LLVMBuildFMul(self.ptr, lhs.ptr, rhs.ptr, name)) - - def udiv(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildUDiv(self.ptr, lhs.ptr, rhs.ptr, name)) - - def sdiv(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildSDiv(self.ptr, lhs.ptr, rhs.ptr, name)) - - def fdiv(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildFDiv(self.ptr, lhs.ptr, rhs.ptr, name)) - - def urem(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildURem(self.ptr, lhs.ptr, rhs.ptr, name)) - - def srem(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildSRem(self.ptr, lhs.ptr, rhs.ptr, name)) - - def frem(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildFRem(self.ptr, lhs.ptr, rhs.ptr, name)) - - def shl(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildShl(self.ptr, lhs.ptr, rhs.ptr, name)) - - def lshr(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildLShr(self.ptr, lhs.ptr, rhs.ptr, name)) - - def ashr(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildAShr(self.ptr, lhs.ptr, rhs.ptr, name)) - - def and_(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildAnd(self.ptr, lhs.ptr, rhs.ptr, name)) - - def or_(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildOr(self.ptr, lhs.ptr, rhs.ptr, name)) - - def xor(self, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildXor(self.ptr, lhs.ptr, rhs.ptr, name)) - - def neg(self, val, name=""): - check_is_value(val) - return _make_value(_core.LLVMBuildNeg(self.ptr, val.ptr, name)) - - def not_(self, val, name=""): - check_is_value(val) - return _make_value(_core.LLVMBuildNot(self.ptr, val.ptr, name)) - - # memory - - def malloc(self, ty, name=""): - check_is_type(ty) - return _make_value(_core.LLVMBuildMalloc(self.ptr, ty.ptr, name)) - - def malloc_array(self, ty, size, name=""): - check_is_type(ty) - check_is_value(size) - return _make_value( - _core.LLVMBuildArrayMalloc(self.ptr, ty.ptr, size.ptr, name)) - - def alloca(self, ty, name=""): - check_is_type(ty) - return _make_value(_core.LLVMBuildAlloca(self.ptr, ty.ptr, name)) - - def alloca_array(self, ty, size, name=""): - check_is_type(ty) - check_is_value(size) - return _make_value( - _core.LLVMBuildArrayAlloca(self.ptr, ty.ptr, size.ptr, name)) - - def free(self, ptr): - check_is_value(ptr) - return _make_value(_core.LLVMBuildFree(self.ptr, ptr.ptr)) - - def load(self, ptr, name="", align=0, volatile=False, invariant=False): - check_is_value(ptr) - inst = _make_value(_core.LLVMBuildLoad(self.ptr, ptr.ptr, name)) - if align: - _core.LLVMLdSetAlignment(inst.ptr, align) - if volatile: - inst.set_volatile(volatile) - if invariant: - mod = self.basic_block.function.module - md = MetaData.get(mod, []) # empty metadata node - inst.set_metadata('invariant.load', md) - return inst - - def store(self, value, ptr, align=0, volatile=False): - check_is_value(value) - check_is_value(ptr) - inst = _make_value(_core.LLVMBuildStore(self.ptr, value.ptr, ptr.ptr)) - if align: - _core.LLVMStSetAlignment(inst.ptr, align) - if volatile: - inst.set_volatile(volatile) - return inst - - def gep(self, ptr, indices, name="", inbounds=False): - check_is_value(ptr) - index_ptrs = unpack_values(indices) - if inbounds: - ret = _core.LLVMBuildInBoundsGEP(self.ptr, ptr.ptr, index_ptrs, name) - else: - ret = _core.LLVMBuildGEP(self.ptr, ptr.ptr, index_ptrs, name) - return _make_value(ret) - - # casts and extensions - - def trunc(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildTrunc(self.ptr, value.ptr, dest_ty.ptr, name)) - - def zext(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildZExt(self.ptr, value.ptr, dest_ty.ptr, name)) - - def sext(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildSExt(self.ptr, value.ptr, dest_ty.ptr, name)) - - def fptoui(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildFPToUI(self.ptr, value.ptr, dest_ty.ptr, name)) - - def fptosi(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildFPToSI(self.ptr, value.ptr, dest_ty.ptr, name)) - - def uitofp(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildUIToFP(self.ptr, value.ptr, dest_ty.ptr, name)) - - def sitofp(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildSIToFP(self.ptr, value.ptr, dest_ty.ptr, name)) - - def fptrunc(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildFPTrunc(self.ptr, value.ptr, dest_ty.ptr, name)) - - def fpext(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildFPExt(self.ptr, value.ptr, dest_ty.ptr, name)) - - def ptrtoint(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildPtrToInt(self.ptr, value.ptr, dest_ty.ptr, name)) - - def inttoptr(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildIntToPtr(self.ptr, value.ptr, dest_ty.ptr, name)) - - def bitcast(self, value, dest_ty, name=""): - check_is_value(value) - check_is_type(dest_ty) - return _make_value( - _core.LLVMBuildBitCast(self.ptr, value.ptr, dest_ty.ptr, name)) - - # comparisons - - def icmp(self, ipred, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildICmp(self.ptr, ipred, lhs.ptr, rhs.ptr, name)) - - def fcmp(self, rpred, lhs, rhs, name=""): - check_is_value(lhs) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildFCmp(self.ptr, rpred, lhs.ptr, rhs.ptr, name)) - - # misc - - def extract_value(self, retval, idx, name=""): - check_is_value(retval) - return _make_value( - _core.LLVMBuildGetResult(self.ptr, retval.ptr, idx, name)) - - # obsolete synonym for extract_value - getresult = extract_value - - def insert_value(self, retval, rhs, idx, name=""): - check_is_value(retval) - check_is_value(rhs) - return _make_value( - _core.LLVMBuildInsertValue(self.ptr, retval.ptr, rhs.ptr, idx, - name)) - - def phi(self, ty, name=""): - check_is_type(ty) - return _make_value(_core.LLVMBuildPhi(self.ptr, ty.ptr, name)) - - def call(self, fn, args, name=""): - check_is_callable(fn) - - err_template = 'Argument type mismatch: expected %s but got %s' - for i, (t, v) in enumerate(zip(fn.type.pointee.args, args)): - if t != v.type: - raise TypeError(err_template % (t, v.type)) - arg_ptrs = unpack_values(args) - return _make_value( - _core.LLVMBuildCall(self.ptr, fn.ptr, arg_ptrs, name)) - - def select(self, cond, then_value, else_value, name=""): - check_is_value(cond) - check_is_value(then_value) - check_is_value(else_value) - return _make_value( - _core.LLVMBuildSelect(self.ptr, cond.ptr, - then_value.ptr, else_value.ptr, name)) - - def vaarg(self, list_val, ty, name=""): - check_is_value(list_val) - check_is_type(ty) - return _make_value( - _core.LLVMBuildVAArg(self.ptr, list_val.ptr, ty.ptr, name)) - - def extract_element(self, vec_val, idx_val, name=""): - check_is_value(vec_val) - check_is_value(idx_val) - return _make_value( - _core.LLVMBuildExtractElement(self.ptr, vec_val.ptr, - idx_val.ptr, name)) - - def insert_element(self, vec_val, elt_val, idx_val, name=""): - check_is_value(vec_val) - check_is_value(elt_val) - check_is_value(idx_val) - return _make_value( - _core.LLVMBuildInsertElement(self.ptr, vec_val.ptr, - elt_val.ptr, idx_val.ptr, name)) - - def shuffle_vector(self, vecA, vecB, mask, name=""): - check_is_value(vecA) - check_is_value(vecB) - check_is_value(mask) - return _make_value( - _core.LLVMBuildShuffleVector(self.ptr, - vecA.ptr, vecB.ptr, mask.ptr, name)) - - # atomics - - def atomic_cmpxchg(self, ptr, old, new, ordering, crossthread=True): - check_is_value(ptr) - check_is_value(old) - check_is_value(new) - inst = _core.LLVMBuildAtomicCmpXchg(self.ptr, ptr.ptr, old.ptr, new.ptr, - ordering.lower(), - int(bool(crossthread))) - return _make_value(inst) - - def atomic_rmw(self, op, ptr, val, ordering, crossthread=True): - check_is_value(ptr) - check_is_value(val) - inst = _core.LLVMBuildAtomicRMW(self.ptr, op.lower(), ptr.ptr, val.ptr, - ordering.lower(), int(bool(crossthread))) - return _make_value(inst) - - def atomic_xchg(self, *args, **kwargs): - return self.atomic_rmw('xchg', *args, **kwargs) - - def atomic_add(self, *args, **kwargs): - return self.atomic_rmw('add', *args, **kwargs) - - def atomic_sub(self, *args, **kwargs): - return self.atomic_rmw('sub', *args, **kwargs) - - def atomic_and(self, *args, **kwargs): - return self.atomic_rmw('and', *args, **kwargs) - - def atomic_nand(self, *args, **kwargs): - return self.atomic_rmw('nand', *args, **kwargs) - - def atomic_or(self, *args, **kwargs): - return self.atomic_rmw('or', *args, **kwargs) - - def atomic_xor(self, *args, **kwargs): - return self.atomic_rmw('xor', *args, **kwargs) - - def atomic_max(self, *args, **kwargs): - return self.atomic_rmw('max', *args, **kwargs) - - def atomic_min(self, *args, **kwargs): - return self.atomic_rmw('min', *args, **kwargs) - - def atomic_umax(self, *args, **kwargs): - return self.atomic_rmw('umax', *args, **kwargs) - - def atomic_umin(self, *args, **kwargs): - return self.atomic_rmw('umin', *args, **kwargs) - - - def atomic_load(self, ptr, ordering, align=1, crossthread=True, - volatile=False, name=""): - check_is_value(ptr) - inst = _make_value(_core.LLVMBuildAtomicLoad( - self.ptr, ptr.ptr, int(align), - ordering.lower(), int(bool(crossthread)))) - if volatile: - inst.set_volatile(volatile) - if inst: - inst.name = name - return inst - - def atomic_store(self, value, ptr, ordering, align=1, crossthread=True, - volatile=False): - check_is_value(value) - check_is_value(ptr) - inst = _make_value(_core.LLVMBuildAtomicStore( - self.ptr, ptr.ptr, value.ptr, int(align), - ordering.lower(), int(bool(crossthread)))) - if volatile: - inst.set_volatile(volatile) - return inst - - def fence(self, ordering, crossthread=True): - inst = _make_value(_core.LLVMBuildFence(self.ptr, ordering.lower(), - int(bool(crossthread)))) - return inst - -#===----------------------------------------------------------------------=== -# Memory buffer -#===----------------------------------------------------------------------=== - -class MemoryBuffer(object): - - @staticmethod - def from_file(fname): - ret = _core.LLVMCreateMemoryBufferWithContentsOfFile(fname) - if isinstance(ret, str): - return (None, ret) - else: - obj = MemoryBuffer(ret) - return (obj, "") - - @staticmethod - def from_stdin(): - ret = _core.LLVMCreateMemoryBufferWithSTDIN() - if isinstance(ret, str): - return (None, ret) - else: - obj = MemoryBuffer(ret) - return (obj, "") - - def __init__(self, ptr): - self.ptr = ptr - - def __del__(self): - _core.LLVMDisposeMemoryBuffer(self.ptr) - - -#===----------------------------------------------------------------------=== -# Misc -#===----------------------------------------------------------------------=== - -def load_library_permanently(filename): - """Load a shared library. - - Load the given shared library (filename argument specifies the full - path of the .so file) using LLVM. Symbols from these are available - from the execution engine thereafter.""" - - ret = _core.LLVMLoadLibraryPermanently(filename) - if isinstance(ret, str): - raise llvm.LLVMException(ret) - -def inline_function(call): - check_is_value(call) - return bool(_core.LLVMInlineFunction(call.ptr)) - -def parse_environment_options(progname, envname): - _core.LLVMParseEnvOpts(progname, envname) - -#===----------------------------------------------------------------------=== -# Initialization -#===----------------------------------------------------------------------=== -if _core.LLVMInitializeNativeTarget(): - raise llvm.LLVMException("No native target!?") -if _core.LLVMInitializeNativeTargetAsmPrinter(): - # should this be an optional feature? - # should user trigger the initialization? - raise llvm.LLVMException("No native asm printer!?") - - -HAS_PTX = HAS_NVPTX = False -if True: # use PTX? - try: - _core.LLVMInitializePTXTarget() - _core.LLVMInitializePTXTargetInfo() - _core.LLVMInitializePTXTargetMC() - _core.LLVMInitializePTXAsmPrinter() - HAS_PTX = True - except AttributeError: - try: - _core.LLVMInitializeNVPTXTarget() - _core.LLVMInitializeNVPTXTargetInfo() - _core.LLVMInitializeNVPTXTargetMC() - _core.LLVMInitializeNVPTXAsmPrinter() - HAS_NVPTX = True - except AttributeError: - pass - + \ No newline at end of file diff --git a/llvm/debuginfo.py b/llvm/debuginfo.py deleted file mode 100644 index 0f18b33..0000000 --- a/llvm/debuginfo.py +++ /dev/null @@ -1,398 +0,0 @@ -""" -Support for debug info metadata. -""" - -import functools - -import llvm.core -from llvm import _dwarf - -#---------------------------------------------------------------------------- -# Some types and type checking functions -#---------------------------------------------------------------------------- - -int32_t = llvm.core.Type.int(32) -bool_t = llvm.core.Type.int(1) -p_int32_t = llvm.core.Type.pointer(int32_t) -null = llvm.core.Constant.null(p_int32_t) - -i32 = functools.partial(llvm.core.Constant.int, int32_t) -i1 = functools.partial(llvm.core.Constant.int, bool_t) - -def is_md(value): - return isinstance(value, (llvm.core.MetaData, llvm.core.NamedMetaData, - llvm.core.Value)) - -def is_mdstr(value): - return isinstance(value, (llvm.core.MetaDataString, llvm.core.Value)) - -#---------------------------------------------------------------------------- -# Callbacks for debug type descriptors -#---------------------------------------------------------------------------- - -def get_i32(llvm_module, value): - return i32(value) - -def get_i1(llvm_module, value): - return i1(value) - -def get_md(llvm_module, value): - if is_md(value): - return value - return value.get_metadata(llvm_module) - -def get_mdstr(llvm_module, value): - if is_mdstr(value): - return value - return llvm.core.MetaDataString.get(llvm_module, value) - -def get_mdlist(llvm_module, value): - if isinstance(value, list): - value = MDList([value]) - return get_md(llvm_module, value) - -def get_lfunc(llvm_module, lfunc): - assert lfunc.module is llvm_module - return lfunc - -#---------------------------------------------------------------------------- -# Debug descriptors that generate LLVM Metadata -#---------------------------------------------------------------------------- - -class desc(object): - """ - Descriptor of a debug field. - - field_name: - name of the field (keyword argument name) - build_metadata: - metadata callback :: (llvm_module, Python value) -> LLVM Value - default: - default value for this field - """ - - def __init__(self, field_name, build_metadata, default=None): - self.field_name = field_name - self.build_metadata = build_metadata - self.default = default - - -def build_operand_list(type_descriptors, idx2name, operands, kwargs): - """ - Build the list of operands from the positional and keyword arguments - to a DebugInfoDescriptor. - - E.g. FileDescriptor("foo.c", "/path/to/file", compile_unit=compile_unit) - - idx2name: {0 : 'source_filename', - 1 : 'source_filedir', - 2 : 'compile_unit' } - operands: ["foo.c", "/path/to/file"] - kwargs: { 'compile_unit' : compile_unit } - """ - for i in range(len(operands), len(type_descriptors)): - name = idx2name[i] - if name in kwargs: - op = kwargs[name] - else: - typedesc = type_descriptors[i] - assert typedesc.default is not None, ( - "No value found for field %s" % typedesc.field_name) - op = typedesc.default - - operands.append(op) - - return operands - - -class DebugInfoDescriptor(object): - """ - Base class to describe a debug info descriptor. - - See http://llvm.org/docs/SourceLevelDebugging.html - """ - - type_descriptors = None # [desc(...)] - idx2name = None # { "field_idx" : field_name } - name2idx = None # { "field_name" : field_idx } - - # Whether the debug descriptor is allowed to be incomplete - # The policy seems unclear ? - accept_optional_data = False - - def __init__(self, *args, **kwargs): - self.class_init() - self.metadata_cache = {} - - operands = list(args) - if kwargs or not self.accept_optional_data: - operands = build_operand_list(self.type_descriptors, - self.idx2name, operands, kwargs) - - self.operands = operands - self.operands_dict = dict( - (typedesc.field_name, operand) - for typedesc, operand in zip(self.type_descriptors, operands)) - - @classmethod - def class_init(cls): - if cls.idx2name is None and cls.type_descriptors is not None: - cls.name2idx = {} - cls.idx2name = {} - - for i, typedesc in enumerate(cls.type_descriptors): - cls.name2idx[typedesc.field_name] = i - cls.idx2name[i] = typedesc.field_name - - def add_metadata(self, metadata_name, metadata): - """ - Replace a metadata value in the operand list. - """ - idx = self.name2idx[metadata_name] - self.operands[idx] = metadata - - #------------------------------------------------------------------------ - # Define metadata in a module - #------------------------------------------------------------------------ - - def get_metadata(self, llvm_module): - """ - Get an existing metadata node for the given LLVM module, or build - one from this instance. - """ - if llvm_module in self.metadata_cache: - node = self.metadata_cache[llvm_module] - else: - node = self.build_metadata(llvm_module) - self.metadata_cache[llvm_module] = node - - return node - - def build_metadata(self, llvm_module): - "Build a metadata node for the given LLVM module" - mdops = [] - for type_desc, operand in zip(self.type_descriptors, self.operands): - try: - field_value = type_desc.build_metadata(llvm_module, operand) - except Exception, e: - if type_desc.build_metadata is get_md: - raise - - raise ValueError("Invalid value for field %r: %s" % ( - type_desc.field_name, e)) - - mdops.append(field_value) - - return llvm.core.MetaData.get(llvm_module, mdops) - - def define(self, llvm_module): - """ - Define this debug descriptor as named debug metadata for the module. - """ - md = self.get_metadata(llvm_module) - llvm.core.MetaData.add_named_operand(llvm_module, "dbg", md) - -#---------------------------------------------------------------------------- -# Convenience descriptors -#---------------------------------------------------------------------------- - -class MDList(DebugInfoDescriptor): - """ - [MetaData] - """ - - def __init__(self, operands): - self.type_descriptors = [desc("op", get_md)] * len(operands) - super(MDList, self).__init__(*operands) - -empty = MDList([]) - -#---------------------------------------------------------------------------- -# Dwarf Debug descriptors -#---------------------------------------------------------------------------- - -class CompileUnitDescriptor(DebugInfoDescriptor): - """ - !0 = metadata !{ - i32, ;; Tag = 17 + LLVMDebugVersion (DW_TAG_compile_unit) - i32, ;; Unused field. - i32, ;; DWARF language identifier (ex. DW_LANG_C89) - metadata, ;; Source file name - metadata, ;; Source file directory (includes trailing slash) - metadata ;; Producer (ex. "4.0.1 LLVM (LLVM research group)") - i1, ;; True if this is a main compile unit. - i1, ;; True if this is optimized. - metadata, ;; Flags - i32 ;; Runtime version - metadata ;; List of enums types - metadata ;; List of retained types - metadata ;; List of subprograms - metadata ;; List of global variables - } - """ - - accept_optional_data = True - - type_descriptors = [ - desc("tag", get_i32), - desc("unused", get_i32), - - # Positional argument list starts here: - desc("langid", get_i32), - desc("source_filename", get_mdstr), - desc("source_filedir", get_mdstr), - desc("producer", get_mdstr), - desc("is_main", get_i1, default=False), - desc("is_optimized", get_i1, default=False), - desc("compile_flags", get_mdstr, default=""), - desc("runtime_version", get_i32, default=0), - desc("enum_types", get_mdlist, default=empty), - desc("retained_types", get_mdlist, default=empty), - desc("subprograms", get_mdlist, default=empty), - desc("global_vars", get_mdlist, default=empty), - ] - - def __init__(self, *args, **kwargs): - super(CompileUnitDescriptor, self).__init__( - _dwarf.DW_TAG_compile_unit + _dwarf.LLVMDebugVersion, # tag - 0, # unused - *args, **kwargs) - - def define(self, llvm_module): - """ - Define this debug descriptor as named debug metadata for the module. - """ - md = self.get_metadata(llvm_module) - llvm.core.MetaData.add_named_operand(llvm_module, "llvm.dbg.cu", md) - - -class FileDescriptor(DebugInfoDescriptor): - """ - !0 = metadata !{ - i32, ;; Tag = 41 + LLVMDebugVersion (DW_TAG_file_type) - metadata, ;; Source file name - metadata, ;; Source file directory (includes trailing slash) - metadata ;; Unused - } - """ - - type_descriptors = [ - desc("tag", get_i32), - - # Positional argument list starts here: - desc("source_filename", get_mdstr), - desc("source_filedir", get_mdstr), - desc("compile_unit", get_md, default=null), - ] - - def __init__(self, *args, **kwargs): - super(FileDescriptor, self).__init__( - _dwarf.DW_TAG_file_type + _dwarf.LLVMDebugVersion, # Tag - *args, **kwargs) - - @classmethod - def from_compileunit(cls, compile_unit_descriptor): - return cls(compile_unit_descriptor.operands_dict["source_filename"], - compile_unit_descriptor.operands_dict["source_filedir"], - compile_unit_descriptor) - - -class SubprogramDescriptor(DebugInfoDescriptor): - """ - !2 = metadata !{ - i32, ;; Tag = 46 + LLVMDebugVersion (DW_TAG_subprogram) - i32, ;; Unused field. - metadata, ;; Reference to context descriptor - metadata, ;; Name - metadata, ;; Display name (fully qualified C++ name) - metadata, ;; MIPS linkage name (for C++) - metadata, ;; Reference to file where defined - i32, ;; Line number where defined - metadata, ;; Reference to type descriptor - i1, ;; True if the global is local to compile unit (static) - i1, ;; True if the global is defined in the compile unit (not extern) - i32, ;; Line number where the scope of the subprogram begins - i32, ;; Virtuality, e.g. dwarf::DW_VIRTUALITY__virtual - i32, ;; Index into a virtual function - metadata, ;; indicates which base type contains the vtable pointer for the - ;; derived class - i32, ;; Flags - Artifical, Private, Protected, Explicit, Prototyped. - i1, ;; isOptimized - Function * , ;; Pointer to LLVM function - metadata, ;; Lists function template parameters - metadata, ;; Function declaration descriptor - metadata ;; List of function variables - } - """ - - accept_optional_data = True - - type_descriptors = [ - desc("tag", get_i32), - desc("unused", get_i32), - - # Positional argument list starts here: - desc("file_desc", get_md), - desc("name", get_mdstr), - desc("display_name", get_mdstr), - desc("mips_linkage_name", get_mdstr), - desc("source_file_ref", get_md), - desc("line_number", get_i32), - desc("signature", get_md), - desc("is_local", get_i1, default=False), - desc("is_definition", get_i1, default=True), - desc("virtual_attribute", get_i32, default=0), - desc("virtual_index", get_i32, default=0), - desc("virttab", get_i32, default=0), - desc("flags", get_i32, default=0), - desc("is_optimized", get_i1, default=False), - desc("llvm_func", get_lfunc), - # Template params - # Func decl - # Func vars - ] - - def __init__(self, *args, **kwargs): - super(SubprogramDescriptor, self).__init__( - _dwarf.DW_TAG_subprogram + _dwarf.LLVMDebugVersion, # Tag - 0, # Unused - *args, **kwargs) - -class BlockDescriptor(DebugInfoDescriptor): - """ - !3 = metadata !{ - i32, ;; Tag = 11 + LLVMDebugVersion (DW_TAG_lexical_block) - metadata,;; Reference to context descriptor - i32, ;; Line number - i32 ;; Column number - } - """ - - type_descriptors = [ - desc("tag", get_i32), - - # Positional argument list starts here: - desc("context_descr", get_md), # FileDescr | BlockDescr | - # SubprogDescr | ComputeUnit - desc("line_number", get_i32), - desc("col_number", get_i32), - ] - - def __init__(self, *args, **kwargs): - super(BlockDescriptor, self).__init__( - _dwarf.DW_TAG_lexical_block + _dwarf.LLVMDebugVersion, - *args, **kwargs) - -class PositionInfoDescriptor(DebugInfoDescriptor): - """ - line number, column number, scope, and original scope - """ - - type_descriptors = [ - desc("line_number", get_i32), - desc("col_number", get_i32), - desc("context_descr", get_md), # Scope of instruction - # (FileDescr etc) - desc("original_context_descr", get_md, # The original scope if inlined - default=null), - ] diff --git a/llvm/ee.py b/llvm/ee.py index e5d6ef1..e69de29 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -1,392 +0,0 @@ -# -# Copyright (c) 2008-10, Mahadevan R All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of this software, nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - -"""Execution Engine and related classes. - -""" - -import llvm # top-level, for common stuff -import llvm.core as core # module, function etc. -import llvm._core as _core # C wrappers -import llvm._util as _util # utility functions -import logging -import os - -logger = logging.getLogger(__name__) - - -# re-export TargetData for backward compatibility. -from llvm.passes import TargetData - -def _detect_avx_support(): - '''FIXME: This is a workaround for AVX support. - ''' - disable_avx_detect = int(os.environ.get('LLVMPY_DISABLE_AVX_DETECT', 0)) - if disable_avx_detect: - return False # enable AVX if user disable AVX detect - force_disable_avx = int(os.environ.get('LLVMPY_FORCE_DISABLE_AVX', 0)) - if force_disable_avx: - return True # force disable AVX - # auto-detect avx - try: - for line in open('/proc/cpuinfo'): - if line.lstrip().startswith('flags') and 'avx' in line.split(): - # enable AVX if flags contain AVX - return False - except IOError: - pass # disable AVX if no /proc/cpuinfo is found - return True # disable AVX if flags does not have AVX - -FORCE_DISABLE_AVX = _detect_avx_support() - -#===----------------------------------------------------------------------=== -# Enumerations -#===----------------------------------------------------------------------=== - -BO_BIG_ENDIAN = 0 -BO_LITTLE_ENDIAN = 1 - -# CodeModel -CM_DEFAULT = 0 -CM_JITDEFAULT = 1 -CM_SMALL = 2 -CM_KERNEL = 3 -CM_MEDIUM = 4 -CM_LARGE = 5 - -#===----------------------------------------------------------------------=== -# Generic value -#===----------------------------------------------------------------------=== - -class GenericValue(object): - - @staticmethod - def int(ty, intval): - core.check_is_type(ty) - ptr = _core.LLVMCreateGenericValueOfInt(ty.ptr, intval, 0) - return GenericValue(ptr) - - @staticmethod - def int_signed(ty, intval): - core.check_is_type(ty) - ptr = _core.LLVMCreateGenericValueOfInt(ty.ptr, intval, 1) - return GenericValue(ptr) - - @staticmethod - def real(ty, floatval): - core.check_is_type(ty) # only float or double - ptr = _core.LLVMCreateGenericValueOfFloat(ty.ptr, floatval) - return GenericValue(ptr) - - @staticmethod - def pointer(*args): - ''' - One argument version takes (addr). - Two argument version takes (ty, addr). [Deprecated] - - `ty` is unused. - `addr` is an integer representing an address. - - TODO: remove two argument version. - ''' - if len(args)==2: - logger.warning("Deprecated: Two argument version of " - "GenericValue.pointer() is deprecated.") - addr = args[1] - elif len(args)!=1: - raise TypeError("pointer() takes 1 or 2 arguments.") - else: - addr = args[0] - ptr = _core.LLVMCreateGenericValueOfPointer(addr) - return GenericValue(ptr) - - def __init__(self, ptr): - self.ptr = ptr - - def __del__(self): - _core.LLVMDisposeGenericValue(self.ptr) - - def as_int(self): - return _core.LLVMGenericValueToInt(self.ptr, 0) - - def as_int_signed(self): - return _core.LLVMGenericValueToInt(self.ptr, 1) - - def as_real(self, ty): - core.check_is_type(ty) # only float or double - return _core.LLVMGenericValueToFloat(ty.ptr, self.ptr) - - def as_pointer(self): - return _core.LLVMGenericValueToPointer(self.ptr) - - -# helper functions for generic value objects -def check_is_generic_value(obj): _util.check_gen(obj, GenericValue) -def _unpack_generic_values(objlist): - return _util.unpack_gen(objlist, check_is_generic_value) - - -#===----------------------------------------------------------------------=== -# Engine builder -#===----------------------------------------------------------------------=== - -class EngineBuilder(object): - @staticmethod - def new(module): - core.check_is_module(module) - _util.check_is_unowned(module) - obj = _core.LLVMCreateEngineBuilder(module.ptr) - return EngineBuilder(obj, module) - - def __init__(self, ptr, module): - self.ptr = ptr - self._module = module - self.__has_mattrs = False - - def __del__(self): - _core.LLVMDisposeEngineBuilder(self.ptr) - - def force_jit(self): - _core.LLVMEngineBuilderForceJIT(self.ptr) - return self - - def force_interpreter(self): - _core.LLVMEngineBuilderForceInterpreter(self.ptr) - return self - - def opt(self, level): - ''' - level valid [0, 1, 2, 3] -- [None, Less, Default, Aggressive] - ''' - assert level in range(4) - _core.LLVMEngineBuilderSetOptLevel(self.ptr, level) - return self - - def mattrs(self, string): - '''set machine attributes as a comma/space separated string - - e.g: +sse,-3dnow - ''' - self.__has_mattrs = True - if FORCE_DISABLE_AVX: - if 'avx' not in map(lambda x: x.strip(), string.split(',')): - # User did not override - string += ',-avx' - _core.LLVMEngineBuilderSetMAttrs(self.ptr, string.replace(',', ' ')) - return self - - def create(self, tm=None): - ''' - tm --- Optional. Provide a TargetMachine. Ownership is transfered - to the returned execution engine. - ''' - if not self.__has_mattrs and FORCE_DISABLE_AVX: - self.mattrs('-avx') - - if tm: - _util.check_is_unowned(tm) - ret = _core.LLVMEngineBuilderCreateTM(self.ptr, tm.ptr) - else: - ret = _core.LLVMEngineBuilderCreate(self.ptr) - if isinstance(ret, str): - raise llvm.LLVMException(ret) - engine = ExecutionEngine(ret, self._module) - if tm: - tm._own(owner=llvm.DummyOwner) - return engine - - def select_target(self): - '''get the corresponding target machine - ''' - ptr = _core.LLVMTargetMachineFromEngineBuilder(self.ptr) - return TargetMachine(ptr) - -#===----------------------------------------------------------------------=== -# Execution engine -#===----------------------------------------------------------------------=== - -class ExecutionEngine(object): - - @staticmethod - def new(module, force_interpreter=False): - eb = EngineBuilder.new(module) - if force_interpreter: - eb.force_interpreter() - return eb.create() - - def __init__(self, ptr, module): - self.ptr = ptr - module._own(self) - - def __del__(self): - _core.LLVMDisposeExecutionEngine(self.ptr) - - def disable_lazy_compilation(self, disabled=True): - _core.LLVMExecutionEngineDisableLazyCompilation(self.ptr, - int(bool(disabled))) - - def run_function(self, fn, args): - core.check_is_function(fn) - ptrs = _unpack_generic_values(args) - gvptr = _core.LLVMRunFunction2(self.ptr, fn.ptr, ptrs) - return GenericValue(gvptr) - - def get_pointer_to_function(self, fn): - core.check_is_function(fn) - return _core.LLVMGetPointerToFunction(self.ptr,fn.ptr) - - def get_pointer_to_global(self, val): - core.check_is_global_value(val) - return _core.LLVMGetPointerToGlobal(self.ptr, val.ptr) - - def add_global_mapping(self, gvar, addr): - assert addr >= 0, "Address cannot not be negative" - _core.LLVMAddGlobalMapping(self.ptr, gvar.ptr, addr) - - def run_static_ctors(self): - _core.LLVMRunStaticConstructors(self.ptr) - - def run_static_dtors(self): - _core.LLVMRunStaticDestructors(self.ptr) - - def free_machine_code_for(self, fn): - core.check_is_function(fn) - _core.LLVMFreeMachineCodeForFunction(self.ptr, fn.ptr) - - def add_module(self, module): - core.check_is_module(module) - _core.LLVMAddModule(self.ptr, module.ptr) - module._own(self) - - def remove_module(self, module): - core.check_is_module(module) - if module.owner != self: - raise llvm.LLVMException("module is not owned by self") - ret = _core.LLVMRemoveModule2(self.ptr, module.ptr) - if isinstance(ret, str): - raise llvm.LLVMException(ret) - return core.Module(ret) - - @property - def target_data(self): - td = TargetData(_core.LLVMGetExecutionEngineTargetData(self.ptr)) - td._own(self) - return td - - -#===----------------------------------------------------------------------=== -# Target machine -#===----------------------------------------------------------------------=== - -def print_registered_targets(): - ''' - Note: print directly to stdout - ''' - _core.LLVMPrintRegisteredTargetsForVersion() - -def get_host_cpu_name(): - '''return the string name of the host CPU - ''' - return _core.LLVMGetHostCPUName() - -def get_default_triple(): - '''return the target triple of the host in str-rep - ''' - return _core.LLVMDefaultTargetTriple() - - -class TargetMachine(llvm.Ownable): - - @staticmethod - def new(triple='', cpu='', features='', opt=2, cm=CM_DEFAULT): - if not triple and not cpu: - triple = get_default_triple() - cpu = get_host_cpu_name() - ptr = _core.LLVMCreateTargetMachine(triple, cpu, features, opt, cm) - return TargetMachine(ptr) - - @staticmethod - def lookup(arch, cpu='', features='', opt=2, cm=CM_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` - ''' - ptr = _core.LLVMTargetMachineLookup(arch, cpu, features, opt, cm) - return TargetMachine(ptr) - - def __init__(self, ptr): - llvm.Ownable.__init__(self, ptr, _core.LLVMDisposeTargetMachine) - - def emit_assembly(self, module): - '''returns byte string of the module as assembly code of the target machine - ''' - return _core.LLVMTargetMachineEmitFile(self.ptr, module.ptr, True) - - def emit_object(self, module): - '''returns byte string of the module as native code of the target machine - ''' - return _core.LLVMTargetMachineEmitFile(self.ptr, module.ptr, False) - - @property - def target_data(self): - '''get target data of this machine - ''' - ptr = _core.LLVMTargetMachineGetTargetData(self.ptr) - td = TargetData(ptr) - td._own(self) - return td - - @property - def target_name(self): - return _core.LLVMTargetMachineGetTargetName(self.ptr) - - @property - def target_short_description(self): - return _core.LLVMTargetMachineGetTargetShortDescription(self.ptr) - - @property - def triple(self): - return _core.LLVMTargetMachineGetTriple(self.ptr) - - @property - def cpu(self): - return _core.LLVMTargetMachineGetCPU(self.ptr) - - @property - def feature_string(self): - return _core.LLVMTargetMachineGetFS(self.ptr) - diff --git a/llvm/extra.cpp b/llvm/extra.cpp deleted file mode 100644 index 7b6c064..0000000 --- a/llvm/extra.cpp +++ /dev/null @@ -1,1361 +0,0 @@ -/* - * Copyright (c) 2008-10, Mahadevan R All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of this software, nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * These are some "extra" functions not available in the standard LLVM-C - * bindings, but are required / good-to-have inorder to implement the - * Python bindings. - */ - -// standard includes -#include -#include -#include -#include -#include - -// LLVM includes -#include "llvm/LLVMContext.h" -#include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Casting.h" -#include "llvm/Constants.h" -#include "llvm/DerivedTypes.h" -#include "llvm/GlobalVariable.h" -//#include "llvm/TypeSymbolTable.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/CallSite.h" -#include "llvm/Support/FormattedStream.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Support/Host.h" - -#include "llvm/IntrinsicInst.h" -#include "llvm/Analysis/Verifier.h" -#include "llvm/Assembly/Parser.h" -#include "llvm/Support/DynamicLibrary.h" -#include "llvm/PassManager.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/Analysis/LoopPass.h" -#include "llvm/Analysis/Passes.h" -#include "llvm/Analysis/DomPrinter.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/IPO.h" -#include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h" -#include "llvm/Transforms/Instrumentation.h" -#include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/Linker.h" -#include "llvm/Support/SourceMgr.h" -#include -#include -#include - - -#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 2 - #include "llvm/DataLayout.h" -#else - #include "llvm/Target/TargetData.h" -#endif - -// LLVM-C includes -#include "llvm-c/Core.h" -#include "llvm-c/ExecutionEngine.h" - -// our includes -#include "extra.h" -#include "llvm_c_extra.h" - -namespace llvm{ -DEFINE_SIMPLE_CONVERSION_FUNCTIONS(EngineBuilder, LLVMEngineBuilderRef) -DEFINE_SIMPLE_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef) -DEFINE_SIMPLE_CONVERSION_FUNCTIONS(NamedMDNode, LLVMNamedMDRef) -DEFINE_SIMPLE_CONVERSION_FUNCTIONS(Pass, LLVMPassRef) - -template -inline T **unwrap(LLVMTypeRef *Tys, unsigned Length) { - (void)Length; - return reinterpret_cast(Tys); -} - -} - -/* - * For use in LLVMDumpPasses to dump passes. - */ -class PassRegistryPrinter : public llvm::PassRegistrationListener{ -public: - std::ostringstream stringstream; - - inline virtual void passEnumerate(const llvm::PassInfo * pass_info){ - stringstream << pass_info->getPassArgument() - << "\t" - << pass_info->getPassName() - << "\n"; - } -}; - - -/* Helper method for LLVMDumpXXXToString() methods. */ -template -char *do_print(W obj) -{ - std::string s; - llvm::raw_string_ostream buf(s); - UW *p = llvm::unwrap(obj); - assert(p); - p->print(buf); - return strdup(buf.str().c_str()); -} - -namespace { -using namespace llvm; -const CodeGenOpt::Level OptLevelMap[] = { - CodeGenOpt::None, - CodeGenOpt::Less, - CodeGenOpt::Default, - CodeGenOpt::Aggressive, -}; - -const CodeModel::Model CodeModelMap[] = { - CodeModel::Default, - CodeModel::JITDefault, - CodeModel::Small, - CodeModel::Kernel, - CodeModel::Medium, - CodeModel::Large, -}; - - -} // end anony namespace - -#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 2 -LLVMPassRef LLVMCreateTargetTransformInfo(LLVMTargetMachineRef tmref){ - using namespace llvm; - TargetMachine * tm = unwrap(tmref); - Pass * tti = new TargetTransformInfo(tm->getScalarTargetTransformInfo(), - tm->getVectorTargetTransformInfo()); - return wrap(tti); -} -#endif - -LLVMPassRef LLVMCreateTargetLibraryInfo(const char * triple){ - using namespace llvm; - Pass * tli = new TargetLibraryInfo(Triple(triple)); - return wrap(tli); -} - -const char * LLVMDefaultTargetTriple(){ - return strdup(llvm::sys::getDefaultTargetTriple().c_str()); -} - -LLVMPassRef LLVMCreatePassByName(const char *name){ - using namespace llvm; - const PassInfo * pi = Pass::lookupPassInfo(StringRef(name)); - if (pi) { - return wrap(pi->createPass()); - } else { // cannot find pass - return NULL; - } -} - -void LLVMDisposePass(LLVMPassRef passref){ - using namespace llvm; - delete unwrap(passref); -} - -const char * LLVMGetPassName(LLVMPassRef passref){ - using namespace llvm; - return unwrap(passref)->getPassName(); -} - -void LLVMPassDump(LLVMPassRef passref){ - using namespace llvm; - return unwrap(passref)->dump(); -} - -void LLVMAddPass(LLVMPassManagerRef pmref, LLVMPassRef passref){ - using namespace llvm; - unwrap(pmref)->add(unwrap(passref)); -} - -LLVMValueRef LLVMGetFunctionFromInlineAsm(LLVMTypeRef funcType, - const char inlineAsm[], - const char constrains[], - bool hasSideEffect, - bool isAlignStack, - int asmDialect) -{ - using namespace llvm; - FunctionType *fnty = unwrap(funcType); - // asmDialect does not exist for LLVM 3.1 - InlineAsm *inlineasmobj = InlineAsm::get(fnty, inlineAsm, constrains, - hasSideEffect, isAlignStack); - return wrap(inlineasmobj); -} - -LLVMModuleRef LLVMCloneModule(LLVMModuleRef mod) -{ - using namespace llvm; - return wrap(CloneModule(unwrap(mod))); -} - -const char * LLVMDumpNamedMDToString(LLVMNamedMDRef nmd) -{ - using namespace llvm; - std::string s; - llvm::raw_string_ostream buf(s); - unwrap(nmd)->print(buf, NULL); - return strdup(buf.str().c_str()); -} - -const char * LLVMNamedMetaDataGetName(LLVMNamedMDRef nmd) -{ - using namespace llvm; - return unwrap(nmd)->getName().data(); -} - -void LLVMNamedMetaDataAddOperand(LLVMNamedMDRef nmd, LLVMValueRef md) -{ - using namespace llvm; - unwrap(nmd)->addOperand(unwrap(md)); -} - -void LLVMEraseNamedMetaData(LLVMNamedMDRef nmd) -{ - using namespace llvm; - unwrap(nmd)->eraseFromParent(); -} - -LLVMNamedMDRef LLVMModuleGetOrInsertNamedMetaData(LLVMModuleRef mod, const char *name) -{ - using namespace llvm; - return wrap(unwrap(mod)->getOrInsertNamedMetadata(name)); -} - -LLVMNamedMDRef LLVMModuleGetNamedMetaData(LLVMModuleRef mod, const char *name) -{ - using namespace llvm; - return wrap(unwrap(mod)->getNamedMetadata(name)); -} - -void LLVMInstSetMetaData(LLVMValueRef instref, const char* mdkind, - LLVMValueRef metaref) -{ - using namespace llvm; - unwrap(instref)->setMetadata(mdkind, unwrap(metaref)); -} - -LLVMValueRef LLVMMetaDataGet(LLVMModuleRef modref, LLVMValueRef * valrefs, - unsigned valct) -{ - using namespace llvm; - LLVMContext & context = unwrap(modref)->getContext(); - MDNode * const node = MDNode::get( - context, - makeArrayRef(unwrap(valrefs, valct), valct)); - return wrap(node); -} - -LLVMValueRef LLVMMetaDataGetOperand(LLVMValueRef mdref, unsigned index) -{ - return wrap(llvm::unwrap(mdref)->getOperand(index)); -} - -unsigned LLVMMetaDataGetNumOperands(LLVMValueRef mdref) -{ - return llvm::unwrap(mdref)->getNumOperands(); -} - -LLVMValueRef LLVMMetaDataStringGet(LLVMModuleRef modref, const char *s) -{ - LLVMContext & context = unwrap(modref)->getContext(); - MDString * const mdstring = MDString::get(context, s); - return wrap(mdstring); -} - -const char *LLVMGetConstExprOpcodeName(LLVMValueRef inst) -{ - return llvm::unwrap(inst)->getOpcodeName(); -} - -unsigned LLVMGetConstExprOpcode(LLVMValueRef inst) -{ - return llvm::unwrap(inst)->getOpcode(); -} - -void LLVMLdSetAlignment(LLVMValueRef inst, unsigned align) -{ - return llvm::unwrap(inst)->setAlignment(align); -} - -void LLVMStSetAlignment(LLVMValueRef inst, unsigned align) -{ - return llvm::unwrap(inst)->setAlignment(align); -} - -const char * LLVMGetHostCPUName() -{ - return strdup(llvm::sys::getHostCPUName().c_str()); -} - -const char * LLVMGetHostCPUFeatures() -{ - // placeholder - // TODO not implemented even in LLVM3.2svn - // llvm::sys::getHostCPUFeatures - return NULL; -} - -int LLVMInitializeNativeTargetAsmPrinter() -{ - return llvm::InitializeNativeTargetAsmPrinter(); -} - - -LLVMTargetMachineRef LLVMTargetMachineLookup(const char *arch, const char *cpu, - const char *features, int opt, - int codemodel, - std::string &error) -{ - using namespace llvm; - Triple TheTriple; - - // begin borrow from LLVM 3.2 code - // because we don't have 3 argument version of lookup() in 3.1 - const Target * TheTarget = NULL; - - const std::string ArchName(arch); - for (TargetRegistry::iterator it = TargetRegistry::begin(), - ie = TargetRegistry::end(); it != ie; ++it) { - if (ArchName == it->getName()) { - TheTarget = &*it; - break; - } - } - - if (!TheTarget) { - error = "Unknown arch"; - return NULL; - } - - Triple::ArchType Type = Triple::getArchTypeForLLVMName(ArchName); - - if (Type != Triple::UnknownArch){ - TheTriple.setArch(Type); - } - // end borrow from LLVM 3.2 code - - if (!TheTarget->hasTargetMachine()){ - error = "No target machine for the arch"; - return NULL; - } - - TargetOptions no_target_options; - TargetMachine * tm = TheTarget->createTargetMachine(TheTriple.str(), cpu, - features, - no_target_options, - Reloc::Default, - CodeModelMap[codemodel], - OptLevelMap[opt]); - - if (!tm){ - error = "Cannot create target machine"; - return NULL; - } - return wrap(tm); -} - -LLVMTargetMachineRef LLVMCreateTargetMachine(const char *triple, - const char *cpu, - const char *features, - int opt, - int codemodel, - std::string &error) -{ - using namespace llvm; - - std::string TheTriple = triple; - const Target * TheTarget = TargetRegistry::lookupTarget(TheTriple, error); - if (!TheTarget) return NULL; - - TargetOptions no_target_options; - TargetMachine * tm = TheTarget->createTargetMachine(TheTriple, cpu, features, - no_target_options, - Reloc::Default, - CodeModelMap[codemodel], - OptLevelMap[opt]); - if (!tm) { - error = "Cannot create target machine"; - return NULL; - } - return wrap(tm); -} - -LLVMTargetMachineRef LLVMTargetMachineFromEngineBuilder(LLVMEngineBuilderRef eb) -{ - using namespace llvm; - TargetMachine * tm = unwrap(eb)->selectTarget(); - return wrap(tm); -} - -void LLVMDisposeTargetMachine(LLVMTargetMachineRef tm){ - delete llvm::unwrap(tm); -} - - -unsigned char* LLVMTargetMachineEmitFile(LLVMTargetMachineRef tmref, - LLVMModuleRef modref, - int assembly, size_t * lenp, - std::string &error) -{ - using namespace llvm; - assert(lenp); - - Module *modulep = unwrap(modref); - assert(modulep); - - // get objectcode into a string - std::string s; - raw_string_ostream buf(s); - - formatted_raw_ostream fso(buf); - - TargetMachine * tm = unwrap(tmref); - - PassManager pm; -#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 2 - if (!tm->getDataLayout()){ - error = "No target data in target machine"; - return NULL; - } - pm.add(new DataLayout(*tm->getDataLayout())); -#else - if (!tm->getTargetData()){ - error = "No target data in target machine"; - return NULL; - } - pm.add(new TargetData(*tm->getTargetData())); -#endif - - - - bool failed; - if( assembly ) { - failed = tm->addPassesToEmitFile(pm, fso, TargetMachine::CGFT_AssemblyFile); - } else { - failed = tm->addPassesToEmitFile(pm, fso, TargetMachine::CGFT_ObjectFile); - } - - if ( failed ) { - error = "No support for emit file"; - return NULL; - } - - pm.run(*modulep); - - // flush all streams - fso.flush(); - buf.flush(); - - const std::string& bc = buf.str(); - - // and then into a new buffer - size_t bclen = bc.size(); - unsigned char *bytes = new unsigned char[bclen]; - memcpy(bytes, bc.data(), bclen); - - /* return */ - *lenp = bclen; - return bytes; -} - -const char* LLVMTargetMachineGetTargetName(LLVMTargetMachineRef tm) -{ - return strdup(llvm::unwrap(tm)->getTarget().getName()); -} - -const char* LLVMTargetMachineGetTargetShortDescription(LLVMTargetMachineRef tm) -{ - return strdup(llvm::unwrap(tm)->getTarget().getShortDescription()); -} - -const char* LLVMTargetMachineGetTriple(LLVMTargetMachineRef tm) -{ - return strdup(llvm::unwrap(tm)->getTargetTriple().str().c_str()); -} - -const char* LLVMTargetMachineGetCPU(LLVMTargetMachineRef tm) -{ - return strdup(llvm::unwrap(tm)->getTargetCPU().str().c_str()); -} - -const char* LLVMTargetMachineGetFS(LLVMTargetMachineRef tm) -{ - return strdup(llvm::unwrap(tm)->getTargetFeatureString().str().c_str()); -} - -void LLVMPrintRegisteredTargetsForVersion(){ - llvm::TargetRegistry::printRegisteredTargetsForVersion(); -} - - - -LLVMTargetDataRef LLVMTargetMachineGetTargetData(LLVMTargetMachineRef tm) -{ - using namespace llvm; -#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 2 - return wrap(new DataLayout(*unwrap(tm)->getDataLayout())); -#else - return wrap(new TargetData(*unwrap(tm)->getTargetData())); -#endif -} - -unsigned char* LLVMGetNativeCodeFromModule(LLVMModuleRef module, int assembly, - size_t * lenp, std::string &error) -{ - using namespace llvm; - assert(lenp); - - Module *modulep = unwrap(module); - assert(modulep); - - // select native default machine - TargetMachine * tm = EngineBuilder(modulep).selectTarget(); - - return LLVMTargetMachineEmitFile(wrap(tm), module, assembly, lenp, error); -} - -static -llvm::AtomicOrdering atomic_ordering_from_string(const char * ordering) -{ - using namespace llvm; - - if ( strcmp(ordering, "unordered") == 0 ) - return Unordered; - else if ( strcmp(ordering, "monotonic") == 0 ) - return Monotonic; - else if ( strcmp(ordering, "acquire") == 0 ) - return Acquire; - else if ( strcmp(ordering, "release") == 0 ) - return Release; - else if ( strcmp(ordering, "acq_rel") == 0 ) - return AcquireRelease; - else if ( strcmp(ordering, "seq_cst") == 0 ) - return SequentiallyConsistent; - else - return NotAtomic; -} - -static -llvm::SynchronizationScope sync_scope_from_int(int crossthread) -{ - if( crossthread ) - return llvm::CrossThread; - else - return llvm::SingleThread; -} - -LLVMValueRef LLVMBuildFence(LLVMBuilderRef builder, const char* ordering, - int crossthread) -{ - using namespace llvm; - AtomicOrdering atomic_order = atomic_ordering_from_string(ordering); - SynchronizationScope sync_scope = sync_scope_from_int(crossthread); - - Value * inst = unwrap(builder)->CreateFence(atomic_order, sync_scope); - return wrap(inst); -} - -LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef builder, const char * opname, - LLVMValueRef ptr, LLVMValueRef val, - const char* ordering, int crossthread) -{ - using namespace llvm; - - AtomicRMWInst::BinOp op; - - if( strcmp(opname, "xchg") == 0 ) - op = AtomicRMWInst::Xchg; - else if( strcmp(opname, "add") == 0 ) - op = AtomicRMWInst::Add; - else if( strcmp(opname, "sub") == 0 ) - op = AtomicRMWInst::Sub; - else if( strcmp(opname, "and") == 0 ) - op = AtomicRMWInst::And; - else if( strcmp(opname, "nand") == 0 ) - op = AtomicRMWInst::Nand; - else if( strcmp(opname, "or") == 0 ) - op = AtomicRMWInst::Or; - else if( strcmp(opname, "xor") == 0 ) - op = AtomicRMWInst::Xor; - else if( strcmp(opname, "max") == 0 ) - op = AtomicRMWInst::Max; - else if( strcmp(opname, "min") == 0 ) - op = AtomicRMWInst::Min; - else if( strcmp(opname, "umax") == 0 ) - op = AtomicRMWInst::UMax; - else if( strcmp(opname, "umin") == 0 ) - op = AtomicRMWInst::UMin; - else - op = AtomicRMWInst::BAD_BINOP; - - AtomicOrdering atomic_order = atomic_ordering_from_string(ordering); - SynchronizationScope sync_scope = sync_scope_from_int(crossthread); - - Value * inst = unwrap(builder)->CreateAtomicRMW(op, unwrap(ptr), unwrap(val), - atomic_order, sync_scope); - return wrap(inst); -} - -LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef builder, LLVMValueRef ptr, - unsigned align, const char* ordering, - int crossthread) -{ - using namespace llvm; - AtomicOrdering atomic_order = atomic_ordering_from_string(ordering); - SynchronizationScope sync_scope = sync_scope_from_int(crossthread); - - LoadInst * inst = unwrap(builder)->CreateLoad(unwrap(ptr)); - - inst->setAtomic(atomic_order, sync_scope); - inst->setAlignment(align); - - return wrap(inst); -} - -LLVMValueRef LLVMBuildAtomicStore(LLVMBuilderRef builder, - LLVMValueRef ptr, LLVMValueRef val, - unsigned align, const char* ordering, - int crossthread) -{ - using namespace llvm; - AtomicOrdering atomic_order = atomic_ordering_from_string(ordering); - SynchronizationScope sync_scope = sync_scope_from_int(crossthread); - - StoreInst * inst = unwrap(builder)->CreateStore(unwrap(val), unwrap(ptr)); - - inst->setAtomic(atomic_order, sync_scope); - inst->setAlignment(align); - - return wrap(inst); -} - -LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, - LLVMValueRef cmp, LLVMValueRef val, - const char* ordering, int crossthread) -{ - using namespace llvm; - - AtomicOrdering atomic_order = atomic_ordering_from_string(ordering); - SynchronizationScope sync_scope = sync_scope_from_int(crossthread); - - Value * inst = unwrap(builder)->CreateAtomicCmpXchg( - unwrap(ptr), unwrap(cmp), unwrap(val), - atomic_order, sync_scope); - return wrap(inst); -} - -LLVMEngineBuilderRef LLVMCreateEngineBuilder(LLVMModuleRef mod) -{ - return llvm::wrap(new EngineBuilder(unwrap(mod))); -} - -void LLVMDisposeEngineBuilder(LLVMEngineBuilderRef eb) -{ - delete llvm::unwrap(eb); -} - -void LLVMEngineBuilderForceJIT(LLVMEngineBuilderRef eb) -{ - using namespace llvm; - unwrap(eb)->setEngineKind(EngineKind::JIT); -} - -void LLVMEngineBuilderForceInterpreter(LLVMEngineBuilderRef eb) -{ - using namespace llvm; - unwrap(eb)->setEngineKind(EngineKind::Interpreter); -} - -void LLVMEngineBuilderSetOptLevel(LLVMEngineBuilderRef eb, int level) -{ - unwrap(eb)->setOptLevel(OptLevelMap[level]); -} - -void LLVMEngineBuilderSetMCPU(LLVMEngineBuilderRef eb, const char * mcpu) -{ // TODO add test when llvm3.2 releases - unwrap(eb)->setMCPU(mcpu); // does not work in llvm3.1 -} - -void LLVMEngineBuilderSetMAttrs(LLVMEngineBuilderRef eb, const char * mattrs) -{ // TODO add test when llvm3.2 releases - std::vector tokenized; - std::istringstream iss(mattrs); - std::string buf; - while ( iss >> buf ){ - tokenized.push_back(buf); - } - unwrap(eb)->setMAttrs(tokenized); // does not work in llvm3.1 -} - -LLVMExecutionEngineRef LLVMEngineBuilderCreate(LLVMEngineBuilderRef eb, std::string & error) -{ - using namespace llvm; - LLVMExecutionEngineRef ret; - - ret = wrap(unwrap(eb)->setErrorStr(&error).create()); - - if ( !error.empty() ) { // error string is set - return NULL; - } else { - return ret; - } -} - -LLVMExecutionEngineRef LLVMEngineBuilderCreateTM(LLVMEngineBuilderRef eb, - LLVMTargetMachineRef tm, - std::string & error) -{ - using namespace llvm; - LLVMExecutionEngineRef ret; - - ret = wrap(unwrap(eb)->setErrorStr(&error).create(unwrap(tm))); - - if ( !error.empty() ) { // error string is set - return NULL; - } else { - return ret; - } -} - -int LLVMPassManagerBuilderGetOptLevel(LLVMPassManagerBuilderRef pmb) -{ - return llvm::unwrap(pmb)->OptLevel; -} - -int LLVMPassManagerBuilderGetSizeLevel(LLVMPassManagerBuilderRef pmb) -{ - return llvm::unwrap(pmb)->SizeLevel; -} - -void LLVMPassManagerBuilderSetVectorize(LLVMPassManagerBuilderRef pmb, int flag) -{ - llvm::unwrap(pmb)->Vectorize = flag; -} - -int LLVMPassManagerBuilderGetVectorize(LLVMPassManagerBuilderRef pmb){ - return llvm::unwrap(pmb)->Vectorize; -} - -#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 2 -void LLVMPassManagerBuilderSetLoopVectorize(LLVMPassManagerBuilderRef pmb, - int flag) -{ - llvm::unwrap(pmb)->LoopVectorize = flag; -} - -int LLVMPassManagerBuilderGetLoopVectorize(LLVMPassManagerBuilderRef pmb){ - return llvm::unwrap(pmb)->LoopVectorize; -} -#endif // llvm-3.2 - - -int LLVMPassManagerBuilderGetDisableUnitAtATime(LLVMPassManagerBuilderRef pmb) -{ - return llvm::unwrap(pmb)->DisableUnitAtATime; -} - -int LLVMPassManagerBuilderGetDisableUnrollLoops(LLVMPassManagerBuilderRef pmb) -{ - return llvm::unwrap(pmb)->DisableUnrollLoops; -} - -int LLVMPassManagerBuilderGetDisableSimplifyLibCalls(LLVMPassManagerBuilderRef pmb) -{ - return llvm::unwrap(pmb)->DisableSimplifyLibCalls; -} - - -int LLVMAddPassByName(LLVMPassManagerRef pm, const char * name) -{ - using namespace llvm; - const PassInfo * pi = Pass::lookupPassInfo(StringRef(name)); - if (pi){ - unwrap(pm)->add(pi->createPass()); - return 1; // success - } else { - return 0; // fail -- cannot find pass - } -} - -void LLVMInitializePasses(){ - using namespace llvm; - PassRegistry ®istry = *PassRegistry::getPassRegistry(); - initializeCore(registry); - initializeScalarOpts(registry); - initializeVectorization(registry); - initializeIPO(registry); - initializeAnalysis(registry); - initializeIPA(registry); - initializeTransformUtils(registry); - initializeInstCombine(registry); - initializeInstrumentation(registry); - initializeTarget(registry); -} - -const char * LLVMDumpPasses() -{ - using namespace llvm; - PassRegistry ®istry = *PassRegistry::getPassRegistry(); - PassRegistryPrinter prp; - registry.enumerateWith(&prp); - return strdup(prp.stringstream.str().c_str()); -} - - -int LLVMIsLiteralStruct(LLVMTypeRef type) -{ - return llvm::unwrap(type)->isLiteral(); -} - -LLVMTypeRef LLVMStructTypeIdentified(const char * name) -{ - using namespace llvm; - return wrap(StructType::create(getGlobalContext(), name)); -} - -void LLVMSetStructBody(LLVMTypeRef type, LLVMTypeRef* elemtys, - unsigned elemct, int is_packed) -{ - using namespace llvm; - ArrayRef elemtys_aryref(unwrap(elemtys), elemct); - unwrap(type)->setBody(elemtys_aryref, is_packed); -} - -void LLVMSetStructName(LLVMTypeRef type, const char * name) -{ - llvm::StructType *st = llvm::unwrap(type); - st->setName(name); -} - -char *LLVMGetModuleIdentifier(LLVMModuleRef module) -{ - return strdup(llvm::unwrap(module)->getModuleIdentifier().c_str()); -} - -void LLVMSetModuleIdentifier(LLVMModuleRef module, const char * name) -{ - llvm::unwrap(module)->setModuleIdentifier(name); -} - -char *LLVMDumpModuleToString(LLVMModuleRef module) -{ - std::string s; - llvm::raw_string_ostream buf(s); - llvm::Module *p = llvm::unwrap(module); - assert(p); - p->print(buf, NULL); - return strdup(buf.str().c_str()); -} - -void LLVMModuleAddLibrary(LLVMModuleRef module, const char *name) -{ - llvm::Module *M = llvm::unwrap(module); - llvm::StringRef namestr = llvm::StringRef(name); - M->addLibrary(namestr); - return; -} - -char *LLVMDumpTypeToString(LLVMTypeRef type) -{ - return do_print(type); -} - -char *LLVMDumpValueToString(LLVMValueRef value) -{ - return do_print(value); -} - -unsigned LLVMModuleGetPointerSize(LLVMModuleRef module) -{ - llvm::Module *modulep = llvm::unwrap(module); - assert(modulep); - - llvm::Module::PointerSize p = modulep->getPointerSize(); - if (p == llvm::Module::Pointer32) - return 32; - else if (p == llvm::Module::Pointer64) - return 64; - return 0; -} - -LLVMValueRef LLVMModuleGetOrInsertFunction(LLVMModuleRef module, - const char *name, LLVMTypeRef function_type) -{ - assert(name); - - llvm::Module *modulep = llvm::unwrap(module); - assert(modulep); - - llvm::FunctionType *ftp = llvm::unwrap(function_type); - assert(ftp); - - llvm::Constant *f = modulep->getOrInsertFunction(name, ftp); - return wrap(f); -} - -int LLVMHasInitializer(LLVMValueRef global_var) -{ - llvm::GlobalVariable *gvp = llvm::unwrap(global_var); - assert(gvp); - - return gvp->hasInitializer(); -} - -#define inst_checkfn(ourfn, llvmfn) \ -unsigned ourfn (LLVMValueRef v) { \ - llvm::Instruction *ip = llvm::unwrap(v); \ - assert(ip); \ - return ip-> llvmfn () ? 1 : 0; \ -} - -inst_checkfn(LLVMInstIsTerminator, isTerminator) -inst_checkfn(LLVMInstIsBinaryOp, isBinaryOp) -inst_checkfn(LLVMInstIsShift, isShift) -inst_checkfn(LLVMInstIsCast, isCast) -inst_checkfn(LLVMInstIsLogicalShift, isLogicalShift) -inst_checkfn(LLVMInstIsArithmeticShift, isArithmeticShift) -inst_checkfn(LLVMInstIsAssociative, isAssociative) -inst_checkfn(LLVMInstIsCommutative, isCommutative) - -unsigned LLVMInstIsVolatile(LLVMValueRef v) -{ - using namespace llvm; - Instruction *ip = unwrap(v); - assert(ip); - return ((isa(*ip) && cast(*ip).isVolatile()) || - (isa(*ip) && cast(*ip).isVolatile()) ); -} - -const char *LLVMInstGetOpcodeName(LLVMValueRef inst) -{ - llvm::Instruction *instp = llvm::unwrap(inst); - assert(instp); - return instp->getOpcodeName(); -} - -unsigned LLVMInstGetOpcode(LLVMValueRef inst) -{ - llvm::Instruction *instp = llvm::unwrap(inst); - assert(instp); - return instp->getOpcode(); -} - -unsigned LLVMCmpInstGetPredicate(LLVMValueRef cmpinst) -{ - llvm::CmpInst *instp = llvm::unwrap(cmpinst); - assert(instp); - return instp->getPredicate(); -} - -LLVMValueRef LLVMInstGetCalledFunction(LLVMValueRef inst) -{ - llvm::Instruction *instp = llvm::unwrap(inst); - return llvm::wrap(CallSite(instp).getCalledFunction()); -} - -void LLVMInstSetCalledFunction(LLVMValueRef inst, LLVMValueRef fn) -{ - using namespace llvm; - Instruction *instp = unwrap(inst); - CallSite(instp).setCalledFunction(unwrap(fn)); -} - -///* llvm::unwrap a set of `n' wrapped objects starting at `values', -// * into a vector of pointers to llvm::unwrapped objects `out'. */ -//template -//void unwrap_vec(W *values, unsigned n, std::vector& out) -//{ -// out.clear(); -// out.reserve(n); -// while (n--) { -// UW *p = llvm::unwrap(*values); -// assert(p); -// out.push_back(p); -// ++values; -// } -//} - -///* Same as llvm::unwrap_vec, but use a vector of const pointers. */ -//template -//void unwrap_cvec(W *values, unsigned n, std::vector& out) -//{ -// out.clear(); - -// while (n--) { -// UW *p = llvm::unwrap(*values); -// assert(p); -// out.push_back(p); -// ++values; -// } -//} - - -LLVMValueRef LLVMBuildRetMultiple(LLVMBuilderRef builder, - LLVMValueRef *values, unsigned n_values) -{ - using namespace llvm; - assert(values); - - IRBuilder<> *builderp = unwrap(builder); - assert(builderp); - - return wrap(builderp->CreateAggregateRet(unwrap(values, n_values), n_values)); -} - -LLVMValueRef LLVMBuildGetResult(LLVMBuilderRef builder, - LLVMValueRef value, unsigned index, const char *name) -{ - assert(name); - - llvm::IRBuilder<> *builderp = llvm::unwrap(builder); - assert(builderp); - - return llvm::wrap(builderp->CreateExtractValue(llvm::unwrap(value), index, name)); -} - -unsigned LLVMValueGetID(LLVMValueRef value) -{ - llvm::Value *valuep = llvm::unwrap(value); - assert(valuep); - - return valuep->getValueID(); -} - - -unsigned LLVMValueGetNumUses(LLVMValueRef value) -{ - llvm::Value *valuep = llvm::unwrap(value); - assert(valuep); - - return valuep->getNumUses(); -} - - -unsigned LLVMValueGetUses(LLVMValueRef value, LLVMValueRef **refs) -{ - llvm::Value *valuep = llvm::unwrap(value); - assert(valuep); - - unsigned n = valuep->getNumUses(); - if (n == 0) - return 0; - - assert(refs); - LLVMValueRef *out = new LLVMValueRef[n]; - if (!out) - return 0; - *refs = out; - - memset(out, 0, sizeof(LLVMValueRef) * n); - llvm::Value::use_iterator it = valuep->use_begin(); - while (it != valuep->use_end()) { - *out++ = llvm::wrap(*it); - ++it; - } - - return n; -} - -void LLVMDisposeValueRefArray(LLVMValueRef *refs) -{ - assert(refs); - delete [] refs; -} - -unsigned LLVMUserGetNumOperands(LLVMValueRef user) -{ - llvm::User *userp = llvm::unwrap(user); - assert(userp); - return userp->getNumOperands(); -} - -LLVMValueRef LLVMUserGetOperand(LLVMValueRef user, unsigned idx) -{ - llvm::User *userp = llvm::unwrap(user); - assert(userp); - llvm::Value *operand = userp->getOperand(idx); - return llvm::wrap(operand); -} - -unsigned LLVMGetDoesNotThrow(LLVMValueRef fn) -{ - llvm::Function *fnp = llvm::unwrap(fn); - assert(fnp); - - return fnp->doesNotThrow(); -} - -void LLVMSetDoesNotThrow(LLVMValueRef fn, int DoesNotThrow) -{ - llvm::Function *fnp = llvm::unwrap(fn); - assert(fnp); - - if ((bool)DoesNotThrow) - fnp->setDoesNotThrow(); -} - - -LLVMValueRef LLVMGetIntrinsic(LLVMModuleRef module, int id, - LLVMTypeRef *types, unsigned n_types) -{ - using namespace llvm; - assert(types); - - Module *modulep = unwrap(module); - assert(modulep); - - Function *intfunc = Intrinsic::getDeclaration(modulep, Intrinsic::ID(id), - makeArrayRef(unwrap(types, n_types), - n_types)); - - return wrap(intfunc); -} - -LLVMModuleRef LLVMGetModuleFromAssembly(const char *asmtext, char **out) -{ - assert(asmtext); - assert(out); - - llvm::Module *modulep; - llvm::SMDiagnostic error; - if (!(modulep = llvm::ParseAssemblyString(asmtext, NULL, error, - llvm::getGlobalContext()))) { - std::string s; - llvm::raw_string_ostream buf(s); - error.print("llvm-py", buf); - *out = strdup(buf.str().c_str()); - return NULL; - } - - return wrap(modulep); -} - -LLVMModuleRef LLVMGetModuleFromBitcode(const char *bitcode, unsigned bclen, - char **out) -{ - assert(bitcode); - assert(out); - - llvm::StringRef as_str(bitcode, bclen); - - llvm::MemoryBuffer *mbp; - if (!(mbp = llvm::MemoryBuffer::getMemBufferCopy(as_str))) - return NULL; - - std::string msg; - llvm::Module *modulep; - if (!(modulep = llvm::ParseBitcodeFile(mbp, llvm::getGlobalContext(), - &msg))) - *out = strdup(msg.c_str()); - - delete mbp; - return wrap(modulep); -} - -#if LLVM_VERSION_MAJOR <= 3 && LLVM_VERSION_MINOR < 2 -// Shamelessly copy from LLVM-3.2 -unsigned LLVMLinkModules(LLVMModuleRef Dest, LLVMModuleRef Src, - int Mode, char **OutMessages) { - std::string Messages; - unsigned Result = Linker::LinkModules(unwrap(Dest), unwrap(Src), Mode, - OutMessages? &Messages : 0); - if (OutMessages) - *OutMessages = strdup(Messages.c_str()); - return Result; -} -#endif - -unsigned char *LLVMGetBitcodeFromModule(LLVMModuleRef module, size_t *lenp) -{ - assert(lenp); - - llvm::Module *modulep = llvm::unwrap(module); - assert(modulep); - - /* get bc into a string */ - std::string s; - llvm::raw_string_ostream buf(s); - llvm::WriteBitcodeToFile(modulep, buf); - const std::string& bc = buf.str(); - - /* and then into a new()-ed block */ - size_t bclen = bc.size(); - unsigned char *bytes = new unsigned char[bclen]; - memcpy(bytes, bc.data(), bclen); - - /* return */ - *lenp = bclen; - return bytes; -} - -/* Return 0 on failure (with errmsg filled in), 1 on success. */ -unsigned LLVMLoadLibraryPermanently(const char* filename, char **errmsg) -{ - printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@1"); - assert(filename); - printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@2"); - assert(errmsg); - printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@3"); - - /* Note: the LLVM API returns true on failure. Don't ask why. */ - std::string msg; - printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@4"); - if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(filename, &msg)) { - printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@5"); - *errmsg = strdup(msg.c_str()); - printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@6"); - return 0; - } - printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7"); - return 1; -} - -void LLVMExecutionEngineDisableLazyCompilation(LLVMExecutionEngineRef ee, int flag) -{ - llvm::unwrap(ee)->DisableLazyCompilation(flag); -} - -void *LLVMGetPointerToFunction(LLVMExecutionEngineRef ee, LLVMValueRef fn) -{ - llvm::ExecutionEngine *eep = llvm::unwrap(ee); - assert(eep); - - llvm::Function *fnp = llvm::unwrap(fn); - assert(fnp); - - return eep->getPointerToFunction(fnp); -} - - -int LLVMInlineFunction(LLVMValueRef call) -{ - llvm::Value *callp = llvm::unwrap(call); - assert(callp); - - llvm::InlineFunctionInfo unused; - - llvm::Instruction *II = llvm::dyn_cast(callp); - if (II->getOpcode() == llvm::Instruction::Call) - return llvm::InlineFunction(static_cast(II), unused); - else if (II->getOpcode() == llvm::Instruction::Invoke) - return llvm::InlineFunction(static_cast(II), unused); - else - return 0; -} - -unsigned LLVMGetParamAlignment(LLVMValueRef arg) -{ - llvm::Argument *argp = llvm::unwrap(arg); - assert(argp); - - unsigned argno = argp->getArgNo(); - - return argp->getParent()->getParamAlignment(argno + 1); -} - - -/* Passes. A few passes (listed below) are used directly from LLVM-C, - * rest are defined here. - */ -/* -#define define_pass(P) \ -void LLVMAdd ## P ## Pass (LLVMPassManagerRef passmgr) { \ - using namespace llvm; \ - llvm::PassManagerBase *pmp = llvm::unwrap(passmgr); \ - assert(pmp); \ - pmp->add( create ## P ## Pass ()); \ -} - -define_pass( AAEval ) -define_pass( AliasAnalysisCounter ) -//define_pass( AlwaysInliner ) -//define_pass( BasicAliasAnalysis ) -define_pass( BlockPlacement ) -define_pass( BreakCriticalEdges ) -define_pass( CodeGenPrepare ) -define_pass( DbgInfoPrinter ) -define_pass( DeadCodeElimination ) -define_pass( DeadInstElimination ) -define_pass( DemoteRegisterToMemory ) -define_pass( DomOnlyPrinter ) -define_pass( DomOnlyViewer ) -define_pass( DomPrinter ) -define_pass( DomViewer ) -define_pass( EdgeProfiler ) -//define_pass( GEPSplitter ) -define_pass( GlobalsModRef ) -define_pass( InstCount ) -define_pass( InstructionNamer ) -define_pass( LazyValueInfo ) -define_pass( LCSSA ) -//define_pass( LiveValues ) -define_pass( LoopDependenceAnalysis ) -define_pass( LoopExtractor ) -define_pass( LoopSimplify ) -define_pass( LoopStrengthReduce ) -define_pass( LowerInvoke ) -define_pass( LowerSwitch ) -define_pass( MergeFunctions ) -define_pass( NoAA ) -define_pass( NoProfileInfo ) -define_pass( OptimalEdgeProfiler ) -define_pass( PartialInlining ) -//define_pass( PartialSpecialization ) -define_pass( PostDomOnlyPrinter ) -define_pass( PostDomOnlyViewer ) -define_pass( PostDomPrinter ) -define_pass( PostDomViewer ) -define_pass( ProfileEstimator ) -define_pass( ProfileLoader ) -define_pass( ProfileVerifier ) -define_pass( ScalarEvolutionAliasAnalysis ) -//define_pass( SimplifyHalfPowrLibCalls ) -define_pass( SingleLoopExtractor ) -define_pass( StripNonDebugSymbols ) -//define_pass( StructRetPromotion ) -//define_pass( TailDuplication ) -define_pass( UnifyFunctionExitNodes ) -*/ -/* we support only internalize(true) */ -/* -llvm::ModulePass *createInternalize2Pass() { return llvm::createInternalizePass(true); } -define_pass( Internalize2 ) -*/ diff --git a/llvm/extra.h b/llvm/extra.h deleted file mode 100644 index b734f1b..0000000 --- a/llvm/extra.h +++ /dev/null @@ -1,676 +0,0 @@ -/* - * Copyright (c) 2008-10, Mahadevan R All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of this software, nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * These are some "extra" functions not available in the standard LLVM-C - * bindings, but are required / good-to-have inorder to implement the - * Python bindings. - */ - -#ifndef LLVM_PY_EXTRA_H -#define LLVM_PY_EXTRA_H - -// select PTX or NVPTX - -#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 2 - #define LLVM_HAS_NVPTX 1 -#else - #define LLVM_HAS_NVPTX 0 -#endif - -#include "llvm-c/Transforms/PassManagerBuilder.h" -#include "llvm_c_extra.h" - - -#ifdef __cplusplus -extern "C" { -#endif - - -#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 2 -/* - * Wraps new TargetTransformInfo( - * TargetMachine::getScalarTargetTransformInfo, - * TargetMachine::getVectorTargetTransformInfo) - */ -LLVMPassRef LLVMCreateTargetTransformInfo(LLVMTargetMachineRef tmref); -#endif - -/* - * Wraps new TargetLibraryInfo - */ -LLVMPassRef LLVMCreateTargetLibraryInfo(const char * triple); - -/* - * Wraps llvm::getDefaultTargetTriple - */ -const char * LLVMDefaultTargetTriple(); - -/* - * Wraps Pass::lookupPassInfo and PassInfo::createPass - */ -LLVMPassRef LLVMCreatePassByName(const char *name); - -/* - * Wraps operator delete (Pass*) - */ -void LLVMDisposePass(LLVMPassRef passref); - -/* - * Wraps Pass::getPassName - */ -const char * LLVMGetPassName(LLVMPassRef passref); - -/* - * Wraps PassManager::add - */ -void LLVMAddPass(LLVMPassManagerRef pmref, LLVMPassRef passref); - -/* - * Wraps Pass::dump - */ -void LLVMPassDump(LLVMPassRef passref); - -/* - * Wraps llvm:InlineAsm::get - */ -LLVMValueRef LLVMGetFunctionFromInlineAsm(LLVMTypeRef funcType, - const char inlineAsm[], - const char constrains[], - bool hasSideEffect, - bool isAlignStack, - int asmDialect); - -/* - * Wraps llvm::CloneModule - */ -LLVMModuleRef LLVMCloneModule(LLVMModuleRef mod); - - -/* - * Wraps NamedMDNode::print() - */ -const char * LLVMDumpNamedMDToString(LLVMNamedMDRef nmd); - -/* - * Wraps NamedMDNode::getName() - */ -const char * LLVMNamedMetaDataGetName(LLVMNamedMDRef nmd); - -/* - * Wraps NamedMDNode::addOperand() - */ -void LLVMNamedMetaDataAddOperand(LLVMNamedMDRef nmd, LLVMValueRef md); - -/* - * Wraps NamedMDNode::eraseFromParent() - */ -void LLVMEraseNamedMetaData(LLVMNamedMDRef nmd); - -/* - * Wraps Module::getOrInsertNamedMetadata - */ -LLVMNamedMDRef LLVMModuleGetOrInsertNamedMetaData(LLVMModuleRef mod, const char *name); - -/* - * Wraps Module::getNamedMetadata - */ -LLVMNamedMDRef LLVMModuleGetNamedMetaData(LLVMModuleRef mod, const char *name); - -/* - * Wraps Instruction::setMetadata() - */ -void LLVMInstSetMetaData(LLVMValueRef instref, const char* mdkind, - LLVMValueRef metaref); - -/* - * Wraps MDNode::get() - */ -LLVMValueRef LLVMMetaDataGet(LLVMModuleRef modref, LLVMValueRef * valrefs, - unsigned valct); - -/* - * Wraps MDNode::getOperand() - */ -LLVMValueRef LLVMMetaDataGetOperand(LLVMValueRef mdref, unsigned index); - -/* - * Wraps MDNode::getNumOperands() - */ -unsigned LLVMMetaDataGetNumOperands(LLVMValueRef mdref); - -/* - * Wraps MDString::get() - */ -LLVMValueRef LLVMMetaDataStringGet(LLVMModuleRef modref, const char *s); - -/* - * Wraps ConstantExpr::getOpcodeName() - */ -const char *LLVMGetConstExprOpcodeName(LLVMValueRef inst); - -/* - * Wraps ConstantExpr::getOpcode() - */ -unsigned LLVMGetConstExprOpcode(LLVMValueRef inst); - -/* - * Wraps LoadInst::SetAlignment - */ -void LLVMLdSetAlignment(LLVMValueRef inst, unsigned align); - -/* - * Wraps StoreInst::SetAlignment - */ -void LLVMStSetAlignment(LLVMValueRef inst, unsigned align); - -const char * LLVMGetHostCPUName(); - -int LLVMInitializeNativeTargetAsmPrinter(); - - -LLVMTargetMachineRef LLVMTargetMachineLookup(const char *arch, const char *cpu, - const char *features, int opt, - int codemodel, std::string &error); - -LLVMTargetMachineRef LLVMCreateTargetMachine(const char *arch, const char *cpu, - const char *features, int opt, - int codemodel, - std::string &error); - -/* - * Wraps EngineBuilder::selectTarget - */ -LLVMTargetMachineRef LLVMTargetMachineFromEngineBuilder(LLVMEngineBuilderRef eb); - -/* - * Wraps operator delete - */ -void LLVMDisposeTargetMachine(LLVMTargetMachineRef tm); - -/* - * Wraps TargetMachine::addPassesToEmitFile - */ -unsigned char* LLVMTargetMachineEmitFile(LLVMTargetMachineRef tmref, - LLVMModuleRef modref, - int assembly, size_t * lenp, - std::string &error); - -/* - * Wraps TargetMachine::getTargetData - */ -LLVMTargetDataRef LLVMTargetMachineGetTargetData(LLVMTargetMachineRef tm); - -/* - * Wraps TargetMachine::getTarget().getName() - */ -const char* LLVMTargetMachineGetTargetName(LLVMTargetMachineRef tm); - -/* - * Wraps TargetMachine::getTarget().getShortDescription() - */ -const char* LLVMTargetMachineGetTargetShortDescription(LLVMTargetMachineRef tm); - -/* - * Wraps TargetMachine::getTargetTriple - */ -const char * LLVMTargetMachineGetTriple(LLVMTargetMachineRef tm); - -/* - * Wraps TargetMachine::getTargetCPU - */ -const char * LLVMTargetMachineGetCPU(LLVMTargetMachineRef tm); - -/* - * Wraps TargetMachine::getTargetFeatureString - */ -const char * LLVMTargetMachineGetFS(LLVMTargetMachineRef tm); - -/* - * Wraps TargetRegister::printRegisteredTargetsForVersion - */ -void LLVMPrintRegisteredTargetsForVersion(); - -/* - * Wraps TargetMachine::addPassesToEmitFile - */ -unsigned char* LLVMGetNativeCodeFromModule(LLVMModuleRef module, int assembly, - size_t * lenp, std::string &error); - -/* - * Wraps IRBuilder::CreateFence - */ -LLVMValueRef LLVMBuildFence(LLVMBuilderRef builder, const char* ordering, - int crossthread); - -/* - * Wraps IRBuilder::CreateLoad, LoadInst::setAtomic - */ -LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef builder, LLVMValueRef ptr, - unsigned align, const char* ordering, - int crossthread); -/* - * Wraps IRBuilder::CreateStore, StoreInst::setAtomic - */ -LLVMValueRef LLVMBuildAtomicStore(LLVMBuilderRef builder, - LLVMValueRef ptr, LLVMValueRef val, - unsigned align, const char* ordering, - int crossthread); - -/* - * Wraps IRBuilder::CreateAtomicRMW - */ -LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef builder, const char * op, - LLVMValueRef ptr, LLVMValueRef val, - const char* ordering, int crossthread); - -/* - * Wraps IRBuilder::CreateAtomicCmpXchg - */ -LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, - LLVMValueRef cmp, LLVMValueRef val, - const char* ordering, int crossthread); - -/* - * Wraps new EngineBuilder - */ -LLVMEngineBuilderRef LLVMCreateEngineBuilder(LLVMModuleRef mod); - -/* - * Wraps delete EngineBuilder - */ -void LLVMDisposeEngineBuilder(LLVMEngineBuilderRef eb); - - -/* - * Wraps EngineBuilder::setEngineKind(EngineKind::JIT) - */ -void LLVMEngineBuilderForceJIT(LLVMEngineBuilderRef eb); - -/* - * Wraps EngineBuilder::setEngineKind(EngineKind::Interpreter) - */ -void LLVMEngineBuilderForceInterpreter(LLVMEngineBuilderRef eb); - - -/* - * Wraps EngineBuilder::setOptLevel - */ -void LLVMEngineBuilderSetOptLevel(LLVMEngineBuilderRef eb, int level); - -/* - * Wraps EngineBuilder::setMCPU - */ -void LLVMEngineBuilderSetMCPU(LLVMEngineBuilderRef eb, const char * mcpu); - -/* - * Wraps EngineBuilder::setMAttrs - */ -void LLVMEngineBuilderSetMAttrs(LLVMEngineBuilderRef eb, const char * mattrs); - -/* - * Wraps EngineBuilder::setErrorStr and EngineBuilder::create - */ -LLVMExecutionEngineRef LLVMEngineBuilderCreate(LLVMEngineBuilderRef eb, - std::string &error); - -/* - * Wraps EngineBuilder::create(TargetMachine*) - */ -LLVMExecutionEngineRef LLVMEngineBuilderCreateTM(LLVMEngineBuilderRef ebref, - LLVMTargetMachineRef tmref, - std::string & error); - - -/* - * Wraps PassManagerBuilder::OptLevel - */ -int LLVMPassManagerBuilderGetOptLevel(LLVMPassManagerBuilderRef pmb); - -/* - * Wraps PassManagerBuilder::SizeLevel - */ -int LLVMPassManagerBuilderGetSizeLevel(LLVMPassManagerBuilderRef pmb); - -/* - * Wraps PassManagerBuilder::Vectorize - */ -void LLVMPassManagerBuilderSetVectorize(LLVMPassManagerBuilderRef pmb, int flag); - -/* - * Wraps PassManagerBuilder::Vectorize - */ -int LLVMPassManagerBuilderGetVectorize(LLVMPassManagerBuilderRef pmb); - -#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 2 -/* - * Wraps PassManagerBuilder::LoopVectorize - */ -void LLVMPassManagerBuilderSetLoopVectorize(LLVMPassManagerBuilderRef pmb, - int flag); - -/* - * Wraps PassManagerBuilder::LoopVectorize - */ -int LLVMPassManagerBuilderGetLoopVectorize(LLVMPassManagerBuilderRef pmb); -#endif // llvm-3.2 - -/* - * Wraps PassManagerBuilder::DisableUnitAtATime - */ -int LLVMPassManagerBuilderGetDisableUnitAtATime(LLVMPassManagerBuilderRef pmb); - -/* - * Wraps PassManagerBuilder::DisableUnrollLoops - */ -int LLVMPassManagerBuilderGetDisableUnrollLoops(LLVMPassManagerBuilderRef pmb); - -/* - * Wraps PassManagerBuilder::DisableSimplifyLibCalls - */ -int LLVMPassManagerBuilderGetDisableSimplifyLibCalls(LLVMPassManagerBuilderRef pmb); - -/* - * Wraps PassManager::add - */ -int LLVMAddPassByName(LLVMPassManagerRef pm, const char * name); - -/* - * Wraps initialize* - */ -void LLVMInitializePasses(void); - -/* - * Wraps PassRegistry::enumerateWith() - * Returns a '\n' separated string of all passes available to `opt`. - */ -const char * LLVMDumpPasses(void); - -/* - * Wraps StructType::isLiteral() - */ -int LLVMIsLiteralStruct(LLVMTypeRef type); - -/* - * Wraps StructType::create() - */ -LLVMTypeRef LLVMStructTypeIdentified(const char * name); - -/* - * StructType::setBody() - */ -void LLVMSetStructBody(LLVMTypeRef type, LLVMTypeRef* elemtys, unsigned elemct, int is_packed); - -/* - * Wraps llvm::StructType::setName() - */ -void LLVMSetStructName(LLVMTypeRef type, const char * name); - - -/* - * Wraps llvm::Module::getModuleIdentifier() - */ -char *LLVMGetModuleIdentifier(LLVMModuleRef module); - -/* - * Wraps llvm::Module::setModuleIdentifier() - */ -void LLVMSetModuleIdentifier(LLVMModuleRef module, const char * name); - -/* Notes: - * - Some returned strings must be disposed of by LLVMDisposeMessage. These are - * indicated in the comments. Where it is not indicated, DO NOT call dispose. - */ - -/* Wraps llvm::Module::print(). Dispose the returned string after use, via - * LLVMDisposeMessage(). */ -char *LLVMDumpModuleToString(LLVMModuleRef module); - -/* Wraps llvm::Module::addLibrary(name). */ -void LLVMModuleAddLibrary(LLVMModuleRef module, const char *name); - -/* Wraps llvm::Type::print(). Dispose the returned string after use, via - * LLVMDisposeMessage(). */ -char *LLVMDumpTypeToString(LLVMTypeRef type); - -/* Wraps llvm::Value::print(). Dispose the returned string after use, via - * LLVMDisposeMessage(). */ -char *LLVMDumpValueToString(LLVMValueRef Val); - -/* Wraps llvm::IRBuilder::CreateRet(). */ -LLVMValueRef LLVMBuildRetMultiple(LLVMBuilderRef bulder, LLVMValueRef *values, - unsigned n_values); - -/* Wraps llvm::IRBuilder::CreateGetResult(). */ -LLVMValueRef LLVMBuildGetResult(LLVMBuilderRef builder, LLVMValueRef value, - unsigned index, const char *name); - -/* Wraps llvm::Value::getValueID(). */ -unsigned LLVMValueGetID(LLVMValueRef value); - -/* Wraps llvm::Value::getNumUses(). */ -unsigned LLVMValueGetNumUses(LLVMValueRef value); - -/* Wraps llvm::Value::use_{begin,end}. Allocates LLVMValueRef's as - * required. Number of objects are returned as return value. If that is - * greater than zero, the pointer given out must be freed by a - * subsequent call to LLVMDisposeValueRefArray(). */ -unsigned LLVMValueGetUses(LLVMValueRef value, LLVMValueRef **refs); - -/* See above. */ -void LLVMDisposeValueRefArray(LLVMValueRef *refs); - -/* Wraps llvm:User::getNumOperands(). */ -unsigned LLVMUserGetNumOperands(LLVMValueRef user); - -/* Wraps llvm:User::getOperand(). */ -LLVMValueRef LLVMUserGetOperand(LLVMValueRef user, unsigned idx); - -/* Wraps llvm::ConstantExpr::getVICmp(). */ -LLVMValueRef LLVMConstVICmp(LLVMIntPredicate predicate, LLVMValueRef lhs, - LLVMValueRef rhs); - -/* Wraps llvm::ConstantExpr::getVFCmp(). */ -LLVMValueRef LLVMConstVFCmp(LLVMRealPredicate predicate, LLVMValueRef lhs, - LLVMValueRef rhs); - -/* Wraps llvm::IRBuilder::CreateVICmp(). */ -LLVMValueRef LLVMBuildVICmp(LLVMBuilderRef builder, LLVMIntPredicate predicate, - LLVMValueRef lhs, LLVMValueRef rhs, const char *name); - -/* Wraps llvm::IRBuilder::CreateVFCmp(). */ -LLVMValueRef LLVMBuildVFCmp(LLVMBuilderRef builder, LLVMRealPredicate predicate, - LLVMValueRef lhs, LLVMValueRef rhs, const char *name); - -/* Wraps llvm::Intrinsic::getDeclaration(). */ -LLVMValueRef LLVMGetIntrinsic(LLVMModuleRef builder, int id, - LLVMTypeRef *types, unsigned n_types); - -/* Wraps llvm::Function::doesNotThrow(). */ -unsigned LLVMGetDoesNotThrow(LLVMValueRef fn); - -/* Wraps llvm::Function::setDoesNotThrow(). */ -void LLVMSetDoesNotThrow(LLVMValueRef fn, int DoesNotThrow); - -/* Wraps llvm::Module::getPointerSize(). */ -unsigned LLVMModuleGetPointerSize(LLVMModuleRef module); - -/* Wraps llvm::Module::getOrInsertFunction(). */ -LLVMValueRef LLVMModuleGetOrInsertFunction(LLVMModuleRef module, - const char *name, LLVMTypeRef function_type); - -/* Wraps llvm::GlobalVariable::hasInitializer(). */ -int LLVMHasInitializer(LLVMValueRef global_var); - -/* The following functions wrap various llvm::Instruction::isXXX() functions. - * All of them take an instruction and return 0 (isXXX returned false) or 1 - * (isXXX returned false). */ -unsigned LLVMInstIsTerminator (LLVMValueRef inst); -unsigned LLVMInstIsBinaryOp (LLVMValueRef inst); -unsigned LLVMInstIsShift (LLVMValueRef inst); -unsigned LLVMInstIsCast (LLVMValueRef inst); -unsigned LLVMInstIsLogicalShift (LLVMValueRef inst); -unsigned LLVMInstIsArithmeticShift (LLVMValueRef inst); -unsigned LLVMInstIsAssociative (LLVMValueRef inst); -unsigned LLVMInstIsCommutative (LLVMValueRef inst); -unsigned LLVMInstIsTrapping (LLVMValueRef inst); - -/* As above, but these are wrap methods from subclasses of Instruction. */ -unsigned LLVMInstIsVolatile (LLVMValueRef inst); - -/* Wraps llvm::Instruction::getOpcodeName(). */ -const char *LLVMInstGetOpcodeName(LLVMValueRef inst); - -/* Wraps llvm::Instruction::getOpcode(). */ -unsigned LLVMInstGetOpcode(LLVMValueRef inst); - -/* Wraps llvm::CmpInst::getPredicate(). */ -unsigned LLVMCmpInstGetPredicate(LLVMValueRef cmpinst); - -/* Wraps llvm::CallSite::getCalledFunction. - */ -LLVMValueRef LLVMInstGetCalledFunction(LLVMValueRef inst); - -/* Wraps llvm::CallSite::setCalledFunction. - */ -void LLVMInstSetCalledFunction(LLVMValueRef inst, LLVMValueRef fn); - -/* Wraps llvm::ParseAssemblyString(). Returns a module reference or NULL (with - * `out' pointing to an error message). Dispose error message after use, via - * LLVMDisposeMessage(). */ -LLVMModuleRef LLVMGetModuleFromAssembly(const char *asmtxt, char **out); - -/* Wraps llvm::ParseBitcodeFile(). Returns a module reference or NULL (with - * `out' pointing to an error message). Dispose error message after use, via - * LLVMDisposeMessage(). */ -LLVMModuleRef LLVMGetModuleFromBitcode(const char *bc, unsigned bclen, - char **out); - -#if LLVM_VERSION_MAJOR <= 3 && LLVM_VERSION_MINOR < 2 -/* Wraps llvm::Linker::LinkModules(). Returns 0 on failure (with errmsg - * filled in) and 1 on success. Dispose error message after use with - * LLVMDisposeMessage(). */ -unsigned LLVMLinkModules(LLVMModuleRef dest, LLVMModuleRef src, int mode, - char **errmsg); -#endif -/* Returns pointer to a heap-allocated block of `*len' bytes containing bit code - * for the given module. NULL on error. */ -unsigned char *LLVMGetBitcodeFromModule(LLVMModuleRef module, size_t *len); - -/* Wraps llvm::sys::DynamicLibrary::LoadLibraryPermanently(). Returns 0 on - * failure (with errmsg filled in) and 1 on success. Dispose error message after - * use, via LLVMDisposeMessage(). */ -unsigned LLVMLoadLibraryPermanently(const char* filename, char **errmsg); - -/* Wraps llvm::ExecutionEngine::DisableLazyCompilation(bool) - */ -void LLVMExecutionEngineDisableLazyCompilation(LLVMExecutionEngineRef ee, - int flag); - -/* Wraps llvm::ExecutionEngine::getPointerToFunction(). Returns a pointer - * to the JITted function. */ -void *LLVMGetPointerToFunction(LLVMExecutionEngineRef ee, LLVMValueRef fn); - -/* Wraps llvm::InlineFunction(). Inlines a function. C is the call - * instruction, created by LLVMBuildCall. Even if it fails, the Function - * containing the call is still in a proper state (not changed). - */ -int LLVMInlineFunction(LLVMValueRef call); - -/* Wraps llvm::getAlignmentFromAttrs from Attributes.h. Compliments the - * already available LLVMSetParamAlignment(). */ -unsigned LLVMGetParamAlignment(LLVMValueRef arg); - -/* Passes. Some passes are used directly from LLVM-C, rest are declared - * here. */ - -/* -#define declare_pass(P) \ - void LLVMAdd ## P ## Pass (LLVMPassManagerRef PM); - -declare_pass( AAEval ) -declare_pass( AliasAnalysisCounter ) -declare_pass( AlwaysInliner ) -declare_pass( BasicAliasAnalysis ) -declare_pass( BlockPlacement ) -declare_pass( BreakCriticalEdges ) -declare_pass( CodeGenPrepare ) -declare_pass( DbgInfoPrinter ) -declare_pass( DeadCodeElimination ) -declare_pass( DeadInstElimination ) -declare_pass( DemoteRegisterToMemory ) -declare_pass( DomOnlyPrinter ) -declare_pass( DomOnlyViewer ) -declare_pass( DomPrinter ) -declare_pass( DomViewer ) -declare_pass( EdgeProfiler ) -//declare_pass( GEPSplitter ) -declare_pass( GlobalsModRef ) -declare_pass( InstCount ) -declare_pass( InstructionNamer ) -declare_pass( LazyValueInfo ) -declare_pass( LCSSA ) -//declare_pass( LiveValues ) -declare_pass( LoopDependenceAnalysis ) -declare_pass( LoopExtractor ) -declare_pass( LoopSimplify ) -declare_pass( LoopStrengthReduce ) -declare_pass( LowerInvoke ) -declare_pass( LowerSwitch ) -declare_pass( MergeFunctions ) -declare_pass( NoAA ) -declare_pass( NoProfileInfo ) -declare_pass( OptimalEdgeProfiler ) -declare_pass( PartialInlining ) -//declare_pass( PartialSpecialization ) -declare_pass( PostDomOnlyPrinter ) -declare_pass( PostDomOnlyViewer ) -declare_pass( PostDomPrinter ) -declare_pass( PostDomViewer ) -declare_pass( ProfileEstimator ) -declare_pass( ProfileLoader ) -declare_pass( ProfileVerifier ) -declare_pass( ScalarEvolutionAliasAnalysis ) -declare_pass( SimplifyHalfPowrLibCalls ) -declare_pass( SingleLoopExtractor ) -declare_pass( StripNonDebugSymbols ) -declare_pass( StructRetPromotion ) -declare_pass( TailDuplication ) -declare_pass( UnifyFunctionExitNodes ) - -declare_pass( Internalize2 ) -*/ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* LLVM_PY_EXTRA_H */ - diff --git a/llvm/llvm_c_extra.h b/llvm/llvm_c_extra.h deleted file mode 100644 index 5728875..0000000 --- a/llvm/llvm_c_extra.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef LLVM_C_EXTRA_H_ -#define LLVM_C_EXTRA_H_ - -#include - - -#ifdef __cplusplus - extern "C" { -#endif - -// Resurrect from llvm-c/Core.h -#define DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ty, ref) \ -inline ty *unwrap(ref P) { \ - return reinterpret_cast(P); \ -} \ - \ -inline ref wrap(const ty *P) { \ - return reinterpret_cast(const_cast(P)); \ -} - -typedef struct LLVMOpaqueEngineBuilder *LLVMEngineBuilderRef; -typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef; -typedef struct LLVMOpaqueNamedMD *LLVMNamedMDRef; -typedef struct LLVMOpaquePass *LLVMPassRef; - -#ifdef __cplusplus - } -#endif - -#endif //LLVM_C_EXTRA_H_ - diff --git a/llvm/passes.py b/llvm/passes.py index 4d7efb4..e69de29 100644 --- a/llvm/passes.py +++ b/llvm/passes.py @@ -1,417 +0,0 @@ -# -# Copyright (c) 2008-10, Mahadevan R All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of this software, nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - -"""Pass managers and passes. - -This module provides the LLVM pass managers and the passes themselves. -All transformation passes listed at http://www.llvm.org/docs/Passes.html -are available. -""" - -import llvm # top-level, for common stuff -import llvm.core as core # module, function etc. -import llvm._core as _core # C wrappers -import llvm._util as _util # Utility functions - -import warnings -#===----------------------------------------------------------------------=== -# Pass manager builder -#===----------------------------------------------------------------------=== - -class PassManagerBuilder(object): - @staticmethod - def new(): - return PassManagerBuilder(_core.LLVMPassManagerBuilderCreate()) - - def __init__(self, ptr): - self.ptr = ptr - - def __del__(self): - _core.LLVMPassManagerBuilderDispose(self.ptr) - - def populate(self, pm): - if isinstance(pm, FunctionPassManager): - return _core.LLVMPassManagerBuilderPopulateFunctionPassManager( - self.ptr, pm.ptr) - else: - return _core.LLVMPassManagerBuilderPopulateModulePassManager( - self.ptr, pm.ptr) - - - def _set_opt_level(self, optlevel): - _core.LLVMPassManagerBuilderSetOptLevel(self.ptr, optlevel) - - def _get_opt_level(self): - return _core.LLVMPassManagerBuilderGetOptLevel(self.ptr) - - opt_level = property(_get_opt_level, _set_opt_level) - - def _set_size_level(self, sizelevel): - _core.LLVMPassManagerBuilderSetSizeLevel(self.ptr, sizelevel) - - def _get_size_level(self): - return _core.LLVMPassManagerBuilderGetSizeLevel(self.ptr) - - size_level = property(_get_size_level, _set_size_level) - - def _set_vectorize(self, enable): - _core.LLVMPassManagerBuilderSetVectorize(self.ptr, int(bool(enable))) - - def _get_vectorize(self): - return bool(_core.LLVMPassManagerBuilderGetVectorize(self.ptr)) - - vectorize = property(_get_vectorize, _set_vectorize) - - def _set_loop_vectorize(self, enable): - if llvm.version >= (3, 2): - _core.LLVMPassManagerBuilderSetLoopVectorize(self.ptr, - int(bool(enable))) - elif enable: - warnings.warn("Ignored. LLVM-3.1 & prior do not support loop vectorizer.") - - def _get_loop_vectorize(self): - try: - return bool(_core.LLVMPassManagerBuilderGetLoopVectorize(self.ptr)) - except AttributeError: - return False - - loop_vectorize = property(_get_loop_vectorize, _set_loop_vectorize) - - def _set_disable_unit_at_a_time(self, disable): - return _core.LLVMPassManagerBuilderSetDisableUnitAtATime( - self.ptr, disable) - - def _get_disable_unit_at_a_time(self): - return _core.LLVMPassManagerBuilderGetDisableUnitAtATime( - self.ptr) - - disable_unit_at_a_time = property(_get_disable_unit_at_a_time, - _set_disable_unit_at_a_time) - - def _set_disable_unroll_loops(self, disable): - return _core.LLVMPassManagerBuilderGetDisableUnrollLoops( - self.ptr, disable) - - def _get_disable_unroll_loops(self): - return _core.LLVMPassManagerBuilderGetDisableUnrollLoops(self.ptr) - - disable_unroll_loops = property(_get_disable_unroll_loops, - _set_disable_unroll_loops) - - def _set_disable_simplify_lib_calls(self, disable): - return _core.LLVMPassManagerBuilderGetDisableSimplifyLibCalls( - self.ptr, disable) - - def _get_disable_simplify_lib_calls(self): - return _core.LLVMPassManagerBuilderGetDisableSimplifyLibCalls(self.ptr) - - disable_simplify_lib_calls = property(_get_disable_simplify_lib_calls, - _set_disable_simplify_lib_calls) - - def use_inliner_with_threshold(self, threshold): - _core.LLVMPassManagerBuilderUseInlinerWithThreshold(self.ptr, threshold) - -#===----------------------------------------------------------------------=== -# Pass manager -#===----------------------------------------------------------------------=== - -class PassManager(object): - - @staticmethod - def new(): - return PassManager(_core.LLVMCreatePassManager()) - - def __init__(self, ptr): - self.ptr = ptr - - def __del__(self): - _core.LLVMDisposePassManager(self.ptr) - - def add(self, pass_obj): - '''Add a pass to the pass manager. - - pass_obj --- Either a Pass instance, a string name of a pass - ''' - if isinstance(pass_obj, Pass): - _util.check_is_unowned(pass_obj) - _core.LLVMAddPass(self.ptr, pass_obj.ptr) - pass_obj._own(self) # PassManager owns the pass - elif _util.isstring(pass_obj): - self._add_pass(pass_obj) - else: - raise llvm.LLVMException("invalid pass_id (%s)" % pass_obj) - - def _add_pass(self, pass_name): - status = _core.LLVMAddPassByName(self.ptr, pass_name) - if not status: - assert pass_name not in PASSES, "Registered but not found?" - raise llvm.LLVMException('Invalid pass name "%s"' % pass_name) - - def run(self, module): - core.check_is_module(module) - return _core.LLVMRunPassManager(self.ptr, module.ptr) - -class FunctionPassManager(PassManager): - - @staticmethod - def new(module): - core.check_is_module(module) - ptr = _core.LLVMCreateFunctionPassManagerForModule(module.ptr) - return FunctionPassManager(ptr) - - def __init__(self, ptr): - PassManager.__init__(self, ptr) - - def initialize(self): - _core.LLVMInitializeFunctionPassManager(self.ptr) - - def run(self, fn): - core.check_is_function(fn) - return _core.LLVMRunFunctionPassManager(self.ptr, fn.ptr) - - def finalize(self): - _core.LLVMFinalizeFunctionPassManager(self.ptr) - - - -#===----------------------------------------------------------------------=== -# Passes -#===----------------------------------------------------------------------=== - -class Pass(llvm.Ownable): - '''Pass Inferface - ''' - def __init__(self, ptr): - llvm.Ownable.__init__(self, ptr, _core.LLVMDisposePass) - self.__name = '' - - @staticmethod - def new(name): - '''Create a new pass by name. - - Note: Not all pass has a default constructor. LLVM will kill - the process if an the pass requires arguments to construct. - The error cannot be caught. - ''' - ptr = _core.LLVMCreatePassByName(name) - p = Pass(ptr) - p.__name = name - return p - - @property - def name(self): - '''The name used in PassRegistry. - ''' - return self.__name - - @property - def description(self): - return _core.LLVMGetPassName(self.ptr) - - def dump(self): - return _core.LLVMPassDump(self.ptr) - - -#===----------------------------------------------------------------------=== -# Target data -#===----------------------------------------------------------------------=== - -class TargetData(Pass): - - @staticmethod - def new(strrep): - return TargetData(_core.LLVMCreateTargetData(strrep)) - - def clone(self): - return TargetData.new(str(self)) - - def __str__(self): - return _core.LLVMTargetDataAsString(self.ptr) - - @property - def byte_order(self): - return _core.LLVMByteOrder(self.ptr) - - @property - def pointer_size(self): - return _core.LLVMPointerSize(self.ptr) - - @property - def target_integer_type(self): - ptr = _core.LLVMIntPtrType(self.ptr); - return core.IntegerType(ptr, core.TYPE_INTEGER) - - def size(self, ty): - core.check_is_type(ty) - return _core.LLVMSizeOfTypeInBits(self.ptr, ty.ptr) - - def store_size(self, ty): - core.check_is_type(ty) - return _core.LLVMStoreSizeOfType(self.ptr, ty.ptr) - - def abi_size(self, ty): - core.check_is_type(ty) - return _core.LLVMABISizeOfType(self.ptr, ty.ptr) - - def abi_alignment(self, ty): - core.check_is_type(ty) - return _core.LLVMABIAlignmentOfType(self.ptr, ty.ptr) - - def callframe_alignment(self, ty): - core.check_is_type(ty) - return _core.LLVMCallFrameAlignmentOfType(self.ptr, ty.ptr) - - def preferred_alignment(self, ty_or_gv): - if isinstance(ty_or_gv, core.Type): - return _core.LLVMPreferredAlignmentOfType(self.ptr, - ty_or_gv.ptr) - elif isinstance(ty_or_gv, core.GlobalVariable): - return _core.LLVMPreferredAlignmentOfGlobal(self.ptr, - ty_or_gv.ptr) - else: - raise core.LLVMException("argument is neither a type nor a global variable") - - def element_at_offset(self, ty, ofs): - core.check_is_type_struct(ty) - ofs = int(ofs) # ofs is unsigned long long - return _core.LLVMElementAtOffset(self.ptr, ty.ptr, ofs) - - def offset_of_element(self, ty, el): - core.check_is_type_struct(ty) - el = int(el) # el should be an int - return _core.LLVMOffsetOfElement(self.ptr, ty.ptr, el) - - -#===----------------------------------------------------------------------=== -# Target Library Info -#===----------------------------------------------------------------------=== - -class TargetLibraryInfo(Pass): - @staticmethod - def new(triple): - ptr = _core.LLVMCreateTargetLibraryInfo(triple) - return TargetLibraryInfo(ptr) - - -#===----------------------------------------------------------------------=== -# Target Transform Info -#===----------------------------------------------------------------------=== - -class TargetTransformInfo(Pass): - @staticmethod - def new(targetmachine): - llvm.require_version_at_least(3, 2) - ptr = _core.LLVMCreateTargetTransformInfo(targetmachine.ptr) - return TargetTransformInfo(ptr) - - -#===----------------------------------------------------------------------=== -# Helpers -#===----------------------------------------------------------------------=== - -def build_pass_managers(tm, opt=2, loop_vectorize=False, vectorize=False, - inline_threshold=2000, pm=True, fpm=True, mod=None): - ''' - tm --- The TargetMachine for which the passes are optimizing for. - The TargetMachine must stay alive until the pass managers - are removed. - opt --- [0-3] Optimization level. Default to 2. - loop_vectorize --- [boolean] Whether to use loop-vectorizer. - vectorize --- [boolean] Whether to use basic-block vectorizer. - inline_threshold --- [int] Threshold for the inliner. - features --- [str] CPU feature string. - pm --- [boolean] Whether to build a module-level pass-manager. - fpm --- [boolean] Whether to build a function-level pass-manager. - mod --- [Module] The module object for the FunctionPassManager. - ''' - if pm: - pm = PassManager.new() - if fpm: - if not mod: - raise TypeError("Keyword 'mod' must be defined") - fpm = FunctionPassManager.new(mod) - - # Populate PassManagers with target specific passes - pmb = PassManagerBuilder.new() - pmb.opt_level = opt - pmb.vectorize = vectorize - pmb.loop_vectorize = loop_vectorize - if inline_threshold: - pmb.use_inliner_with_threshold(inline_threshold) - if pm: - pm.add(tm.target_data.clone()) - pm.add(TargetLibraryInfo.new(tm.triple)) - if llvm.version >= (3, 2): - pm.add(TargetTransformInfo.new(tm)) - pmb.populate(pm) - - if fpm: - fpm.add(tm.target_data) - fpm.add(TargetLibraryInfo.new(tm.triple)) - if llvm.version >= (3, 2): - fpm.add(TargetTransformInfo.new(tm)) - pmb.populate(fpm) - fpm.initialize() - - from collections import namedtuple - return namedtuple('passmanagers', ['pm', 'fpm'])(pm=pm, fpm=fpm) - - -#===----------------------------------------------------------------------=== -# Misc. -#===----------------------------------------------------------------------=== - -# Intialize passes -PASSES = None - -def _dump_all_passes(): - passes_sep_by_line = _core.LLVMDumpPasses() - strip = lambda S : S.strip() - for line in passes_sep_by_line.splitlines(): - passarg, passname = map(strip, line.split('\t', 1)) - if passarg: - yield passarg, passname - -def _initialize_passes(): - global PASSES - _core.LLVMInitializePasses() - PASSES = dict(_dump_all_passes()) - - # build globals - def transform(name): - return "PASS_%s" % (name.upper().replace('-', '_')) - - global_symbols = globals() - for i in PASSES: - assert i not in global_symbols - global_symbols[transform(i)] = i - -_initialize_passes() - diff --git a/llvm/py3k_update.diff b/llvm/py3k_update.diff deleted file mode 100644 index 2bb11a9..0000000 --- a/llvm/py3k_update.diff +++ /dev/null @@ -1,973 +0,0 @@ ---- .\setup-win32.py (original) -+++ .\setup-win32.py (refactored) -@@ -145,10 +145,10 @@ - - # get llvm config - llvm_dir, llvm_build_dir, is_good = get_llvm_config() -- print "Using llvm-dir=" + llvm_dir + " and llvm-build-dir=" + llvm_build_dir -+ print("Using llvm-dir=" + llvm_dir + " and llvm-build-dir=" + llvm_build_dir) - if not is_good: -- print "Cannot find llvm-dir or llvm-build-dir" -- print "Try again with --llvm-dir=/path/to/llvm-top-dir --llvm-build-dir=/path/to/llvm/cmake/dir." -+ print("Cannot find llvm-dir or llvm-build-dir") -+ print("Try again with --llvm-dir=/path/to/llvm-top-dir --llvm-build-dir=/path/to/llvm/cmake/dir.") - return 1 - - # setup ---- .\setup.py (original) -+++ .\setup.py (refactored) -@@ -120,10 +120,10 @@ - # get llvm config - llvm_config, is_good = get_llvm_config() - if is_good: -- print "Using llvm-config=" + llvm_config -+ print("Using llvm-config=" + llvm_config) - else: -- print "Cannot invoke llvm-config (tried '%s')." % llvm_config -- print "Try again with --llvm-config=/path/to/llvm-config." -+ print("Cannot invoke llvm-config (tried '%s')." % llvm_config) -+ print("Try again with --llvm-config=/path/to/llvm-config.") - return 1 - - # setup ---- .\llvm\__init__.py (original) -+++ .\llvm\__init__.py (refactored) -@@ -68,12 +68,12 @@ - - def _own(self, owner): - if self.owner: -- raise LLVMException, "object already owned" -+ raise LLVMException("object already owned") - self.owner = owner - - def _disown(self): - if not self.owner: -- raise LLVMException, "not owned" -+ raise LLVMException("not owned") - self.owner = None - - def __del__(self): -@@ -135,15 +135,13 @@ - # Cacheables - #===----------------------------------------------------------------------=== - --class Cacheable(object): -+class Cacheable(object, metaclass=_ObjectCache): - """Objects that can be cached. - - Objects that wrap a PyCObject are cached to avoid "aliasing", i.e., - two Python objects each containing a PyCObject which internally points - to the same C pointer.""" - -- __metaclass__ = _ObjectCache -- - def forget(self): - _ObjectCache.forget(self) - ---- .\llvm\_util.py (original) -+++ .\llvm\_util.py (refactored) -@@ -45,11 +45,11 @@ - if not isinstance(obj, typ): - typ_str = typ.__name__ - msg = "argument not an instance of llvm.core.%s" % typ_str -- raise TypeError, msg -+ raise TypeError(msg) - - def check_is_unowned(ownable): - if ownable.owner: -- raise llvm.LLVMException, "object is already owned" -+ raise llvm.LLVMException("object is already owned") - - - #===----------------------------------------------------------------------=== ---- .\llvm\core.py (original) -+++ .\llvm\core.py (refactored) -@@ -297,7 +297,7 @@ - if isinstance(typ, PointerType) and \ - isinstance(typ.pointee, FunctionType): - return -- raise TypeError, "argument is neither a function nor a function pointer" -+ raise TypeError("argument is neither a function nor a function pointer") - - def _to_int(v): - if v: -@@ -341,9 +341,9 @@ - data = fileobj.read() - ret = _core.LLVMGetModuleFromBitcode(data) - if not ret: -- raise llvm.LLVMException, "Unable to create module from bitcode" -+ raise llvm.LLVMException("Unable to create module from bitcode") - elif isinstance(ret, str): -- raise llvm.LLVMException, ret -+ raise llvm.LLVMException(ret) - else: - return Module(ret) - -@@ -355,10 +355,9 @@ - data = fileobj.read() - ret = _core.LLVMGetModuleFromAssembly(data) - if not ret: -- raise llvm.LLVMException, \ -- "Unable to create module from assembly" -+ raise llvm.LLVMException("Unable to create module from assembly") - elif isinstance(ret, str): -- raise llvm.LLVMException, ret -+ raise llvm.LLVMException(ret) - else: - return Module(ret) - -@@ -437,7 +436,7 @@ - other.forget() # remove it from object cache - ret = _core.LLVMLinkModules(self.ptr, other.ptr) - if isinstance(ret, str): -- raise llvm.LLVMException, ret -+ raise llvm.LLVMException(ret) - # Do not try to destroy the other module's llvm::Module*. - other._own(llvm.DummyOwner()) - -@@ -506,7 +505,7 @@ - error.""" - ret = _core.LLVMVerifyModule(self.ptr) - if ret != "": -- raise llvm.LLVMException, ret -+ raise llvm.LLVMException(ret) - - def to_bitcode(self, fileobj): - """Write bitcode representation of module to given file-like -@@ -514,7 +513,7 @@ - - data = _core.LLVMGetBitcodeFromModule(self.ptr) - if not data: -- raise llvm.LLVMException, "Unable to create bitcode" -+ raise llvm.LLVMException("Unable to create bitcode") - fileobj.write(data) - - -@@ -1236,7 +1235,7 @@ - check_is_module(module) - ptr = _core.LLVMGetNamedGlobal(module.ptr, name) - if not ptr: -- raise llvm.LLVMException, ("no global named `%s`" % name) -+ raise llvm.LLVMException("no global named `%s`" % name) - return _make_value(ptr) - - def delete(self): -@@ -1307,7 +1306,7 @@ - check_is_module(module) - ptr = _core.LLVMGetNamedFunction(module.ptr, name) - if not ptr: -- raise llvm.LLVMException, ("no function named `%s`" % name) -+ raise llvm.LLVMException("no function named `%s`" % name) - return _make_value(ptr) - - @staticmethod -@@ -2006,7 +2005,7 @@ - - ret = _core.LLVMLoadLibraryPermanently(filename) - if isinstance(ret, str): -- raise llvm.LLVMException, ret -+ raise llvm.LLVMException(ret) - - def inline_function(call): - check_is_value(call) ---- .\llvm\ee.py (original) -+++ .\llvm\ee.py (refactored) -@@ -103,12 +103,11 @@ - return _core.LLVMPreferredAlignmentOfGlobal(self.ptr, - ty_or_gv.ptr) - else: -- raise core.LLVMException, \ -- "argument is neither a type nor a global variable" -+ raise core.LLVMException("argument is neither a type nor a global variable") - - def element_at_offset(self, ty, ofs): - core.check_is_type_struct(ty) -- ofs = long(ofs) # ofs is unsigned long long -+ ofs = int(ofs) # ofs is unsigned long long - return _core.LLVMElementAtOffset(self.ptr, ty.ptr, ofs) - - def offset_of_element(self, ty, el): -@@ -185,7 +184,7 @@ - _util.check_is_unowned(module) - ret = _core.LLVMCreateExecutionEngine(module.ptr, int(force_interpreter)) - if isinstance(ret, str): -- raise llvm.LLVMException, ret -+ raise llvm.LLVMException(ret) - return ExecutionEngine(ret, module) - - def __init__(self, ptr, module): -@@ -223,10 +222,10 @@ - def remove_module(self, module): - core.check_is_module(module) - if module.owner != self: -- raise llvm.LLVMException, "module is not owned by self" -+ raise llvm.LLVMException("module is not owned by self") - ret = _core.LLVMRemoveModule2(self.ptr, module.ptr) - if isinstance(ret, str): -- raise llvm.LLVMException, ret -+ raise llvm.LLVMException(ret) - return core.Module(ret) - - @property ---- .\llvm\passes.py (original) -+++ .\llvm\passes.py (refactored) -@@ -245,8 +245,7 @@ - elif tgt_data_or_pass_id in _pass_creator: - self._add_pass(tgt_data_or_pass_id) - else: -- raise llvm.LLVMException, \ -- ("invalid pass_id (%s)" % str(tgt_data_or_pass_id)) -+ raise llvm.LLVMException("invalid pass_id (%s)" % str(tgt_data_or_pass_id)) - - def _add_target_data(self, tgt): - _core.LLVMAddTargetData(tgt.ptr, self.ptr) ---- .\test\JITTutorial1.py (original) -+++ .\test\JITTutorial1.py (refactored) -@@ -28,4 +28,4 @@ - - bldr.ret (tmp_2) - --print module -+print(module) ---- .\test\JITTutorial2.py (original) -+++ .\test\JITTutorial2.py (refactored) -@@ -47,4 +47,4 @@ - recur_2 = bldr.call (gcd, (x_sub_y, y,), "tmp") - bldr.ret (recur_2) - --print module -+print(module) ---- .\test\asm.py (original) -+++ .\test\asm.py (refactored) -@@ -9,9 +9,9 @@ - - # write it's assembly representation to a file - asm = str(m) --print >> file("/tmp/testasm.ll", "w"), asm -+print(asm, file=file("/tmp/testasm.ll", "w")) - - # read it back into a module - m2 = Module.from_assembly(file("/tmp/testasm.ll")) --print m2 -+print(m2) - ---- .\test\call-jit-ctypes.py (original) -+++ .\test\call-jit-ctypes.py (refactored) -@@ -42,7 +42,7 @@ - - if 0: - # print the created module -- print my_module -+ print(my_module) - - # compile the function - ee = ExecutionEngine.new(my_module) ---- .\test\example-jit.py (original) -+++ .\test\example-jit.py (refactored) -@@ -29,5 +29,5 @@ - retval = ee.run_function(f_sum, [arg1, arg2]) - - # The return value is also GenericValue. Let's print it. --print "returned", retval.as_int() -+print("returned", retval.as_int()) - ---- .\test\example.py (original) -+++ .\test\example.py (refactored) -@@ -41,5 +41,5 @@ - - # We've completed the definition now! Let's see the LLVM assembly - # language representation of what we've created: --print my_module -+print(my_module) - ---- .\test\intrinsic.py (original) -+++ .\test\intrinsic.py (refactored) -@@ -16,7 +16,7 @@ - val = Constant.int(Type.int(), 42) - bswap = Function.intrinsic(mod, INTR_BSWAP, [Type.int()]) - b.call(bswap, [val]) --print mod -+print(mod) - - # the output is: - # -@@ -50,7 +50,7 @@ - onemc2 = b.sub(one, cos2, "onemc2") - sin = b.call(sqrt, [onemc2], "sin") - b.ret(sin) --print mod -+print(mod) - - # - # ; ModuleID = 'test' ---- .\test\objcache.py (original) -+++ .\test\objcache.py (refactored) -@@ -4,17 +4,17 @@ - - def check(a, b): - if a is b: -- print "OK" -+ print("OK") - else: -- print "FAIL" -+ print("FAIL") - - def check_isnot(a, b): - if not (a is b): -- print "OK" -+ print("OK") - else: -- print "FAIL" -+ print("FAIL") - --print "Testing module aliasing ..", -+print("Testing module aliasing ..", end=' ') - m1 = Module.new('a') - t = Type.int() - ft = Type.function(t, [t]) -@@ -22,75 +22,75 @@ - m2 = f1.module - check(m1, m2) - --print "Testing global vairable aliasing 1 .. ", -+print("Testing global vairable aliasing 1 .. ", end=' ') - gv1 = GlobalVariable.new(m1, t, "gv") - gv2 = GlobalVariable.get(m1, "gv") - check(gv1, gv2) - --print "Testing global vairable aliasing 2 .. ", -+print("Testing global vairable aliasing 2 .. ", end=' ') - gv3 = m1.global_variables[0] - check(gv1, gv3) - --print "Testing global vairable aliasing 3 .. ", -+print("Testing global vairable aliasing 3 .. ", end=' ') - gv2 = None - gv3 = None - gv1.delete() - gv4 = GlobalVariable.new(m1, t, "gv") - check_isnot(gv1, gv4) - --print "Testing function aliasing 1 ..", -+print("Testing function aliasing 1 ..", end=' ') - b1 = f1.append_basic_block('entry') - f2 = b1.function - check(f1, f2) - --print "Testing function aliasing 2 ..", -+print("Testing function aliasing 2 ..", end=' ') - f3 = m1.get_function_named("func") - check(f1, f3) - --print "Testing function aliasing 3 ..", -+print("Testing function aliasing 3 ..", end=' ') - f4 = Function.get_or_insert(m1, ft, "func") - check(f1, f4) - --print "Testing function aliasing 4 ..", -+print("Testing function aliasing 4 ..", end=' ') - f5 = Function.get(m1, "func") - check(f1, f5) - --print "Testing function aliasing 5 ..", -+print("Testing function aliasing 5 ..", end=' ') - f6 = m1.get_or_insert_function(ft, "func") - check(f1, f6) - --print "Testing function aliasing 6 ..", -+print("Testing function aliasing 6 ..", end=' ') - f7 = m1.functions[0] - check(f1, f7) - --print "Testing argument aliasing .. ", -+print("Testing argument aliasing .. ", end=' ') - a1 = f1.args[0] - a2 = f1.args[0] - check(a1, a2) - --print "Testing basic block aliasing 1 .. ", -+print("Testing basic block aliasing 1 .. ", end=' ') - b2 = f1.basic_blocks[0] - check(b1, b2) - --print "Testing basic block aliasing 2 .. ", -+print("Testing basic block aliasing 2 .. ", end=' ') - b3 = f1.get_entry_basic_block() - check(b1, b3) - --print "Testing basic block aliasing 3 .. ", -+print("Testing basic block aliasing 3 .. ", end=' ') - b31 = f1.entry_basic_block - check(b1, b31) - --print "Testing basic block aliasing 4 .. ", -+print("Testing basic block aliasing 4 .. ", end=' ') - bldr = Builder.new(b1) - b4 = bldr.basic_block - check(b1, b4) - --print "Testing basic block aliasing 5 .. ", -+print("Testing basic block aliasing 5 .. ", end=' ') - i1 = bldr.ret_void() - b5 = i1.basic_block - check(b1, b5) - --print "Testing instruction aliasing 1 .. ", -+print("Testing instruction aliasing 1 .. ", end=' ') - i2 = b5.instructions[0] - check(i1, i2) - -@@ -100,9 +100,9 @@ - v2 = phi.get_incoming_value(0) - b6 = phi.get_incoming_block(0) - --print "Testing PHI / basic block aliasing 5 .. ", -+print("Testing PHI / basic block aliasing 5 .. ", end=' ') - check(b1, b6) - --print "Testing PHI / value aliasing .. ", -+print("Testing PHI / value aliasing .. ", end=' ') - check(f1.args[0], v2) - ---- .\test\operands.py (original) -+++ .\test\operands.py (refactored) -@@ -28,9 +28,9 @@ - def __init__(self): pass - def read(self): return test_module - m = Module.from_assembly(strstream()) --print "-"*60 --print m --print "-"*60 -+print("-"*60) -+print(m) -+print("-"*60) - - test_func = m.get_function_named("test_func") - prod = m.get_function_named("prod") -@@ -38,16 +38,16 @@ - #===----------------------------------------------------------------------=== - # test operands - --print -+print() - i1 = test_func.basic_blocks[0].instructions[0] - i2 = test_func.basic_blocks[0].instructions[1] --print "Testing User.operand_count ..", -+print("Testing User.operand_count ..", end=' ') - if i1.operand_count == 3 and i2.operand_count == 2: -- print "OK" -+ print("OK") - else: -- print "FAIL" -+ print("FAIL") - --print "Testing User.operands ..", -+print("Testing User.operands ..", end=' ') - c1 = i1.operands[0] is prod - c2 = i1.operands[1] is test_func.args[0] - c3 = i1.operands[2] is test_func.args[1] -@@ -56,22 +56,22 @@ - c6 = len(i1.operands) == 3 - c7 = len(i2.operands) == 2 - if c1 and c2 and c3 and c5 and c6 and c7: -- print "OK" -+ print("OK") - else: -- print "FAIL" --print -+ print("FAIL") -+print() - - #===----------------------------------------------------------------------=== - # show test_function - --print "Examining test_function `test_test_func':" -+print("Examining test_function `test_test_func':") - idx = 1 - for inst in test_func.basic_blocks[0].instructions: -- print "Instruction #%d:" % (idx,) -- print " operand_count =", inst.operand_count -- print " operands:" -+ print("Instruction #%d:" % (idx,)) -+ print(" operand_count =", inst.operand_count) -+ print(" operands:") - oidx = 1 - for op in inst.operands: -- print " %d: %s" % (oidx, repr(op)) -+ print(" %d: %s" % (oidx, repr(op))) - oidx += 1 - idx += 1 ---- .\test\passes.py (original) -+++ .\test\passes.py (refactored) -@@ -36,8 +36,8 @@ - } - """ - m = Module.from_assembly(strstream(asm)) --print "-"*72 --print m -+print("-"*72) -+print(m) - - # Let's run a module-level inlining pass. First, create a pass manager. - pm = PassManager.new() -@@ -55,8 +55,8 @@ - del pm - - # Print the result. Note the change in @test2. --print "-"*72 --print m -+print("-"*72) -+print(m) - - - # Let's run a DCE pass on the the function 'test1' now. First create a -@@ -73,5 +73,5 @@ - fpm.run( m.get_function_named('test1') ) - - # Print the result. Note the change in @test1. --print "-"*72 --print m -+print("-"*72) -+print(m) ---- .\test\test.py (original) -+++ .\test\test.py (refactored) -@@ -69,7 +69,7 @@ - - # done - if gc.garbage: -- print "garbage = ", gc.garbage -+ print("garbage = ", gc.garbage) - - - main() ---- .\test\testall.py (original) -+++ .\test\testall.py (refactored) -@@ -15,12 +15,12 @@ - - - def do_llvmexception(): -- print " Testing class LLVMException" -+ print(" Testing class LLVMException") - e = LLVMException() - - - def do_ownable(): -- print " Testing class Ownable" -+ print(" Testing class Ownable") - o = Ownable(None, lambda x: None) - try: - o._own(None) -@@ -30,7 +30,7 @@ - - - def do_misc(): -- print " Testing miscellaneous functions" -+ print(" Testing miscellaneous functions") - try: - load_library_permanently("/usr/lib/libm.so") - except LLVMException: -@@ -42,14 +42,14 @@ - - - def do_llvm(): -- print " Testing module llvm" -+ print(" Testing module llvm") - do_llvmexception() - do_ownable() - do_misc() - - - def do_module(): -- print " Testing class Module" -+ print(" Testing class Module") - m = Module.new('test') - m.target = 'a' - a = m.target -@@ -101,7 +101,7 @@ - - - def do_type(): -- print " Testing class Type" -+ print(" Testing class Type") - for i in range(1,100): - Type.int(i) - Type.float() -@@ -151,14 +151,14 @@ - - - def do_typehandle(): -- print " Testing class TypeHandle" -+ print(" Testing class TypeHandle") - th = TypeHandle.new(Type.opaque()) - ts = Type.struct([ Type.int(), Type.pointer(th.type) ]) - th.type.refine(ts) - - - def do_value(): -- print " Testing class Value" -+ print(" Testing class Value") - k = Constant.int(ti, 42) - k.name = 'a' - s = k.name -@@ -186,7 +186,7 @@ - - - def do_constant(): -- print " Testing class Constant" -+ print(" Testing class Constant") - Constant.null(ti) - Constant.all_ones(ti) - Constant.undef(ti) -@@ -231,7 +231,7 @@ - - - def do_global_value(): -- print " Testing class GlobalValue" -+ print(" Testing class GlobalValue") - m = Module.new('a') - gv = GlobalVariable.new(m, Type.int(), 'b') - s = gv.is_declaration -@@ -247,7 +247,7 @@ - - - def do_global_variable(): -- print " Testing class GlobalVariable" -+ print(" Testing class GlobalVariable") - m = Module.new('a') - gv = GlobalVariable.new(m, Type.int(), 'b') - gv = GlobalVariable.get(m, 'b') -@@ -260,7 +260,7 @@ - - - def do_argument(): -- print " Testing class Argument" -+ print(" Testing class Argument") - m = Module.new('a') - ft = Type.function(ti, [ti]) - f = Function.new(m, ft, 'func') -@@ -272,7 +272,7 @@ - - - def do_function(): -- print " Testing class Function" -+ print(" Testing class Function") - ft = Type.function(ti, [ti]*20) - zz = Function.new(Module.new('z'), ft, 'foobar') - del zz -@@ -307,7 +307,7 @@ - - - def do_instruction(): -- print " Testing class Instruction" -+ print(" Testing class Instruction") - m = Module.new('a') - ft = Type.function(ti, [ti]*20) - f = Function.new(m, ft, 'func') -@@ -320,7 +320,7 @@ - - - def do_callorinvokeinstruction(): -- print " Testing class CallOrInvokeInstruction" -+ print(" Testing class CallOrInvokeInstruction") - m = Module.new('a') - ft = Type.function(ti, [ti]) - f = Function.new(m, ft, 'func') -@@ -337,7 +337,7 @@ - - - def do_phinode(): -- print " Testing class PhiNode" -+ print(" Testing class PhiNode") - m = Module.new('a') - ft = Type.function(ti, [ti]) - f = Function.new(m, ft, 'func') -@@ -354,7 +354,7 @@ - - - def do_switchinstruction(): -- print " Testing class SwitchInstruction" -+ print(" Testing class SwitchInstruction") - m = Module.new('a') - ft = Type.function(ti, [ti]) - f = Function.new(m, ft, 'func') -@@ -365,7 +365,7 @@ - - - def do_basicblock(): -- print " Testing class BasicBlock" -+ print(" Testing class BasicBlock") - m = Module.new('a') - ft = Type.function(ti, [ti]) - f = Function.new(m, ft, 'func') -@@ -395,7 +395,7 @@ - - - def do_builder(): -- print " Testing class Builder" -+ print(" Testing class Builder") - m = Module.new('a') - ft = Type.function(ti, [ti]) - f = Function.new(m, ft, 'func') -@@ -488,7 +488,7 @@ - - - def do_llvm_core(): -- print " Testing module llvm.core" -+ print(" Testing module llvm.core") - do_module() - do_type() - do_typehandle() -@@ -508,7 +508,7 @@ - - - def do_targetdata(): -- print " Testing class TargetData" -+ print(" Testing class TargetData") - t = TargetData.new('') - v = str(t) - v = t.byte_order -@@ -530,7 +530,7 @@ - - - def do_genericvalue(): -- print " Testing class GenericValue" -+ print(" Testing class GenericValue") - v = GenericValue.int(ti, 1) - v = GenericValue.int_signed(ti, 1) - v = GenericValue.real(Type.float(), 3.14) -@@ -540,7 +540,7 @@ - - - def do_executionengine(): -- print " Testing class ExecutionEngine" -+ print(" Testing class ExecutionEngine") - m = Module.new('a') - ee = ExecutionEngine.new(m, True) - ft = Type.function(ti, []) -@@ -567,14 +567,14 @@ - - - def do_llvm_ee(): -- print " Testing module llvm.ee" -+ print(" Testing module llvm.ee") - do_targetdata() - do_genericvalue() - do_executionengine() - - - def do_passmanager(): -- print " Testing class PassManager" -+ print(" Testing class PassManager") - pm = PassManager.new() - pm.add(TargetData.new('')) - for i in [getattr(llvm.passes, x) for x in \ -@@ -586,7 +586,7 @@ - - - def do_functionpassmanager(): -- print " Testing class FunctionPassManager" -+ print(" Testing class FunctionPassManager") - m = Module.new('a') - ft = Type.function(ti, []) - f = m.add_function(ft, 'func') -@@ -602,13 +602,13 @@ - - - def do_llvm_passes(): -- print " Testing module llvm.passes" -+ print(" Testing module llvm.passes") - do_passmanager() - do_functionpassmanager() - - - def main(): -- print "Testing package llvm" -+ print("Testing package llvm") - do_llvm() - do_llvm_core() - do_llvm_ee() ---- .\test\testattrs.py (original) -+++ .\test\testattrs.py (refactored) -@@ -1,7 +1,7 @@ - #!/usr/bin/env python - - from llvm.core import * --from cStringIO import StringIO -+from io import StringIO - - - def make_module(): ---- .\test\typehandle.py (original) -+++ .\test\typehandle.py (refactored) -@@ -16,4 +16,4 @@ - m.add_type_name("struct.node", th.type) - - # show what we created --print m -+print(m) ---- .\test\uses.py (original) -+++ .\test\uses.py (refactored) -@@ -13,11 +13,11 @@ - tmp3 = bld.add(tmp1, f.args[2], "tmp3") - bld.ret(tmp3) - --print "-"*60 --print m --print "-"*60 -+print("-"*60) -+print(m) -+print("-"*60) - --print "Testing use count ..", -+print("Testing use count ..", end=' ') - c1 = f.args[0].use_count == 1 - c2 = f.args[1].use_count == 1 - c3 = f.args[2].use_count == 1 -@@ -25,11 +25,11 @@ - c5 = tmp2.use_count == 0 - c6 = tmp3.use_count == 1 - if c1 and c2 and c3 and c4 and c5 and c6: -- print "OK" -+ print("OK") - else: -- print "FAIL" -+ print("FAIL") - --print "Testing uses ..", -+print("Testing uses ..", end=' ') - c1 = f.args[0].uses[0] is tmp1 - c2 = len(f.args[0].uses) == 1 - c3 = f.args[1].uses[0] is tmp2 -@@ -40,6 +40,6 @@ - c8 = len(tmp2.uses) == 0 - c9 = len(tmp3.uses) == 1 - if c1 and c2 and c3 and c4 and c5 and c6 and c7 and c8 and c9: -- print "OK" -+ print("OK") - else: -- print "FAIL" -+ print("FAIL") ---- .\tools\intrgen.py (original) -+++ .\tools\intrgen.py (refactored) -@@ -26,7 +26,7 @@ - idx = 1 - for i in intr: - s = 'INTR_' + i.upper() -- print '%s = %d' % (s.ljust(maxw), idx) -+ print('%s = %d' % (s.ljust(maxw), idx)) - idx += 1 - - gen(sys.argv[1]) ---- .\tools\intrs_for_doc.py (original) -+++ .\tools\intrs_for_doc.py (refactored) -@@ -21,5 +21,5 @@ - outf = open(OUTF, 'wt') - i = 0 - while i < len(intrs): -- print >>outf, "`" + "`,`".join(intrs[i:min(i+NCOLS,len(intrs)+1)]) + "`" -+ print("`" + "`,`".join(intrs[i:min(i+NCOLS,len(intrs)+1)]) + "`", file=outf) - i += NCOLS ---- .\www\makeweb.py (original) -+++ .\www\makeweb.py (refactored) -@@ -52,7 +52,7 @@ - - - def _rmtree_warn(fn, path, excinfo): -- print "** WARNING **: error while doing %s on %s" % (fn, path) -+ print("** WARNING **: error while doing %s on %s" % (fn, path)) - - - def _can_skip(opts, infile, outfile): -@@ -67,14 +67,14 @@ - cmd = cmdfn(opts, infile, outfile_actual) - if _can_skip(opts, infile, outfile_actual): - if opts.verbose >= 2: -- print "up to date %s -> %s" % (infile, outfile_actual) -+ print("up to date %s -> %s" % (infile, outfile_actual)) - return - if cmd: - # do cmd - if opts.verbose: -- print "process %s -> %s" % (infile, outfile_actual) -+ print("process %s -> %s" % (infile, outfile_actual)) - if opts.verbose >= 3: -- print "command is [%s]" % cmd -+ print("command is [%s]" % cmd) - if not opts.dryrun: - os.system(cmd) - # else if cmd is None, do nothing -@@ -83,7 +83,7 @@ - # nothing matched, default action is to copy - if not _can_skip(opts, infile, outfile): - if opts.verbose: -- print "copying %s -> %s" % (infile, outfile) -+ print("copying %s -> %s" % (infile, outfile)) - if not opts.dryrun: - shutil.copy(infile, outfile) - -@@ -95,14 +95,14 @@ - - # if it exists, it must be a dir! - if odexists and not os.path.isdir(outdir): -- print "** WARNING **: output dir '%s' exists but is " \ -- "not a dir, skipping" % outdir -+ print("** WARNING **: output dir '%s' exists but is " \ -+ "not a dir, skipping" % outdir) - return - - # make outdir if not existing - if not odexists: - if opts.verbose: -- print "creating %s" % outdir -+ print("creating %s" % outdir) - if not opts.dryrun: - os.mkdir(outdir) - -@@ -114,8 +114,8 @@ - # process files - if os.path.isfile(inp): - if os.path.exists(outp) and not os.path.isfile(outp): -- print "** WARNING **: output '%s' corresponding to " \ -- "input '%s' is not a file, skipping" % (outp, inp) -+ print("** WARNING **: output '%s' corresponding to " \ -+ "input '%s' is not a file, skipping" % (outp, inp)) - else: - process_file(opts, inp, outp) - -@@ -124,15 +124,15 @@ - # if dir is in skip list, silently ignore - if elem in DIR_SKIP_TBL: - if opts.verbose >= 3: -- print "skipping %s" % inp -+ print("skipping %s" % inp) - continue - # just recurse - make(opts, inp, outp) - - # neither a file nor a dir - else: -- print "** WARNING **: input '%s' is neither file nor " \ -- "dir, skipping" % inp -+ print("** WARNING **: input '%s' is neither file nor " \ -+ "dir, skipping" % inp) - - - def get_opts(): -@@ -173,14 +173,14 @@ - def main(): - opts, src, dest = get_opts() - if opts.verbose >= 3: -- print ("running with options:\nsrc = [%s]\ndest = [%s]\nverbose = [%d]\n" +\ -+ print(("running with options:\nsrc = [%s]\ndest = [%s]\nverbose = [%d]\n" +\ - "dry-run = [%d]\nclean-first = [%d]\nforce = [%d]") %\ -- (src, dest, opts.verbose, opts.dryrun, opts.clean, opts.force) -+ (src, dest, opts.verbose, opts.dryrun, opts.clean, opts.force)) - if opts.dryrun and opts.verbose == 0: - opts.verbose = 1 - if opts.clean: - if opts.dryrun or opts.verbose: -- print "removing tree %s" % dest -+ print("removing tree %s" % dest) - if not opts.dryrun: - os.rmtree(dest, True, _rmtree_warn) - make(opts, src, dest) diff --git a/llvm/py3k_update.output b/llvm/py3k_update.output deleted file mode 100644 index 4ea51a4..0000000 --- a/llvm/py3k_update.output +++ /dev/null @@ -1,62 +0,0 @@ -C:\Users\AndrewBC\src\llvm-py>python "C:\Program Files\Python27\Tools\Scripts\2to3.py" -w -f all -f idioms . > llvm/py3k_update.diff -RefactoringTool: Skipping implicit fixer: buffer -RefactoringTool: Skipping implicit fixer: set_literal -RefactoringTool: Skipping implicit fixer: ws_comma -RefactoringTool: Refactored .\setup-win32.py -RefactoringTool: Refactored .\setup.py -RefactoringTool: Refactored .\llvm\__init__.py -RefactoringTool: Refactored .\llvm\_util.py -RefactoringTool: Refactored .\llvm\core.py -RefactoringTool: Refactored .\llvm\ee.py -RefactoringTool: Refactored .\llvm\passes.py -RefactoringTool: Refactored .\test\JITTutorial1.py -RefactoringTool: Refactored .\test\JITTutorial2.py -RefactoringTool: Refactored .\test\asm.py -RefactoringTool: Refactored .\test\call-jit-ctypes.py -RefactoringTool: Refactored .\test\example-jit.py -RefactoringTool: Refactored .\test\example.py -RefactoringTool: Refactored .\test\intrinsic.py -RefactoringTool: Refactored .\test\objcache.py -RefactoringTool: Refactored .\test\operands.py -RefactoringTool: Refactored .\test\passes.py -RefactoringTool: Refactored .\test\test.py -RefactoringTool: Refactored .\test\testall.py -RefactoringTool: Refactored .\test\testattrs.py -RefactoringTool: Refactored .\test\typehandle.py -RefactoringTool: Refactored .\test\uses.py -RefactoringTool: Refactored .\tools\intrgen.py -RefactoringTool: Refactored .\tools\intrs_for_doc.py -RefactoringTool: Refactored .\www\makeweb.py -RefactoringTool: Can't parse .\www\src\examples\JITTutorial1.py: ParseError: bad input: type=17, value=u'/', context=('', (1, 2)) -RefactoringTool: Can't parse .\www\src\examples\JITTutorial2.py: ParseError: bad input: type=17, value=u'/', context=('', (1, 2)) -RefactoringTool: Files that need to be modified: -RefactoringTool: .\setup-win32.py -RefactoringTool: .\setup.py -RefactoringTool: .\llvm\__init__.py -RefactoringTool: .\llvm\_util.py -RefactoringTool: .\llvm\core.py -RefactoringTool: .\llvm\ee.py -RefactoringTool: .\llvm\passes.py -RefactoringTool: .\test\JITTutorial1.py -RefactoringTool: .\test\JITTutorial2.py -RefactoringTool: .\test\asm.py -RefactoringTool: .\test\call-jit-ctypes.py -RefactoringTool: .\test\example-jit.py -RefactoringTool: .\test\example.py -RefactoringTool: .\test\intrinsic.py -RefactoringTool: .\test\objcache.py -RefactoringTool: .\test\operands.py -RefactoringTool: .\test\passes.py -RefactoringTool: .\test\test.py -RefactoringTool: .\test\testall.py -RefactoringTool: .\test\testattrs.py -RefactoringTool: .\test\typehandle.py -RefactoringTool: .\test\uses.py -RefactoringTool: .\tools\intrgen.py -RefactoringTool: .\tools\intrs_for_doc.py -RefactoringTool: .\www\makeweb.py -RefactoringTool: There were 2 errors: -RefactoringTool: Can't parse .\www\src\examples\JITTutorial1.py: ParseError: bad input: type=17, value=u'/', context=('', (1, 2)) -RefactoringTool: Can't parse .\www\src\examples\JITTutorial2.py: ParseError: bad input: type=17, value=u'/', context=('', (1, 2)) - -C:\Users\AndrewBC\src\llvm-py> \ No newline at end of file diff --git a/llvm/tbaa.py b/llvm/tbaa.py deleted file mode 100644 index b510ce2..0000000 --- a/llvm/tbaa.py +++ /dev/null @@ -1,51 +0,0 @@ -from llvm.core import * - -class TBAABuilder(object): - '''Simplify creation of TBAA metadata. - - Each TBAABuidler object operates on a module. - User can create multiple TBAABuilder on a module - ''' - - def __init__(self, module, rootid): - ''' - module --- the module to use. - root --- string name to identify the TBAA root. - ''' - self.__module = module - self.__rootid = rootid - self.__rootmd = self.__new_md(rootid) - - @classmethod - def new(cls, module, rootid): - return cls(module, rootid) - - def get_node(self, name, parent=None, const=False): - '''Returns a MetaData object representing a TBAA node. - - Use loadstore_instruction.set_metadata('tbaa', node) to - bind a type to a memory. - ''' - parent = parent or self.root - const = Constant.int(Type.int(), int(bool(const))) - return self.__new_md(name, parent, const) - - @property - def module(self): - return self.__module - - @property - def root(self): - return self.__rootmd - - @property - def root_name(self): - return self.__rootid - - def __new_md(self, *args): - contents = list(args) - for i, v in enumerate(contents): - if isinstance(v, str): - contents[i] = MetaDataString.get(self.module, v) - return MetaData.get(self.module, contents) - diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py deleted file mode 100644 index 05b7d72..0000000 --- a/llvm/test_llvmpy.py +++ /dev/null @@ -1,1249 +0,0 @@ -""" -LLVM tests -""" -import os -import sys -import math -import shutil -import unittest -import subprocess -import tempfile -import contextlib - -is_py3k = bool(sys.version_info[0] == 3) -BITS = tuple.__itemsize__ * 8 - -if is_py3k: - from io import StringIO -else: - from cStringIO import StringIO - - -import llvm -from llvm.core import (Module, Type, GlobalVariable, Function, Builder, - Constant, MetaData, MetaDataString, inline_function) -from llvm.ee import EngineBuilder -import llvm.core as lc -import llvm.passes as lp -import llvm.ee as le - - -tests = [] - - -# --------------------------------------------------------------------------- - -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 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 ''. - 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 ''. - m2.id = m.id # Copy the name from `m` - - self.assertEqual(str(m2).strip(), asm.strip()) - -tests.append(TestAsm) - -# --------------------------------------------------------------------------- - -class TestAttr(TestCase): - def make_module(self): - test_module = """ - define i32 @sum(i32, i32) { - entry: - %2 = add i32 %0, %1 - ret i32 %2 - } - """ - return Module.from_assembly(StringIO(test_module)) - - 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) - -# --------------------------------------------------------------------------- - -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()) - - old = bldr.load(ptr) - 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()) - - val = Constant.int(Type.int(), 1234) - - 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) - -# --------------------------------------------------------------------------- - -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) - -# --------------------------------------------------------------------------- - -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) - -# --------------------------------------------------------------------------- - -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) - self.assertFalse(pmb.disable_simplify_lib_calls) - - # 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) - -# --------------------------------------------------------------------------- - -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() - ee = EngineBuilder.new(module).create() - - with self.assertRaises(llvm.LLVMException): - # Ensure the module is owned. - llvm._util.check_is_unowned(module) - - self.run_foo(ee, module) - - - def test_enginebuilder_with_tm(self): - tm = le.TargetMachine.new() - module = self.make_test_module() - ee = EngineBuilder.new(module).create(tm) - - with self.assertRaises(llvm.LLVMException): - # Ensure the targetmachine is owned. - llvm._util.check_is_unowned(tm) - - - with self.assertRaises(llvm.LLVMException): - # Ensure the module is owned. - llvm._util.check_is_unowned(module) - - 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) - -# --------------------------------------------------------------------------- - -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) -# --------------------------------------------------------------------------- - -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.get_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) - -# --------------------------------------------------------------------------- - -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).decode('utf-8')) - self.assertTrue(le.get_host_cpu_name()) - - def test_ptx(self): - if lc.HAS_PTX: - arch = 'ptx64' - elif lc.HAS_NVPTX: - arch = 'nvptx64' - else: - return # skip this test - m, func = self._build_module() - func.calling_convention = lc.CC_PTX_KERNEL # set calling conv - ptxtm = le.TargetMachine.lookup(arch=arch, cpu='compute_20') - self.assertTrue(ptxtm.triple) - self.assertTrue(ptxtm.cpu) - ptxasm = ptxtm.emit_assembly(m).decode('utf-8') - self.assertIn('foo', ptxasm) - if lc.HAS_NVPTX: - self.assertIn('.address_size 64', ptxasm) - self.assertIn('compute_20', ptxasm) - - def _build_module(self): - m = 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 - - def _build_bad_archname(self): - with self.assertRaises(RuntimeError): - tm = TargetMachine.lookup("ain't no arch name") - -tests.append(TestTargetMachines) - -# --------------------------------------------------------------------------- - -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): - 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: - fout.write(output) - - self._compile(src) - - def test_object(self): - if sys.platform == 'darwin': - # skip this test on MacOSX for now - return - - 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) - -if sys.platform != 'win32': - tests.append(TestNative) - -# --------------------------------------------------------------------------- - -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) - -tests.append(TestNativeAsm) - -# --------------------------------------------------------------------------- - -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) - -# --------------------------------------------------------------------------- - -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) - -# --------------------------------------------------------------------------- - -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) - -# --------------------------------------------------------------------------- - -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) - -# --------------------------------------------------------------------------- - -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) - -# --------------------------------------------------------------------------- -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) - - def test_cpu_support6(self): - features = [] - mattrs = ','.join(map(lambda s: '-%s' % s, features)) - print 'disable mattrs', mattrs - self._template(mattrs) - -tests.append(TestCPUSupport) - -# --------------------------------------------------------------------------- -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 - ee = le.ExecutionEngine.new(mod) - 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) - -# --------------------------------------------------------------------------- - -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 ) ; :0 [#uses -# } -# -# declare i32 @llvm.bswap.i32(i32) nounwind readnone -# -# define float @mysin(float %x) { -# entry: -# %cosx = call float @llvm.cos.f32( float %x ) ; [#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 - ee = le.ExecutionEngine.new(mod) - 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) - -# --------------------------------------------------------------------------- - -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) - -# --------------------------------------------------------------------------- - -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) - -# --------------------------------------------------------------------------- - -def run(verbosity=1): - print('llvmpy is installed in: ' + os.path.dirname(__file__)) - print('llvmpy version: ' + llvm.__version__) - print(sys.version) - - suite = unittest.TestSuite() - for cls in tests: - suite.addTest(unittest.makeSuite(cls)) - - # The default stream fails in IPython qtconsole on Windows, - # so just using sys.stdout - runner = unittest.TextTestRunner(verbosity=verbosity, stream=sys.stdout) - return runner.run(suite) - - -if __name__ == '__main__': - run() diff --git a/llvm/wrap.cpp b/llvm/wrap.cpp deleted file mode 100644 index 6702ade..0000000 --- a/llvm/wrap.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2008-10, Mahadevan R All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of this software, nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "wrap.h" - -const char PYCAP_OBJECT_NAME[] = "llvm.wrap.h"; - -/*===----------------------------------------------------------------------===*/ -/* Type ctor/dtor */ -/*===----------------------------------------------------------------------===*/ - - -/*===----------------------------------------------------------------------===*/ -/* Helper functions */ -/*===----------------------------------------------------------------------===*/ - -void *get_object_arg(PyObject *args) -{ - PyObject *o; - - if (!PyArg_ParseTuple(args, "O", &o)) - throw py_exception(); - - return pycap_get(o); -} - -// must delete [] returned array -void **make_array_from_list(PyObject *list, int n) -{ - void **arr = new void*[n] ; - - int i; - for (i=0; i(e); - } - } - - return arr; -} diff --git a/llvm/wrap.h b/llvm/wrap.h deleted file mode 100644 index ce2dd88..0000000 --- a/llvm/wrap.h +++ /dev/null @@ -1,1277 +0,0 @@ -/* - * Copyright (c) 2008-10, Mahadevan R All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of this software, nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * Functions and macros to aid in wrapping. - */ - -#ifndef LLVM_PY_WRAP_H -#define LLVM_PY_WRAP_H - - -/* python includes */ -#include -// #include //unused? - -//// For pre-2.7 compatbility, use the following include, which provides -//// alias for PyCapsule. -//// See http://docs.python.org/py3k/howto/cporting.html -#include "capsulethunk.h" // pre-2.7 compatibility for PyCapsule - - -/* llvm includes */ -#include "llvm-c/Core.h" -#include "llvm-c/Analysis.h" -#include "llvm-c/ExecutionEngine.h" -#include "llvm-c/Target.h" - -// workaround missing bool type -#define bool int -#include "llvm-c/Transforms/PassManagerBuilder.h" -#undef bool - -#include "llvm_c_extra.h" - -#include -#include - -class py_exception: public std::exception{}; - -#define LLVMPY_TRY \ - try { - -#define LLVMPY_CATCH_ALL \ - } catch (const std::bad_alloc&) { \ - return PyErr_NoMemory(); \ - } catch (const py_exception &) { \ - return NULL; \ - } catch (const std::exception& e) { \ - PyErr_SetString(PyExc_RuntimeError, e.what()); \ - return NULL; \ - } catch (...) { \ - std::ostringstream oss; \ - oss << "Unknown exception " << __FILE__ << ":" << __LINE__; \ - PyErr_SetString(PyExc_RuntimeError, oss.str().c_str()); \ - return NULL; \ - } - -/*===----------------------------------------------------------------------===*/ -/* Typedefs */ -/*===----------------------------------------------------------------------===*/ - -typedef unsigned long long llvmwrap_ull; -typedef long long llvmwrap_ll; - -/*===----------------------------------------------------------------------===*/ -/* Type ctor/dtor */ -/*===----------------------------------------------------------------------===*/ - -extern const char PYCAP_OBJECT_NAME[] ; - -// Cast python object to aTYPE -template -aTYPE pycap_get( PyObject* obj ) -{ - void *p = PyCapsule_GetPointer(obj, PYCAP_OBJECT_NAME); - if (!p){ - throw py_exception(); - } - return static_cast (p); -} - -// Contruct python object to hold aTYPE pointer -template -PyObject* pycap_new( aTYPE p ) -{ - if (p){ - return PyCapsule_New(p, PYCAP_OBJECT_NAME, NULL); - } - Py_RETURN_NONE; -} - -/*===----------------------------------------------------------------------===*/ -/* Helper methods */ -/*===----------------------------------------------------------------------===*/ - -/** - * Accept a single object argument of type PyCObject and return the - * opaque pointer contained in it. - */ -void *get_object_arg(PyObject *args); - -template -aTYPE get_object_arg( PyObject* obj ) -{ - return static_cast ( get_object_arg(obj) ); -} - -/** - * Given a PyList object (list) having n (= PyList_Size(list)) elements, - * each list object being a PyCObject, return a new()-ed array of - * opaque pointers from the PyCObjects. The 'n' is passed explicitly - * since the caller will have to query it once anyway, and we can avoid - * a second call internally. - */ -void **make_array_from_list(PyObject *list, int n); - -template -LLTYPE make_array_from_list(PyObject *list, int n) -{ - LLTYPE p = reinterpret_cast(make_array_from_list(list, n)) ; - if ( !p ) throw py_exception(); - return p; -} - -template -PyObject* make_list( aTYPE p[], size_t n ) -{ - PyObject *list = PyList_New(n); - - if (!list) - return NULL; - - size_t i; - for (i=0; i( p[i] ); - PyList_SetItem(list, i, elem); - } - - return list; -} - -/*===----------------------------------------------------------------------===*/ -/* Wrapper macros */ -/*===----------------------------------------------------------------------===*/ - -/* The following wrapper macros define functions that wrap over LLVM-C APIs - * of various signatures. Though they look hairy, they all follow some - * conventions. - */ - - -/****************************************************************************** - ****************************************************************************** - *** PyCapsule Calls - ****************************************************************************** - *****************************************************************************/ - -#define _wrap_none2none(func) \ -static PyObject * \ -_w ## func(PyObject * self, PyObject * args) \ -{ \ - LLVMPY_TRY \ - if (!PyArg_ParseTuple(args, "")) \ - return NULL; \ - func(); \ - Py_RETURN_NONE; \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1) - */ -#define _wrap_obj2obj(func, intype1, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - intype1 arg1 = get_object_arg(args); \ - \ - return pycap_new( func( arg1 ) ); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(int arg1) - */ -#define _wrap_int2obj(func, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - int arg1; \ - \ - if (!PyArg_ParseTuple(args, "i", &arg1)) \ - return NULL; \ - \ - return pycap_new( func( arg1 ) ); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2) - */ -#define _wrap_objobj2obj(func, intype1, intype2, outtype)\ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2; \ - \ - if (!PyArg_ParseTuple(args, "OO", &obj1, &obj2)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype2 arg2 = pycap_get< intype2 > (obj2); \ - \ - return pycap_new( func( arg1, arg2 ) ); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * void func(intype1 arg1, intype2 arg2) - */ -#define _wrap_objobj2none(func, intype1, intype2) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2; \ - \ - if (!PyArg_ParseTuple(args, "OO", &obj1, &obj2)) \ - return NULL; \ - \ - intype1 arg1 = pycap_get< intype1 > (obj1); \ - intype2 arg2 = pycap_get< intype2 > (obj2); \ - \ - func (arg1, arg2); \ - Py_RETURN_NONE; \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, arg2) - */ -#define _wrap_objint2obj(func, intype1, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1; \ - size_t arg2; \ - \ - if (!PyArg_ParseTuple(args, "OI", &obj1, &arg2)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - \ - return pycap_new( func( arg1, arg2 ) ); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, intype3 arg3) - */ -#define _wrap_objobjobj2obj(func, intype1, intype2, intype3, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2, *obj3; \ - \ - if (!PyArg_ParseTuple(args, "OOO", &obj1, &obj2, &obj3)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype2 arg2 = pycap_get< intype2 > (obj2); \ - const intype3 arg3 = pycap_get< intype3 > (obj3); \ - \ - return pycap_new( func( arg1, arg2, arg3 ) ); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * void func(intype1 arg1, intype2 arg2, intype3 arg3) - */ -#define _wrap_objobjobj2none(func, intype1, intype2, intype3) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2, *obj3; \ - \ - if (!PyArg_ParseTuple(args, "OOO", &obj1, &obj2, &obj3)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype2 arg2 = pycap_get< intype2 > (obj2); \ - const intype3 arg3 = pycap_get< intype3 > (obj3); \ - \ - func (arg1, arg2, arg3); \ - Py_RETURN_NONE; \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func( arg1, intype2 arg2, intype3 arg3) - */ -#define _wrap_intobjobj2obj(func, intype2, intype3, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - size_t arg1; \ - PyObject *obj2, *obj3; \ - \ - if (!PyArg_ParseTuple(args, "IOO", &arg1, &obj2, &obj3)) \ - return NULL; \ - \ - const intype2 arg2 = pycap_get< intype2 > (obj2); \ - const intype3 arg3 = pycap_get< intype3 > (obj3); \ - \ - return pycap_new( func( arg1, arg2, arg3 ) ); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(enum_intype1 arg1, intype2 arg2, intype3 arg3) - */ -#define _wrap_enumobjobj2obj(func, intype1, intype2, intype3, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - intype1 arg1; \ - PyObject *obj2, *obj3; \ - \ - if (!PyArg_ParseTuple(args, "IOO", &arg1, &obj2, &obj3)) \ - return NULL; \ - \ - const intype2 arg2 = pycap_get< intype2 > (obj2); \ - const intype3 arg3 = pycap_get< intype3 > (obj3); \ - \ - return pycap_new( func( arg1, arg2, arg3 ) ); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(const char *s) - */ -#define _wrap_str2obj(func, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - const char *arg1; \ - \ - if (!PyArg_ParseTuple(args, "s", &arg1)) \ - return NULL; \ - \ - return pycap_new( func( arg1 ) ); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func() - */ -#define _wrap_none2obj(func, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - if (!PyArg_ParseTuple(args, "")) \ - return NULL; \ - \ - return pycap_new( func() ); \ - LLVMPY_CATCH_ALL \ -} - - -/** - * Wrap LLVM functions of the type - * const char * func() - */ - #define _wrap_none2str(func) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - if (!PyArg_ParseTuple(args, "")) \ - return NULL; \ - return PyUnicode_FromString(func()); \ - LLVMPY_CATCH_ALL \ -} - - -/** - * Wrap LLVM functions of the type - * const char *func(intype1 arg1) - */ -#define _wrap_obj2str(func, intype1) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - const intype1 arg1 = get_object_arg(args) ; \ - return PyUnicode_FromString( func (arg1)); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * void func(intype1 arg1) - */ -#define _wrap_obj2none(func, intype1) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - const intype1 arg1 = get_object_arg(args) ; \ - func (arg1); \ - Py_RETURN_NONE; \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * void func(intype1 arg1, const char *arg2) - */ -#define _wrap_objstr2none(func, intype1) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1; \ - const char *arg2; \ - \ - if (!PyArg_ParseTuple(args, "Os", &obj1, &arg2)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 >( obj1 ); \ - \ - func (arg1, arg2); \ - Py_RETURN_NONE; \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, const char *arg2) - */ -#define _wrap_objstr2obj(func, intype1, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1; \ - const char *arg2; \ - \ - if (!PyArg_ParseTuple(args, "Os", &obj1, &arg2)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - \ - return pycap_new( func( arg1, arg2 ) ); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * void func(intype1 arg1, arg2) - */ -#define _wrap_objint2none(func, intype1) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1; \ - int arg2; \ - \ - if (!PyArg_ParseTuple(args, "Oi", &obj1, &arg2)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - \ - func (arg1, arg2); \ - Py_RETURN_NONE; \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * void func(intype1 arg1, enum_intype2 arg2) - */ -#define _wrap_objenum2none(func, intype1, intype2) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - intype2 arg2; \ - PyObject *obj1; \ - \ - if (!PyArg_ParseTuple(args, "Oi", &obj1, &arg2)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 >( obj1 ); \ - \ - func (arg1, arg2); \ - Py_RETURN_NONE; \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, const char *arg3) - */ -#define _wrap_objobjstr2obj(func, intype1, intype2, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2; \ - const char *arg3; \ - \ - if (!PyArg_ParseTuple(args, "OOs", &obj1, &obj2, &arg3)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype2 arg2 = pycap_get< intype2 > (obj2); \ - \ - return pycap_new ( func (arg1, arg2, arg3)); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, int arg3) - */ -#define _wrap_objobjint2obj(func, intype1, intype2, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2; \ - int arg3; \ - \ - if (!PyArg_ParseTuple(args, "OOi", &obj1, &obj2, &arg3)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype2 arg2 = pycap_get< intype2 > (obj2); \ - \ - return pycap_new( func( arg1, arg2, arg3 ) ) ; \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, unsigned long long arg3) - */ -#define _wrap_objobjull2obj(func, intype1, intype2, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2; \ - unsigned long long arg3; \ - \ - if (!PyArg_ParseTuple(args, "OOK", &obj1, &obj2, &arg3)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype2 arg2 = pycap_get< intype2 > (obj2); \ - \ - return pycap_new( func( arg1, arg2, arg3 ) ) ; \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * void func(intype1 arg1, arg2, arg3) - */ -#define _wrap_objintint2none(func, intype1) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1; \ - int arg2, arg3; \ - \ - if (!PyArg_ParseTuple(args, "Oii", &obj1, &arg2, &arg3)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - \ - func (arg1, arg2, arg3); \ - Py_RETURN_NONE; \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * void func(intype1 arg1, arg2, enum_intype3 arg3) - */ -#define _wrap_objintenum2none(func, intype1, intype3) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1; \ - int arg2; \ - intype3 arg3; \ - \ - if (!PyArg_ParseTuple(args, "Oii", &obj1, &arg2, &arg3)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 >( obj1 ); \ - \ - func (arg1, arg2, arg3); \ - Py_RETURN_NONE; \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, const char *arg2, intype3 arg3) - */ -#define _wrap_objstrobj2obj(func, intype1, intype3, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj3; \ - const char *arg2; \ - \ - if (!PyArg_ParseTuple(args, "OsO", &obj1, &arg2, &obj3)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype3 arg3 = pycap_get< intype3 > (obj3); \ - \ - return pycap_new( func( arg1, arg2, arg3 ) ); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * void func(intype1 arg1, const char *arg2, intype3 arg3) - */ -#define _wrap_objstrobj2none(func, intype1, intype3) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj3; \ - const char *arg2; \ - \ - if (!PyArg_ParseTuple(args, "OsO", &obj1, &arg2, &obj3)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype3 arg3 = pycap_get< intype3 > (obj3); \ - \ - func(arg1, arg2, arg3); \ - \ - Py_RETURN_NONE; \ - LLVMPY_CATCH_ALL \ -} - - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, int arg3, const char *arg4) - */ -#define _wrap_objobjintstr2obj(func, intype1, intype2, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2; \ - int arg3; \ - const char *arg4; \ - \ - if (!PyArg_ParseTuple(args, "OOis", &obj1, &obj2, &arg3, &arg4)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype2 arg2 = pycap_get< intype2 > (obj2); \ - \ - return pycap_new( func( arg1, arg2, arg3, arg4 ) ) ; \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, intype3, int arg3, const char *arg4) - */ -#define _wrap_objobjobjintstr2obj(func, intype1, intype2, intype3, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2, *obj3; \ - int arg4; \ - const char *arg5; \ - \ - if (!PyArg_ParseTuple(args, "OOOis", &obj1, &obj2, &obj3, &arg4, \ - &arg5)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype2 arg2 = pycap_get< intype2 > (obj2); \ - const intype3 arg3 = pycap_get< intype3 > (obj3); \ - \ - return pycap_new( func( arg1, arg2, arg3, arg4, arg5 ) ) ; \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, const char *arg4) - */ -#define _wrap_objobjobjstr2obj(func, intype1, intype2, intype3, outtype)\ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2, *obj3; \ - const char *arg4; \ - \ - if (!PyArg_ParseTuple(args, "OOOs", &obj1, &obj2, &obj3, &arg4)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype2 arg2 = pycap_get< intype2 > (obj2); \ - const intype3 arg3 = pycap_get< intype3 > (obj3); \ - \ - return pycap_new( func( arg1, arg2, arg3, arg4 ) ); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, const char *arg3, arg4) - */ -#define _wrap_objobjstrint2obj(func, intype1, intype2, outtype)\ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2; \ - const char *arg3; \ - int arg4; \ - \ - if (!PyArg_ParseTuple(args, "OOsi", &obj1, &obj2, &arg3, &arg4)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype2 arg2 = pycap_get< intype2 > (obj2); \ - \ - return pycap_new( func( arg1, arg2, arg3, arg4 ) ); \ - LLVMPY_CATCH_ALL \ -} - - - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, arg3, const char *arg4, arg5) - */ -#define _wrap_objobjintstrint2obj(func, intype1, intype2, outtype)\ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2; \ - int arg3; \ - const char *arg4; \ - int arg5; \ - \ - if (!PyArg_ParseTuple(args, "OOisi", &obj1, &obj2, &arg3, &arg4, &arg5)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype2 arg2 = pycap_get< intype2 > (obj2); \ - \ - return pycap_new( func( arg1, arg2, arg3, arg4, arg5 ) ); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, const char *arg2, arg3) - */ -#define _wrap_objstrint2obj(func, intype1, outtype)\ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1; \ - const char *arg2; \ - int arg3; \ - \ - if (!PyArg_ParseTuple(args, "Osi", &obj1, &arg2, &arg3)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - \ - return pycap_new( func( arg1, arg2, arg3 ) ); \ - LLVMPY_CATCH_ALL \ -} - - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, intype3, const char *arg4, arg5) - */ -#define _wrap_objobjobjstrint2obj(func, intype1, intype2, intype3, outtype)\ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2, *obj3; \ - const char *arg4; \ - int arg5; \ - \ - if (!PyArg_ParseTuple(args, "OOOsi", &obj1, &obj2, &obj3, &arg4, &arg5)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype2 arg2 = pycap_get< intype2 > (obj2); \ - const intype3 arg3 = pycap_get< intype3 > (obj3); \ - \ - return pycap_new( func( arg1, arg2, arg3, arg4, arg5 ) ); \ - LLVMPY_CATCH_ALL \ -} - - - - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, intype3, arg4, const char *arg5, arg6) - */ -#define _wrap_objobjobjintstrint2obj(func, intype1, intype2, intype3, outtype)\ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2, *obj3; \ - int arg4; \ - const char *arg5; \ - int arg6; \ - \ - if (!PyArg_ParseTuple(args, "OOOisi", &obj1, &obj2, &obj3, &arg4, &arg5, &arg6)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype2 arg2 = pycap_get< intype2 > (obj2); \ - const intype3 arg3 = pycap_get< intype3 > (obj3); \ - \ - return pycap_new( func( arg1, arg2, arg3, arg4, arg5, arg6 ) );\ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, intype4, const char *arg5, arg6) - */ -#define _wrap_objobjobjobjstrint2obj(func, intype1, intype2, intype3, intype4, outtype)\ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2, *obj3, *obj4; \ - const char *arg5; \ - int arg6; \ - \ - if (!PyArg_ParseTuple(args, "OOOOsi", &obj1, &obj2, &obj3, &obj4, &arg5, &arg6)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype2 arg2 = pycap_get< intype2 > (obj2); \ - const intype3 arg3 = pycap_get< intype3 > (obj3); \ - const intype4 arg4 = pycap_get< intype4 > (obj4); \ - \ - return pycap_new( func( arg1, arg2, arg3, arg4, arg5, arg6 ) ); \ - LLVMPY_CATCH_ALL \ -} - - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, const char* arg2, intype3 arg3, intype4, const char *arg5, arg6) - */ -#define _wrap_objstrobjobjstrint2obj(func, intype1, intype3, intype4, outtype)\ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj3, *obj4; \ - const char *arg2; \ - const char *arg5; \ - int arg6; \ - \ - if (!PyArg_ParseTuple(args, "OsOOsi", &obj1, &arg2, &obj3, &obj4, &arg5, &arg6)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype3 arg3 = pycap_get< intype3 > (obj3); \ - const intype4 arg4 = pycap_get< intype4 > (obj4); \ - \ - return pycap_new( func( arg1, arg2, arg3, arg4, arg5, arg6 ) ); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, arg4) - */ -#define _wrap_objobjobjint2obj(func, intype1, intype2, intype3, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2, *obj3; \ - int arg4; \ - \ - if (!PyArg_ParseTuple(args, "OOOi", &obj1, &obj2, &obj3, &arg4)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype2 arg2 = pycap_get< intype2 > (obj2); \ - const intype3 arg3 = pycap_get< intype3 > (obj3); \ - \ - return pycap_new( func( arg1, arg2, arg3, arg4 ) ); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, intype arg4) - */ -#define _wrap_objobjobjobj2obj(func, intype1, intype2, intype3, \ - intype4, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2, *obj3, *obj4; \ - \ - if (!PyArg_ParseTuple(args, "OOOO", &obj1, &obj2, &obj3, &obj4)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype2 arg2 = pycap_get< intype2 > (obj2); \ - const intype3 arg3 = pycap_get< intype3 > (obj3); \ - const intype4 arg4 = pycap_get< intype4 > (obj4); \ - return pycap_new( func( arg1, arg2, arg3, arg4 ) );\ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, intype arg4, const char *arg5) - */ -#define _wrap_objobjobjobjstr2obj(func, intype1, intype2, intype3, \ - intype4, outtype)\ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2, *obj3, *obj4; \ - const char *arg5; \ - \ - if (!PyArg_ParseTuple(args, "OOOOs", &obj1, &obj2, &obj3, &obj4, &arg5)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype2 arg2 = pycap_get< intype2 > (obj2); \ - const intype3 arg3 = pycap_get< intype3 > (obj3); \ - const intype4 arg4 = pycap_get< intype4 > (obj4); \ - \ - return pycap_new( func( arg1, arg2, arg3, arg4, arg5 ) );\ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, enum_intype2 arg2, intype3 arg3, intype4 arg4, const char *arg5) - */ -#define _wrap_objenumobjobjstr2obj(func, intype1, intype2, intype3, \ - intype4, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj3, *obj4; \ - intype2 arg2 ; \ - const char *arg5; \ - \ - if (!PyArg_ParseTuple(args, "OiOOs", &obj1, &arg2, &obj3, &obj4, &arg5)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype3 arg3 = pycap_get< intype3 > (obj3); \ - const intype4 arg4 = pycap_get< intype4 > (obj4); \ - \ - return pycap_new( func( arg1, arg2, arg3, arg4, arg5 ) ); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 *arg2v, unsigned arg2n) - * where arg2v is an array of intype2 elements, arg2n in length. - */ -#define _wrap_objlist2obj(func, intype1, intype2, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2; \ - \ - if (!PyArg_ParseTuple(args, "OO", &obj1, &obj2)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 >( obj1 ); \ - const size_t arg2n = PyList_Size(obj2); \ - intype2 *arg2v = make_array_from_list< intype2 *>(obj2, arg2n); \ - \ - outtype ret = func (arg1, arg2v, arg2n); \ - delete [] arg2v ; \ - return pycap_new( ret ); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 *arg1v, unsigned arg1n, int arg2) - * where arg1v is an array of intype1 elements, arg1n in length. - */ -#define _wrap_listint2obj(func, intype1, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1; \ - int arg2; \ - \ - if (!PyArg_ParseTuple(args, "Oi", &obj1, &arg2)) \ - return NULL; \ - \ - const size_t arg1n = PyList_Size(obj1); \ - intype1 *arg1v = make_array_from_list< intype1 *>(obj1, arg1n); \ - \ - outtype ret = func (arg1v, arg1n, arg2); \ - delete [] arg1v; \ - return pycap_new( ret ); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 *arg1v, unsigned arg1n) - * where arg1v is an array of intype1 elements, arg1n in length. - */ -#define _wrap_list2obj(func, intype1, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1; \ - \ - if (!PyArg_ParseTuple(args, "O", &obj1)) \ - return NULL; \ - \ - const size_t arg1n = PyList_Size(obj1); \ - intype1 *arg1v = make_array_from_list< intype1 *>(obj1, arg1n); \ - \ - outtype ret = func (arg1v, arg1n); \ - delete [] arg1v; \ - return pycap_new( ret ); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 *arg2v, unsigned arg2n, int arg3) - * where arg2v is an array of intype2 elements, arg2n in length. - */ -#define _wrap_objlistint2obj(func, intype1, intype2, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2; \ - int arg3; \ - \ - if (!PyArg_ParseTuple(args, "OOi", &obj1, &obj2, &arg3)) \ - return NULL; \ - \ - intype1 arg1 = pycap_get< intype1 >( obj1 ); \ - const size_t arg2n = PyList_Size(obj2); \ - intype2 *arg2v = make_array_from_list< intype2 *>(obj2, arg2n); \ - \ - outtype ret = func (arg1, arg2v, arg2n, arg3); \ - delete [] arg2v ; \ - return pycap_new( ret ); \ - LLVMPY_CATCH_ALL \ -} - - -/** - * Wrap LLVM functions of the type - * void func(intype1 arg1, intype2 *arg2v, unsigned arg2n, int arg3) - * where arg2v is an array of intype2 elements, arg2n in length. - */ -#define _wrap_objlistint2none(func, intype1, intype2) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2; \ - int arg3; \ - \ - if (!PyArg_ParseTuple(args, "OOi", &obj1, &obj2, &arg3)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 >( obj1 ); \ - const size_t arg2n = PyList_Size(obj2); \ - intype2 *arg2v = make_array_from_list< intype2 *>(obj2, arg2n); \ - \ - func (arg1, arg2v, arg2n, arg3); \ - delete [] arg2v ; \ - Py_RETURN_NONE; \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, int arg2, intype3 *arg3v, unsigned arg3n) - * where arg3v is an array of intype3 elements, arg3n in length. - */ -#define _wrap_objintlist2obj(func, intype1, intype3, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj3; \ - int arg2; \ - \ - if (!PyArg_ParseTuple(args, "OiO", &obj1, &arg2, &obj3)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 >( obj1 ); \ - const size_t arg3n = PyList_Size(obj3); \ - intype3 *arg3v = make_array_from_list< intype3 *>(obj3, arg3n); \ - \ - outtype ret = func (arg1, arg2, arg3v, arg3n); \ - delete [] arg3v ; \ - return pycap_new( ret ); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, intype3 *arg3v, unsigned arg3n) - * where arg3v is an array of intype3 elements, arg3n in length. - */ -#define _wrap_objobjlist2obj(func, intype1, intype2, intype3, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2, *obj3; \ - \ - if (!PyArg_ParseTuple(args, "OOO", &obj1, &obj2, &obj3)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype2 arg2 = pycap_get< intype2 > (obj2); \ - const size_t arg3n = PyList_Size(obj3); \ - intype3 *arg3v = make_array_from_list< intype3 *>(obj3, arg3n); \ - \ - outtype ret = func (arg1, arg2, arg3v, arg3n); \ - delete [] arg3v ; \ - return pycap_new( ret ); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, intype3 *arg3v, unsigned arg3n, const char *arg4) - * where arg3v is an array of intype3 elements, arg3n in length. - */ -#define _wrap_objobjliststr2obj(func, intype1, intype2, intype3, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - PyObject *obj1, *obj2, *obj3; \ - const char *arg4; \ - \ - if (!PyArg_ParseTuple(args, "OOOs", &obj1, &obj2, &obj3, &arg4)) \ - return NULL; \ - \ - const intype1 arg1 = pycap_get< intype1 > (obj1); \ - const intype2 arg2 = pycap_get< intype2 > (obj2); \ - const size_t arg3n = PyList_Size(obj3); \ - intype3 *arg3v = make_array_from_list< intype3 *>(obj3, arg3n); \ - \ - outtype ret = func (arg1, arg2, arg3v, arg3n, arg4); \ - delete [] arg3v ; \ - return pycap_new( ret ); \ - LLVMPY_CATCH_ALL \ -} - -/** - * Wrap LLVM dump-to-string functions of the type - * char *func(intype1) - * where the return value has to be disposed after use by calling - * LLVMDisposeMessage. - */ -#define _wrap_dumper(func, intype1) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - LLVMPY_TRY \ - intype1 arg1 = get_object_arg(args); \ - \ - const char *val = func (arg1); \ - PyObject *ret = PyUnicode_FromString(val); \ - LLVMDisposeMessage(const_cast(val)); \ - return ret; \ - LLVMPY_CATCH_ALL \ -} - - -#endif /* LLVM_PY_WRAP_H */ From c98a1274d9cd80fc4bc3da38cc00230d5839e91b Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 5 Feb 2013 18:48:09 -0600 Subject: [PATCH 248/516] Add Linker and Assembly (IR) Parser --- newbinding/src/Assembly/Parser.py | 14 ++++++++ newbinding/src/Linker.py | 51 +++++++++++++++++++++++++++++ newbinding/src/Support/SourceMgr.py | 10 ++++++ 3 files changed, 75 insertions(+) create mode 100644 newbinding/src/Assembly/Parser.py create mode 100644 newbinding/src/Linker.py create mode 100644 newbinding/src/Support/SourceMgr.py diff --git a/newbinding/src/Assembly/Parser.py b/newbinding/src/Assembly/Parser.py new file mode 100644 index 0000000..1858bcd --- /dev/null +++ b/newbinding/src/Assembly/Parser.py @@ -0,0 +1,14 @@ +from binding import * +from ..namespace import llvm +from ..Module import Module +from ..LLVMContext import LLVMContext +from ..Support.SourceMgr import SMDiagnostic + +llvm.includes.add('llvm/Assembly/Parser.h') + +ParseAssemblyString = llvm.Function('ParseAssemblyString', + ptr(Module), + cast(str, ConstCharPtr), + ptr(Module), # can be None + ref(SMDiagnostic), + ref(LLVMContext)) diff --git a/newbinding/src/Linker.py b/newbinding/src/Linker.py new file mode 100644 index 0000000..0b846d6 --- /dev/null +++ b/newbinding/src/Linker.py @@ -0,0 +1,51 @@ +from binding import * +from namespace import llvm +from ADT.StringRef import StringRef +from Module import Module +from LLVMContext import LLVMContext + +llvm.includes.add('llvm/Linker.h') + +Linker = llvm.Class() + +@Linker +class Linker: + ControlFlags = Enum('Verbose, QuietWarnings, QuietErrors') + LinkerMode = Enum('DestroySource, PreserveSource') + + _new_w_empty = Constructor(cast(str, StringRef), + cast(str, StringRef), + ref(LLVMContext), + cast(int, Unsigned)).require_only(3) + + _new_w_existing = Constructor(cast(str, StringRef), + ptr(Module), + cast(int, Unsigned)).require_only(2) + + @CustomPythonStaticMethod + def new(progname, module_or_name, *args): + if isinstance(module_or_name, Module): + return _new_w_existing(progname, module_or_name, *args) + else: + return _new_w_empty(progname, module_or_name, *args) + + delete = Destructor() + + getModule = Method(ptr(Module)) + releaseModule = Method(ptr(Module)) + getLastError = Method(cast(ConstStdString, str)) + + LinkInModule = CustomMethod('Linker_LinkInModule', + PyObjectPtr, # boolean + ptr(Module), + PyObjectPtr, # errmsg + ) + + LinkModules = CustomStaticMethod('Linker_LinkModules', + PyObjectPtr, # boolean + ptr(Module), + ptr(Module), + LinkerMode, + PyObjectPtr, # errsg + ) + diff --git a/newbinding/src/Support/SourceMgr.py b/newbinding/src/Support/SourceMgr.py new file mode 100644 index 0000000..7dc75be --- /dev/null +++ b/newbinding/src/Support/SourceMgr.py @@ -0,0 +1,10 @@ +from binding import * +from ..namespace import llvm + +llvm.includes.add('llvm/Support/SourceMgr.h') + +@llvm.Class() +class SMDiagnostic: + new = Constructor() + delete = Destructor() + From 9c81fa1f63ba56c76b9a10009216e23667763c53 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 5 Feb 2013 18:48:46 -0600 Subject: [PATCH 249/516] Add more functions to GlobalValue GlobalVariable, StructType and Module --- newbinding/include/llvm_binding/extra.h | 82 +++++++++++++++++++++++++ newbinding/src/GlobalValue.py | 18 ++++++ newbinding/src/GlobalVariable.py | 44 ++++++++++++- newbinding/src/Module.py | 26 +++++++- newbinding/src/Type.py | 27 +++++++- newbinding/src/Value.py | 14 +++-- 6 files changed, 201 insertions(+), 10 deletions(-) diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h index 77b399d..fd4eb4e 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/extra.h @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -8,6 +9,10 @@ #include #include #include +#include +#include + +#include "auto_pyobject.h" namespace extra{ using namespace llvm; @@ -496,3 +501,80 @@ PyObject* TargetMachine_addPassesToEmitFile( } } +static +PyObject* Linker_LinkInModule(llvm::Linker* Linker, + llvm::Module* Mod, + PyObject* ErrMsg) +{ + std::string errmsg; + bool failed = Linker->LinkInModule(Mod, &errmsg); + if (not failed) { + Py_RETURN_FALSE; + } else { + if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) { + return NULL; + } + Py_RETURN_TRUE; + } +} + +static +PyObject* Linker_LinkModules(llvm::Module* Dest, + llvm::Module* Src, + unsigned Mode, + PyObject* ErrMsg) +{ + std::string errmsg; + bool failed = llvm::Linker::LinkModules(Dest, Src, Mode, &errmsg); + if (not failed) { + Py_RETURN_FALSE; + } else { + if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) { + return NULL; + } + Py_RETURN_TRUE; + } +} + +static +PyObject* StructType_setBody(llvm::StructType* Self, + PyObject* Elems, + bool isPacked=false) +{ + using namespace llvm; + std::vector elements; + Py_ssize_t N = PySequence_Size(Elems); + elements.reserve(N); + for (Py_ssize_t i=0; i < N; ++i) { + auto_pyobject obj = PySequence_GetItem(Elems, i); + auto_pyobject capsule = PyObject_GetAttrString(*obj, "_ptr"); + if (!capsule) { + return NULL; + } + void * ptr = PyCapsule_GetPointer(*capsule, "llvm::Type"); + if (!ptr) { + return NULL; + } + Type* type = static_cast(ptr); + elements.push_back(type); + } + + Self->setBody(elements, isPacked); + + Py_RETURN_NONE; +} + +static +PyObject* Module_list_globals(llvm::Module* Mod) +{ + return iplist_to_pylist(Mod->getGlobalList(), + "llvm::Value", "llvm::GlobalVariable"); +} + +static +PyObject* Module_list_functions(llvm::Module* Mod) +{ + return iplist_to_pylist(Mod->getFunctionList(), + "llvm::Value", "llvm::Function"); +} + diff --git a/newbinding/src/GlobalValue.py b/newbinding/src/GlobalValue.py index 40825a8..d14d48a 100644 --- a/newbinding/src/GlobalValue.py +++ b/newbinding/src/GlobalValue.py @@ -6,3 +6,21 @@ from Value import GlobalValue class GlobalValue: _include_ = 'llvm/GlobalValue.h' + LinkageTypes = Enum(''' + ExternalLinkage, AvailableExternallyLinkage, LinkOnceAnyLinkage, + LinkOnceODRLinkage, LinkOnceODRAutoHideLinkage, WeakAnyLinkage, + WeakODRLinkage, AppendingLinkage, InternalLinkage, PrivateLinkage, + LinkerPrivateLinkage, LinkerPrivateWeakLinkage, DLLImportLinkage, + DLLExportLinkage, ExternalWeakLinkage, CommonLinkage + ''') + + VisibilityTypes = Enum('''DefaultVisibility, + HiddenVisibility, + ProtectedVisibility''') + + setLinkage = Method(Void, LinkageTypes) + getLinkage = Method(LinkageTypes) + + setVisibility = Method(Void, VisibilityTypes) + getVisibility = Method(VisibilityTypes) + diff --git a/newbinding/src/GlobalVariable.py b/newbinding/src/GlobalVariable.py index 548a8d1..70203d5 100644 --- a/newbinding/src/GlobalVariable.py +++ b/newbinding/src/GlobalVariable.py @@ -1,8 +1,48 @@ from binding import * from namespace import llvm + from GlobalValue import GlobalValue +GlobalVariable = llvm.Class(GlobalValue) -@llvm.Class(GlobalValue) +from Constant import Constant +from Module import Module +from Type import Type +from ADT.StringRef import StringRef + +@GlobalVariable class GlobalVariable: - pass + ThreadLocalMode = Enum('''NotThreadLocal, GeneralDynamicTLSModel, + LocalDynamicTLSModel, InitialExecTLSModel, + LocalExecTLSModel + ''') + new = Constructor(ref(Module), + ptr(Type), + cast(bool, Bool), # is constant + GlobalValue.LinkageTypes, + ptr(Constant), # initializer -- can be None + cast(str, StringRef), # name + ptr(GlobalVariable), # insert before + ThreadLocalMode, + cast(int, Unsigned), # address-space + # cast(bool, Bool), # externally initialized + ).require_only(5) + + setThreadLocal = Method(Void, cast(bool, Bool)) + setThreadLocalMode = Method(Void, ThreadLocalMode) + isThreadLocal = Method(cast(Bool, bool)) + + isConstant = Method(cast(Bool, bool)) + setConstant = Method(Void, ptr(Constant)) + + setInitializer = Method(Void, ptr(Constant)) + getInitializer = Method(ptr(Constant)) + hasInitializer = Method(cast(Bool, bool)) + + hasUniqueInitializer = Method(cast(Bool, bool)) + hasDefinitiveInitializer = Method(cast(Bool, bool)) + +# isExternallyInitialized = Method(cast(Bool, bool)) +# setExternallyinitialized = Method(Void, cast(bool, Bool)) + + \ No newline at end of file diff --git a/newbinding/src/Module.py b/newbinding/src/Module.py index 539c486..706fe48 100644 --- a/newbinding/src/Module.py +++ b/newbinding/src/Module.py @@ -1,14 +1,19 @@ from binding import * from namespace import llvm + +Module = llvm.Class() + from LLVMContext import LLVMContext from ADT.StringRef import StringRef from Constant import Constant +from GlobalVariable import GlobalVariable from Function import Function from DerivedTypes import FunctionType from Support.raw_ostream import raw_ostream from Assembly.AssemblyAnnotationWriter import AssemblyAnnotationWriter +from Type import Type, StructType -@llvm.Class() +@Module class Module: _include_ = "llvm/Module.h" # Enumerators @@ -38,6 +43,21 @@ class Module: # Function Accessors getOrInsertFunction = Method(ptr(Constant), cast(str, StringRef), ptr(FunctionType)) + getFunction = Method(ptr(Function), cast(str, StringRef)) + + # Function Iteration + list_functions = CustomMethod('Module_list_functions', PyObjectPtr) + + # GlobalVariabe Accessors + getGlobalVariable = Method(ptr(GlobalVariable), + cast(str, StringRef), + cast(bool, Bool), + ).require_only(1) + getNamedGlobal = Method(ptr(GlobalVariable), cast(str, StringRef)) + getOrInsertGlobal = Method(ptr(Constant), cast(str, StringRef), ptr(Type)) + + # GlobalVariable Iteration + list_globals = CustomMethod('Module_list_globals', PyObjectPtr) # Utilities dump = Method(Void) @@ -52,3 +72,7 @@ class Module: return os.str() dropAllReferences = Method() + + getTypeByName = Method(ptr(StructType), cast(str, StringRef)) + + \ No newline at end of file diff --git a/newbinding/src/Type.py b/newbinding/src/Type.py index 8e6b381..09b8ba9 100644 --- a/newbinding/src/Type.py +++ b/newbinding/src/Type.py @@ -110,6 +110,12 @@ class Type: getIntNPtrTy = StaticMethod(ptr(PointerType), ref(LLVMContext), cast(int, Unsigned)) + @CustomPythonMethod + def __str__(self): + import extra + os = extra.make_raw_ostream_for_printing() + self.print_(os) + return os.str() @IntegerType class IntegerType: @@ -130,4 +136,23 @@ class PointerType: @StructType class StructType: - pass + isPacked = Method(cast(Bool, bool)) + isLiteral = Method(cast(Bool, bool)) + isOpaque = Method(cast(Bool, bool)) + hasName = Method(cast(Bool, bool)) + getName = Method(cast(StringRef, str)) + setName = Method(Void, cast(str, StringRef)) + setBody = CustomMethod('StructType_setBody', + PyObjectPtr, # None + PyObjectPtr, # ArrayRef + cast(bool, Bool), + ).require_only(1) + getNumElements = Method(cast(Unsigned, int)) + getElementType = Method(ptr(Type), cast(int, Unsigned)) + + create = StaticMethod(ptr(StructType), + ref(LLVMContext), + cast(str, StringRef), + ).require_only(1) + isValidElementType = StaticMethod(cast(Bool, bool), ptr(Type)) + diff --git a/newbinding/src/Value.py b/newbinding/src/Value.py index 5841746..5675fa5 100644 --- a/newbinding/src/Value.py +++ b/newbinding/src/Value.py @@ -1,13 +1,8 @@ from binding import * from namespace import llvm -from Support.raw_ostream import raw_ostream -from Assembly.AssemblyAnnotationWriter import AssemblyAnnotationWriter -from Type import Type -from LLVMContext import LLVMContext -from ADT.StringRef import StringRef -Value = llvm.Class() # forward declarations +Value = llvm.Class() Argument = llvm.Class(Value) MDNode = llvm.Class(Value) User = llvm.Class(Value) @@ -16,6 +11,13 @@ Constant = llvm.Class(User) GlobalValue = llvm.Class(Constant) Function = llvm.Class(GlobalValue) +from Support.raw_ostream import raw_ostream +from Assembly.AssemblyAnnotationWriter import AssemblyAnnotationWriter +from Type import Type +from LLVMContext import LLVMContext +from ADT.StringRef import StringRef + + @Value class Value: From 39de8c400332ffac9bfbdbaba4fd8ca48f08bdc4 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 5 Feb 2013 18:49:33 -0600 Subject: [PATCH 250/516] Expand test --- newbinding/test_binding.py | 59 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/newbinding/test_binding.py b/newbinding/test_binding.py index 1321eb6..578c532 100644 --- a/newbinding/test_binding.py +++ b/newbinding/test_binding.py @@ -151,6 +151,10 @@ def test_basic_jit_use(): m2.setModuleIdentifier(m.getModuleIdentifier()) assert str(m2) == str(m) + # parse llvm ir + m3 = api.ParseAssemblyString(str(m), None, api.SMDiagnostic.new(), context) + m3.setModuleIdentifier(m.getModuleIdentifier()) + assert str(m3) == str(m) def test_engine_builder(): api.InitializeNativeTarget() @@ -223,10 +227,64 @@ def test_engine_builder(): assert 'foo' in asm +def test_linker(): + context = api.getGlobalContext() + mA = api.Module.new("modA", context) + mB = api.Module.new("modB", context) + def create_function(m, name): + int32ty = api.Type.getIntNTy(context, 32) + fnty = api.FunctionType.get(int32ty, [int32ty], False) + fn = m.getOrInsertFunction(name, fnty)._downcast(api.Function) + bb = api.BasicBlock.Create(context, "entry", fn, None) + builder = api.IRBuilder.new(context) + builder.SetInsertPoint(bb) + builder.CreateRet(fn.getArgumentList()[0]) + create_function(mA, 'foo') + create_function(mB, 'bar') + errmsg = StringIO() + linkermode = api.Linker.LinkerMode.PreserveSource + failed = api.Linker.LinkModules(mA, mB, linkermode, errmsg) + assert not failed, errmsg.getvalue() + assert mA.getFunction('foo') + assert mA.getFunction('bar') + + assert set(mA.list_functions()) == set([mA.getFunction('foo'), + mA.getFunction('bar')]) + +def test_structtype(): + context = api.getGlobalContext() + m = api.Module.new("modname", context) + + assert m.getTypeByName("truck") is None + + truck = api.StructType.create(context, "truck") + assert 'type opaque' in str(truck) + elemtys = [api.Type.getInt32Ty(context), api.Type.getDoubleTy(context)] + truck.setBody(elemtys) + + assert 'i32' in str(truck) + assert 'double' in str(truck) + + assert m.getTypeByName("truck") is truck + +def test_globalvariable(): + context = api.getGlobalContext() + m = api.Module.new("modname", context) + + ty = api.Type.getInt32Ty(context) + LinkageTypes = api.GlobalVariable.LinkageTypes + linkage = LinkageTypes.ExternalLinkage + gvar = api.GlobalVariable.new(m, ty, False, linkage, None, "apple") + assert '@apple = external global i32' in str(m) + + gvar2 = m.getNamedGlobal('apple') + assert gvar2 is gvar + + print m.list_globals() def main(): for name, value in globals().items(): @@ -234,6 +292,7 @@ def main(): print name.center(80, '-') value() + if __name__ == '__main__': main() From cd1fa4c4d825efab4cc8b3ac1375f72dd2725dbe Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 6 Feb 2013 21:30:36 -0600 Subject: [PATCH 251/516] Add binding for Attributes, Argument, Constants, CallingConv, GlobalValue, GlobalVariable, etc. --- newbinding/gen/binding.py | 1 + newbinding/include/llvm_binding/conversion.h | 22 ++ newbinding/include/llvm_binding/extra.h | 152 +++++++++-- newbinding/src/Analysis/Verifier.py | 25 ++ newbinding/src/Analysis/__init__.py | 10 + newbinding/src/Argument.py | 4 + newbinding/src/Attributes.py | 39 +++ newbinding/src/CallingConv.py | 11 + newbinding/src/Constant.py | 260 ++++++++++++++++++- newbinding/src/DerivedTypes.py | 1 - newbinding/src/Function.py | 5 + newbinding/src/GlobalValue.py | 21 ++ newbinding/src/GlobalVariable.py | 3 +- newbinding/src/IRBuilder.py | 29 ++- newbinding/src/Metadata.py | 17 ++ newbinding/src/Module.py | 13 +- newbinding/src/Transforms/Utils/Cloning.py | 8 + newbinding/src/Transforms/Utils/__init__.py | 15 ++ newbinding/src/Transforms/__init__.py | 11 +- newbinding/src/Type.py | 59 ++++- newbinding/src/User.py | 8 +- newbinding/src/Value.py | 13 + 22 files changed, 692 insertions(+), 35 deletions(-) create mode 100644 newbinding/src/Analysis/Verifier.py create mode 100644 newbinding/src/Analysis/__init__.py create mode 100644 newbinding/src/Attributes.py create mode 100644 newbinding/src/CallingConv.py create mode 100644 newbinding/src/Transforms/Utils/Cloning.py create mode 100644 newbinding/src/Transforms/Utils/__init__.py diff --git a/newbinding/gen/binding.py b/newbinding/gen/binding.py index d9b44af..09cd9bf 100644 --- a/newbinding/gen/binding.py +++ b/newbinding/gen/binding.py @@ -69,6 +69,7 @@ LongLong = BuiltinTypes('long long') Float = BuiltinTypes('float') Double = BuiltinTypes('double') Uint64 = BuiltinTypes('uint64_t') +Int64 = BuiltinTypes('int64_t') Size_t = BuiltinTypes('size_t') VoidPtr = BuiltinTypes('void*') Bool = BuiltinTypes('bool') diff --git a/newbinding/include/llvm_binding/conversion.h b/newbinding/include/llvm_binding/conversion.h index a1fc87c..cf4e639 100644 --- a/newbinding/include/llvm_binding/conversion.h +++ b/newbinding/include/llvm_binding/conversion.h @@ -64,6 +64,28 @@ int py_str_to(PyObject *strobj, const char* &strref){ return 1; } + +static +int py_int_to(PyObject *intobj, int64_t & val){ + if (!PyInt_Check(intobj)) { + // raise TypeError + PyErr_SetString(PyExc_TypeError, "Expecting an int"); + return 0; + } + if (PyLong_Check(intobj)) { + val = PyLong_AsLongLong(intobj); + } else { + val = PyInt_AsLong(intobj); + } + if (PyErr_Occurred()){ + return NULL; + } + // success + return 1; +} + + + static int py_int_to(PyObject *intobj, unsigned & val){ if (!PyInt_Check(intobj)) { diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h index fd4eb4e..85e1ea5 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/extra.h @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include "auto_pyobject.h" @@ -171,6 +173,33 @@ PyObject* iplist_to_pylist(iplist &IPL, const char * capsuleName, className); } +template +struct extract { + + template + static + bool from_py_sequence(VecTy& vec, PyObject* seq, const char *capsuleName) + { + Py_ssize_t N = PySequence_Size(seq); + for (Py_ssize_t i = 0; i < N; ++i) { + auto_pyobject item = PySequence_GetItem(seq, i); + if (!item) { + return false; + } + auto_pyobject capsule = PyObject_GetAttrString(*item, "_ptr"); + if (!capsule) { + return false; + } + void* ptr = PyCapsule_GetPointer(*capsule, capsuleName); + if (!ptr) { + return false; + } + vec.push_back(static_cast(ptr)); + } + return true; + } + +}; //static //bool string_equal(const char *A, const char *B){ // for (; *A and *B; ++A, ++B) { @@ -492,7 +521,7 @@ PyObject* TargetMachine_addPassesToEmitFile( if (!buf) { return NULL; } - if ( -1 == PyFile_WriteObject(buf, Out, Py_PRINT_RAW) ){ + if (-1 == PyFile_WriteObject(buf, Out, Py_PRINT_RAW)){ return NULL; } Py_RETURN_TRUE; @@ -501,6 +530,30 @@ PyObject* TargetMachine_addPassesToEmitFile( } } +static +PyObject* Constant_getIntegerValue(llvm::Type* Ty, PyObject* pyint) +{ + using namespace llvm; + if (!Ty->isIntegerTy()) { + PyErr_SetString(PyExc_ValueError, "Type should be of integer type."); + return NULL; + } + unsigned width = Ty->getIntegerBitWidth(); + if (width > sizeof(unsigned long long)*8) { + PyErr_SetString(PyExc_ValueError, "Integer value is too large."); + } + Constant* K; + if (PyLong_Check(pyint)){ + APInt apint(width, PyLong_AsLongLong(pyint), true); + K = Constant::getIntegerValue(Ty, apint); + } else { + APInt apint(width, PyInt_AsLong(pyint), true); + K = Constant::getIntegerValue(Ty, apint); + } + return pycapsule_new(K, "llvm::Value", "llvm::Constant"); +} + + static PyObject* Linker_LinkInModule(llvm::Linker* Linker, llvm::Module* Mod, @@ -543,24 +596,8 @@ PyObject* StructType_setBody(llvm::StructType* Self, { using namespace llvm; std::vector elements; - Py_ssize_t N = PySequence_Size(Elems); - elements.reserve(N); - for (Py_ssize_t i=0; i < N; ++i) { - auto_pyobject obj = PySequence_GetItem(Elems, i); - auto_pyobject capsule = PyObject_GetAttrString(*obj, "_ptr"); - if (!capsule) { - return NULL; - } - void * ptr = PyCapsule_GetPointer(*capsule, "llvm::Type"); - if (!ptr) { - return NULL; - } - Type* type = static_cast(ptr); - elements.push_back(type); - } - + extract::from_py_sequence(elements, Elems, "llvm::Type"); Self->setBody(elements, isPacked); - Py_RETURN_NONE; } @@ -578,3 +615,82 @@ PyObject* Module_list_functions(llvm::Module* Mod) "llvm::Value", "llvm::Function"); } +static +PyObject* Module_list_named_metadata(llvm::Module* Mod) +{ + return iplist_to_pylist(Mod->getFunctionList(), + "llvm::NamedMDNode", "llvm::NamedMDNode"); + +} + +static +PyObject* llvm_verifyModule(const llvm::Module& Fn, + llvm::VerifierFailureAction Action, + PyObject* ErrMsg) +{ + std::string errmsg; + bool failed = llvm::verifyModule(Fn, Action, &errmsg); + + if (failed) { + if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) { + return NULL; + } + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } +} + +static +PyObject* ConstantArray_get(llvm::ArrayType* Ty, PyObject* Consts) +{ + using namespace llvm; + + std::vector vec_consts; + bool ok = extract::from_py_sequence(vec_consts, Consts, + "llvm::Value"); + if (not ok) return NULL; + Constant* ary = ConstantArray::get(Ty, vec_consts); + return pycapsule_new(ary, "llvm::Value", "llvm::Constant"); +} + +static +PyObject* ConstantStruct_get(llvm::StructType* Ty, PyObject* Elems) +{ + using namespace llvm; + + std::vector vec_consts; + bool ok = extract::from_py_sequence(vec_consts, Elems, + "llvm::Value"); + if (not ok) return NULL; + Constant* ary = ConstantStruct::get(Ty, vec_consts); + return pycapsule_new(ary, "llvm::Value", "llvm::Constant"); +} + +static +PyObject* ConstantStruct_getAnon(PyObject* Elems, + bool isPacked=false) +{ + using namespace llvm; + + std::vector vec_consts; + bool ok = extract::from_py_sequence(vec_consts, Elems, + "llvm::Value"); + if (not ok) return NULL; + Constant* ary = ConstantStruct::getAnon(vec_consts, isPacked); + return pycapsule_new(ary, "llvm::Value", "llvm::Constant"); +} + +static +PyObject* ConstantVector_get(PyObject* Elems) +{ + using namespace llvm; + + std::vector vec_consts; + bool ok = extract::from_py_sequence(vec_consts, Elems, + "llvm::Value"); + if (not ok) return NULL; + Constant* ary = ConstantVector::get(vec_consts); + return pycapsule_new(ary, "llvm::Value", "llvm::Constant"); +} + diff --git a/newbinding/src/Analysis/Verifier.py b/newbinding/src/Analysis/Verifier.py new file mode 100644 index 0000000..5b47740 --- /dev/null +++ b/newbinding/src/Analysis/Verifier.py @@ -0,0 +1,25 @@ +from binding import * +from ..namespace import llvm +from ..Module import Module +from ..Function import Function + +llvm.includes.add('llvm/Analysis/Verifier.h') + +VerifierFailureAction = llvm.Enum('VerifierFailureAction', + '''AbortProcessAction + PrintMessageAction + ReturnStatusAction''') + +verifyModule = llvm.CustomFunction('verifyModule', + 'llvm_verifyModule', + PyObjectPtr, # boolean -- failed? + ref(Module), + VerifierFailureAction, + PyObjectPtr, # errmsg + ) + +verifyFunction = llvm.Function('verifyFunction', + cast(Bool, bool), # failed? + ref(Function), + VerifierFailureAction) + diff --git a/newbinding/src/Analysis/__init__.py b/newbinding/src/Analysis/__init__.py new file mode 100644 index 0000000..da0beed --- /dev/null +++ b/newbinding/src/Analysis/__init__.py @@ -0,0 +1,10 @@ +import os.path, importlib + +def _init(): + for fname in os.listdir(os.path.dirname(__file__)): + if ((fname.endswith('.py') or fname.endswith('.pyc')) and + not fname.startswith('__init__')): + modname = os.path.basename(fname).rsplit('.', 1)[0] + importlib.import_module('.' + modname, __name__) + +_init() diff --git a/newbinding/src/Argument.py b/newbinding/src/Argument.py index 08b35be..eac4b07 100644 --- a/newbinding/src/Argument.py +++ b/newbinding/src/Argument.py @@ -1,9 +1,13 @@ from binding import * from namespace import llvm from Value import Argument +from Attributes import Attributes @Argument class Argument: _include_ = 'llvm/Argument.h' + addAttr = Method(Void, ref(Attributes)) + removeAttr = Method(Void, ref(Attributes)) + getParamAlignment = Method(cast(Unsigned, int)) diff --git a/newbinding/src/Attributes.py b/newbinding/src/Attributes.py new file mode 100644 index 0000000..235d2c8 --- /dev/null +++ b/newbinding/src/Attributes.py @@ -0,0 +1,39 @@ +from binding import * +from namespace import llvm +from LLVMContext import LLVMContext + +llvm.includes.add('llvm/Attributes.h') + +Attributes = llvm.Class() +AttrBuilder = llvm.Class() + + +@Attributes +class Attributes: + AttrVal = Enum('''None, AddressSafety, Alignment, AlwaysInline, + ByVal, InlineHint, InReg, MinSize, + Naked, Nest, NoAlias, NoCapture, + NoImplicitFloat, NoInline, NonLazyBind, NoRedZone, + NoReturn, NoUnwind, OptimizeForSize, ReadNone, + ReadOnly, ReturnsTwice, SExt, StackAlignment, + StackProtect, StackProtectReq, StructRet, UWTable, ZExt''') + + delete = Destructor() + + get = Method(Attributes, ref(LLVMContext), ref(AttrBuilder)) + + +@AttrBuilder +class AttrBuilder: + + new = Constructor() + delete = Destructor() + + clear = Method() + + addAttribute = Method(ref(AttrBuilder), Attributes.AttrVal) + removeAttribute = Method(ref(AttrBuilder), Attributes.AttrVal) + + addAlignmentAttr = Method(ref(AttrBuilder), cast(int, Unsigned)) + + diff --git a/newbinding/src/CallingConv.py b/newbinding/src/CallingConv.py new file mode 100644 index 0000000..6d0baea --- /dev/null +++ b/newbinding/src/CallingConv.py @@ -0,0 +1,11 @@ +from binding import * +from namespace import llvm + +@llvm.Class() # actually a namespace +class CallingConv: + ID = Enum(''' + C, Fast, Cold, GHC, FirstTargetCC, X86_StdCall, X86_FastCall, + ARM_APCS, ARM_AAPCS, ARM_AAPCS_VFP, MSP430_INTR, X86_ThisCall, + PTX_Kernel, PTX_Device, MBLAZE_INTR, MBLAZE_SVOL, SPIR_FUNC, + SPIR_KERNEL, Intel_OCL_BI + ''') # HiPE diff --git a/newbinding/src/Constant.py b/newbinding/src/Constant.py index c59fef4..9027e3f 100644 --- a/newbinding/src/Constant.py +++ b/newbinding/src/Constant.py @@ -1,8 +1,266 @@ from binding import * from namespace import llvm -from Value import Constant +from LLVMContext import LLVMContext +from ADT.StringRef import StringRef +from ADT.SmallVector import SmallVector_Value, SmallVector_Unsigned +from Type import Type, IntegerType, ArrayType, StructType +from Value import Constant, Value +from Instruction import CmpInst @Constant class Constant: + _downcast_ = Value + + isNullValue = Method(cast(bool, Bool)) + isAllOnesValue = Method(cast(bool, Bool)) + isNegativeZeroValue = Method(cast(bool, Bool)) + #isZeroValue = Method(cast(bool, Bool)) + canTrap = Method(cast(bool, Bool)) + isThreadDependent = Method(cast(bool, Bool)) + isConstantUsed = Method(cast(bool, Bool)) + + _getAggregateElement_by_int = Method(ptr(Constant), cast(int, Unsigned)) + _getAggregateElement_by_int.realname = 'getAggregateElement' + _getAggregateElement_by_const = Method(ptr(Constant), ptr(Constant)) + _getAggregateElement_by_const.realname = 'getAggregateElement' + + @CustomPythonMethod + def getAggregateElement(self, elt): + if isinstance(elt, Constant): + return self._getAggregateElement_by_const(elt) + else: + return self._getAggregateElement_by_int(elt) + + + removeDeadConstantUsers = Method() + + getNullValue = StaticMethod(ptr(Constant), ptr(Type)) + getAllOnesValue = StaticMethod(ptr(Constant), ptr(Type)) + getIntegerValue = CustomStaticMethod('Constant_getIntegerValue', + PyObjectPtr, # ptr(Constant), + ptr(Type), + PyObjectPtr) + + +UndefValue = llvm.Class(Constant) + +@UndefValue +class UndefValue: + getSequentialElement = Method(ptr(UndefValue)) + getStructElement = Method(ptr(UndefValue), cast(int, Unsigned)) + + _getElementValue_by_const = Method(ptr(UndefValue), ptr(Constant)) + _getElementValue_by_const.realname = 'getElementValue' + + _getElementValue_by_int = Method(ptr(UndefValue), cast(int, Unsigned)) + _getElementValue_by_int.realname = 'getElementValue' + + @CustomPythonMethod + def getElementValue(self, idx): + if isinstance(idx, Constant): + return self._getElementValue_by_const(idx) + else: + return self._getElementValue_by_int(idx) + + destroyConstant = Method() + + get = StaticMethod(ptr(UndefValue), ptr(Type)) + + +ConstantInt = llvm.Class(Constant) + +@ConstantInt +class ConstantInt: + get = StaticMethod(ptr(ConstantInt), + ptr(IntegerType), + cast(int, Unsigned), + cast(bool, Bool), + ).require_only(2) + isValueValidForType = StaticMethod(cast(Bool, bool), + ptr(Type), + cast(int, Int64)) + getZExtValue = Method(cast(Uint64, int)) + getSExtValue = Method(cast(Int64, int)) + +ConstantFP = llvm.Class(Constant) + +@ConstantFP +class ConstantFP: + get = StaticMethod(ptr(Constant), ptr(Type), cast(float, Double)) + getNegativeZero = StaticMethod(ptr(ConstantFP), ptr(Type)) + getInfinity = StaticMethod(ptr(ConstantFP), ptr(Type), cast(bool, Bool)) + + isZero = Method(cast(Bool, bool)) + isNegative = Method(cast(Bool, bool)) + isNaN = Method(cast(Bool, bool)) + + +ConstantArray = llvm.Class(Constant) + +@ConstantArray +class ConstantArray: + get = CustomStaticMethod('ConstantArray_get', + PyObjectPtr, # ptr(Constant), + ptr(ArrayType), + PyObjectPtr, # Constants + ) + +ConstantStruct = llvm.Class(Constant) + +@ConstantStruct +class ConstantStruct: + get = CustomStaticMethod('ConstantStruct_get', + PyObjectPtr, # ptr(Constant) + ptr(StructType), + PyObjectPtr, # Constants + ) + getAnon = CustomStaticMethod('ConstantStruct_getAnon', + PyObjectPtr, # ptr(Constant) + PyObjectPtr, # constants + cast(bool, Bool), # packed + ).require_only(1) + +ConstantVector = llvm.Class(Constant) + +@ConstantVector +class ConstantVector: + get = CustomStaticMethod('ConstantVector_get', + PyObjectPtr, # ptr(Constant) + PyObjectPtr, # constants + ) + +ConstantDataSequential = llvm.Class(Constant) + +@ConstantDataSequential +class ConstantDataSequential: pass +ConstantDataArray = llvm.Class(ConstantDataSequential) + +@ConstantDataArray +class ConstantDataArray: + getString = StaticMethod(ptr(Constant), + ref(LLVMContext), + cast(str, StringRef), + cast(bool, Bool) + ).require_only(2) + + +ConstantExpr = llvm.Class(Constant) + +def _factory(*args): + return StaticMethod(ptr(Constant), *args) + +def _factory_const(*args): + return _factory(ptr(Constant), *args) + +def _factory_const2(*args): + return _factory(ptr(Constant), ptr(Constant), *args) + +def _factory_const_nuw_nsw(): + return _factory_const(cast(bool, Bool), cast(bool, Bool)).require_only(1) + +def _factory_const2_nuw_nsw(): + return _factory_const2(cast(bool, Bool), cast(bool, Bool)).require_only(2) + +def _factory_const2_exact(): + return _factory_const2(cast(bool, Bool)).require_only(2) + +def _factory_const_type(): + return _factory_const(ptr(Type)) + +@ConstantExpr +class ConstantExpr: + getAlignOf = _factory(ptr(Type)) + getSizeOf = _factory(ptr(Type)) + getOffsetOf = _factory(ptr(Type), ptr(Constant)) + getNeg = _factory_const_nuw_nsw() + getFNeg = _factory_const() + getNot = _factory_const() + getAdd = _factory_const2_nuw_nsw() + getFAdd = _factory_const2() + getSub = _factory_const2_nuw_nsw() + getFSub = _factory_const2() + getMul = _factory_const2_nuw_nsw() + getFMul = _factory_const2() + getUDiv = _factory_const2_exact() + getSDiv = _factory_const2_exact() + getFDiv = _factory_const2() + getURem = _factory_const2() + getSRem = _factory_const2() + getFRem = _factory_const2() + getAnd = _factory_const2() + getOr = _factory_const2() + getXor = _factory_const2() + getShl = _factory_const2_nuw_nsw() + getLShr = _factory_const2_exact() + getAShr = _factory_const2_exact() + getTrunc = _factory_const_type() + getSExt = _factory_const_type() + getZExt = _factory_const_type() + getFPTrunc = _factory_const_type() + getFPExtend = _factory_const_type() + getUIToFP = _factory_const_type() + getSIToFP = _factory_const_type() + getFPToUI = _factory_const_type() + getFPToSI = _factory_const_type() + getPtrToInt = _factory_const_type() + getIntToPtr = _factory_const_type() + getBitCast = _factory_const_type() + + getCompare = _factory(CmpInst.Predicate, ptr(Constant), ptr(Constant)) + getICmp = _factory(CmpInst.Predicate, ptr(Constant), ptr(Constant)) + getFCmp = _factory(CmpInst.Predicate, ptr(Constant), ptr(Constant)) + + getPointerCast = _factory_const_type() + getIntegerCast = _factory_const(ptr(Type), cast(bool, Bool)) + getFPCast = _factory_const_type() + getSelect = _factory(ptr(Constant), ptr(Constant), ptr(Constant)) + + + _getGEP = _factory(ptr(Constant), ref(SmallVector_Value), cast(bool, Bool)) + _getGEP.require_only(2) + _getGEP.realname = 'getGetElementPtr' + + @CustomPythonStaticMethod + def getGetElementPtr(*args): + import extra + args = list(args) + valuelist = args[1] + args[1] = extra.make_small_vector_from_values(*valuelist) + return ConstantExpr._getGEP(*args) + + getExtractElement = _factory_const2() + getInsertElement = _factory_const2(ptr(Constant)) + getShuffleVector = _factory_const2(ptr(Constant)) + + _getExtractValue = _factory(ptr(Constant), ref(SmallVector_Unsigned)) + _getExtractValue.realname = 'getExtractValue' + + @CustomPythonStaticMethod + def getExtractValue(*args): + import extra + args = list(args) + valuelist = args[1] + args[1] = extra.make_small_vector_from_unsigned(*valuelist) + return ConstantExpr._getExtractValue(*args) + + _getInsertValue = _factory(ptr(Constant), ptr(Constant), + ref(SmallVector_Unsigned)) + _getInsertValue.realname = 'getInsertValue' + + @CustomPythonStaticMethod + def getInsertValue(*args): + import extra + args = list(args) + valuelist = args[2] + args[1] = extra.make_small_vector_from_unsigned(*valuelist) + return ConstantExpr._getInsertValue(*args) + + getOpcode = Method(cast(Unsigned, int)) + getOpcodeName = Method(cast(ConstCharPtr, str)) + isCast = Method(cast(Bool, bool)) + isCompare = Method(cast(Bool, bool)) + hasIndices = Method(cast(Bool, bool)) + isGEPWithNoNotionalOverIndexing = Method(cast(Bool, bool)) + diff --git a/newbinding/src/DerivedTypes.py b/newbinding/src/DerivedTypes.py index af9e757..e71f1a8 100644 --- a/newbinding/src/DerivedTypes.py +++ b/newbinding/src/DerivedTypes.py @@ -25,7 +25,6 @@ class FunctionType: else: return FunctionType._get(*args) - isVarArg = Method(cast(Bool, bool)) getReturnType = Method(ptr(Type)) getParamType = Method(ptr(Type), cast(int, Unsigned)) diff --git a/newbinding/src/Function.py b/newbinding/src/Function.py index 5cebf84..ee59990 100644 --- a/newbinding/src/Function.py +++ b/newbinding/src/Function.py @@ -4,6 +4,7 @@ from Value import GlobalValue, Constant, Function, Argument from Type import Type from DerivedTypes import FunctionType from LLVMContext import LLVMContext +from CallingConv import CallingConv @Function class Function: @@ -17,5 +18,9 @@ class Function: getIntrinsicID = Method(cast(Unsigned, int)) isIntrinsic = Method(cast(Bool, bool)) + getCallingConv = Method(CallingConv.ID) + setCallingConv = Method(Void, CallingConv.ID) + + getArgumentList = CustomMethod('Function_getArgumentList', PyObjectPtr) getBasicBlockList = CustomMethod('Function_getBasicBlockList', PyObjectPtr) diff --git a/newbinding/src/GlobalValue.py b/newbinding/src/GlobalValue.py index d14d48a..02ba4ea 100644 --- a/newbinding/src/GlobalValue.py +++ b/newbinding/src/GlobalValue.py @@ -1,6 +1,8 @@ from binding import * from namespace import llvm from Value import GlobalValue +from Module import Module +from ADT.StringRef import StringRef @GlobalValue class GlobalValue: @@ -24,3 +26,22 @@ class GlobalValue: setVisibility = Method(Void, VisibilityTypes) getVisibility = Method(VisibilityTypes) + setLinkage = Method(Void, LinkageTypes) + getLinkage = Method(LinkageTypes) + + getAlignment = Method(cast(Unsigned, int)) + setAlignment = Method(Void, cast(int, Unsigned)) + + hasSection = Method(cast(Bool, bool)) + getSection = Method(cast(ConstStdString, str)) + setSection = Method(Void, cast(str, StringRef)) + + isDiscardableIfUnused = Method(cast(Bool, bool)) + mayBeOverridden = Method(cast(Bool, bool)) + isWeakForLinker = Method(cast(Bool, bool)) + copyAttributesFrom = Method(Void, ptr(GlobalValue)) + destroyConstant = Method() + isDeclaration = Method(cast(Bool, bool)) + removeFromParent = Method() + eraseFromParent = Method() + getParent = Method(ptr(Module)) diff --git a/newbinding/src/GlobalVariable.py b/newbinding/src/GlobalVariable.py index 70203d5..a11f259 100644 --- a/newbinding/src/GlobalVariable.py +++ b/newbinding/src/GlobalVariable.py @@ -33,7 +33,7 @@ class GlobalVariable: isThreadLocal = Method(cast(Bool, bool)) isConstant = Method(cast(Bool, bool)) - setConstant = Method(Void, ptr(Constant)) + setConstant = Method(Void, cast(bool, Bool)) setInitializer = Method(Void, ptr(Constant)) getInitializer = Method(ptr(Constant)) @@ -45,4 +45,5 @@ class GlobalVariable: # isExternallyInitialized = Method(cast(Bool, bool)) # setExternallyinitialized = Method(Void, cast(bool, Bool)) + eraseFromParent = Method() \ No newline at end of file diff --git a/newbinding/src/IRBuilder.py b/newbinding/src/IRBuilder.py index 61dd99b..e0cac79 100644 --- a/newbinding/src/IRBuilder.py +++ b/newbinding/src/IRBuilder.py @@ -242,13 +242,32 @@ class IRBuilder: ptr(Value), cast(str, StringRef)) CreateShuffleVector.require_only(3) - CreateExtractValue = Method(ptr(Value), ptr(Value), ref(SmallVector_Unsigned), - cast(str, StringRef)) - CreateExtractValue.require_only(2) + _CreateExtractValue = Method(ptr(Value), ptr(Value), + ref(SmallVector_Unsigned), + cast(str, StringRef)) + _CreateExtractValue.require_only(2) + _CreateExtractValue.realname = 'CreateExtractValue' - CreateInsertValue = Method(ptr(Value), ptr(Value), ptr(Value), + @CustomPythonMethod + def CreateExtractValue(self, args): + import extra + args = list(args) + valuelist = args[1] + args[1] = extra.make_small_vector_from_unsigned(*valuelist) + return self._CreateExtractValue(*args) + + _CreateInsertValue = Method(ptr(Value), ptr(Value), ptr(Value), ref(SmallVector_Unsigned), cast(str, StringRef)) - CreateInsertValue.require_only(3) + _CreateInsertValue.require_only(3) + _CreateInsertValue.realname = 'CreateInsertValue' + + @CustomPythonMethod + def CreateInsertValue(self, args): + import extra + args = list(args) + valuelist = args[2] + args[1] = extra.make_small_vector_from_unsigned(*valuelist) + return self._CreateInsertValue(*args) CreateLandingPad = Method(ptr(LandingPadInst), ptr(Type), ptr(Value), cast(int, Unsigned), cast(str, StringRef)) diff --git a/newbinding/src/Metadata.py b/newbinding/src/Metadata.py index 78dbe15..96dbc01 100644 --- a/newbinding/src/Metadata.py +++ b/newbinding/src/Metadata.py @@ -1,7 +1,24 @@ from binding import * from namespace import llvm from Value import MDNode +from ADT.StringRef import StringRef +from Module import Module +from Support.raw_ostream import raw_ostream +from Assembly.AssemblyAnnotationWriter import AssemblyAnnotationWriter @MDNode class MDNode: pass + +@llvm.Class() +class NamedMDNode: + eraseFromParent = Method() + dropAllReferences = Method() + getParent = Method(ptr(Module)) + getOperand = Method(ptr(MDNode), cast(int, Unsigned)) + getNumOperands = Method(cast(Unsigned, int)) + getName = Method(cast(StringRef, str)) + print_ = Method(Void, ref(raw_ostream), ptr(AssemblyAnnotationWriter)) + print_.realname = "print" + dump = Method() + diff --git a/newbinding/src/Module.py b/newbinding/src/Module.py index 706fe48..7718cd6 100644 --- a/newbinding/src/Module.py +++ b/newbinding/src/Module.py @@ -12,6 +12,7 @@ from DerivedTypes import FunctionType from Support.raw_ostream import raw_ostream from Assembly.AssemblyAnnotationWriter import AssemblyAnnotationWriter from Type import Type, StructType +from Metadata import NamedMDNode @Module class Module: @@ -59,6 +60,16 @@ class Module: # GlobalVariable Iteration list_globals = CustomMethod('Module_list_globals', PyObjectPtr) + # Named MetaData Accessors + getNamedMetadata = Method(ptr(NamedMDNode), cast(str, StringRef)) + getOrInsertNamedMetadata = Method(ptr(NamedMDNode), cast(str, StringRef)) + eraseNamedMetadata = Method(Void, ptr(NamedMDNode)) + + # Named MetaData Iteration + list_named_metadata = CustomMethod('Module_list_named_metadata', + PyObjectPtr) + + # Utilities dump = Method(Void) print_ = Method(Void, ref(raw_ostream), ptr(AssemblyAnnotationWriter)) @@ -74,5 +85,3 @@ class Module: dropAllReferences = Method() getTypeByName = Method(ptr(StructType), cast(str, StringRef)) - - \ No newline at end of file diff --git a/newbinding/src/Transforms/Utils/Cloning.py b/newbinding/src/Transforms/Utils/Cloning.py new file mode 100644 index 0000000..c7f7a86 --- /dev/null +++ b/newbinding/src/Transforms/Utils/Cloning.py @@ -0,0 +1,8 @@ +from binding import * +from src.namespace import llvm +from src.Module import Module + +llvm.includes.add('llvm/Transforms/Utils/Cloning.h') +CloneModule = llvm.Function('CloneModule', ptr(Module), ptr(Module)) + + diff --git a/newbinding/src/Transforms/Utils/__init__.py b/newbinding/src/Transforms/Utils/__init__.py new file mode 100644 index 0000000..98c06fc --- /dev/null +++ b/newbinding/src/Transforms/Utils/__init__.py @@ -0,0 +1,15 @@ +import os.path, importlib + +def _init(): + base = os.path.dirname(__file__) + for fname in os.listdir(base): + print fname + is_python_script = fname.endswith('.py') or fname.endswith('.pyc') + is_init_script = fname.startswith('__init__') + is_directory = os.path.isdir(os.path.join(base, fname)) + if (is_directory or is_python_script) and not is_init_script : + modname = os.path.basename(fname).rsplit('.', 1)[0] + importlib.import_module('.' + modname, __name__) + +_init() + diff --git a/newbinding/src/Transforms/__init__.py b/newbinding/src/Transforms/__init__.py index da0beed..98c06fc 100644 --- a/newbinding/src/Transforms/__init__.py +++ b/newbinding/src/Transforms/__init__.py @@ -1,10 +1,15 @@ import os.path, importlib def _init(): - for fname in os.listdir(os.path.dirname(__file__)): - if ((fname.endswith('.py') or fname.endswith('.pyc')) and - not fname.startswith('__init__')): + base = os.path.dirname(__file__) + for fname in os.listdir(base): + print fname + is_python_script = fname.endswith('.py') or fname.endswith('.pyc') + is_init_script = fname.startswith('__init__') + is_directory = os.path.isdir(os.path.join(base, fname)) + if (is_directory or is_python_script) and not is_init_script : modname = os.path.basename(fname).rsplit('.', 1)[0] importlib.import_module('.' + modname, __name__) _init() + diff --git a/newbinding/src/Type.py b/newbinding/src/Type.py index 09b8ba9..4078a9d 100644 --- a/newbinding/src/Type.py +++ b/newbinding/src/Type.py @@ -9,17 +9,29 @@ IntegerType = llvm.Class(Type) CompositeType = llvm.Class(Type) StructType = llvm.Class(CompositeType) SequentialType = llvm.Class(CompositeType) +ArrayType = llvm.Class(SequentialType) PointerType = llvm.Class(SequentialType) +VectorType = llvm.Class(SequentialType) @Type class Type: _include_ = 'llvm/Type.h' + TypeID = Enum(''' + VoidTyID, HalfTyID, FloatTyID, DoubleTyID, + X86_FP80TyID, FP128TyID, PPC_FP128TyID, LabelTyID, + MetadataTyID, X86_MMXTyID, IntegerTyID, FunctionTyID, + StructTyID, ArrayTyID, PointerTyID, VectorTyID, + NumTypeIDs, LastPrimitiveTyID, FirstDerivedTyID + ''') + getContext = Method(ref(LLVMContext)) dump = Method() print_ = Method(Void, ref(raw_ostream)) print_.realname = 'print' + getTypeID = Method(TypeID) + def type_checker(): return Method(cast(Bool, bool)) @@ -81,7 +93,8 @@ class Type: getPPC_FP128Ty = type_factory() getX86_MMXTy = type_factory() - getIntNTy = StaticMethod(ptr(IntegerType), ref(LLVMContext), cast(Unsigned, int)) + getIntNTy = StaticMethod(ptr(IntegerType), + ref(LLVMContext), cast(Unsigned, int)) def integer_factory(): return StaticMethod(ptr(IntegerType), ref(LLVMContext)) @@ -117,6 +130,20 @@ class Type: self.print_(os) return os.str() + getContainedType = Method(ptr(Type), cast(int, Unsigned)) + getNumContainedTypes = Method(cast(int, Unsigned)) + + getArrayNumElements = Method(cast(Uint64, int)) + getArrayElementType = Method(ptr(Type)) + + getVectorNumElements = Method(cast(Unsigned, int)) + getVectorElementType = Method(ptr(Type)) + + getPointerElementType = Method(ptr(Type)) + getPointerAddressSpace = Method(cast(Unsigned, int)) + getPointerTo = Method(ptr(PointerType), cast(int, Unsigned)) + + @IntegerType class IntegerType: pass @@ -130,9 +157,30 @@ class CompositeType: class SequentialType: pass +@ArrayType +class ArrayType: + getNumElements = Method(cast(Uint64, int)) + get = StaticMethod(ptr(ArrayType), ptr(Type), cast(int, Uint64)) + isValidElementType = StaticMethod(cast(Bool, bool), ptr(Type)) + @PointerType class PointerType: - pass + getAddressSpace = Method(cast(Unsigned, int)) + get = StaticMethod(ptr(PointerType), ptr(Type), cast(int, Unsigned)) + getUnqual = StaticMethod(ptr(PointerType), ptr(Type)) + isValidElementType = StaticMethod(cast(Bool, bool), ptr(Type)) + +@VectorType +class VectorType: + getNumElements = Method(cast(Unsigned, int)) + getBitWidth = Method(cast(Unsigned, int)) + get = StaticMethod(ptr(VectorType), ptr(Type), cast(int, Unsigned)) + getInteger = StaticMethod(ptr(VectorType), ptr(VectorType)) + getExtendedElementVectorType = StaticMethod(ptr(VectorType), + ptr(VectorType)) + getTruncatedElementVectorType = StaticMethod(ptr(VectorType), + ptr(VectorType)) + isValidElementType = StaticMethod(cast(Bool, bool), ptr(Type)) @StructType class StructType: @@ -154,5 +202,12 @@ class StructType: ref(LLVMContext), cast(str, StringRef), ).require_only(1) + + get = StaticMethod(ptr(StructType), + ref(LLVMContext), + cast(bool, Bool), # is packed + ).require_only(1) + + isValidElementType = StaticMethod(cast(Bool, bool), ptr(Type)) diff --git a/newbinding/src/User.py b/newbinding/src/User.py index 57d58bc..9a077c1 100644 --- a/newbinding/src/User.py +++ b/newbinding/src/User.py @@ -1,7 +1,11 @@ from binding import * from namespace import llvm -from Value import User +from Value import Value, User @User class User: - pass + _downcast_ = Value + getOperand = Method(ptr(Value), cast(int, Unsigned)) + setOperand = Method(Void, cast(int, Unsigned), ptr(Value)) + getNumOperands = Method(cast(Unsigned, int)) + diff --git a/newbinding/src/Value.py b/newbinding/src/Value.py index 5675fa5..5d8c0a9 100644 --- a/newbinding/src/Value.py +++ b/newbinding/src/Value.py @@ -21,6 +21,16 @@ from ADT.StringRef import StringRef @Value class Value: + ValueTy = Enum(''' + ArgumentVal, BasicBlockVal, FunctionVal, GlobalAliasVal, + GlobalVariableVal, UndefValueVal, BlockAddressVal, ConstantExprVal, + ConstantAggregateZeroVal, ConstantDataArrayVal, ConstantDataVectorVal, + ConstantIntVal, ConstantFPVal, ConstantArrayVal, ConstantStructVal, + ConstantVectorVal, ConstantPointerNullVal, MDNodeVal, MDStringVal, + InlineAsmVal, PseudoSourceValueVal, FixedStackPseudoSourceValueVal, + InstructionVal, ConstantFirstVal, ConstantLastVal + ''') + dump = Method() print_ = Method(Void, ref(raw_ostream), ptr(AssemblyAnnotationWriter)) @@ -41,6 +51,7 @@ class Value: hasOneUse = Method(cast(Bool, bool)) hasNUses = Method(cast(Bool, bool), cast(int, Unsigned)) isUsedInBasicBlock = Method(cast(Bool, bool), BasicBlock) + getNumUses = Method(cast(Unsigned, int)) @CustomPythonMethod def __str__(self): @@ -48,3 +59,5 @@ class Value: os = extra.make_raw_ostream_for_printing() self.print_(os, None) return os.str() + + getValueID = Method(cast(Unsigned, int)) From aa5b969961b4390a2e68dab0d6c14b23c7e92933 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 6 Feb 2013 21:31:24 -0600 Subject: [PATCH 252/516] Expand test --- newbinding/test_binding.py | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/newbinding/test_binding.py b/newbinding/test_binding.py index 578c532..5b51ecb 100644 --- a/newbinding/test_binding.py +++ b/newbinding/test_binding.py @@ -82,8 +82,16 @@ def test_basic_jit_use(): errio = StringIO() print m - # build pass manager + # verifier + action = api.VerifierFailureAction.ReturnStatusAction + corrupted = api.verifyFunction(fn, action) + assert not corrupted + corrupted = api.verifyModule(m, action, errio) + print corrupted + assert not corrupted, errio.getvalue() + + # build pass manager pmb = api.PassManagerBuilder.new() pmb.OptLevel = 3 assert pmb.OptLevel == 3 @@ -156,6 +164,11 @@ def test_basic_jit_use(): m3.setModuleIdentifier(m.getModuleIdentifier()) assert str(m3) == str(m) + # test clone + m4 = api.CloneModule(m) + assert m4 is not m + assert str(m4) == str(m) + def test_engine_builder(): api.InitializeNativeTarget() context = api.getGlobalContext() @@ -286,6 +299,26 @@ def test_globalvariable(): print m.list_globals() + +def test_sequentialtypes(): + context = api.getGlobalContext() + int32ty = api.Type.getInt32Ty(context) + ary_int32x4 = api.ArrayType.get(int32ty, 4) + assert '[4 x i32]' == str(ary_int32x4) + ptr_int32 = api.PointerType.get(int32ty, 1) + assert 'i32 addrspace(1)*' == str(ptr_int32) + vec_int32x4 = api.VectorType.get(int32ty, 4) + assert '<4 x i32>' == str(vec_int32x4) + + +def test_constants(): + context = api.getGlobalContext() + int32ty = api.Type.getInt32Ty(context) + ary_int32x4 = api.ArrayType.get(int32ty, 4) + intconst = api.ConstantInt.get(int32ty, 123) + aryconst = api.ConstantArray.get(ary_int32x4, [intconst] * 4) + assert str(aryconst.getAggregateElement(0)) == str(intconst) + def main(): for name, value in globals().items(): if name.startswith('test_') and callable(value): From 11cc78d780772ec90bab2581fc86e6a5046cf170 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 7 Feb 2013 13:27:03 -0600 Subject: [PATCH 253/516] Add binding for Intrinsics. Add support for functions that free the resource but is not a destructor. --- newbinding/capsule.py | 14 +++++++++--- newbinding/gen/binding.py | 3 +++ newbinding/include/llvm_binding/extra.h | 19 ++++++++++++++++ newbinding/src/Function.py | 29 +++++++++++++++++++++++++ newbinding/src/GlobalValue.py | 2 ++ newbinding/src/GlobalVariable.py | 2 +- newbinding/src/Intrinsics.py | 17 +++++++++++++++ newbinding/test_binding.py | 10 +++++++++ 8 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 newbinding/src/Intrinsics.py diff --git a/newbinding/capsule.py b/newbinding/capsule.py index 8c2f10e..e29948d 100644 --- a/newbinding/capsule.py +++ b/newbinding/capsule.py @@ -92,8 +92,12 @@ _cache = defaultdict(WeakValueDictionary) def release_ownership(old): logger.debug('Release %s', old) addr = Capsule.getPointer(old) - if _addr2dtor[addr] is None: - # Guard deduplicated release + + if _addr2dtor.get(addr) is None: + clsname = Capsule.getClassName(old) + if not _pyclasses[clsname]._has_dtor(): + return + # Guard duplicated release raise Exception("Already released") _addr2dtor[addr] = None @@ -117,7 +121,7 @@ def wrap(cap, owned=False): try: # lookup cached object return _cache[cls][addr] except KeyError: - if not owned and hasattr(cls, '_delete_'): + if not owned and cls._has_dtor(): _addr2dtor[addr] = cls._delete_ obj = cap.instantiate() _cache[cls][addr] = obj # cache it @@ -164,6 +168,10 @@ class Wrapper(object): def _downcast(self, newcls): return downcast(self, newcls) + @classmethod + def _has_dtor(cls): + return hasattr(cls, '_delete_') + def downcast(obj, cls): import _api if type(obj) is cls: diff --git a/newbinding/gen/binding.py b/newbinding/gen/binding.py index 09cd9bf..1c7c7ca 100644 --- a/newbinding/gen/binding.py +++ b/newbinding/gen/binding.py @@ -283,6 +283,7 @@ class Method(object): self.signatures = [] self.includes = set() self._add_signature(return_type, *args) + self.disowning = False def _add_signature(self, return_type, *args): prev_lens = set(map(len, self.signatures)) @@ -350,6 +351,8 @@ class Method(object): decl = writer.function(self.name, args=('self',), varargs='args') with decl as (this, varargs): unwrap_this = writer.unwrap(this) + if self.disowning: + writer.release_ownership(unwrap_this) unwrapped = writer.unwrap_many(varargs) self.process_ownedptr_args(writer, unwrapped) diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h index 85e1ea5..0d9ba16 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/extra.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "auto_pyobject.h" @@ -694,3 +695,21 @@ PyObject* ConstantVector_get(PyObject* Elems) return pycapsule_new(ary, "llvm::Value", "llvm::Constant"); } +static +PyObject* Intrinsic_getDeclaration(llvm::Module* Mod, + unsigned ID, + PyObject* Types=NULL) +{ + using namespace llvm; + Function* Fn = NULL; + if (Types) { + std::vector types; + bool ok = extract::from_py_sequence(types, Types, "llvm::Type"); + if (!ok) return NULL; + Fn = Intrinsic::getDeclaration(Mod, (Intrinsic::ID)ID, types); + } else { + Fn = Intrinsic::getDeclaration(Mod, (Intrinsic::ID)ID); + } + return pycapsule_new(Fn, "llvm::Value", "llvm::Function"); +} + diff --git a/newbinding/src/Function.py b/newbinding/src/Function.py index ee59990..d82b5d3 100644 --- a/newbinding/src/Function.py +++ b/newbinding/src/Function.py @@ -1,6 +1,8 @@ from binding import * from namespace import llvm from Value import GlobalValue, Constant, Function, Argument +from BasicBlock import BasicBlock +from Attributes import Attributes from Type import Type from DerivedTypes import FunctionType from LLVMContext import LLVMContext @@ -21,6 +23,33 @@ class Function: getCallingConv = Method(CallingConv.ID) setCallingConv = Method(Void, CallingConv.ID) + hasGC = Method(cast(bool, Bool)) + getGC = Method(cast(ConstCharPtr, str)) + setGC = Method(Void, cast(str, ConstCharPtr)) + getArgumentList = CustomMethod('Function_getArgumentList', PyObjectPtr) getBasicBlockList = CustomMethod('Function_getBasicBlockList', PyObjectPtr) + getEntryBlock = Method(ref(BasicBlock)) + + copyAttributesFrom = Method(Void, ptr(GlobalValue)) + + setDoesNotThrow = Method() + doesNotThrow = Method(cast(Bool, bool)) + setDoesNotReturn = Method() + doesNotReturn = Method(cast(Bool, bool)) + setOnlyReadsMemory = Method() + onlyReadsMemory = Method(cast(Bool, bool)) + setDoesNotAccessMemory = Method() + doesNotAccessMemory = Method(cast(Bool, bool)) + + deleteBody = Method() + viewCFG = Method() + viewCFGOnly = Method() + + addFnAttr = Method(Void, Attributes.AttrVal) + removeFnAttr = Method(Void, ref(Attributes)) + + eraseFromParent = Method() + eraseFromParent.disowning = True + diff --git a/newbinding/src/GlobalValue.py b/newbinding/src/GlobalValue.py index 02ba4ea..f21d5af 100644 --- a/newbinding/src/GlobalValue.py +++ b/newbinding/src/GlobalValue.py @@ -44,4 +44,6 @@ class GlobalValue: isDeclaration = Method(cast(Bool, bool)) removeFromParent = Method() eraseFromParent = Method() + eraseFromParent.disowning = True + getParent = Method(ptr(Module)) diff --git a/newbinding/src/GlobalVariable.py b/newbinding/src/GlobalVariable.py index a11f259..4ee91fb 100644 --- a/newbinding/src/GlobalVariable.py +++ b/newbinding/src/GlobalVariable.py @@ -45,5 +45,5 @@ class GlobalVariable: # isExternallyInitialized = Method(cast(Bool, bool)) # setExternallyinitialized = Method(Void, cast(bool, Bool)) - eraseFromParent = Method() + \ No newline at end of file diff --git a/newbinding/src/Intrinsics.py b/newbinding/src/Intrinsics.py new file mode 100644 index 0000000..0f1bcb4 --- /dev/null +++ b/newbinding/src/Intrinsics.py @@ -0,0 +1,17 @@ +from binding import * +from namespace import llvm + +from Module import Module +from Function import Function + + +Intrinsic = llvm.Class() # fake class (actually a namespace) + +@Intrinsic +class Intrinsic: + getDeclaration = CustomStaticMethod('Intrinsic_getDeclaration', + PyObjectPtr, # Function* + ptr(Module), + cast(int, Unsigned), # intrinsic id + PyObjectPtr, # list of Type + ).require_only(2) diff --git a/newbinding/test_binding.py b/newbinding/test_binding.py index 5b51ecb..9003f7d 100644 --- a/newbinding/test_binding.py +++ b/newbinding/test_binding.py @@ -319,6 +319,16 @@ def test_constants(): aryconst = api.ConstantArray.get(ary_int32x4, [intconst] * 4) assert str(aryconst.getAggregateElement(0)) == str(intconst) +def test_intrinsic(): + context = api.getGlobalContext() + m = api.Module.new("modname", context) + INTR_SIN = 1652 + floatty = api.Type.getFloatTy(context) + fn = api.Intrinsic.getDeclaration(m, INTR_SIN, [floatty]) + assert 'llvm.sin.f32' in str(fn) + fn.eraseFromParent() + assert 'llvm.sin.f32' not in str(m) + def main(): for name, value in globals().items(): if name.startswith('test_') and callable(value): From 541c119fc38ef87e7ade743ceb4402db7f213b68 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 7 Feb 2013 13:50:16 -0600 Subject: [PATCH 254/516] Add binding for MDNode, MDString, InlineAsm --- newbinding/include/llvm_binding/extra.h | 17 +++++++++++++++-- newbinding/src/InlineAsm.py | 24 ++++++++++++++++++++++++ newbinding/src/Metadata.py | 23 +++++++++++++++++++++-- newbinding/src/Value.py | 1 + 4 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 newbinding/src/InlineAsm.py diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h index 0d9ba16..df0cecd 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/extra.h @@ -697,8 +697,8 @@ PyObject* ConstantVector_get(PyObject* Elems) static PyObject* Intrinsic_getDeclaration(llvm::Module* Mod, - unsigned ID, - PyObject* Types=NULL) + unsigned ID, + PyObject* Types=NULL) { using namespace llvm; Function* Fn = NULL; @@ -713,3 +713,16 @@ PyObject* Intrinsic_getDeclaration(llvm::Module* Mod, return pycapsule_new(Fn, "llvm::Value", "llvm::Function"); } +static +PyObject* MDNode_get(llvm::LLVMContext &Cxt, PyObject* Vals) +{ + std::vector vals; + bool ok = extract::from_py_sequence(vals, Vals, "llvm::Value"); + if (not ok) return NULL; + llvm::MDNode* md = llvm::MDNode::get(Cxt, vals); + return pycapsule_new(md, "llvm::Value", "llvm::MDNode"); +} + + + + diff --git a/newbinding/src/InlineAsm.py b/newbinding/src/InlineAsm.py new file mode 100644 index 0000000..a4ce16b --- /dev/null +++ b/newbinding/src/InlineAsm.py @@ -0,0 +1,24 @@ +from binding import * +from namespace import llvm +from Value import Value +from DerivedTypes import FunctionType +from ADT.StringRef import StringRef + +llvm.includes.add('llvm/InlineAsm.h') + +InlineAsm = llvm.Class(Value) + +@InlineAsm +class InlineAsm: + AsmDialect = Enum('AD_ATT', 'AD_Intel') + ConstraintPrefix = Enum('''isInput, isOutput, isClobber''') + + get = StaticMethod(ptr(InlineAsm), + ptr(FunctionType), + cast(str, StringRef), # AsmString + cast(str, StringRef), # Constrains + cast(bool, Bool), # hasSideEffects + cast(bool, Bool), # isAlignStack + AsmDialect, # default = AD_ATT + ).require_only(4) + diff --git a/newbinding/src/Metadata.py b/newbinding/src/Metadata.py index 96dbc01..bda09e1 100644 --- a/newbinding/src/Metadata.py +++ b/newbinding/src/Metadata.py @@ -1,14 +1,32 @@ from binding import * from namespace import llvm -from Value import MDNode +from Value import Value, MDNode, MDString +from LLVMContext import LLVMContext from ADT.StringRef import StringRef from Module import Module +from Function import Function from Support.raw_ostream import raw_ostream from Assembly.AssemblyAnnotationWriter import AssemblyAnnotationWriter @MDNode class MDNode: - pass + replaceOperandWith = Method(Void, cast(int, Unsigned), ptr(Value)) + getOperand = Method(ptr(Value), cast(int, Unsigned)) + getNumOperands = Method(cast(Unsigned, int)) + isFunctionLocal = Method(cast(Bool, bool)) + getFunction = Method(const(ptr(Function))) + + get = CustomStaticMethod('MDNode_get', + PyObjectPtr, # MDNode* + ref(LLVMContext), + PyObjectPtr, # ArrayRef + ) + +@MDString +class MDString: + get = StaticMethod(ptr(MDString), ref(LLVMContext), cast(str, StringRef)) + getString = Method(cast(StringRef, str)) + getLength = Method(cast(int, Unsigned)) @llvm.Class() class NamedMDNode: @@ -18,6 +36,7 @@ class NamedMDNode: getOperand = Method(ptr(MDNode), cast(int, Unsigned)) getNumOperands = Method(cast(Unsigned, int)) getName = Method(cast(StringRef, str)) + addOperand = Method(Void, ptr(MDNode)) print_ = Method(Void, ref(raw_ostream), ptr(AssemblyAnnotationWriter)) print_.realname = "print" dump = Method() diff --git a/newbinding/src/Value.py b/newbinding/src/Value.py index 5d8c0a9..27bcda0 100644 --- a/newbinding/src/Value.py +++ b/newbinding/src/Value.py @@ -5,6 +5,7 @@ from namespace import llvm Value = llvm.Class() Argument = llvm.Class(Value) MDNode = llvm.Class(Value) +MDString = llvm.Class(Value) User = llvm.Class(Value) BasicBlock = llvm.Class(Value) Constant = llvm.Class(User) From 113f30ffab758fc1bf7b0c9d7889ed5297379bf5 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 7 Feb 2013 15:23:31 -0600 Subject: [PATCH 255/516] Add more to Instruction --- newbinding/gen/binding.py | 1 + newbinding/src/Constant.py | 23 ++++--- newbinding/src/Instruction.py | 121 +++++++++++++++++++++++++++++++--- newbinding/src/Metadata.py | 9 +++ 4 files changed, 135 insertions(+), 19 deletions(-) diff --git a/newbinding/gen/binding.py b/newbinding/gen/binding.py index 1c7c7ca..c1e1d1e 100644 --- a/newbinding/gen/binding.py +++ b/newbinding/gen/binding.py @@ -70,6 +70,7 @@ Float = BuiltinTypes('float') Double = BuiltinTypes('double') Uint64 = BuiltinTypes('uint64_t') Int64 = BuiltinTypes('int64_t') +Int = BuiltinTypes('int') Size_t = BuiltinTypes('size_t') VoidPtr = BuiltinTypes('void*') Bool = BuiltinTypes('bool') diff --git a/newbinding/src/Constant.py b/newbinding/src/Constant.py index 9027e3f..42541c4 100644 --- a/newbinding/src/Constant.py +++ b/newbinding/src/Constant.py @@ -1,10 +1,22 @@ from binding import * from namespace import llvm + +from Value import Constant, Value + +UndefValue = llvm.Class(Constant) +ConstantInt = llvm.Class(Constant) +ConstantFP = llvm.Class(Constant) +ConstantArray = llvm.Class(Constant) +ConstantStruct = llvm.Class(Constant) +ConstantVector = llvm.Class(Constant) +ConstantDataSequential = llvm.Class(Constant) +ConstantDataArray = llvm.Class(ConstantDataSequential) +ConstantExpr = llvm.Class(Constant) + from LLVMContext import LLVMContext from ADT.StringRef import StringRef from ADT.SmallVector import SmallVector_Value, SmallVector_Unsigned from Type import Type, IntegerType, ArrayType, StructType -from Value import Constant, Value from Instruction import CmpInst @Constant @@ -42,7 +54,6 @@ class Constant: PyObjectPtr) -UndefValue = llvm.Class(Constant) @UndefValue class UndefValue: @@ -67,7 +78,6 @@ class UndefValue: get = StaticMethod(ptr(UndefValue), ptr(Type)) -ConstantInt = llvm.Class(Constant) @ConstantInt class ConstantInt: @@ -82,7 +92,6 @@ class ConstantInt: getZExtValue = Method(cast(Uint64, int)) getSExtValue = Method(cast(Int64, int)) -ConstantFP = llvm.Class(Constant) @ConstantFP class ConstantFP: @@ -95,7 +104,6 @@ class ConstantFP: isNaN = Method(cast(Bool, bool)) -ConstantArray = llvm.Class(Constant) @ConstantArray class ConstantArray: @@ -105,7 +113,6 @@ class ConstantArray: PyObjectPtr, # Constants ) -ConstantStruct = llvm.Class(Constant) @ConstantStruct class ConstantStruct: @@ -120,7 +127,6 @@ class ConstantStruct: cast(bool, Bool), # packed ).require_only(1) -ConstantVector = llvm.Class(Constant) @ConstantVector class ConstantVector: @@ -129,13 +135,11 @@ class ConstantVector: PyObjectPtr, # constants ) -ConstantDataSequential = llvm.Class(Constant) @ConstantDataSequential class ConstantDataSequential: pass -ConstantDataArray = llvm.Class(ConstantDataSequential) @ConstantDataArray class ConstantDataArray: @@ -146,7 +150,6 @@ class ConstantDataArray: ).require_only(2) -ConstantExpr = llvm.Class(Constant) def _factory(*args): return StaticMethod(ptr(Constant), *args) diff --git a/newbinding/src/Instruction.py b/newbinding/src/Instruction.py index dda6b48..79cf4a3 100644 --- a/newbinding/src/Instruction.py +++ b/newbinding/src/Instruction.py @@ -1,6 +1,11 @@ from binding import * from namespace import llvm -from Value import User +from Value import Value, MDNode, User, BasicBlock, Function +from ADT.StringRef import StringRef +from CallingConv import CallingConv +from Attributes import Attributes +from Constant import ConstantInt + Instruction = llvm.Class(User) AtomicCmpXchgInst = llvm.Class(Instruction) @@ -54,7 +59,49 @@ FPTruncInst = llvm.Class(CastInst) @Instruction class Instruction: - pass + removeFromParent = Method() + eraseFromParent = Method() + eraseFromParent.disowning = True + + getParent = Method(ptr(BasicBlock)) + getOpcode = Method(cast(Unsigned, int)) + getOpcodeName = Method(cast(ConstCharPtr, str)) + + insertBefore = Method(Void, ptr(Instruction)) + insertAfter = Method(Void, ptr(Instruction)) + moveBefore = Method(Void, ptr(Instruction)) + + isTerminator = Method(cast(Bool, bool)) + isBinaryOp = Method(cast(Bool, bool)) + isShift = Method(cast(Bool, bool)) + isCast = Method(cast(Bool, bool)) + isLogicalShift = Method(cast(Bool, bool)) + isArithmeticShift = Method(cast(Bool, bool)) + hasMetadata = Method(cast(Bool, bool)) + hasMetadataOtherThanDebugLoc = Method(cast(Bool, bool)) + isAssociative = Method(cast(Bool, bool)) + isCommutative = Method(cast(Bool, bool)) + isIdempotent = Method(cast(Bool, bool)) + isNilpotent = Method(cast(Bool, bool)) + mayWriteToMemory = Method(cast(Bool, bool)) + mayReadFromMemory = Method(cast(Bool, bool)) + mayReadOrWriteMemory = Method(cast(Bool, bool)) + mayThrow = Method(cast(Bool, bool)) + mayHaveSideEffects = Method(cast(Bool, bool)) + + hasMetadata = Method(cast(Bool, bool)) + getMetadata = Method(ptr(MDNode), cast(str, StringRef)) + setMetadata = Method(Void, cast(str, StringRef), ptr(MDNode)) + + clone = Method(ptr(Instruction)) + +# LLVM 3.3 +# hasUnsafeAlgebra = Method(cast(Bool, bool)) +# hasNoNans = Method(cast(Bool, bool)) +# hasNoInfs = Method(cast(Bool, bool)) +# hasNoSignedZeros = Method(cast(Bool, bool)) +# hasAllowReciprocal = Method(cast(Bool, bool)) + @AtomicCmpXchgInst class AtomicCmpXchgInst: @@ -71,7 +118,16 @@ class BinaryOperator: @CallInst class CallInst: - pass + _downcast_ = Value, Instruction + getCallingConv = Method(CallingConv.ID) + setCallingConv = Method(Void, CallingConv.ID) + getParamAlignment = Method(cast(Unsigned, int), cast(int, Unsigned)) + addAttribute = Method(Void, cast(int, Unsigned), ref(Attributes)) + removeAttribute = Method(Void, cast(int, Unsigned), ref(Attributes)) + getCalledFunction = Method(ptr(Function)) + getCalledValue = Method(ptr(Value)) + setCalledFunction = Method(Void, ptr(Function)) + isInlineAsm = Method(cast(Bool, bool)) @CmpInst class CmpInst: @@ -87,6 +143,8 @@ class CmpInst: 'LAST_ICMP_PREDICATE', 'BAD_ICMP_PREDICATE',) + getPredicate = Method(Predicate) + @ExtractElementInst class ExtractElementInst: pass @@ -113,7 +171,14 @@ class LandingPadInst: @PHINode class PHINode: - pass + getNumIncomingValues = Method(cast(Unsigned, int)) + getIncomingValue = Method(ptr(Value), cast(int, Unsigned)) + setIncomingValue = Method(Void, cast(int, Unsigned), ptr(Value)) + getIncomingBlock = Method(ptr(BasicBlock), cast(int, Unsigned)) + setIncomingBlock = Method(Void, cast(int, Unsigned), ptr(BasicBlock)) + addIncoming = Method(Void, ptr(Value), ptr(BasicBlock)) + hasConstantValue = Method(ptr(Value)) + getBasicBlockIndex = Method(cast(Int, int), ptr(BasicBlock)) @SelectInst class SelectInst: @@ -125,11 +190,24 @@ class ShuffleVectorInst: @StoreInst class StoreInst: - pass + _downcast_ = Instruction + isVolatile = Method(cast(Bool, bool)) + isSimple = Method(cast(Bool, bool)) + isUnordered = Method(cast(Bool, bool)) + isAtomic = Method(cast(Bool, bool)) + + setVolatile = Method(Void, cast(Bool, bool)) + + getAlignment = Method(cast(Unsigned, int)) + setAlignment = Method(Void, cast(int, Unsigned)) + + classof = StaticMethod(cast(Bool, bool), ptr(Value)) @TerminatorInst class TerminatorInst: - pass + getNumSuccessors = Method(cast(Unsigned, int)) + getSuccessor = Method(ptr(BasicBlock), cast(int, Unsigned)) + setSuccessor = Method(Void, cast(int, Unsigned), ptr(BasicBlock)) @UnaryInstruction class UnaryInstruction: @@ -162,7 +240,15 @@ class IndirectBrInst: @InvokeInst class InvokeInst: - pass + _downcast_ = Value, Instruction + getCallingConv = Method(CallingConv.ID) + setCallingConv = Method(Void, CallingConv.ID) + getParamAlignment = Method(cast(Unsigned, int), cast(int, Unsigned)) + addAttribute = Method(Void, cast(int, Unsigned), ref(Attributes)) + removeAttribute = Method(Void, cast(int, Unsigned), ref(Attributes)) + getCalledFunction = Method(ptr(Function)) + getCalledValue = Method(ptr(Value)) + setCalledFunction = Method(Void, ptr(Function)) @ResumeInst class ResumeInst: @@ -174,7 +260,13 @@ class ReturnInst: @SwitchInst class SwitchInst: - pass + getCondition = Method(ptr(Value)) + setCondition = Method(Void, ptr(Value)) + getDefaultDest = Method(ptr(BasicBlock)) + setDefaultDest = Method(Void, ptr(BasicBlock)) + getNumCases = Method(cast(int, Unsigned)) + addCase = Method(Void, ptr(ConstantInt), ptr(BasicBlock)) + @UnreachableInst class UnreachableInst: @@ -195,7 +287,18 @@ class ExtractValueInst: @LoadInst class LoadInst: - pass + _downcast_ = Value, Instruction + isVolatile = Method(cast(Bool, bool)) + isSimple = Method(cast(Bool, bool)) + isUnordered = Method(cast(Bool, bool)) + isAtomic = Method(cast(Bool, bool)) + + setVolatile = Method(Void, cast(Bool, bool)) + + getAlignment = Method(cast(Unsigned, int)) + setAlignment = Method(Void, cast(int, Unsigned)) + + classof = StaticMethod(cast(Bool, bool), ptr(Value)) @VAArgInst class VAArgInst: diff --git a/newbinding/src/Metadata.py b/newbinding/src/Metadata.py index bda09e1..338cbbd 100644 --- a/newbinding/src/Metadata.py +++ b/newbinding/src/Metadata.py @@ -31,6 +31,8 @@ class MDString: @llvm.Class() class NamedMDNode: eraseFromParent = Method() + eraseFromParent.disowning = True + dropAllReferences = Method() getParent = Method(ptr(Module)) getOperand = Method(ptr(MDNode), cast(int, Unsigned)) @@ -41,3 +43,10 @@ class NamedMDNode: print_.realname = "print" dump = Method() + + @CustomPythonMethod + def __str__(self): + import extra + os = extra.make_raw_ostream_for_printing() + self.print_(os, None) + return os.str() \ No newline at end of file From b9ac22d13688cb7ae2c99e14fbed92d96312e566 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 7 Feb 2013 15:31:54 -0600 Subject: [PATCH 256/516] More to BasicBlock --- newbinding/include/llvm_binding/extra.h | 8 +++++++- newbinding/src/BasicBlock.py | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h index df0cecd..bde92a7 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/extra.h @@ -724,5 +724,11 @@ PyObject* MDNode_get(llvm::LLVMContext &Cxt, PyObject* Vals) } - +static +PyObject* BasicBlock_getInstList(llvm::BasicBlock* BB) +{ + return iplist_to_pylist(BB->getInstList(), + "llvm::Value", + "llvm::Instruction"); +} diff --git a/newbinding/src/BasicBlock.py b/newbinding/src/BasicBlock.py index 61a09d7..81edf37 100644 --- a/newbinding/src/BasicBlock.py +++ b/newbinding/src/BasicBlock.py @@ -20,3 +20,5 @@ class BasicBlock: isLandingPad = Method(cast(Bool, bool)) removePredecessor = Method(Void, ptr(BasicBlock), cast(bool, Bool)) removePredecessor |= Method(Void, ptr(BasicBlock)) + + getInstList = CustomMethod('BasicBlock_getInstList', PyObjectPtr) \ No newline at end of file From fe383ca326342472b325f60e79fca563873f10cd Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 7 Feb 2013 17:40:00 -0600 Subject: [PATCH 257/516] More to IRBuilder and Instruction --- newbinding/include/llvm_binding/extra.h | 15 +++++++ newbinding/src/IRBuilder.py | 54 ++++++++++++++++++++----- newbinding/src/Instruction.py | 40 ++++++++++++++---- 3 files changed, 90 insertions(+), 19 deletions(-) diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h index bde92a7..75739de 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/extra.h @@ -14,6 +14,7 @@ #include #include #include +#include #include "auto_pyobject.h" @@ -732,3 +733,17 @@ PyObject* BasicBlock_getInstList(llvm::BasicBlock* BB) "llvm::Instruction"); } +static +PyObject* IRBuilder_CreateAggregateRet(llvm::IRBuilder<>* builder, + PyObject* Vals, + unsigned N) +{ + using namespace llvm; + std::vector vec_values; + bool ok = extract::from_py_sequence(vec_values, Vals, "llvm::Value"); + if (not ok) return NULL; + Value** ptr_values = &vec_values[0]; + ReturnInst* inst = builder->CreateAggregateRet(ptr_values, N); + return pycapsule_new(inst, "llvm::Value", "llvm:ReturnInst"); +} + diff --git a/newbinding/src/IRBuilder.py b/newbinding/src/IRBuilder.py index e0cac79..2965367 100644 --- a/newbinding/src/IRBuilder.py +++ b/newbinding/src/IRBuilder.py @@ -2,6 +2,7 @@ from binding import * from namespace import llvm from LLVMContext import LLVMContext from BasicBlock import BasicBlock +from Instruction import Instruction from Instruction import ReturnInst, CallInst, BranchInst, SwitchInst from Instruction import IndirectBrInst, InvokeInst, ResumeInst, PHINode from Instruction import UnreachableInst, AllocaInst, LoadInst, StoreInst @@ -23,12 +24,30 @@ class IRBuilder: new = Constructor(ref(LLVMContext)) delete = Destructor() - SetInsertPoint = Method(Void, ptr(BasicBlock)) + GetInsertBlock = Method(ptr(BasicBlock)) + + _SetInsertPoint_end_of_bb = Method(Void, ptr(BasicBlock)) + _SetInsertPoint_end_of_bb.realname = 'SetInsertPoint' + _SetInsertPoint_before_instr = Method(Void, ptr(Instruction)) + _SetInsertPoint_before_instr.realname = 'SetInsertPoint' + + @CustomPythonMethod + def SetInsertPoint(self, pt): + if isinstance(pt, Instruction): + return self._SetInsertPoint_before_instr(pt) + elif isinstance(pt, BasicBlock): + return self._SetInsertPoint_end_of_bb(pt) + else: + raise ValueError("Expected either an Instruction or a BasicBlock") isNamePreserving = Method(cast(Bool, bool)) CreateRetVoid = Method(ptr(ReturnInst)) CreateRet = Method(ptr(ReturnInst), ptr(Value)) + CreateAggregateRet = CustomMethod('IRBuilder_CreateAggregateRet', + PyObjectPtr, # ptr(ReturnInst), + PyObjectPtr, # list of Value + cast(int, Unsigned)) CreateBr = Method(ptr(BranchInst), ptr(BasicBlock)) @@ -42,9 +61,18 @@ class IRBuilder: CreateIndirectBr = Method(ptr(IndirectBrInst), ptr(Value), cast(int, Unsigned)).require_only(1) - CreateInvoke = Method(ptr(InvokeInst), ptr(Value), ptr(BasicBlock), + _CreateInvoke = Method(ptr(InvokeInst), ptr(Value), ptr(BasicBlock), ptr(BasicBlock), ref(SmallVector_Value), cast(str, StringRef)).require_only(4) + _CreateInvoke.realname = 'CreateInvoke' + + @CustomPythonMethod + def CreateInvoke(self, *args): + import extra + args = list(args) + valuelist = args[3] + args[3] = extra.make_small_vector_from_values(*valuelist) + return self._CreateInvoke(*args) CreateResume = Method(ptr(ResumeInst), ptr(Value)) @@ -114,8 +142,11 @@ class IRBuilder: ptr(Value), cast(str, StringRef)).require_only(1) - CreateAlloca = Method(ptr(AllocaInst), ptr(Type), ptr(Value), - cast(str, StringRef)).require_only(2) + CreateAlloca = Method(ptr(AllocaInst), + ptr(Type), # ty + ptr(Value), # arysize = 0 + cast(str, StringRef), # name = '' + ).require_only(1) CreateLoad = Method(ptr(LoadInst), ptr(Value), cast(str, StringRef)).require_only(1) @@ -208,6 +239,14 @@ class IRBuilder: cast(str, StringRef)).require_only(2) _CreateCall.realname = 'CreateCall' + @CustomPythonMethod + def CreateCall(self, *args): + import extra + args = list(args) + valuelist = args[1] + args[1] = extra.make_small_vector_from_values(*valuelist) + return self._CreateCall(*args) + # Skip specialized CreateICmp* and CreateFCmp* CreateICmp = Method(ptr(Value), CmpInst.Predicate, ptr(Value), ptr(Value), @@ -219,13 +258,6 @@ class IRBuilder: CreatePHI = Method(ptr(PHINode), ptr(Type), cast(int, Unsigned), cast(str, StringRef)).require_only(2) - @CustomPythonMethod - def CreateCall(self, *args): - import extra - args = list(args) - valuelist = args[1] - args[1] = extra.make_small_vector_from_values(*valuelist) - return self._CreateCall(*args) CreateSelect = Method(ptr(Value), ptr(Value), ptr(Value), ptr(Value), cast(str, StringRef)).require_only(3) diff --git a/newbinding/src/Instruction.py b/newbinding/src/Instruction.py index 79cf4a3..ca64072 100644 --- a/newbinding/src/Instruction.py +++ b/newbinding/src/Instruction.py @@ -5,6 +5,7 @@ from ADT.StringRef import StringRef from CallingConv import CallingConv from Attributes import Attributes from Constant import ConstantInt +from Type import Type Instruction = llvm.Class(User) @@ -57,6 +58,17 @@ FPToSIInst = llvm.Class(CastInst) FPToUIInst = llvm.Class(CastInst) FPTruncInst = llvm.Class(CastInst) +AtomicOrdering = llvm.Enum('AtomicOrdering', + 'NotAtomic', 'Unordered', 'Monotonic', 'Acquire', + 'Release', 'AcquireRelease', + 'SequentiallyConsistent') + +SynchronizationScope = llvm.Enum('SynchronizationScope', + 'SingleThread', 'CrossThread') + + + + @Instruction class Instruction: removeFromParent = Method() @@ -129,6 +141,18 @@ class CallInst: setCalledFunction = Method(Void, ptr(Function)) isInlineAsm = Method(cast(Bool, bool)) + CreateMalloc = StaticMethod(ptr(Instruction), + ptr(BasicBlock), # insertAtEnd + ptr(Type), # intptrty + ptr(Type), # allocty + ptr(Value), # allocsz + ptr(Value), # array size = 0 + ptr(Function), # malloc fn = 0 + cast(str, StringRef), # name + ).require_only(4) + + CreateFree = StaticMethod(ptr(Instruction), ptr(Value), ptr(BasicBlock)) + @CmpInst class CmpInst: Predicate = Enum('FCMP_FALSE', 'FCMP_OEQ', 'FCMP_OGT', 'FCMP_OGE', @@ -201,6 +225,10 @@ class StoreInst: getAlignment = Method(cast(Unsigned, int)) setAlignment = Method(Void, cast(int, Unsigned)) + setAtomic = Method(Void, + AtomicOrdering, + SynchronizationScope).require_only(1) + classof = StaticMethod(cast(Bool, bool), ptr(Value)) @TerminatorInst @@ -298,6 +326,10 @@ class LoadInst: getAlignment = Method(cast(Unsigned, int)) setAlignment = Method(Void, cast(int, Unsigned)) + setAtomic = Method(Void, + AtomicOrdering, + SynchronizationScope).require_only(1) + classof = StaticMethod(cast(Bool, bool), ptr(Value)) @VAArgInst @@ -345,11 +377,3 @@ class FPToUIInst: class FPTruncInst: pass -AtomicOrdering = llvm.Enum('AtomicOrdering', - 'NotAtomic', 'Unordered', 'Monotonic', 'Acquire', - 'Release', 'AcquireRelease', - 'SequentiallyConsistent') - -SynchronizationScope = llvm.Enum('SynchronizationScope', - 'SingleThread', 'CrossThread') - From 7c39bd1f5beb2182a6863ad48bd6d874041a53c1 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 8 Feb 2013 16:03:29 -0600 Subject: [PATCH 258/516] Refactor to allow sub-namespace declaration --- newbinding/Makefile | 10 +- newbinding/capsule.py | 2 +- newbinding/gen/binding.py | 225 ++++++++++++++++----- newbinding/gen/codegen.py | 6 + newbinding/gen/gen.py | 135 +++---------- newbinding/include/llvm_binding/binding.h | 12 +- newbinding/src/CallingConv.py | 5 +- newbinding/src/EngineBuilder.py | 7 +- newbinding/src/Intrinsics.py | 17 +- newbinding/src/Support/CodeGen.py | 26 +-- newbinding/src/Support/DynamicLibrary.py | 6 + newbinding/src/Target/TargetLibraryInfo.py | 5 +- newbinding/src/namespace.py | 5 +- 13 files changed, 264 insertions(+), 197 deletions(-) create mode 100644 newbinding/src/Support/DynamicLibrary.py diff --git a/newbinding/Makefile b/newbinding/Makefile index 0e7924f..9de1fb0 100644 --- a/newbinding/Makefile +++ b/newbinding/Makefile @@ -5,18 +5,18 @@ all: _api.so _capsule.so _api.so _capsule.so: api.cpp capsule.cpp $(PYTHON) setup.py build_ext --inplace -api.cpp api.py: src/*.py include/llvm_binding/*.h gen/gen.py gen/binding.py +api.cpp api/__init__.py: src/*.py include/llvm_binding/*.h gen/gen.py gen/binding.py $(PYTHON) gen/gen.py api src clean: cleantemp rm -f _api.so _capsule.so + rm -rf api + py_clean cleantemp: - rm -f api.cpp api.py - rm -f src/*.pyc src/Transforms/*.pyc src/ADT/*.pyc src/Assembly/*.pyc src/CodeGen/*.pyc src/ExecutionEngine/*.pyc src/Target/*.pyc src/Transforms/*.pyc + rm -f api.cpp - -check: _api.so api.py +check: _api.so api/__init__.py $(PYTHON) test_binding.py @PHONY: all clean check diff --git a/newbinding/capsule.py b/newbinding/capsule.py index e29948d..d98a23d 100644 --- a/newbinding/capsule.py +++ b/newbinding/capsule.py @@ -182,7 +182,7 @@ def downcast(obj, cls): fname = 'downcast_%s_to_%s' % (fromty, toty) fname = fname.replace('::', '_') try: - caster = getattr(_api, fname) + caster = getattr(_api.downcast, fname) except AttributeError: fmt = "Downcast from %s to %s is not supported" raise TypeError(fmt % (fromty, toty)) diff --git a/newbinding/gen/binding.py b/newbinding/gen/binding.py index c1e1d1e..601ac6e 100644 --- a/newbinding/gen/binding.py +++ b/newbinding/gen/binding.py @@ -1,19 +1,157 @@ import inspect, textwrap import functools import codegen as cg +import os _rank = 0 namespaces = {} RESERVED = frozenset(['None']) -class Namespace(object): - def __init__(self, name): - self.name = name +def makedir(directory): + if not os.path.exists(directory): + os.makedirs(directory) + +class SubModule(object): + def __init__(self): + self.methods = [] self.enums = [] self.classes = [] - self.functions = [] + self.namespaces = [] + self.attrs = [] self.includes = set() + + def aggregate_includes(self): + includes = set(self.includes) + for unit in self.iter_all(): + if isinstance(unit, SubModule): + includes |= unit.aggregate_includes() + else: + includes |= unit.includes + return includes + + def aggregate_downcast(self): + dclist = [] + for cls in self.classes: + for bcls in cls.downcastables: + from_to = bcls.fullname, cls.fullname + name = 'downcast_%s_to_%s' % tuple(map(cg.mangle, from_to)) + fn = Function(namespaces[''], name, ptr(cls), ptr(bcls)) + dclist.append((from_to, fn)) + for ns in self.namespaces: + dclist.extend(ns.aggregate_downcast()) + return dclist + + def iter_all(self): + for fn in self.methods: + yield fn + for cls in self.classes: + yield cls + for enum in self.enums: + yield enum + for attr in self.attrs: + yield attr + for ns in self.namespaces: + yield ns + + + def generate_method_table(self, println): + writer = cg.CppCodeWriter(println) + writer.println('static') + writer.println('PyMethodDef meth_%s[] = {' % cg.mangle(self.fullname)) + with writer.indent(): + fmt = '{ "%(name)s", (PyCFunction)%(func)s, METH_VARARGS, NULL },' + for meth in self.methods: + name = meth.name + func = meth.c_name + writer.println(fmt % locals()) + for enumkind in self.enums: + for enum in enumkind.value_names: + name = enum + func = enumkind.c_name(enum) + writer.println(fmt % locals()) + for attr in self.attrs: + # getter + name = attr.getter_name + func = attr.getter_c_name + writer.println(fmt % locals()) + # setter + name = attr.setter_name + func = attr.setter_c_name + writer.println(fmt % locals()) + writer.println('{ NULL },') + writer.println('};') + writer.println() + + def generate_downcasts(self, println): + for ((fromty, toty), fn) in self.downcastlist: + name = fn.name + fmt = ''' +static +%(toty)s* %(name)s(%(fromty)s* arg) +{ + return typecast<%(toty)s>::from(arg); +} + ''' + println(fmt % locals()) + + fn.generate_cpp(println) + + def generate_cpp(self, println, extras=()): + for unit in self.iter_all(): + unit.generate_cpp(println) + self.generate_method_table(println) + self.generate_submodule_table(println, extras=extras) + + def generate_submodule_table(self, println, extras=()): + writer = cg.CppCodeWriter(println) + writer.println('static') + name = cg.mangle(self.fullname) + writer.println('SubModuleEntry submodule_%(name)s[] = {' % locals()) + with writer.indent(): + for cls in self.classes: + name = cls.name + table = cg.mangle(cls.fullname) + writer.println('{ "%(name)s", meth_%(table)s, NULL },' % + locals()) + for ns in self.namespaces: + name = ns.localname + table = cg.mangle(ns.fullname) + fmt = '{ "%(name)s", meth_%(table)s, submodule_%(table)s },' + writer.println(fmt % locals()) + for name, table in extras: + writer.println('{ "%(name)s", %(table)s, NULL },' % locals()) + writer.println('{ NULL }') + writer.println('};') + writer.println('') + + def generate_py(self, rootdir='.', name=''): + name = name or self.localname + if self.namespaces: # should make new directory + path = os.path.join(rootdir, name) + makedir(path) + filepath = os.path.join(path, '__init__.py') + else: + filepath = os.path.join(rootdir, '%s.py' % name) + with open(filepath, 'w') as pyfile: + println = cg.wrap_println_from_file(pyfile) + println('import _api, capsule') + for ns in self.namespaces: + println('from . import %s' % ns.localname) + println() + for unit in self.iter_all(): + if not isinstance(unit, Namespace): + writer = cg.PyCodeWriter(println) + unit.compile_py(writer) + + for ns in self.namespaces: + ns.generate_py(rootdir=path) + + +class Namespace(SubModule): + def __init__(self, name): + SubModule.__init__(self) + self.name = name namespaces[name] = self def Class(self, *bases): @@ -23,12 +161,12 @@ class Namespace(object): def Function(self, *args): fn = Function(self, *args) - self.functions.append(fn) + self.methods.append(fn) return fn def CustomFunction(self, *args): fn = CustomFunction(self, *args) - self.functions.append(fn) + self.methods.append(fn) return fn def Enum(self, name, *value_names): @@ -36,12 +174,23 @@ class Namespace(object): enum.parent = self enum.name = name self.enums.append(enum) + assert name not in vars(self), 'Duplicated' + setattr(self, name, enum) return enum + def Namespace(self, name): + ns = Namespace('::'.join([self.name, name])) + self.namespaces.append(ns) + return ns + @property def fullname(self): return self.name + @property + def localname(self): + return self.name.rsplit('::', 1)[-1] + def __str__(self): return self.name @@ -80,18 +229,15 @@ ConstCharPtr = BuiltinTypes('const char*') PyObjectPtr = BuiltinTypes('PyObject*') PyObjectPtr.format='O' -class Class(_Type): +class Class(SubModule, _Type): format = 'O' def __init__(self, ns, *bases): + SubModule.__init__(self) self.ns = ns self.bases = bases self._is_defined = False - self.methods = [] self.pymethods = [] - self.enums = [] - self.attrs = [] - self.includes = set() self.downcastables = set() def __call__(self, defn): @@ -110,6 +256,7 @@ class Class(_Type): self.enums.append(v) v.name = k v.parent = self + assert k not in vars(self), "Duplicated: %s" % k setattr(self, k, v) elif isinstance(v, Attr): self.attrs.append(v) @@ -133,43 +280,6 @@ class Class(_Type): self.downcastables.add(i) return self - def compile_cpp(self, writer): - # generate methods - for meth in self.methods: - meth.compile_cpp(writer) - for enum in self.enums: - enum.compile_cpp(writer) - for attr in self.attrs: - attr.compile_cpp(writer) - - # generate method table - writer.println('static') - writer.println('PyMethodDef %s[] = {' % cg.mangle(self.fullname)) - with writer.indent(): - fmt = '{ "%(name)s", (PyCFunction)%(func)s, METH_VARARGS, NULL },' - for meth in self.methods: - name = meth.name - func = meth.c_name - writer.println(fmt % locals()) - for enumkind in self.enums: - for enum in enumkind.value_names: - name = enum - func = enumkind.c_name(enum) - writer.println(fmt % locals()) - for attr in self.attrs: - # getter - name = attr.getter_name - func = attr.getter_c_name - writer.println(fmt % locals()) - # setter - name = attr.setter_name - func = attr.setter_c_name - writer.println(fmt % locals()) - - writer.println('{ NULL },') - writer.println('};') - writer.println() - def compile_py(self, writer): clsname = self.name bases = 'capsule.Wrapper' @@ -256,6 +366,9 @@ class Enum(object): def c_name(self, enum): return cg.mangle("%s_%s_%s" % (self.parent, self.name, enum)) + def generate_cpp(self, println): + self.compile_cpp(cg.CppCodeWriter(println)) + def compile_cpp(self, writer): for enum in self.value_names: with writer.py_function(self.c_name(enum)): @@ -322,6 +435,9 @@ class Method(object): def __str__(self): return self.fullname + def generate_cpp(self, println): + self.compile_cpp(cg.CppCodeWriter(println)) + def compile_cpp(self, writer): with writer.py_function(self.c_name): if len(self.signatures) == 1: @@ -454,9 +570,12 @@ class Function(Method): with writer.function(self.name, varargs='args') as varargs: unwrapped = writer.unwrap_many(varargs) self.process_ownedptr_args(writer, unwrapped) - func = self.name - ret = writer.call('_api.%s' % func, - varargs=unwrapped) + if '::' in self.parent.name: + ns = self.parent.name.split('::', 1)[-1].replace('::', '.') + func = '.'.join([ns, self.name]) + else: + func = self.name + ret = writer.call('_api.%s' % func, varargs=unwrapped) wrapped = writer.wrap(ret, self.is_return_ownedptr()) writer.return_value(wrapped) writer.println() @@ -630,6 +749,7 @@ class Attr(object): def __init__(self, getter, setter): self.getter = getter self.setter = setter + self.includes = set() @property def fullname(self): @@ -658,6 +778,9 @@ class Attr(object): def setter_c_name(self): return cg.mangle('%s_set' % self.fullname) + def generate_cpp(self, println): + self.compile_cpp(cg.CppCodeWriter(println)) + def compile_cpp(self, writer): # getter with writer.py_function(self.getter_c_name): diff --git a/newbinding/gen/codegen.py b/newbinding/gen/codegen.py index 5a31e38..dd499d6 100644 --- a/newbinding/gen/codegen.py +++ b/newbinding/gen/codegen.py @@ -4,6 +4,12 @@ NULL = 'NULL' _symbols = set() +def wrap_println_from_file(file): + def println(s=''): + file.write(s) + file.write('\n') + return println + def indent(println): def _println(s=''): println("%s%s" % (' '* 4, s)) diff --git a/newbinding/gen/gen.py b/newbinding/gen/gen.py index 89399f3..bb7eab3 100644 --- a/newbinding/gen/gen.py +++ b/newbinding/gen/gen.py @@ -14,7 +14,7 @@ PyInit_%(module)s(void) { PyObject *module = create_python_module("%(module)s", %(methtable)s); if (module) { -if (populate_submodules(module, submodules)) +if (populate_submodules(module, submodule_llvm)) return module; } return NULL; @@ -27,7 +27,7 @@ init%(module)s(void) { PyObject *module = create_python_module("%(module)s", %(methtable)s); if (module) { -populate_submodules(module, submodules); +populate_submodules(module, submodule_llvm); } } #endif @@ -49,65 +49,25 @@ def populate_headers(println): println('#include "%s"' % inc) println() - -def wrap_println_from_file(file): - def println(s=''): - file.write(s) - file.write('\n') - return println - def main(): outputfilename = sys.argv[1] entry_modname = sys.argv[2] sys.path += [os.path.dirname(os.curdir)] entry_module = __import__(entry_modname) - units = [] - for ns in namespaces.values(): - print 'namespace', ns - for fn in ns.functions: - print fn - units.append(fn) - for cls in ns.classes: - print cls - units.append(cls) - for enum in ns.enums: - print enum - units.append(enum) - - # add extra stuffs - downcastlist = [] - ## add downcast - for cls in units: - if isinstance(cls, Class): - for bcls in cls.downcastables: - from_to = bcls.fullname, cls.fullname - name = 'downcast_%s_to_%s' % tuple(map(codegen.mangle, from_to)) - fn = Function(namespaces[''], name, ptr(cls), ptr(bcls)) - downcastlist.append((from_to, fn)) - units.append(fn) - + rootns = namespaces['llvm'] # Generate C++ source with open('%s.cpp' % outputfilename, 'w') as cppfile: - println = wrap_println_from_file(cppfile) - - # extra headers - populate_headers(println) - - # required headers - includes = set() - for ns in namespaces.values(): - includes |= ns.includes - for u in units: - includes |= u.includes - - for inc in includes: + println = codegen.wrap_println_from_file(cppfile) + populate_headers(println) # extra headers + # print all includes + for inc in rootns.aggregate_includes(): println('#include "%s"' % inc) println() - - # generate downcast - for ((fromty, toty), fn) in downcastlist: + # print all downcast + downcast_fns = rootns.aggregate_downcast() + for ((fromty, toty), fn) in downcast_fns: name = fn.name fmt = ''' static @@ -117,65 +77,28 @@ static } ''' println(fmt % locals()) + + fn.generate_cpp(println) - # write methods and method tables - for u in units: - writer = codegen.CppCodeWriter(println) - u.compile_cpp(writer) - else: - del writer - - # write function table - writer = codegen.CppCodeWriter(println) - writer.println('static') - writer.println('PyMethodDef methtable[] = {') - with writer.indent(): - fmt = '{ "%(name)s", (PyCFunction)%(func)s, METH_VARARGS, NULL },' - for u in units: - if isinstance(u, Function): - name = u.name - func = u.c_name - writer.println(fmt % locals()) - for u in units: - if isinstance(u, Enum): - for enum in u.value_names: - name = enum - func = u.c_name(enum) - writer.println(fmt % locals()) - - writer.println('{ NULL },') - writer.println('};') - writer.println() - del writer - - - # write submodule table - writer = codegen.CppCodeWriter(println) - writer.println('static') - writer.println('SubModuleEntry submodules[] = {') - with writer.indent(): - for cls in units: - if isinstance(cls, Class): - name = cls.name - table = codegen.mangle(cls.fullname) - writer.println('{ "%(name)s", %(table)s },' % locals()) - writer.println('{ "extra", extra_methodtable },') - writer.println('{ NULL }') - writer.println('};') - writer.println('') - del writer - - println(extension_entry % {'module': '_api', 'methtable': 'methtable'}) + println('static') + println('PyMethodDef downcast_methodtable[] = {') + fmt = '{ "%(name)s", (PyCFunction)%(func)s, METH_VARARGS, NULL },' + for _, fn in downcast_fns: + name = fn.name + func = fn.c_name + println(fmt % locals()) + println('{ NULL }') + println('};') + println() + # generate submodule + rootns.generate_cpp(println, extras=[('extra', 'extra_methodtable'), + ('downcast', 'downcast_methodtable')]) + println(extension_entry % {'module' : '_api', + 'methtable': 'meth_llvm'}) # Generate Python source - with open('%s.py' % outputfilename, 'w') as pyfile: - println = wrap_println_from_file(pyfile) - println('import _api, capsule') - println() - for u in units: - writer = codegen.PyCodeWriter(println) - u.compile_py(writer) - + rootns.generate_py(rootdir='.', name='api') + if __name__ == '__main__': main() diff --git a/newbinding/include/llvm_binding/binding.h b/newbinding/include/llvm_binding/binding.h index 58a8ad0..68af615 100644 --- a/newbinding/include/llvm_binding/binding.h +++ b/newbinding/include/llvm_binding/binding.h @@ -63,13 +63,23 @@ create_python_submodule(PyObject* parent, const char* name, struct SubModuleEntry{ const char* name; PyMethodDef* methtable; + SubModuleEntry* submodule; }; static int populate_submodules(PyObject* parent, SubModuleEntry* entries){ for(SubModuleEntry* iter = entries; iter->name; ++iter){ - if (!create_python_submodule(parent, iter->name, iter->methtable)) + PyObject* submodule = create_python_submodule(parent, + iter->name, + iter->methtable); + if (!submodule){ return 0; + } else if (iter->submodule){ + // Recursively populate submodules + if (!populate_submodules(submodule, iter->submodule)) { + return 0; + } + } } return 1; } diff --git a/newbinding/src/CallingConv.py b/newbinding/src/CallingConv.py index 6d0baea..71b4ad3 100644 --- a/newbinding/src/CallingConv.py +++ b/newbinding/src/CallingConv.py @@ -1,9 +1,8 @@ from binding import * from namespace import llvm -@llvm.Class() # actually a namespace -class CallingConv: - ID = Enum(''' +CallingConv = llvm.Namespace('CallingConv') +ID = CallingConv.Enum('ID', ''' C, Fast, Cold, GHC, FirstTargetCC, X86_StdCall, X86_FastCall, ARM_APCS, ARM_AAPCS, ARM_AAPCS_VFP, MSP430_INTR, X86_ThisCall, PTX_Kernel, PTX_Device, MBLAZE_INTR, MBLAZE_SVOL, SPIR_FUNC, diff --git a/newbinding/src/EngineBuilder.py b/newbinding/src/EngineBuilder.py index 4b68a25..c3feafe 100644 --- a/newbinding/src/EngineBuilder.py +++ b/newbinding/src/EngineBuilder.py @@ -10,9 +10,8 @@ from ADT.Triple import Triple EngineBuilder = llvm.Class() -@llvm.Class() # a fake class (actually a namespace) -class EngineKind: - Kind = Enum('JIT', 'Interpreter') +EngineKind = llvm.Namespace('EngineKind') +Kind = EngineKind.Enum('Kind', 'JIT', 'Interpreter') @EngineBuilder class EngineBuilder: @@ -22,7 +21,7 @@ class EngineBuilder: def _setter(*args): return Method(ref(EngineBuilder), *args) - setEngineKind = _setter(EngineKind.Kind) + setEngineKind = _setter(Kind) setJITMemoryManager = _setter(ptr(JITMemoryManager)) setErrorStr = CustomMethod('EngineBuilder_setErrorStr', diff --git a/newbinding/src/Intrinsics.py b/newbinding/src/Intrinsics.py index 0f1bcb4..5314112 100644 --- a/newbinding/src/Intrinsics.py +++ b/newbinding/src/Intrinsics.py @@ -5,13 +5,12 @@ from Module import Module from Function import Function -Intrinsic = llvm.Class() # fake class (actually a namespace) +Intrinsic = llvm.Namespace('Intrinsic') -@Intrinsic -class Intrinsic: - getDeclaration = CustomStaticMethod('Intrinsic_getDeclaration', - PyObjectPtr, # Function* - ptr(Module), - cast(int, Unsigned), # intrinsic id - PyObjectPtr, # list of Type - ).require_only(2) +getDeclaration = Intrinsic.CustomFunction('getDeclaration', + 'Intrinsic_getDeclaration', + PyObjectPtr, # Function* + ptr(Module), + cast(int, Unsigned), # intrinsic id + PyObjectPtr, # list of Type + ).require_only(2) diff --git a/newbinding/src/Support/CodeGen.py b/newbinding/src/Support/CodeGen.py index 013caa1..3bc6f9d 100644 --- a/newbinding/src/Support/CodeGen.py +++ b/newbinding/src/Support/CodeGen.py @@ -1,20 +1,20 @@ from binding import * from ..namespace import llvm -@llvm.Class() -class Reloc: - Model = Enum('Default', 'Static', 'PIC_', 'DynamicNoPIC') -@llvm.Class() -class CodeModel: - Model = Enum('Default', 'JITDefault', 'Small', 'Kernel', 'Medium', 'Large') +Reloc = llvm.Namespace('Reloc') +Reloc.Enum('Model', + 'Default', 'Static', 'PIC_', 'DynamicNoPIC') -@llvm.Class() -class TLSModel: - Model = Enum('GeneralDynamic', 'LocalDynamic', 'InitialExec', 'LocalExec') +CodeModel = llvm.Namespace('CodeModel') +CodeModel.Enum('Model', + 'Default', 'JITDefault', 'Small', 'Kernel', 'Medium', 'Large') -@llvm.Class() -class CodeGenOpt: - 'Actually a namespace' - Level = Enum('None', 'Less', 'Default', 'Aggressive') +TLSModel = llvm.Namespace('TLSModel') +TLSModel.Enum('Model', + 'GeneralDynamic', 'LocalDynamic', 'InitialExec', 'LocalExec') + +CodeGenOpt = llvm.Namespace('CodeGenOpt') +CodeGenOpt.Enum('Level', + 'None', 'Less', 'Default', 'Aggressive') diff --git a/newbinding/src/Support/DynamicLibrary.py b/newbinding/src/Support/DynamicLibrary.py new file mode 100644 index 0000000..7f661d3 --- /dev/null +++ b/newbinding/src/Support/DynamicLibrary.py @@ -0,0 +1,6 @@ +from binding import * +from ..namespace import sys + +DynamicLibrary = sys.Namespace('DynamicLibrary') +#LoadLibraryPermanently + diff --git a/newbinding/src/Target/TargetLibraryInfo.py b/newbinding/src/Target/TargetLibraryInfo.py index b90c619..d98b00b 100644 --- a/newbinding/src/Target/TargetLibraryInfo.py +++ b/newbinding/src/Target/TargetLibraryInfo.py @@ -6,9 +6,8 @@ from ..ADT.StringRef import StringRef TargetLibraryInfo = llvm.Class(ImmutablePass) -@llvm.Class() -class LibFunc: - Func = Enum(''' +LibFunc = llvm.Namespace('LibFunc') +LibFunc.Enum('Func', ''' ZdaPv, ZdlPv, Znaj, ZnajRKSt9nothrow_t, Znam, ZnamRKSt9nothrow_t, Znwj, ZnwjRKSt9nothrow_t, Znwm, ZnwmRKSt9nothrow_t, cxa_atexit, cxa_guard_abort, diff --git a/newbinding/src/namespace.py b/newbinding/src/namespace.py index 3a081af..f833af8 100644 --- a/newbinding/src/namespace.py +++ b/newbinding/src/namespace.py @@ -1,4 +1,7 @@ from binding import * -llvm = Namespace('llvm') default = Namespace('') + +llvm = Namespace('llvm') +sys = llvm.Namespace('sys') + From 6eae24bcf3966471dc8404805af5c609a331642c Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 8 Feb 2013 18:10:52 -0600 Subject: [PATCH 259/516] Set default namespace to top-level C++ namespace. --- newbinding/gen/binding.py | 58 +++++++------ newbinding/gen/gen.py | 16 ++-- newbinding/test_binding.py | 170 ++++++++++++++++++------------------- 3 files changed, 124 insertions(+), 120 deletions(-) diff --git a/newbinding/gen/binding.py b/newbinding/gen/binding.py index 601ac6e..51620a8 100644 --- a/newbinding/gen/binding.py +++ b/newbinding/gen/binding.py @@ -83,19 +83,19 @@ class SubModule(object): writer.println('};') writer.println() - def generate_downcasts(self, println): - for ((fromty, toty), fn) in self.downcastlist: - name = fn.name - fmt = ''' -static -%(toty)s* %(name)s(%(fromty)s* arg) -{ - return typecast<%(toty)s>::from(arg); -} - ''' - println(fmt % locals()) - - fn.generate_cpp(println) +# def generate_downcasts(self, println): +# for ((fromty, toty), fn) in self.downcastlist: +# name = fn.name +# fmt = ''' +#static +#%(toty)s* %(name)s(%(fromty)s* arg) +#{ +# return typecast< %(toty)s >::from(arg); +#} +# ''' +# println(fmt % locals()) +# +# fn.generate_cpp(println) def generate_cpp(self, println, extras=()): for unit in self.iter_all(): @@ -151,7 +151,7 @@ static class Namespace(SubModule): def __init__(self, name): SubModule.__init__(self) - self.name = name + self.name = name = name.lstrip(':') namespaces[name] = self def Class(self, *bases): @@ -187,6 +187,10 @@ class Namespace(SubModule): def fullname(self): return self.name + @property + def py_name(self): + return self.name.replace('::', '.') + @property def localname(self): return self.name.rsplit('::', 1)[-1] @@ -313,6 +317,11 @@ class Class(SubModule, _Type): name = self.name return '::'.join([self.ns.fullname, name]) + @property + def py_name(self): + ns = self.ns.name.split('::') + return '.'.join(ns + [self.name]) + def __str__(self): return self.fullname @@ -323,7 +332,7 @@ class Class(SubModule, _Type): writer.die_if_false(raw) ptrty = ptr(self).fullname ty = self.fullname - fmt = 'typecast<%(ty)s >::from(%(raw)s)' + fmt = 'typecast< %(ty)s >::from(%(raw)s)' casted = writer.declare(ptrty, fmt % locals()) writer.die_if_false(casted) return casted @@ -385,7 +394,7 @@ class Enum(object): else: k = v fmt = '%(k)s = %(p)s.%(v)s()' - p = '.'.join(['_api'] + self.parent.fullname.split('::')[1:]) + p = '.'.join(['_api'] + self.parent.fullname.split('::')) writer.println(fmt % locals()) writer.println() @@ -415,7 +424,7 @@ class Method(object): @property def fullname(self): - return '::'.join([self.parent.fullname, self.realname]) + return '::'.join([self.parent.fullname, self.realname]).lstrip(':') @property def realname(self): @@ -472,8 +481,7 @@ class Method(object): writer.release_ownership(unwrap_this) unwrapped = writer.unwrap_many(varargs) self.process_ownedptr_args(writer, unwrapped) - - func = '.'.join([self.parent.name, self.name]) + func = '.'.join([self.parent.py_name, self.name]) ret = writer.call('_api.%s' % func, args=(unwrap_this,), varargs=unwrapped) @@ -537,7 +545,7 @@ class StaticMethod(Method): unwrapped = writer.unwrap_many(varargs) self.process_ownedptr_args(writer, unwrapped) - func = '.'.join([self.parent.name, self.name]) + func = '.'.join([self.parent.py_name, self.name]) ret = writer.call('_api.%s' % func, varargs=unwrapped) wrapped = writer.wrap(ret, self.is_return_ownedptr()) writer.return_value(wrapped) @@ -570,11 +578,7 @@ class Function(Method): with writer.function(self.name, varargs='args') as varargs: unwrapped = writer.unwrap_many(varargs) self.process_ownedptr_args(writer, unwrapped) - if '::' in self.parent.name: - ns = self.parent.name.split('::', 1)[-1].replace('::', '.') - func = '.'.join([ns, self.name]) - else: - func = self.name + func = '.'.join([self.parent.py_name, self.name]) ret = writer.call('_api.%s' % func, varargs=unwrapped) wrapped = writer.wrap(ret, self.is_return_ownedptr()) writer.return_value(wrapped) @@ -603,7 +607,7 @@ class Destructor(Method): writer.return_value(None) def compile_py(self, writer): - func = '.'.join([self.parent.name, self.name]) + func = '.'.join([self.parent.py_name, self.name]) writer.println('_delete_ = _api.%s' % func) @@ -799,7 +803,7 @@ class Attr(object): def compile_py(self, writer): name = self.name - parent = '.'.join(self.parent.fullname.split('::')[1:]) + parent = '.'.join(self.parent.fullname.split('::')) getter = '.'.join([parent, self.getter_name]) setter = '.'.join([parent, self.setter_name]) writer.println('@property') diff --git a/newbinding/gen/gen.py b/newbinding/gen/gen.py index bb7eab3..c5d30de 100644 --- a/newbinding/gen/gen.py +++ b/newbinding/gen/gen.py @@ -12,9 +12,9 @@ extern "C" { PyObject * PyInit_%(module)s(void) { -PyObject *module = create_python_module("%(module)s", %(methtable)s); +PyObject *module = create_python_module("%(module)s", meth_%(ns)s); if (module) { -if (populate_submodules(module, submodule_llvm)) +if (populate_submodules(module, submodule_%(ns)s)) return module; } return NULL; @@ -25,9 +25,9 @@ return NULL; PyMODINIT_FUNC init%(module)s(void) { -PyObject *module = create_python_module("%(module)s", %(methtable)s); +PyObject *module = create_python_module("%(module)s", meth_%(ns)s); if (module) { -populate_submodules(module, submodule_llvm); +populate_submodules(module, submodule_%(ns)s); } } #endif @@ -55,7 +55,7 @@ def main(): sys.path += [os.path.dirname(os.curdir)] entry_module = __import__(entry_modname) - rootns = namespaces['llvm'] + rootns = namespaces[''] # Generate C++ source with open('%s.cpp' % outputfilename, 'w') as cppfile: @@ -73,7 +73,7 @@ def main(): static %(toty)s* %(name)s(%(fromty)s* arg) { - return typecast<%(toty)s>::from(arg); + return typecast< %(toty)s >::from(arg); } ''' println(fmt % locals()) @@ -93,8 +93,8 @@ static # generate submodule rootns.generate_cpp(println, extras=[('extra', 'extra_methodtable'), ('downcast', 'downcast_methodtable')]) - println(extension_entry % {'module' : '_api', - 'methtable': 'meth_llvm'}) + println(extension_entry % {'module' : '_api', + 'ns' : ''}) # Generate Python source rootns.generate_py(rootdir='.', name='api') diff --git a/newbinding/test_binding.py b/newbinding/test_binding.py index 9003f7d..7fa5e2c 100644 --- a/newbinding/test_binding.py +++ b/newbinding/test_binding.py @@ -1,22 +1,22 @@ -import api +from api import llvm import extra import _capsule from StringIO import StringIO -api.capsule.set_debug(True) +llvm.capsule.set_debug(True) def test_basic_jit_use(): - api.InitializeNativeTarget() - api.InitializeNativeTargetAsmPrinter() - context = api.getGlobalContext() + llvm.InitializeNativeTarget() + llvm.InitializeNativeTargetAsmPrinter() + context = llvm.getGlobalContext() - m = api.Module.new("modname", context) + m = llvm.Module.new("modname", context) print m.getModuleIdentifier() m.setModuleIdentifier('modname2') print m.getModuleIdentifier() print 'endianness', m.getEndianness() - assert m.getEndianness() == api.Module.Endianness.AnyEndianness + assert m.getEndianness() == llvm.Module.Endianness.AnyEndianness print 'pointer-size', m.getPointerSize() - assert m.getPointerSize() == api.Module.PointerSize.AnyPointerSize + assert m.getPointerSize() == llvm.Module.PointerSize.AnyPointerSize m.dump() @@ -25,21 +25,21 @@ def test_basic_jit_use(): print os.str() - int1ty = api.Type.getInt1Ty(context) + int1ty = llvm.Type.getInt1Ty(context) int1ty.dump() assert int1ty.isIntegerTy(1) - fnty = api.FunctionType.get(int1ty, False) + fnty = llvm.FunctionType.get(int1ty, False) fnty.dump() - types = [api.Type.getIntNTy(context, 8), api.Type.getIntNTy(context, 32)] - fnty = api.FunctionType.get(api.Type.getIntNTy(context, 8), types, False) + types = [llvm.Type.getIntNTy(context, 8), llvm.Type.getIntNTy(context, 32)] + fnty = llvm.FunctionType.get(llvm.Type.getIntNTy(context, 8), types, False) print fnty const = m.getOrInsertFunction("foo", fnty) - fn = const._downcast(api.Function) + fn = const._downcast(llvm.Function) print fn assert fn.hasName() assert 'foo' == fn.getName() @@ -58,10 +58,10 @@ def test_basic_jit_use(): assert isinstance(fn_uselist, list) assert len(fn_uselist) == 0 - builder = api.IRBuilder.new(context) + builder = llvm.IRBuilder.new(context) print builder - bb = api.BasicBlock.Create(context, "entry", fn, None) + bb = llvm.BasicBlock.Create(context, "entry", fn, None) assert bb.empty() builder.SetInsertPoint(bb) @@ -83,23 +83,23 @@ def test_basic_jit_use(): print m # verifier - action = api.VerifierFailureAction.ReturnStatusAction + action = llvm.VerifierFailureAction.ReturnStatusAction - corrupted = api.verifyFunction(fn, action) + corrupted = llvm.verifyFunction(fn, action) assert not corrupted - corrupted = api.verifyModule(m, action, errio) + corrupted = llvm.verifyModule(m, action, errio) print corrupted assert not corrupted, errio.getvalue() # build pass manager - pmb = api.PassManagerBuilder.new() + pmb = llvm.PassManagerBuilder.new() pmb.OptLevel = 3 assert pmb.OptLevel == 3 - pmb.LibraryInfo = api.TargetLibraryInfo.new() - pmb.Inliner = api.createFunctionInliningPass() + pmb.LibraryInfo = llvm.TargetLibraryInfo.new() + pmb.Inliner = llvm.createFunctionInliningPass() - fpm = api.FunctionPassManager.new(m) - pm = api.PassManager.new() + fpm = llvm.FunctionPassManager.new(m) + pm = llvm.PassManager.new() pmb.populateFunctionPassManager(fpm) pmb.populateModulePassManager(pm) @@ -114,14 +114,14 @@ def test_basic_jit_use(): # build engine - ee = api.ExecutionEngine.createJIT(m, errio) + ee = llvm.ExecutionEngine.createJIT(m, errio) print ee, errio.getvalue() print ee.getDataLayout().getStringRepresentation() datalayout_str = 'e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64' - assert datalayout_str == str(api.DataLayout.new(datalayout_str)) - assert datalayout_str == str(api.DataLayout.new(str(api.DataLayout.new(datalayout_str)))) + assert datalayout_str == str(llvm.DataLayout.new(datalayout_str)) + assert datalayout_str == str(llvm.DataLayout.new(str(llvm.DataLayout.new(datalayout_str)))) fn2 = ee.FindFunctionNamed(fn.getName()) assert fn2 is fn @@ -129,8 +129,8 @@ def test_basic_jit_use(): assert ee.getPointerToFunction(fn) assert ee.getPointerToNamedFunction('printf') - gv0 = api.GenericValue.CreateInt(arg0.getType(), 12, False) - gv1 = api.GenericValue.CreateInt(arg1.getType(), -32, True) + gv0 = llvm.GenericValue.CreateInt(arg0.getType(), 12, False) + gv1 = llvm.GenericValue.CreateInt(arg1.getType(), -32, True) assert gv0.valueIntWidth() == arg0.getType().getIntegerBitWidth() assert gv1.valueIntWidth() == arg1.getType().getIntegerBitWidth() @@ -138,7 +138,7 @@ def test_basic_jit_use(): assert gv0.toUnsignedInt() == 12 assert gv1.toSignedInt() == -32 - gv1 = api.GenericValue.CreateInt(arg1.getType(), 32, False) + gv1 = llvm.GenericValue.CreateInt(arg1.getType(), 32, False) gvR = ee.runFunction(fn, (gv0, gv1)) @@ -146,13 +146,13 @@ def test_basic_jit_use(): # write bitcode bc_buffer = StringIO() - api.WriteBitcodeToFile(m, bc_buffer) + llvm.WriteBitcodeToFile(m, bc_buffer) bc = bc_buffer.getvalue() bc_buffer.close() # read bitcode errbuf = StringIO() - m2 = api.ParseBitCodeFile(bc, context, errbuf) + m2 = llvm.ParseBitCodeFile(bc, context, errbuf) if not m2: raise Exception(errbuf.getvalue()) else: @@ -160,35 +160,35 @@ def test_basic_jit_use(): assert str(m2) == str(m) # parse llvm ir - m3 = api.ParseAssemblyString(str(m), None, api.SMDiagnostic.new(), context) + m3 = llvm.ParseAssemblyString(str(m), None, llvm.SMDiagnostic.new(), context) m3.setModuleIdentifier(m.getModuleIdentifier()) assert str(m3) == str(m) # test clone - m4 = api.CloneModule(m) + m4 = llvm.CloneModule(m) assert m4 is not m assert str(m4) == str(m) def test_engine_builder(): - api.InitializeNativeTarget() - context = api.getGlobalContext() + llvm.InitializeNativeTarget() + context = llvm.getGlobalContext() - m = api.Module.new("modname", context) + m = llvm.Module.new("modname", context) - int32ty = api.Type.getIntNTy(context, 32) - fnty = api.FunctionType.get(int32ty, [int32ty], False) - fn = m.getOrInsertFunction("foo", fnty)._downcast(api.Function) - bb = api.BasicBlock.Create(context, "entry", fn, None) - builder = api.IRBuilder.new(context) + int32ty = llvm.Type.getIntNTy(context, 32) + fnty = llvm.FunctionType.get(int32ty, [int32ty], False) + fn = m.getOrInsertFunction("foo", fnty)._downcast(llvm.Function) + bb = llvm.BasicBlock.Create(context, "entry", fn, None) + builder = llvm.IRBuilder.new(context) builder.SetInsertPoint(bb) builder.CreateRet(fn.getArgumentList()[0]) print fn - eb = api.EngineBuilder.new(m) - eb2 = eb.setEngineKind(api.EngineKind.Kind.JIT) + eb = llvm.EngineBuilder.new(m) + eb2 = eb.setEngineKind(llvm.EngineKind.Kind.JIT) assert eb is eb2 - eb.setOptLevel(api.CodeGenOpt.Level.Aggressive).setUseMCJIT(False) + eb.setOptLevel(llvm.CodeGenOpt.Level.Aggressive).setUseMCJIT(False) tm = eb.selectTarget() @@ -205,7 +205,7 @@ def test_engine_builder(): ee = eb.create(tm) - triple = api.Triple.new('x86_64-unknown-linux') + triple = llvm.Triple.new('x86_64-unknown-linux') assert triple.getArchName() == 'x86_64' assert triple.getVendorName() == 'unknown' assert triple.getOSName() == 'linux' @@ -216,18 +216,18 @@ def test_engine_builder(): print tm.getDataLayout() - pm = api.PassManager.new() - pm.add(api.DataLayout.new(str(tm.getDataLayout()))) - pm.add(api.TargetLibraryInfo.new()) + pm = llvm.PassManager.new() + pm.add(llvm.DataLayout.new(str(tm.getDataLayout()))) + pm.add(llvm.TargetLibraryInfo.new()) # write assembly - pm = api.PassManager.new() - pm.add(api.DataLayout.new(str(tm.getDataLayout()))) + pm = llvm.PassManager.new() + pm.add(llvm.DataLayout.new(str(tm.getDataLayout()))) raw = extra.make_raw_ostream_for_printing() - formatted = api.formatted_raw_ostream.new(raw, False) + formatted = llvm.formatted_raw_ostream.new(raw, False) - cgft = api.TargetMachine.CodeGenFileType.CGFT_AssemblyFile + cgft = llvm.TargetMachine.CodeGenFileType.CGFT_AssemblyFile failed = tm.addPassesToEmitFile(pm, formatted, cgft, False) assert not failed @@ -241,17 +241,17 @@ def test_engine_builder(): def test_linker(): - context = api.getGlobalContext() + context = llvm.getGlobalContext() - mA = api.Module.new("modA", context) - mB = api.Module.new("modB", context) + mA = llvm.Module.new("modA", context) + mB = llvm.Module.new("modB", context) def create_function(m, name): - int32ty = api.Type.getIntNTy(context, 32) - fnty = api.FunctionType.get(int32ty, [int32ty], False) - fn = m.getOrInsertFunction(name, fnty)._downcast(api.Function) - bb = api.BasicBlock.Create(context, "entry", fn, None) - builder = api.IRBuilder.new(context) + int32ty = llvm.Type.getIntNTy(context, 32) + fnty = llvm.FunctionType.get(int32ty, [int32ty], False) + fn = m.getOrInsertFunction(name, fnty)._downcast(llvm.Function) + bb = llvm.BasicBlock.Create(context, "entry", fn, None) + builder = llvm.IRBuilder.new(context) builder.SetInsertPoint(bb) builder.CreateRet(fn.getArgumentList()[0]) @@ -259,8 +259,8 @@ def test_linker(): create_function(mB, 'bar') errmsg = StringIO() - linkermode = api.Linker.LinkerMode.PreserveSource - failed = api.Linker.LinkModules(mA, mB, linkermode, errmsg) + linkermode = llvm.Linker.LinkerMode.PreserveSource + failed = llvm.Linker.LinkModules(mA, mB, linkermode, errmsg) assert not failed, errmsg.getvalue() assert mA.getFunction('foo') assert mA.getFunction('bar') @@ -269,14 +269,14 @@ def test_linker(): mA.getFunction('bar')]) def test_structtype(): - context = api.getGlobalContext() - m = api.Module.new("modname", context) + context = llvm.getGlobalContext() + m = llvm.Module.new("modname", context) assert m.getTypeByName("truck") is None - truck = api.StructType.create(context, "truck") + truck = llvm.StructType.create(context, "truck") assert 'type opaque' in str(truck) - elemtys = [api.Type.getInt32Ty(context), api.Type.getDoubleTy(context)] + elemtys = [llvm.Type.getInt32Ty(context), llvm.Type.getDoubleTy(context)] truck.setBody(elemtys) assert 'i32' in str(truck) @@ -285,13 +285,13 @@ def test_structtype(): assert m.getTypeByName("truck") is truck def test_globalvariable(): - context = api.getGlobalContext() - m = api.Module.new("modname", context) + context = llvm.getGlobalContext() + m = llvm.Module.new("modname", context) - ty = api.Type.getInt32Ty(context) - LinkageTypes = api.GlobalVariable.LinkageTypes + ty = llvm.Type.getInt32Ty(context) + LinkageTypes = llvm.GlobalVariable.LinkageTypes linkage = LinkageTypes.ExternalLinkage - gvar = api.GlobalVariable.new(m, ty, False, linkage, None, "apple") + gvar = llvm.GlobalVariable.new(m, ty, False, linkage, None, "apple") assert '@apple = external global i32' in str(m) gvar2 = m.getNamedGlobal('apple') @@ -301,30 +301,30 @@ def test_globalvariable(): def test_sequentialtypes(): - context = api.getGlobalContext() - int32ty = api.Type.getInt32Ty(context) - ary_int32x4 = api.ArrayType.get(int32ty, 4) + context = llvm.getGlobalContext() + int32ty = llvm.Type.getInt32Ty(context) + ary_int32x4 = llvm.ArrayType.get(int32ty, 4) assert '[4 x i32]' == str(ary_int32x4) - ptr_int32 = api.PointerType.get(int32ty, 1) + ptr_int32 = llvm.PointerType.get(int32ty, 1) assert 'i32 addrspace(1)*' == str(ptr_int32) - vec_int32x4 = api.VectorType.get(int32ty, 4) + vec_int32x4 = llvm.VectorType.get(int32ty, 4) assert '<4 x i32>' == str(vec_int32x4) def test_constants(): - context = api.getGlobalContext() - int32ty = api.Type.getInt32Ty(context) - ary_int32x4 = api.ArrayType.get(int32ty, 4) - intconst = api.ConstantInt.get(int32ty, 123) - aryconst = api.ConstantArray.get(ary_int32x4, [intconst] * 4) + context = llvm.getGlobalContext() + int32ty = llvm.Type.getInt32Ty(context) + ary_int32x4 = llvm.ArrayType.get(int32ty, 4) + intconst = llvm.ConstantInt.get(int32ty, 123) + aryconst = llvm.ConstantArray.get(ary_int32x4, [intconst] * 4) assert str(aryconst.getAggregateElement(0)) == str(intconst) def test_intrinsic(): - context = api.getGlobalContext() - m = api.Module.new("modname", context) + context = llvm.getGlobalContext() + m = llvm.Module.new("modname", context) INTR_SIN = 1652 - floatty = api.Type.getFloatTy(context) - fn = api.Intrinsic.getDeclaration(m, INTR_SIN, [floatty]) + floatty = llvm.Type.getFloatTy(context) + fn = llvm.Intrinsic.getDeclaration(m, INTR_SIN, [floatty]) assert 'llvm.sin.f32' in str(fn) fn.eraseFromParent() assert 'llvm.sin.f32' not in str(m) From 355332d6d848ec162ffcdaed9e70d52ef5915efb Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 8 Feb 2013 18:12:07 -0600 Subject: [PATCH 260/516] Add NVPTX components --- newbinding/setup.py | 22 ++++++++++++++++------ newbinding/src/Support/TargetSelect.py | 21 ++++++++++++++++----- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/newbinding/setup.py b/newbinding/setup.py index 6e2ceb5..bb23c32 100644 --- a/newbinding/setup.py +++ b/newbinding/setup.py @@ -26,12 +26,22 @@ macros = [('__STDC_CONSTANT_MACROS', None), extra_link_args = ldflags.split() -libs_core, objs_core = get_libs_and_objs(['core', 'analysis', 'scalaropts', - 'executionengine', 'jit', 'native', - 'interpreter', 'bitreader', - 'bitwriter', 'instrumentation', 'ipa', - 'ipo', 'transformutils', 'asmparser', - 'linker', 'support', 'vectorize']) +components = ['core', 'analysis', 'scalaropts', + 'executionengine', 'jit', 'native', + 'interpreter', 'bitreader', + 'bitwriter', 'instrumentation', 'ipa', + 'ipo', 'transformutils', 'asmparser', + 'linker', 'support', 'vectorize', + ] + +nvptx = ['nvptx', + 'nvptxasmprinter', + 'nvptxcodegen', + 'nvptxdesc', + 'nvptxinfo'] + +libs_core, objs_core = get_libs_and_objs(components + nvptx) + ext_modules = [Extension(name='_api', sources=['api.cpp'], diff --git a/newbinding/src/Support/TargetSelect.py b/newbinding/src/Support/TargetSelect.py index 208ef4b..ca97c24 100644 --- a/newbinding/src/Support/TargetSelect.py +++ b/newbinding/src/Support/TargetSelect.py @@ -1,17 +1,28 @@ from binding import * -from ..namespace import llvm +from ..namespace import llvm, default llvm.includes.add('llvm/Support/TargetSelect.h') InitializeNativeTarget = llvm.Function('InitializeNativeTarget') -#llvm.Function('InitializeAllTargets') - InitializeNativeTargetAsmPrinter = llvm.Function( 'InitializeNativeTargetAsmPrinter', cast(Bool, bool)) - InitializeNativeTargetAsmParser = llvm.Function( 'InitializeNativeTargetAsmParser', cast(Bool, bool)) - InitializeNativeTargetDisassembler = llvm.Function( 'InitializeNativeTargetDisassembler', cast(Bool, bool)) + +#InitializeAllTargets = llvm.Function('InitializeAllTargets') +#InitializeAllTargetInfos = llvm.Function('InitializeAllTargetInfos') +#InitializeAllTargetMCs = llvm.Function('InitializeAllTargetMCs') +#InitializeAllAsmPrinters = llvm.Function('InitializeAllAsmPrinters') + +#LLVMInitializePTXTarget = default.Function('LLVMInitializePTXTarget') +#LLVMInitializePTXTargetInfo = default.Function('LLVMInitializePTXTargetInfo') +#LLVMInitializePTXTargetMC = default.Function('LLVMInitializePTXTargetMC') +#LLVMInitializePTXAsmPrinter = default.Function('LLVMInitializePTXAsmPrinter') + +LLVMInitializeNVPTXTarget = default.Function('LLVMInitializeNVPTXTarget') +LLVMInitializeNVPTXTargetInfo = default.Function('LLVMInitializeNVPTXTargetInfo') +LLVMInitializeNVPTXTargetMC = default.Function('LLVMInitializeNVPTXTargetMC') +LLVMInitializeNVPTXAsmPrinter = default.Function('LLVMInitializeNVPTXAsmPrinter') From c66dad7ecede9cf6c5224711dc1485605633320d Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 8 Feb 2013 18:12:36 -0600 Subject: [PATCH 261/516] Implement commandline namespace --- newbinding/src/Support/CommandLine.py | 12 ++++++++++++ newbinding/src/namespace.py | 5 ++--- 2 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 newbinding/src/Support/CommandLine.py diff --git a/newbinding/src/Support/CommandLine.py b/newbinding/src/Support/CommandLine.py new file mode 100644 index 0000000..2a114f7 --- /dev/null +++ b/newbinding/src/Support/CommandLine.py @@ -0,0 +1,12 @@ +from binding import * +from src.namespace import cl + +cl.includes.add('llvm/Support/CommandLine.h') + +ParseEnvironmentOptions = cl.Function('ParseEnvironmentOptions', + Void, + cast(str, ConstCharPtr), # progName + cast(str, ConstCharPtr), # envvar + cast(str, ConstCharPtr), # overiew = 0 + ).require_only(2) + diff --git a/newbinding/src/namespace.py b/newbinding/src/namespace.py index f833af8..8ad62a3 100644 --- a/newbinding/src/namespace.py +++ b/newbinding/src/namespace.py @@ -1,7 +1,6 @@ from binding import * default = Namespace('') - -llvm = Namespace('llvm') +llvm = default.Namespace('llvm') sys = llvm.Namespace('sys') - +cl = llvm.Namespace('cl') From 60336d1c5fe9fc897e1c5899131e663f7a3f1a6d Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 8 Feb 2013 18:12:51 -0600 Subject: [PATCH 262/516] Add DynamicLibrary and InlineFunction --- newbinding/include/llvm_binding/extra.h | 26 ++++++++++++++++++++++ newbinding/src/Support/DynamicLibrary.py | 26 ++++++++++++++++++++-- newbinding/src/Transforms/Utils/Cloning.py | 15 ++++++++++++- 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h index 75739de..d045d5c 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/extra.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -747,3 +748,28 @@ PyObject* IRBuilder_CreateAggregateRet(llvm::IRBuilder<>* builder, return pycapsule_new(inst, "llvm::Value", "llvm:ReturnInst"); } +static +PyObject* DynamicLibrary_LoadLibraryPermanently(const char * Filename, + PyObject* ErrMsg = 0) +{ + using namespace llvm::sys; + bool failed; + if (ErrMsg) { + std::string errmsg; + failed = DynamicLibrary::LoadLibraryPermanently(Filename, &errmsg); + if (failed) { + if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) { + return NULL; + } + } + } else { + failed = DynamicLibrary::LoadLibraryPermanently(Filename); + } + + if (failed) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } +} + diff --git a/newbinding/src/Support/DynamicLibrary.py b/newbinding/src/Support/DynamicLibrary.py index 7f661d3..7dce97a 100644 --- a/newbinding/src/Support/DynamicLibrary.py +++ b/newbinding/src/Support/DynamicLibrary.py @@ -1,6 +1,28 @@ from binding import * from ..namespace import sys +from ..ADT.StringRef import StringRef -DynamicLibrary = sys.Namespace('DynamicLibrary') -#LoadLibraryPermanently +DynamicLibrary = sys.Class() + +@DynamicLibrary +class DynamicLibrary: + _include_ = 'llvm/Support/DynamicLibrary.h' + isValid = Method(cast(Bool, bool)) + getAddressOfSymbol = Method(cast(VoidPtr, int), cast(str, ConstCharPtr)) + + LoadPermanentLibrary = CustomStaticMethod( + 'DynamicLibrary_LoadLibraryPermanently', + PyObjectPtr, # bool --- failed? + cast(str, ConstCharPtr), # filename + PyObjectPtr, # std::string * errmsg = 0 + ).require_only(1) + + SearchForAddressOfSymbol = StaticMethod(cast(VoidPtr, int), # address + cast(str, ConstCharPtr), # symName + ) + + AddSymbol = StaticMethod(Void, + cast(str, StringRef), # symbolName + cast(int, VoidPtr), # address + ) diff --git a/newbinding/src/Transforms/Utils/Cloning.py b/newbinding/src/Transforms/Utils/Cloning.py index c7f7a86..1971177 100644 --- a/newbinding/src/Transforms/Utils/Cloning.py +++ b/newbinding/src/Transforms/Utils/Cloning.py @@ -1,8 +1,21 @@ from binding import * from src.namespace import llvm from src.Module import Module +from src.Instruction import CallInst llvm.includes.add('llvm/Transforms/Utils/Cloning.h') + +@llvm.Class() +class InlineFunctionInfo: + new = Constructor() + delete = Destructor() + + CloneModule = llvm.Function('CloneModule', ptr(Module), ptr(Module)) - +InlineFunction = llvm.Function('InlineFunction', + cast(Bool, bool), # bool --- failed + ptr(CallInst), + ref(InlineFunctionInfo), + cast(bool, Bool), # insert lifetime = true + ).require_only(2) From 8700bbc4f16192f84d77989ecc5ef0ab640d3bdf Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 8 Feb 2013 18:13:16 -0600 Subject: [PATCH 263/516] Fix segfault on exit --- newbinding/include/llvm_binding/binding.h | 1 + 1 file changed, 1 insertion(+) diff --git a/newbinding/include/llvm_binding/binding.h b/newbinding/include/llvm_binding/binding.h index 68af615..b5c5b48 100644 --- a/newbinding/include/llvm_binding/binding.h +++ b/newbinding/include/llvm_binding/binding.h @@ -57,6 +57,7 @@ create_python_submodule(PyObject* parent, const char* name, if (-1 == PyModule_AddObject(parent, name, submod)) { return NULL; } + Py_INCREF(submod); // otherwise, it would segfault on exit return submod; } From 1fb6b05715f4eba36583e2210d1a58e555b5a121 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 8 Feb 2013 18:13:45 -0600 Subject: [PATCH 264/516] Finished wrapper in llvm.core --- .gitignore | 3 + llvm/__init__.py | 11 + llvm/core.py | 2196 +++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 1980 insertions(+), 230 deletions(-) diff --git a/.gitignore b/.gitignore index 6d0cc2b..6d6296f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,7 @@ build _build *.pyc +*.so /llvm/_intrinsic_ids.py +llvm_ +newbinding/api/* \ No newline at end of file diff --git a/llvm/__init__.py b/llvm/__init__.py index e69de29..23f3f4d 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -0,0 +1,11 @@ +class Wrapper(object): + def __init__(self, ptr): + self.__ptr = ptr + + @property + def _ptr(self): + return self.__ptr + + +def _extract_ptrs(objs): + return [x._ptr for x in objs] diff --git a/llvm/core.py b/llvm/core.py index 0bf99fd..6d5f0d1 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -2,6 +2,9 @@ try: from cStringIO import StringIO except ImportError: from StringIO import StringIO +import contextlib + +import llvm import api @@ -9,248 +12,263 @@ import api # Enumerations #===----------------------------------------------------------------------=== -# type kinds (LLVMTypeKind enum) -TYPE_VOID = 0 -TYPE_HALF = 1 -TYPE_FLOAT = 2 -TYPE_DOUBLE = 3 -TYPE_X86_FP80 = 4 -TYPE_FP128 = 5 -TYPE_PPC_FP128 = 6 -TYPE_LABEL = 7 -TYPE_INTEGER = 8 -TYPE_FUNCTION = 9 -TYPE_STRUCT = 10 -TYPE_ARRAY = 11 -TYPE_POINTER = 12 -TYPE_VECTOR = 13 -TYPE_METADATA = 14 -TYPE_X86_MMX = 15 +# type id (llvm::Type::TypeID) +TYPE_VOID = api.llvm.Type.TypeID.VoidTyID +TYPE_HALF = api.llvm.Type.TypeID.HalfTyID +TYPE_FLOAT = api.llvm.Type.TypeID.FloatTyID +TYPE_DOUBLE = api.llvm.Type.TypeID.DoubleTyID +TYPE_X86_FP80 = api.llvm.Type.TypeID.X86_FP80TyID +TYPE_FP128 = api.llvm.Type.TypeID.FP128TyID +TYPE_PPC_FP128 = api.llvm.Type.TypeID.PPC_FP128TyID +TYPE_LABEL = api.llvm.Type.TypeID.LabelTyID +TYPE_INTEGER = api.llvm.Type.TypeID.IntegerTyID +TYPE_FUNCTION = api.llvm.Type.TypeID.FunctionTyID +TYPE_STRUCT = api.llvm.Type.TypeID.StructTyID +TYPE_ARRAY = api.llvm.Type.TypeID.ArrayTyID +TYPE_POINTER = api.llvm.Type.TypeID.PointerTyID +TYPE_VECTOR = api.llvm.Type.TypeID.VectorTyID +TYPE_METADATA = api.llvm.Type.TypeID.MetadataTyID +TYPE_X86_MMX = api.llvm.Type.TypeID.X86_MMXTyID # value IDs (llvm::Value::ValueTy enum) -VALUE_ARGUMENT = 0 -VALUE_BASIC_BLOCK = 1 -VALUE_FUNCTION = 2 -VALUE_GLOBAL_ALIAS = 3 -VALUE_GLOBAL_VARIABLE = 4 -VALUE_UNDEF_VALUE = 5 -VALUE_BLOCK_ADDRESS = 6 -VALUE_CONSTANT_EXPR = 7 -VALUE_CONSTANT_AGGREGATE_ZERO = 8 -VALUE_CONSTANT_DATA_ARRAY = 9 -VALUE_CONSTANT_DATA_VECTOR = 10 -VALUE_CONSTANT_INT = 11 -VALUE_CONSTANT_FP = 12 -VALUE_CONSTANT_ARRAY = 13 -VALUE_CONSTANT_STRUCT = 14 -VALUE_CONSTANT_VECTOR = 15 -VALUE_CONSTANT_POINTER_NULL = 16 -VALUE_MD_NODE = 17 -VALUE_MD_STRING = 18 -VALUE_INLINE_ASM = 19 -VALUE_PSEUDO_SOURCE_VALUE = 20 -VALUE_FIXED_STACK_PSEUDO_SOURCE_VALUE = 21 -VALUE_INSTRUCTION = 22 +# According to the doxygen docs, it is not a good idea to use these enums. +# There are more values than those declared. +VALUE_ARGUMENT = api.llvm.Value.ValueTy.ArgumentVal +VALUE_BASIC_BLOCK = api.llvm.Value.ValueTy.BasicBlockVal +VALUE_FUNCTION = api.llvm.Value.ValueTy.FunctionVal +VALUE_GLOBAL_ALIAS = api.llvm.Value.ValueTy.GlobalAliasVal +VALUE_GLOBAL_VARIABLE = api.llvm.Value.ValueTy.GlobalVariableVal +VALUE_UNDEF_VALUE = api.llvm.Value.ValueTy.UndefValueVal +VALUE_BLOCK_ADDRESS = api.llvm.Value.ValueTy.BlockAddressVal +VALUE_CONSTANT_EXPR = api.llvm.Value.ValueTy.ConstantExprVal +VALUE_CONSTANT_AGGREGATE_ZERO = api.llvm.Value.ValueTy.ConstantAggregateZeroVal +VALUE_CONSTANT_DATA_ARRAY = api.llvm.Value.ValueTy.ConstantDataArrayVal +VALUE_CONSTANT_DATA_VECTOR = api.llvm.Value.ValueTy.ConstantDataVectorVal +VALUE_CONSTANT_INT = api.llvm.Value.ValueTy.ConstantIntVal +VALUE_CONSTANT_FP = api.llvm.Value.ValueTy.ConstantFPVal +VALUE_CONSTANT_ARRAY = api.llvm.Value.ValueTy.ConstantArrayVal +VALUE_CONSTANT_STRUCT = api.llvm.Value.ValueTy.ConstantStructVal +VALUE_CONSTANT_VECTOR = api.llvm.Value.ValueTy.ConstantVectorVal +VALUE_CONSTANT_POINTER_NULL = api.llvm.Value.ValueTy.ConstantPointerNullVal +VALUE_MD_NODE = api.llvm.Value.ValueTy.MDNodeVal +VALUE_MD_STRING = api.llvm.Value.ValueTy.MDStringVal +VALUE_INLINE_ASM = api.llvm.Value.ValueTy.InlineAsmVal +VALUE_PSEUDO_SOURCE_VALUE = api.llvm.Value.ValueTy.PseudoSourceValueVal +VALUE_FIXED_STACK_PSEUDO_SOURCE_VALUE = api.llvm.Value.ValueTy.FixedStackPseudoSourceValueVal +VALUE_INSTRUCTION = api.llvm.Value.ValueTy.InstructionVal -# instruction opcodes (from include/llvm/Instruction.def) -OPCODE_RET = 1 -OPCODE_BR = 2 -OPCODE_SWITCH = 3 -OPCODE_INDIRECT_BR = 4 -OPCODE_INVOKE = 5 -OPCODE_RESUME = 6 -OPCODE_UNREACHABLE = 7 -OPCODE_ADD = 8 -OPCODE_FADD = 9 -OPCODE_SUB = 10 -OPCODE_FSUB = 11 -OPCODE_MUL = 12 -OPCODE_FMUL = 13 -OPCODE_UDIV = 14 -OPCODE_SDIV = 15 -OPCODE_FDIV = 16 -OPCODE_UREM = 17 -OPCODE_SREM = 18 -OPCODE_FREM = 19 -OPCODE_SHL = 20 -OPCODE_LSHR = 21 -OPCODE_ASHR = 22 -OPCODE_AND = 23 -OPCODE_OR = 24 -OPCODE_XOR = 25 -OPCODE_ALLOCA = 26 -OPCODE_LOAD = 27 -OPCODE_STORE = 28 -OPCODE_GETELEMENTPTR = 29 -OPCODE_FENCE = 30 -OPCODE_ATOMICCMPXCHG = 31 -OPCODE_ATOMICRMW = 32 -OPCODE_TRUNC = 33 -OPCODE_ZEXT = 34 -OPCODE_SEXT = 35 -OPCODE_FPTOUI = 36 -OPCODE_FPTOSI = 37 -OPCODE_UITOFP = 38 -OPCODE_SITOFP = 39 -OPCODE_FPTRUNC = 40 -OPCODE_FPEXT = 41 -OPCODE_PTRTOINT = 42 -OPCODE_INTTOPTR = 43 -OPCODE_BITCAST = 44 -OPCODE_ICMP = 45 -OPCODE_FCMP = 46 -OPCODE_PHI = 47 -OPCODE_CALL = 48 -OPCODE_SELECT = 49 -OPCODE_USEROP1 = 50 -OPCODE_USEROP2 = 51 -OPCODE_VAARG = 52 -OPCODE_EXTRACTELEMENT = 53 -OPCODE_INSERTELEMENT = 54 -OPCODE_SHUFFLEVECTOR = 55 -OPCODE_EXTRACTVALUE = 56 -OPCODE_INSERTVALUE = 57 -OPCODE_LANDINGPAD = 58 +## instruction opcodes (from include/llvm/Instruction.def) +#OPCODE_RET = 1 +#OPCODE_BR = 2 +#OPCODE_SWITCH = 3 +#OPCODE_INDIRECT_BR = 4 +#OPCODE_INVOKE = 5 +#OPCODE_RESUME = 6 +#OPCODE_UNREACHABLE = 7 +#OPCODE_ADD = 8 +#OPCODE_FADD = 9 +#OPCODE_SUB = 10 +#OPCODE_FSUB = 11 +#OPCODE_MUL = 12 +#OPCODE_FMUL = 13 +#OPCODE_UDIV = 14 +#OPCODE_SDIV = 15 +#OPCODE_FDIV = 16 +#OPCODE_UREM = 17 +#OPCODE_SREM = 18 +#OPCODE_FREM = 19 +#OPCODE_SHL = 20 +#OPCODE_LSHR = 21 +#OPCODE_ASHR = 22 +#OPCODE_AND = 23 +#OPCODE_OR = 24 +#OPCODE_XOR = 25 +#OPCODE_ALLOCA = 26 +#OPCODE_LOAD = 27 +#OPCODE_STORE = 28 +#OPCODE_GETELEMENTPTR = 29 +#OPCODE_FENCE = 30 +#OPCODE_ATOMICCMPXCHG = 31 +#OPCODE_ATOMICRMW = 32 +#OPCODE_TRUNC = 33 +#OPCODE_ZEXT = 34 +#OPCODE_SEXT = 35 +#OPCODE_FPTOUI = 36 +#OPCODE_FPTOSI = 37 +#OPCODE_UITOFP = 38 +#OPCODE_SITOFP = 39 +#OPCODE_FPTRUNC = 40 +#OPCODE_FPEXT = 41 +#OPCODE_PTRTOINT = 42 +#OPCODE_INTTOPTR = 43 +#OPCODE_BITCAST = 44 +#OPCODE_ICMP = 45 +#OPCODE_FCMP = 46 +#OPCODE_PHI = 47 +#OPCODE_CALL = 48 +#OPCODE_SELECT = 49 +#OPCODE_USEROP1 = 50 +#OPCODE_USEROP2 = 51 +#OPCODE_VAARG = 52 +#OPCODE_EXTRACTELEMENT = 53 +#OPCODE_INSERTELEMENT = 54 +#OPCODE_SHUFFLEVECTOR = 55 +#OPCODE_EXTRACTVALUE = 56 +#OPCODE_INSERTVALUE = 57 +#OPCODE_LANDINGPAD = 58 +# +## calling conventions +#CC_C = 0 +#CC_FASTCALL = 8 +#CC_COLDCALL = 9 +#CC_GHC = 10 +#CC_X86_STDCALL = 64 +#CC_X86_FASTCALL = 65 +#CC_ARM_APCS = 66 +#CC_ARM_AAPCS = 67 +#CC_ARM_AAPCS_VFP = 68 +#CC_MSP430_INTR = 69 +#CC_X86_THISCALL = 70 +#CC_PTX_KERNEL = 71 +#CC_PTX_DEVICE = 72 +#CC_MBLAZE_INTR = 73 +#CC_MBLAZE_SVOL = 74 +# +# +## int predicates +#ICMP_EQ = 32 +#ICMP_NE = 33 +#ICMP_UGT = 34 +#ICMP_UGE = 35 +#ICMP_ULT = 36 +#ICMP_ULE = 37 +#ICMP_SGT = 38 +#ICMP_SGE = 39 +#ICMP_SLT = 40 +#ICMP_SLE = 41 +# +## same as ICMP_xx, for backward compatibility +#IPRED_EQ = ICMP_EQ +#IPRED_NE = ICMP_NE +#IPRED_UGT = ICMP_UGT +#IPRED_UGE = ICMP_UGE +#IPRED_ULT = ICMP_ULT +#IPRED_ULE = ICMP_ULE +#IPRED_SGT = ICMP_SGT +#IPRED_SGE = ICMP_SGE +#IPRED_SLT = ICMP_SLT +#IPRED_SLE = ICMP_SLE +# +## real predicates +#FCMP_FALSE = 0 +#FCMP_OEQ = 1 +#FCMP_OGT = 2 +#FCMP_OGE = 3 +#FCMP_OLT = 4 +#FCMP_OLE = 5 +#FCMP_ONE = 6 +#FCMP_ORD = 7 +#FCMP_UNO = 8 +#FCMP_UEQ = 9 +#FCMP_UGT = 10 +#FCMP_UGE = 11 +#FCMP_ULT = 12 +#FCMP_ULE = 13 +#FCMP_UNE = 14 +#FCMP_TRUE = 15 +# +## real predicates +#RPRED_FALSE = FCMP_FALSE +#RPRED_OEQ = FCMP_OEQ +#RPRED_OGT = FCMP_OGT +#RPRED_OGE = FCMP_OGE +#RPRED_OLT = FCMP_OLT +#RPRED_OLE = FCMP_OLE +#RPRED_ONE = FCMP_ONE +#RPRED_ORD = FCMP_ORD +#RPRED_UNO = FCMP_UNO +#RPRED_UEQ = FCMP_UEQ +#RPRED_UGT = FCMP_UGT +#RPRED_UGE = FCMP_UGE +#RPRED_ULT = FCMP_ULT +#RPRED_ULE = FCMP_ULE +#RPRED_UNE = FCMP_UNE +#RPRED_TRUE = FCMP_TRUE +# +## linkages (see llvm-c/Core.h) +#LINKAGE_EXTERNAL = 0 +#LINKAGE_AVAILABLE_EXTERNALLY = 1 +#LINKAGE_LINKONCE_ANY = 2 +#LINKAGE_LINKONCE_ODR = 3 +#LINKAGE_WEAK_ANY = 4 +#LINKAGE_WEAK_ODR = 5 +#LINKAGE_APPENDING = 6 +#LINKAGE_INTERNAL = 7 +#LINKAGE_PRIVATE = 8 +#LINKAGE_DLLIMPORT = 9 +#LINKAGE_DLLEXPORT = 10 +#LINKAGE_EXTERNAL_WEAK = 11 +#LINKAGE_GHOST = 12 +#LINKAGE_COMMON = 13 +#LINKAGE_LINKER_PRIVATE = 14 +#LINKAGE_LINKER_PRIVATE_WEAK = 15 +#LINKAGE_LINKER_PRIVATE_WEAK_DEF_AUTO = 16 +# +## visibility (see llvm/GlobalValue.h) +#VISIBILITY_DEFAULT = 0 +#VISIBILITY_HIDDEN = 1 +#VISIBILITY_PROTECTED = 2 -# calling conventions -CC_C = 0 -CC_FASTCALL = 8 -CC_COLDCALL = 9 -CC_GHC = 10 -CC_X86_STDCALL = 64 -CC_X86_FASTCALL = 65 -CC_ARM_APCS = 66 -CC_ARM_AAPCS = 67 -CC_ARM_AAPCS_VFP = 68 -CC_MSP430_INTR = 69 -CC_X86_THISCALL = 70 -CC_PTX_KERNEL = 71 -CC_PTX_DEVICE = 72 -CC_MBLAZE_INTR = 73 -CC_MBLAZE_SVOL = 74 +# parameter attributes llvm::Attributes::AttrVal (see llvm/Attributes.h) +ATTR_NONE = api.llvm.Attributes.AttrVal.None_ +ATTR_ZEXT = api.llvm.Attributes.AttrVal.ZExt +ATTR_SEXT = api.llvm.Attributes.AttrVal.SExt +ATTR_NO_RETURN = api.llvm.Attributes.AttrVal.NoReturn +ATTR_IN_REG = api.llvm.Attributes.AttrVal.InReg +ATTR_STRUCT_RET = api.llvm.Attributes.AttrVal.StructRet +ATTR_NO_UNWIND = api.llvm.Attributes.AttrVal.NoUnwind +ATTR_NO_ALIAS = api.llvm.Attributes.AttrVal.NoAlias +ATTR_BY_VAL = api.llvm.Attributes.AttrVal.ByVal +ATTR_NEST = api.llvm.Attributes.AttrVal.Nest +ATTR_READ_NONE = api.llvm.Attributes.AttrVal.ReadNone +ATTR_READONLY = api.llvm.Attributes.AttrVal.ReadOnly +ATTR_NO_INLINE = api.llvm.Attributes.AttrVal.NoInline +ATTR_ALWAYS_INLINE = api.llvm.Attributes.AttrVal.AlwaysInline +ATTR_OPTIMIZE_FOR_SIZE = api.llvm.Attributes.AttrVal.OptimizeForSize +ATTR_STACK_PROTECT = api.llvm.Attributes.AttrVal.StackProtect +ATTR_STACK_PROTECT_REQ = api.llvm.Attributes.AttrVal.StackProtectReq +ATTR_ALIGNMENT = api.llvm.Attributes.AttrVal.Alignment +ATTR_NO_CAPTURE = api.llvm.Attributes.AttrVal.NoCapture +ATTR_NO_REDZONE = api.llvm.Attributes.AttrVal.NoRedZone +ATTR_NO_IMPLICIT_FLOAT = api.llvm.Attributes.AttrVal.NoImplicitFloat +ATTR_NAKED = api.llvm.Attributes.AttrVal.Naked +ATTR_INLINE_HINT = api.llvm.Attributes.AttrVal.InlineHint +ATTR_STACK_ALIGNMENT = api.llvm.Attributes.AttrVal.StackAlignment -# int predicates -ICMP_EQ = 32 -ICMP_NE = 33 -ICMP_UGT = 34 -ICMP_UGE = 35 -ICMP_ULT = 36 -ICMP_ULE = 37 -ICMP_SGT = 38 -ICMP_SGE = 39 -ICMP_SLT = 40 -ICMP_SLE = 41 +class Module(llvm.Wrapper): + """A Module instance stores all the information related to an LLVM module. -# same as ICMP_xx, for backward compatibility -IPRED_EQ = ICMP_EQ -IPRED_NE = ICMP_NE -IPRED_UGT = ICMP_UGT -IPRED_UGE = ICMP_UGE -IPRED_ULT = ICMP_ULT -IPRED_ULE = ICMP_ULE -IPRED_SGT = ICMP_SGT -IPRED_SGE = ICMP_SGE -IPRED_SLT = ICMP_SLT -IPRED_SLE = ICMP_SLE + Modules are the top level container of all other LLVM Intermediate + Representation (IR) objects. Each module directly contains a list of + globals variables, a list of functions, a list of libraries (or + other modules) this module depends on, a symbol table, and various + data about the target's characteristics. -# real predicates -FCMP_FALSE = 0 -FCMP_OEQ = 1 -FCMP_OGT = 2 -FCMP_OGE = 3 -FCMP_OLT = 4 -FCMP_OLE = 5 -FCMP_ONE = 6 -FCMP_ORD = 7 -FCMP_UNO = 8 -FCMP_UEQ = 9 -FCMP_UGT = 10 -FCMP_UGE = 11 -FCMP_ULT = 12 -FCMP_ULE = 13 -FCMP_UNE = 14 -FCMP_TRUE = 15 + Construct a Module only using the static methods defined below, *NOT* + using the constructor. A correct usage is: -# real predicates -RPRED_FALSE = FCMP_FALSE -RPRED_OEQ = FCMP_OEQ -RPRED_OGT = FCMP_OGT -RPRED_OGE = FCMP_OGE -RPRED_OLT = FCMP_OLT -RPRED_OLE = FCMP_OLE -RPRED_ONE = FCMP_ONE -RPRED_ORD = FCMP_ORD -RPRED_UNO = FCMP_UNO -RPRED_UEQ = FCMP_UEQ -RPRED_UGT = FCMP_UGT -RPRED_UGE = FCMP_UGE -RPRED_ULT = FCMP_ULT -RPRED_ULE = FCMP_ULE -RPRED_UNE = FCMP_UNE -RPRED_TRUE = FCMP_TRUE - -# linkages (see llvm-c/Core.h) -LINKAGE_EXTERNAL = 0 -LINKAGE_AVAILABLE_EXTERNALLY = 1 -LINKAGE_LINKONCE_ANY = 2 -LINKAGE_LINKONCE_ODR = 3 -LINKAGE_WEAK_ANY = 4 -LINKAGE_WEAK_ODR = 5 -LINKAGE_APPENDING = 6 -LINKAGE_INTERNAL = 7 -LINKAGE_PRIVATE = 8 -LINKAGE_DLLIMPORT = 9 -LINKAGE_DLLEXPORT = 10 -LINKAGE_EXTERNAL_WEAK = 11 -LINKAGE_GHOST = 12 -LINKAGE_COMMON = 13 -LINKAGE_LINKER_PRIVATE = 14 -LINKAGE_LINKER_PRIVATE_WEAK = 15 -LINKAGE_LINKER_PRIVATE_WEAK_DEF_AUTO = 16 - -# visibility (see llvm/GlobalValue.h) -VISIBILITY_DEFAULT = 0 -VISIBILITY_HIDDEN = 1 -VISIBILITY_PROTECTED = 2 - -# parameter attributes (see llvm/Attributes.h) -ATTR_NONE = 0 -ATTR_ZEXT = 1 -ATTR_SEXT = 2 -ATTR_NO_RETURN = 4 -ATTR_IN_REG = 8 -ATTR_STRUCT_RET = 16 -ATTR_NO_UNWIND = 32 -ATTR_NO_ALIAS = 64 -ATTR_BY_VAL = 128 -ATTR_NEST = 256 -ATTR_READ_NONE = 512 -ATTR_READONLY = 1024 -ATTR_NO_INLINE = 1<<11 -ATTR_ALWAYS_INLINE = 1<<12 -ATTR_OPTIMIZE_FOR_SIZE = 1<<13 -ATTR_STACK_PROTECT = 1<<14 -ATTR_STACK_PROTECT_REQ = 1<<15 -ATTR_ALIGNMENT = 1<<16 -ATTR_NO_CAPTURE = 1<<21 -ATTR_NO_REDZONE = 1<<22 -ATTR_NO_IMPLICIT_FLOAT = 1<<23 -ATTR_NAKED = 1<<24 -ATTR_INLINE_HINT = 1<<25 -ATTR_STACK_ALIGNMENT = 7<<26 -ATTR_HOTPATCH = 1<<29 - -class Module(object): + module_obj = Module.new('my_module') + """ @staticmethod def new(id): """Create a new Module instance. Creates an instance of Module, having the id `id'. """ - context = api.getGlobalContext() - m = api.Module.new(id, context) + context = api.llvm.getGlobalContext() + m = api.llvm.Module.new(id, context) return Module(m) @staticmethod @@ -266,14 +284,1732 @@ class Module(object): else: bc = fileobj_or_str.read() errbuf = StringIO() - m = api.ParseBitCodeFile(bc, context, errbuf) + m = api.llvm.ParseBitCodeFile(bc, context, errbuf) if not m: raise Exception(errbuf.getvalue()) errbuf.close() return Module(m) - def __init__(self, ptr): - self.ptr = ptr + + @staticmethod + def from_assembly(fileobj_or_str): + """Create a Module instance from the contents of an LLVM + assembly (.ll) file. + + + fileobj_or_str -- takes a file-like object or string that contains + a module represented in llvm-ir assembly. + """ + if isinstance(fileobj_or_str, str): + ir = fileobj_or_str + else: + ir = fileobj_or_str.read() + errbuf = StringIO() + m = api.llvm.ParseAssemblyString(ir, None, api.llvm.SMDIagnostic.new(), context) + errbuf.close() + return Module(m) + + def __str__(self): + """Text representation of a module. + + Returns the textual representation (`llvm assembly') of the + module. Use it like this: + + ll = str(module_obj) + print module_obj # same as `print ll' + """ + return str(self.ptr) + + def __eq__(self, rhs): + if isinstance(rhs, Module): + return str(self) == str(rhs) + else: + return False + + def __ne__(self, rhs): + return not (self == rhs) + + + def _get_target(self): + return self.ptr.getTargetTriple() + + def _set_target(self, value): + return self.ptr.setTargetTriple(value) + + target = property(_get_target, _set_target, + doc="The target triple string describing the target host.") + + + def _get_data_layout(self): + return self.ptr.getDataLayout() + + def _set_data_layout(self, value): + return self.ptr.setDataLayout(value) + + data_layout = property(_get_data_layout, _set_data_layout, + doc = """The data layout string for the module's target platform. + + The data layout strings is an encoded representation of + the type sizes and alignments expected by this module. + """ + ) + + @property + def pointer_size(self): + return self.getPointerSize() + + def link_in(self, other, preserve=False): + """Link the `other' module into this one. + + The `other' module is linked into this one such that types, + global variables, function, etc. are matched and resolved. + + The `other' module is no longer valid after this method is + invoked, all refs to it should be dropped. + + In the future, this API might be replaced with a full-fledged + Linker class. + """ + assert isinstance(other, Module) + enum_mode = api.llvm.Linker.LinkMode + mode = enum_mode.PreserveSource if preserve else enum_mode.DestroySource + + with contextlib.closing(StringIO()) as errmsg: + failed = api.llvm.Linker.LinkModule(self._ptr, + other._ptr, + mode, + errmsg) + if failed: + raise llvm.LLVMException(errmsg) + + def get_type_named(self, name): + typ = self.ptr.getTypeByName(name) + return StructType(typ) + + def add_global_variable(self, ty, name, addrspace=0): + """Add a global variable of given type with given name.""" + external = api.llvm.GlobalVariable.LinkageTypes.ExternalLinkage + notthreadlocal = api.llvm.GlobalVariable.ThreadLocalMode.NotThreadLocal + init = None + insertbefore = None + ptr = api.llvm.GlobalVariable.new(self, + ty._ptr, + False, + external, + init, + name, + insertbefore, + notthreadlocal, + addrspace) + return GlobalVariable(ptr) + + def get_global_variable_named(self, name): + """Return a GlobalVariable object for the given name.""" + ptr = self.ptr.getNamedGlobal(name) + return GlobalVariable(ptr) + + @property + def global_variables(self): + return self.ptr.list_globals() + + def add_function(self, ty, name): + """Add a function of given type with given name.""" + fn = self.get_function_named(name) + if fn is not None: + raise llvm.LLVMException("Duplicated function %s" % name) + return self.get_or_insert_function(ty, name) + + def get_function_named(self, name): + """Return a Function object representing function with given name.""" + fn = self.ptr.getFunction(name) + if fn is None: + return None + return Function(fn) + + def get_or_insert_function(self, ty, name): + """Like get_function_named(), but does add_function() first, if + function is not present.""" + constant = self.ptr.getOrInsertFunction(name, ty._ptr) + fn = constant._downcast(api.llvm.Function) + return Function(fn) + + @property + def functions(self): + """All functions in this module.""" + return map(Function, self.ptr.list_functions()) + + def verify(self): + """Verify module. + + Checks module for errors. Raises `llvm.LLVMException' on any + error.""" + action = api.llvm.VerifierFailureAction.ReturnStatusAction + errio = StringIO() + broken = api.llvm.verifyModule(self.ptr, action, errio) + if broken: + raise llvm.LLVMException(errio.getvalue()) + + def to_bitcode(self, fileobj=None): + """Write bitcode representation of module to given file-like + object. + + fileobj -- A file-like object to where the bitcode is written. + If it is None, the bitcode is returned. + + Return value -- Returns None if fileobj is not None. + Otherwise, return the bitcode as a bytestring. + """ + ret = False + if fileobj is None: + ret = True + fileobj = StringIO + api.llvm.WriteBitcodeToFile(self.ptr, fileobj) + if ret: + return fileobj.getvalue() + + def _get_id(self): + return self.ptr.getModuleIdentifier(self.ptr) + + def _set_id(self, string): + self.ptr.setModuleIdentifier(string) + + id = property(_get_id, _set_id) + + def _to_native_something(self, fileobj, cgft): + ret = False + if fileobj is None: + ret = True + fileobj = StringIO() + cgft = api.llvm.TargetMachine.CodeGenFileType.CGFT_AssemblyFile + cgft = api.llvm.TargetMachine.CodeGenFileType.CGFT_ObjectFile + failed = tm.addPassesToEmitFile(pm, formatted, cgft, False) + if failed: + raise llvm.LLVMException("Failed to write native object file") + if ret: + return fileobj.getvalue() + + + def to_native_object(self, fileobj=None): + '''Outputs the byte string of the module as native object code + + If a fileobj is given, the output is written to it; + Otherwise, the output is returned + ''' + CGFT = api.llvm.TargetMachine.CodeGenFileType + return self._to_native_something(fileobj, CGFT.CGFT_ObjectFile) + + def to_native_assembly(self, fileobj=None): + '''Outputs the byte string of the module as native assembly code + + If a fileobj is given, the output is written to it; + Otherwise, the output is returned + ''' + CGFT = api.llvm.TargetMachine.CodeGenFileType + return self._to_native_something(fileobj, CGFT.CGFT_AssemblyFile) + + def get_or_insert_named_metadata(self, name): + return NamedMetadata(self.ptr.getOrInsertNamedMetadata(name)) + + def get_named_metadata(self, name): + return NamedMetadata(self.ptr.get_named_metadata(name)) + + def clone(self): + return NamedMetadata(api.llvm.CloneModule(self.ptr)) + +class Type(llvm.Wrapper): + """Represents a type, like a 32-bit integer or an 80-bit x86 float. + + Use one of the static methods to create an instance. Example: + ty = Type.double() + """ + + @staticmethod + def int(bits=32): + """Create an integer type having the given bit width.""" + context = api.llvm.getGlobalContext() + ptr = api.llvm.Type.getIntNTy(context, bits) + return Type(ptr) + + @staticmethod + def float(): + """Create a 32-bit floating point type.""" + context = api.llvm.getGlobalContext() + ptr = api.llvm.Type.getFloatTy(context) + return Type(ptr) + + @staticmethod + def double(): + """Create a 64-bit floating point type.""" + context = api.llvm.getGlobalContext() + ptr = api.llvm.Type.getDoubleTy(context) + return Type(ptr) + + @staticmethod + def x86_fp80(): + """Create a 80-bit x86 floating point type.""" + context = api.llvm.getGlobalContext() + ptr = api.llvm.Type.getX86_FP80Ty(context) + return Type(ptr) + + @staticmethod + def fp128(): + """Create a 128-bit floating point type (with 112-bit + mantissa).""" + context = api.llvm.getGlobalContext() + ptr = api.llvm.Type.getFP128Ty(context) + return Type(ptr) + + @staticmethod + def ppc_fp128(): + """Create a 128-bit floating point type (two 64-bits).""" + context = api.llvm.getGlobalContext() + ptr = api.llvm.Type.getPPC_FP128Ty(context) + return Type(ptr) + + + @staticmethod + def function(return_ty, param_tys, var_arg=False): + """Create a function type. + + Creates a function type that returns a value of type + `return_ty', takes arguments of types as given in the iterable + `param_tys'. Set `var_arg' to True (default is False) for a + variadic function.""" + ptr = api.llvm.FunctionType.get(return_ty._ptr, + llvm._extract_ptrs(param_tys), + var_arg) + return FunctionType(ptr) + + @staticmethod + def opaque(name): + """Create a opaque StructType""" + context = api.llvm.getGlobalContext() + ptr = api.llvm.StructType.create(context, name) + return StructType(ptr) + + @staticmethod + def struct(element_tys, name=''): # not packed + """Create a (unpacked) structure type. + + Creates a structure type with elements of types as given in the + iterable `element_tys'. This method creates a unpacked + structure. For a packed one, use the packed_struct() method. + + If name is not '', creates a identified type; + otherwise, creates a literal type.""" + context = api.llvm.getGlobalContext() + is_packed = False + ptr = api.llvm.StructType.create(context) + ptr.setBody(_extract_ptrs(element_tys), is_packed) + return StructType(ptr) + + @staticmethod + def packed_struct(element_tys, name=''): + """Create a (packed) structure type. + + Creates a structure type with elements of types as given in the + iterable `element_tys'. This method creates a packed + structure. For an unpacked one, use the struct() method. + + If name is not '', creates a identified type; + otherwise, creates a literal type.""" + context = api.llvm.getGlobalContext() + is_packed = True + ptr = api.llvm.StructType.create(context) + ptr.setBody(_extract_ptrs(element_tys), is_packed) + return StructType(ptr) + + @staticmethod + def array(element_ty, count): + """Create an array type. + + Creates a type for an array of elements of type `element_ty', + having 'count' elements.""" + ptr = api.llvm.ArrayType.get(element_ty._ptr, count) + return ArrayType(ptr) + + @staticmethod + def pointer(pointee_ty, addr_space=0): + """Create a pointer type. + + Creates a pointer type, which can point to values of type + `pointee_ty', in the address space `addr_space'.""" + ptr = api.llvm.PointerType.get(pointee_ty._ptr, addr_space) + return PointerType(ptr) + + @staticmethod + def vector(element_ty, count): + """Create a vector type. + + Creates a type for a vector of elements of type `element_ty', + having `count' elements.""" + ptr = api.llvm.VectorType.get(element_ty._ptr, count) + return VectorType(ptr) + + @staticmethod + def void(): + """Create a void type. + + Represents the `void' type.""" + context = api.llvm.getGlobalContext() + ptr = api.llvm.Type.getVoidTy(context) + return Type(ptr) + + @staticmethod + def label(): + """Create a label type.""" + context = api.llvm.getGlobalContext() + ptr = api.llvm.Type.getLabelTy(context) + return Type(ptr) + + def __new__(cls, ptr): + tyid = ptr.getTypeID() + + idmap = { + TYPE_HALF: IntegerType, + TYPE_INTEGER: IntegerType, + TYPE_FUNCTION: FunctionType, + TYPE_STRUCT: StructType, + TYPE_ARRAY: ArrayType, + TYPE_POINTER: PointerType, + TYPE_VECTOR: VectorType, + } + + try: + newcls = idmap[tyid] + except KeyError: + newcls = Type + obj = llvm.Wrapper.__new__(newcls) + return obj + + def __str__(self): + return str(self._ptr) + + def __eq__(self, rhs): + return self._ptr is rhs._ptr + + def __ne__(self, rhs): + return not (self == rhs) + +class IntegerType(Type): + """Represents an integer type.""" + + @property + def width(self): + """The width of the integer type, in bits.""" + return self._ptr.getIntegerBitWidth() + +class FunctionType(Type): + """Represents a function type.""" + + @property + def return_type(self): + """The type of the value returned by this function.""" + return Type(self._ptr.getReturnType()) + + @property + def vararg(self): + """True if this function is variadic.""" + return self._ptr.isVarArg() + + @property + def args(self): + """An iterable that yields Type objects, representing the types of the + arguments accepted by this function, in order.""" + tys = [Type(self._ptr.getParamType(i)) for i in range(self.arg_count)] + + @property + def arg_count(self): + """Number of arguments accepted by this function. + + Same as len(obj.args), but faster.""" + return self._ptr.getNumParams() + + + +class StructType(Type): + """Represents a structure type.""" + + @property + def element_count(self): + """Number of elements (members) in the structure. + + Same as len(obj.elements), but faster.""" + return self._ptr.getNumElements() + + @property + def elements(self): + """An iterable that yields Type objects, representing the types of the + elements (members) of the structure, in order.""" + return [Type(self._ptr.getElementType(i)) + for i in range(self._ptr.getNumElements())] + + def set_body(self, elems, packed=False): + """Filled the body of a opaque type. + """ + # check + if not self.is_opaque: + raise llvm.LLVMException("Body is already defined.") + + self._ptr.setBody(llvm._extract_ptrs(elems), packed) + + @property + def packed(self): + """True if the structure is packed, False otherwise.""" + return self._ptr.isPacked() + + def _set_name(self, name): + self._ptr.setName(name) + + def _get_name(self): + return self._ptr.getName() + + name = property(_get_name, _set_name) + + @property + def is_literal(self): + return self.isLiteral() + + @property + def is_identified(self): + return not self.is_literal() + + @property + def is_opaque(self): + return self.isOpaque() + +class ArrayType(Type): + """Represents an array type.""" + + @property + def element(self): + return Type(self._ptr.getArrayElementType()) + + @property + def count(self): + return self._ptr.getNumElements() + +class PointerType(Type): + + @property + def pointee(self): + return Type(self._ptr.getPointerElementType()) + + @property + def address_space(self): + return self._ptr.getAddressSpace() + +class VectorType(Type): + + @property + def element(self): + return self._ptr.getVectorElementType() + + @property + def count(self): + return self._ptr.getNumElements() + +class Value(llvm.Wrapper): + + def __str__(self): + return str(self._ptr) + + def __eq__(self, rhs): + if isinstance(rhs, Value): + return str(self) == str(rhs) + else: + return False + + def __ne__(self, rhs): + return not self == rhs + + def _get_name(self): + return self._ptr.getName() + + def _set_name(self, value): + return self._ptr.setName(value) + + name = property(_get_name, _set_name) + + @property + def value_id(self): + return self._ptr.getValueID() + + @property + def type(self): + return Type(self._ptr.getType()) + + @property + def use_count(self): + return self._ptr.getNumUses() + + @property + def uses(self): + return map(User, self._ptr.list_use()) + +class User(Value): + + @property + def operand_count(self): + return self._ptr.getNumOperands() + + @property + def operands(self): + """Yields operands of this instruction.""" + return [Value(self._ptr.getOperand(i)) + for i in range(self.operand_count)] + + def _get_operand(self, i): + return _make_value(_core.LLVMUserGetOperand(self.ptr, i)) + +class Constant(User): + + @staticmethod + def null(ty): + return Value(api.llvm.Constant.getNullValue(ty._ptr)) + + @staticmethod + def all_ones(ty): + return Value(api.llvm.Constant.getAllOnesValue(ty._ptr)) + + @staticmethod + def undef(ty): + return Value(api.llvm.UndefValue.get(ty._ptr)) + + @staticmethod + def int(ty, value): + return Value(api.llvm.ConstantInt.get(ty._ptr, value, False)) + + @staticmethod + def int_signextend(ty, value): + return Value(api.llvm.ConstantInt.get(ty._ptr, value, True)) + + @staticmethod + def real(ty, value): + return Value(api.llvm.ConstantFP.get(ty._ptr, value)) + + @staticmethod + def string(strval): # dont_null_terminate=True + return Value(api.llvm.ConstantDataArray.getString(strval, False)) + + @staticmethod + def stringz(strval): # dont_null_terminate=False + return Value(api.llvm.ConstantDataArray.getString(strval, True)) + + @staticmethod + def array(ty, consts): + return Value(api.llvm.ConstantArray.get(ty._ptr, consts)) + + @staticmethod + def struct(consts): # not packed + return Value(api.llvm.ConstantStruct.getAnon(llvm._extract_ptrs(consts), + False)) + + @staticmethod + def packed_struct(consts): + return Value(api.llvm.ConstantStruct.getAnon(llvm._extract_ptrs(consts), + False)) + + @staticmethod + def vector(consts): + return Value(api.llvm.ConstantVector.get(llvm._extract_ptrs(consts))) + + @staticmethod + def sizeof(ty): + return Value(api.llvm.ConstantExpr.getSizeOf(ty._ptr)) + + def neg(self): + return Value(api.llvm.ConstantExpr.getNeg(self._ptr)) + + def not_(self): + return Value(api.llvm.ConstantExpr.getNot(self._ptr)) + + def add(self, rhs): + return Value(api.llvm.ConstantExpr.getAdd(self._ptr, rhs._ptr)) + + def fadd(self, rhs): + return Value(api.llvm.ConstantExpr.getFAdd(self._ptr, rhs._ptr)) + + def sub(self, rhs): + return Value(api.llvm.ConstantExpr.getSub(self._ptr, rhs._ptr)) + + def fsub(self, rhs): + return Value(api.llvm.ConstantExpr.getFSub(self._ptr, rhs._ptr)) + + def mul(self, rhs): + return Value(api.llvm.ConstantExpr.getMul(self._ptr, rhs._ptr)) + + def fmul(self, rhs): + return Value(api.llvm.ConstantExpr.getFMul(self._ptr, rhs._ptr)) + + def udiv(self, rhs): + return Value(api.llvm.ConstantExpr.getUDiv(self._ptr, rhs._ptr)) + + def sdiv(self, rhs): + return Value(api.llvm.ConstantExpr.getSDiv(self._ptr, rhs._ptr)) + + def fdiv(self, rhs): + return Value(api.llvm.ConstantExpr.getFDiv(self._ptr, rhs._ptr)) + + def urem(self, rhs): + return Value(api.llvm.ConstantExpr.getURem(self._ptr, rhs._ptr)) + + def srem(self, rhs): + return Value(api.llvm.ConstantExpr.getSRem(self._ptr, rhs._ptr)) + + def frem(self, rhs): + return Value(api.llvm.ConstantExpr.getFRem(self._ptr, rhs._ptr)) + + def and_(self, rhs): + return Value(api.llvm.ConstantExpr.getAnd(self._ptr, rhs._ptr)) + + def or_(self, rhs): + return Value(api.llvm.ConstantExpr.getOr(self._ptr, rhs._ptr)) + + def xor(self, rhs): + return Value(api.llvm.ConstantExpr.getXor(self._ptr, rhs._ptr)) + + def icmp(self, int_pred, rhs): + return Value(api.llvm.ConstantExpr.getICmp(int_pred, self._ptr, rhs._ptr)) + + def fcmp(self, real_pred, rhs): + return Value(api.llvm.ConstantExpr.getFCmp(real_pred, self._ptr, rhs._ptr)) + + def shl(self, rhs): + return Value(api.llvm.ConstantExpr.getShl(self._ptr, rhs._ptr)) + + def lshr(self, rhs): + return Value(api.llvm.ConstantExpr.getLShr(self._ptr, rhs._ptr)) + + def ashr(self, rhs): + return Value(api.llvm.ConstantExpr.getAShr(self._ptr, rhs._ptr)) + + def gep(self, indices): + indices = llvm._extract_ptrs(indices) + return Value(api.llvm.ConstantExpr.getGetElementPtr(self._ptr, indices)) + + def trunc(self, ty): + return Value(api.llvm.ConstantExpr.getTrunc(self._ptr, ty)) + + def sext(self, ty): + return Value(api.llvm.ConstantExpr.getSExt(self._ptr, ty)) + + def zext(self, ty): + return Value(api.llvm.ConstantExpr.getZExt(self._ptr, ty)) + + def fptrunc(self, ty): + return Value(api.llvm.ConstantExpr.getFPTrunc(self._ptr, ty)) + + def fpext(self, ty): + return Value(api.llvm.ConstantExpr.getFPExtend(self._ptr, ty)) + + def uitofp(self, ty): + return Value(api.llvm.ConstantExpr.getUIToFP(self._ptr, ty)) + + def sitofp(self, ty): + return Value(api.llvm.ConstantExpr.getSIToFP(self._ptr, ty)) + + def fptoui(self, ty): + return Value(api.llvm.ConstantExpr.getFPToUI(self._ptr, ty)) + + def fptosi(self, ty): + return Value(api.llvm.ConstantExpr.getFPToSI(self._ptr, ty)) + + def ptrtoint(self, ty): + return Value(api.llvm.ConstantExpr.getPtrToInt(self._ptr, ty)) + + def inttoptr(self, ty): + return Value(api.llvm.ConstantExpr.getIntToPtr(self._ptr, ty)) + + def bitcast(self, ty): + return Value(api.llvm.ConstantExpr.getBitCast(self._ptr, ty)) + + def select(self, true_const, false_const): + return Value(api.llvm.ConstantExpr.getSelect(self._ptr, + true_const._ptr, + false_const._ptr)) + + def extract_element(self, index): # note: self must be a _vector_ constant + return Value(api.llvm.ConstantExpr.getExtractElement(self._ptr, index._ptr)) + + def insert_element(self, value, index): + return Value(api.llvm.ConstantExpr.getExtractElement(self._ptr, + value._ptr, + index._ptr)) + + def shuffle_vector(self, vector_b, mask): + return Value(api.llvm.ConstantExpr.getShuffleVector(self._ptr, + vector_b._ptr, + mask._ptr)) + +class ConstantExpr(Constant): + @property + def opcode(self): + return self._ptr.getOpcode() + + @property + def opcode_name(self): + return self._ptr.getOpcodeName() + +class ConstantAggregateZero(Constant): + pass + + +class ConstantDataArray(Constant): + pass + + +class ConstantDataVector(Constant): + pass + + +class ConstantInt(Constant): + @property + def z_ext_value(self): + '''Obtain the zero extended value for an integer constant value.''' + # Warning: assertion failure when value does not fit in 64 bits + return self._ptr.getZExtValue() + + @property + def s_ext_value(self): + '''Obtain the sign extended value for an integer constant value.''' + # Warning: assertion failure when value does not fit in 64 bits + return self._ptr.getSExtValue() + + +class ConstantFP(Constant): + pass + + +class ConstantArray(Constant): + pass + + +class ConstantStruct(Constant): + pass + + +class ConstantVector(Constant): + pass + + +class ConstantPointerNull(Constant): + pass + + +class UndefValue(Constant): + pass + + +class GlobalValue(Constant): + + def _get_linkage(self): + return self._ptr.getLinkage() + + def _set_linkage(self, value): + self._ptr.setLinkage(value) + + linkage = property(_get_linkage, _set_linkage) + + def _get_section(self): + return self._ptr.getSection() + + def _set_section(self, value): + return self._ptr.setSection(value) + + section = property(_get_section, _set_section) + + def _get_visibility(self): + return self._ptr.getVisibility() + + def _set_visibility(self, value): + return self._ptr.setVisibility(value) + + visibility = property(_get_visibility, _set_visibility) + + def _get_alignment(self): + return self._ptr.getAlignment() + + def _set_alignment(self, value): + return self._ptr.setAlignment(value) + + alignment = property(_get_alignment, _set_alignment) + + @property + def is_declaration(self): + return self._ptr.isDeclaration() + + @property + def module(self): + return Module(self._ptr.getParent()) + + + +class GlobalVariable(GlobalValue): + + @staticmethod + def new(module, ty, name, addrspace=0): + linkage = api.llvm.GlobalValue.LinkageTypes + external_linkage = linkage.ExternalLinkage + tlmode = api.llvm.GlobalVariable.ThreadLocalMode + not_threadlocal = tlmode.NotThreadLocal + gv = api.llvm.GlobalVariablel.new(module._ptr, + ty._ptr, + False, # is constant + external_linkage, + None, # initializer + name, + None, # insert before + not_threadlocal, + addrspace) + return GlobalVariable(gv) + + @staticmethod + def get(module, name): + gv = GlobalVariable(module._ptr.getNamedGlobal(name)) + if not gv: + llvm.LLVMException("no global named `%s`" % name) + return gv + + def delete(self): + self._ptr.eraseFromParent() + + def _get_initializer(self): + if not self._ptr.hasInitializer(): + return None + return Constant(self._ptr.getInitializer()) + + def _set_initializer(self, const): + self._ptr.setInitializer(const._ptr) + + def _del_initializer(self): + self._ptr.setInitializer(None) + + initializer = property(_get_initializer, _set_initializer) + + def _get_is_global_constant(self): + return self._ptr.isConstant() + + def _set_is_global_constant(self, value): + self._ptr.setConstant(value) + + global_constant = property(_get_is_global_constant, + _set_is_global_constant) + + def _get_thread_local(self): + return self._ptr.isThreadLocal() + + def _set_thread_local(self, value): + return self._ptr.setThreadLocal(value) + + thread_local = property(_get_thread_local, _set_thread_local) + +class Argument(Value): + + def add_attribute(self, attr): + attrbldr = api.llvm.AttrBuilder() + attrbldr.addAttribute(attr) + attrs = api.llvm.Attributes.get(context, attrbldr) + self._ptr.addAttr(attrs) + + def remove_attribute(self, attr): + attrbldr = api.llvm.AttrBuilder() + attrbldr.addAttribute(attr) + attrs = api.llvm.Attributes.get(context, attrbldr) + self._ptr.removeAttr(attrs) + + def _set_alignment(self, align): + attrbldr = api.llvm.AttrBuilder() + attrbldr.addAlignmentAttr(align) + attrs = api.llvm.Attributes.get(context, attrbldr) + self._ptr.addAttr(attrs) + + def _get_alignment(self): + return self._ptr.getParamAlignment() + + alignment = property(_get_alignment, + _set_alignment) + +class Function(GlobalValue): + + @staticmethod + def new(module, func_ty, name): + return module.add_function(func_ty, name) + + @staticmethod + def get_or_insert(module, func_ty, name): + return module.get_or_insert_function(func_ty, name) + + @staticmethod + def get(module, name): + return module.get_function_named(name) + + @staticmethod + def intrinsic(module, intrinsic_id, types): + fn = api.llvm.Intrinsic.getDeclaration(module._ptr, + intrinsic_id, + types) + return Function(fn) + + def delete(self): + self._ptr.eraseFromParent() + + @property + def intrinsic_id(self): + self._ptr.getIntrinsicID() + + def _get_cc(self): + return self._ptr.getCallingConv() + + def _set_cc(self, value): + self._ptr.setCallingConv(value) + + calling_convention = property(_get_cc, _set_cc) + + def _get_coll(self): + return self._ptr.getGC() + + def _set_coll(self, value): + return self._ptr.setGC(value) + + collector = property(_get_coll, _set_coll) + + # the nounwind attribute: + def _get_does_not_throw(self): + return self._ptr.doesNotThrow() + + def _set_does_not_throw(self,value): + assert value + self._ptr.setDoesNotThow() + + does_not_throw = property(_get_does_not_throw, _set_does_not_throw) + + @property + def args(self): + return self._ptr.getArgumentList() + + @property + def basic_block_count(self): + return len(self.basic_blocks) + + @property + def entry_basic_block(self): + return self._ptr.getEntryBlock() + + def append_basic_block(self, name): + context = api.llvm.getGlobalContext() + bb = api.llvm.BasicBlock.Create(context, name, self._ptr, None) + return BasicBlock(bb) + + @property + def basic_blocks(self): + return self._ptr.getBasicBlockList() + + def viewCFG(self): + return self._ptr.viewCFG() + + def add_attribute(self, attr): + _core.LLVMAddFunctionAttr(self.ptr, attr) + + def remove_attribute(self, attr): + attrbldr = api.llvm.AttrBuilder() + attrbldr.addAttribute(attr) + attrs = api.llvm.Attributes.get(context, attrbldr) + self._ptr.removeFnAttr(attrs) + + def viewCFGOnly(self): + return self._ptr.viewCFGOnly() + + def verify(self): + # Although we're just asking LLVM to return the success or + # failure, it appears to print result to stderr and abort. + + # Note: LLVM has a bug in preverifier that will always abort + # the process upon failure. + return api.llvm.verifyFunction() + +#===----------------------------------------------------------------------=== +# InlineAsm +#===----------------------------------------------------------------------=== + +class InlineAsm(Value): + @staticmethod + def get(functype, asm, constrains, side_effect=False, + align_stack=False, dialect=api.llvm.InlineAsm.AsmDialect.AD_ATT): + ilasm = api.llvm.InlineAsm.get(functype._ptr, asm, contrains, side_effect, + align_stack, dialect) + return InlineAsm(ilasm) + +#===----------------------------------------------------------------------=== +# MetaData +#===----------------------------------------------------------------------=== + +class MetaData(Value): + @staticmethod + def get(module, values): + ''' + values -- must be an iterable of Constant or None. None is treated as "null". + ''' + context = api.llvm.getGlobalContext() + ptr = api.llvm.MDNode.get(context, llvm._extract_ptrs(values)) + return MetaData(ptr) + + @staticmethod + def get_named_operands(module, name): + namedmd = module.get_named_metadata(name)._ptr + return [MetaData(namedmd.getOperand(i)) + for i in namedmd.getNumOperands()] + + @staticmethod + def add_named_operand(module, name, operand): + namedmd = module.get_or_insert_named_metadata(name)._ptr + namedmd.addOperand(operand._ptr) + + @property + def operand_count(self): + return self._ptr.getOperand() + + @property + def operands(self): + """Yields operands of this metadata.""" + return [Value(self._ptr.getOperand(i)) for i in self.operand_count] + + +class MetaDataString(Value): + @staticmethod + def get(module, s): + context = api.llvm.getGlobalContext() + ptr = api.llvm.MDString.get(context, s) + return MetaDataString(ptr) + + @property + def string(self): + '''Same as MDString::getString''' + return self._ptr.getString() + + +class NamedMetaData(llvm.Wrapper): + @staticmethod + def get_or_insert(mod, name): + return mod.get_or_insert_named_metadata(name) + + @staticmethod + def get(mod, name): + return mod.get_named_metadata(name) + + def delete(self): + self._ptr.eraseFromParent() + + @property + def name(self): + return self._ptr.getName() + + def __str__(self): + return str(self._ptr) + + def add(self, operand): + self._ptr.addOperand(operand._ptr) + + +#===----------------------------------------------------------------------=== +# Instruction +#===----------------------------------------------------------------------=== + +class Instruction(User): + + @property + def basic_block(self): + return BasicBlock(self._ptr.getParent()) + + @property + def is_terminator(self): + return self._ptr.isTerminator() + + @property + def is_binary_op(self): + return self._ptr.isBinaryOp() + + @property + def is_shift(self): + return self._ptr.isShift() + + @property + def is_cast(self): + return self._ptr.isCast() + + @property + def is_logical_shift(self): + return self._ptr.isLogicalShift() + + @property + def is_arithmetic_shift(self): + return self._ptr.isArithmeticShift() + + @property + def is_associative(self): + return self._ptr.isAssociative() + + @property + def is_commutative(self): + return self._ptr.isCommutative() + + @property + def is_volatile(self): + """True if this is a volatile load or store.""" + if api.llvm.LoadInst.classof(self._ptr): + return self._ptr._downcast(api.llvm.LoadInst).isVolatile() + elif api.llvm.StoreInst.classof(self._ptr): + return self._ptr._downcast(api.llvm.StoreInst).isVolatile() + else: + return False + + def set_volatile(self, flag): + if api.llvm.LoadInst.classof(self._ptr): + return self._ptr._downcast(api.llvm.LoadInst).setVolatile(flag) + elif api.llvm.StoreInst.classof(self._ptr): + return self._ptr._downcast(api.llvm.StoreInst).setVolatile(flag) + else: + return False + + def set_metadata(self, kind, metadata): + self._ptr.setMetadata(kind, metadata._ptr) + + @property + def opcode(self): + return self._ptr.getOpcode() + + @property + def opcode_name(self): + return self._ptr.getOpcodeName() + + def erase_from_parent(self): + return self._ptr.eraseFromParent() + + +class CallOrInvokeInstruction(Instruction): + + def _get_cc(self): + return self._ptr.getCallingConv() + + def _set_cc(self, value): + return self._ptr.setCallingConv(value) + + calling_convention = property(_get_cc, _set_cc) + + def add_parameter_attribute(self, idx, attr): + attrbldr = api.llvm.AttrBuilder() + attrbldr.addAttribute(attr) + attrs = api.llvm.Attributes.get(context, attrbldr) + self._ptr.addAttribute(idx, attrs) + + def remove_parameter_attribute(self, idx, attr): + attrbldr = api.llvm.AttrBuilder() + attrbldr.addAttribute(attr) + attrs = api.llvm.Attributes.get(context, attrbldr) + self._ptr.removeAttribute(idx, attrs) + + def set_parameter_alignment(self, idx, align): + attrbldr = api.llvm.AttrBuilder() + attrbldr.addAlignmentAttr(align) + attrs = api.llvm.Attributes.get(context, attrbldr) + self._ptr.addAttribute(idx, attrs) + + def _get_called_function(self): + function = self._ptr.getCalledFunction() + if function: # Return value can be None on indirect call/invoke + return Value(function) + + def _set_called_function(self, function): + self._ptr.setCalledFunction(function) + + called_function = property(_get_called_function, _set_called_function) + + +class PHINode(Instruction): + + @property + def incoming_count(self): + return self._ptr.getNumIncomingValues() + + def add_incoming(self, value, block): + self._ptr.addIncoming(value._ptr, block._ptr) + + def get_incoming_value(self, idx): + return self._ptr.getIncomingValue(idx) + + def get_incoming_block(self, idx): + return self._ptr.getIncomingBlock(idx) + + +class SwitchInstruction(Instruction): + + def add_case(self, const, bblk): + self._ptr.addCase(const._ptr, bblk._ptr) + + +class CompareInstruction(Instruction): + + @property + def predicate(self): + return self._ptr.getPredicate() + + +#===----------------------------------------------------------------------=== +# Basic block +#===----------------------------------------------------------------------=== + +class BasicBlock(Value): + + def insert_before(self, name): + context = api.llvm.getGlobalContext() + ptr = api.llvm.BasicBlock.Create(context, name, self.function._ptr, + self._ptr) + return BasicBlock(ptr) + + def delete(self): + self._ptr.eraseFromParent() + + @property + def function(self): + return Function(self._ptr.getParent()) + + @property + def instructions(self): + return map(Value, self._ptr.getInstList()) + + +#===----------------------------------------------------------------------=== +# Builder +#===----------------------------------------------------------------------=== + +class Builder(llvm.Wrapper): + + @staticmethod + def new(basic_block): + context = api.llvm.getGlobalContext() + ptr = api.llvm.IRBuilder.new(context) + ptr.SetInsertPoint(basic_block._ptr) + return BasicBlock(ptr) + + def position_at_beginning(self, bblk): + """Position the builder at the beginning of the given block. + + Next instruction inserted will be first one in the block.""" + + # Instruction list won't be long anyway, + # Does not matter much to build a list of all instructions + instrs = bblk._ptr.getInstList() + if instrs: + self.position_before(instrs[0]) + else: + self.position_at_end(bblk) + + def position_at_end(self, bblk): + """Position the builder at the end of the given block. + + Next instruction inserted will be last one in the block.""" + self._ptr.SetInsertPoint(bblk._ptr) + + def position_before(self, instr): + """Position the builder before the given instruction. + + The instruction can belong to a basic block other than the + current one.""" + self._ptr.SetInsertPoint(instr._ptr) + + @property + def basic_block(self): + """The basic block where the builder is positioned.""" + return BasicBlock(self._ptr.GetInsertBlock()) + + # terminator instructions + + def ret_void(self): + return Value(self._ptr.CreateRetVoid()) + + def ret(self, value): + return Value(self._ptr.CreateRet(value._ptr)) + + def ret_many(self, values): + values = llvm._extract_ptrs(values) + return Value(self._ptr.CreateAggregateRet(values, len(values))) + + def branch(self, bblk): + if __debug__: + for instr in self.basic_block.instructions: + assert not instr.is_terminator, "BasicBlock can only have one terminator" + return Value(self._ptr.CreateBr(bblk._ptr)) + + def cbranch(self, if_value, then_blk, else_blk): + return Value(self._ptr.CreateCondBr(if_value._ptr, + then_blk._ptr, + else_blk._ptr)) + + def switch(self, value, else_blk, n=10): + return Value(self._ptr.CreateSwitch(self.value._ptr, + self.else_blk._ptr, + n)) + + def invoke(self, func, args, then_blk, catch_blk, name=""): + return Value(self._ptr.CreateInvoke(self.func._ptr, + self.then_blk._ptr, + self.catch_blk._ptr, + args)) + + def unreachable(self): + return Value(self._ptr.CreateUnreachable()) + + # arithmethic, bitwise and logical + + def add(self, lhs, rhs, name=""): + return Value(self._ptr.CreateAdd(lhs._ptr, rhs._ptr, name)) + + def fadd(self, lhs, rhs, name=""): + return Value(self._ptr.CreateFAdd(lhs._ptr, rhs._ptr, name)) + + def sub(self, lhs, rhs, name=""): + return Value(self._ptr.CreateSub(lhs._ptr, rhs._ptr, name)) + + def fsub(self, lhs, rhs, name=""): + return Value(self._ptr.CreateFSub(lhs._ptr, rhs._ptr, name)) + + def mul(self, lhs, rhs, name=""): + return Value(self._ptr.CreateMul(lhs._ptr, rhs._ptr, name)) + + def fmul(self, lhs, rhs, name=""): + return Value(self._ptr.CreateFMul(lhs._ptr, rhs._ptr, name)) + + def udiv(self, lhs, rhs, name=""): + return Value(self._ptr.CreateUDiv(lhs._ptr, rhs._ptr, name)) + + def sdiv(self, lhs, rhs, name=""): + return Value(self._ptr.CreateSDiv(lhs._ptr, rhs._ptr, name)) + + def fdiv(self, lhs, rhs, name=""): + return Value(self._ptr.CreateFDiv(lhs._ptr, rhs._ptr, name)) + + def urem(self, lhs, rhs, name=""): + return Value(self._ptr.CreateURem(lhs._ptr, rhs._ptr, name)) + + def srem(self, lhs, rhs, name=""): + return Value(self._ptr.CreateSRem(lhs._ptr, rhs._ptr, name)) + + def frem(self, lhs, rhs, name=""): + return Value(self._ptr.CreateFRem(lhs._ptr, rhs._ptr, name)) + + def shl(self, lhs, rhs, name=""): + return Value(self._ptr.CreateShl(lhs._ptr, rhs._ptr, name)) + + def lshr(self, lhs, rhs, name=""): + return Value(self._ptr.CreateLShr(lhs._ptr, rhs._ptr, name)) + + def ashr(self, lhs, rhs, name=""): + return Value(self._ptr.CreateAShr(lhs._ptr, rhs._ptr, name)) + + def and_(self, lhs, rhs, name=""): + return Value(self._ptr.CreateAnd(lhs._ptr, rhs._ptr, name)) + + def or_(self, lhs, rhs, name=""): + return Value(self._ptr.CreateOr(lhs._ptr, rhs._ptr, name)) + + def xor(self, lhs, rhs, name=""): + return Value(self._ptr.CreateXor(lhs._ptr, rhs._ptr, name)) + + def neg(self, val, name=""): + return Value(self._ptr.CreateNeg(val._ptr, name)) + + def not_(self, val, name=""): + return Value(self._ptr.CreateNot(val._ptr, name)) + + # memory + + def malloc(self, ty, name=""): + context = api.llvm.getGlobalContext() + intty = api.llvm.Type.getInt32Ty(context) + sizeof = api.llvm.ConstantExpr.getSizeOf(ty) + zero = api.llvm.ConstantInt.get(intty, 0) + # XXX: how do I know when to insert? + # assume to end of block for now + inst = api.llvm.CallInst.CreateMalloc(self.basic_block._ptr, + intty, + ty._ptr, + sizeof, + zero, + None, + name) + return Value(inst) + + def malloc_array(self, ty, size, name=""): + sizeof = api.llvm.ConstantExpr.getSizeOf(ty) + # XXX: how do I know when to insert? + # assume to end of block for now + inst = api.llvm.CallInst.CreateMalloc(self.basic_block._ptr, + size.type._ptr, + ty._ptr, + sizeof, + size._ptr, + None, + name) + return Value(inst) + + def alloca(self, ty, name=""): + zero = api.llvm.ConstantInt.get(intty, 0) + return Value(self._ptr.CreateAlloca(ty._ptr, zero, name)) + + def alloca_array(self, ty, size, name=""): + return Value(self._ptr.CreateAlloca(ty._ptr, size._ptr, name)) + + def free(self, ptr): + return Value(api.llvm.CallInst.CreateFree(ptr._ptr, self.basic_block._ptr)) + + def load(self, ptr, name="", align=0, volatile=False, invariant=False): + inst = Value(self._ptr.CreateLoad(ptr._ptr, name)) + if align: + inst._ptr.setAlignment(align) + if volatile: + inst.set_volatile(volatile) + if invariant: + mod = self.basic_block.function.module + md = MetaData.get(mod, []) # empty metadata node + inst.set_metadata('invariant.load', md) + return inst + + def store(self, value, ptr, align=0, volatile=False): + inst = Value(self._ptr.CreateStore(value._ptr, ptr._ptr)) + if align: + inst._ptr.setAlignment(align) + if volatile: + inst.set_volatile(volatile) + return inst + + def gep(self, ptr, indices, name="", inbounds=False): + if inbounds: + ret = self._ptr.CreateInBoundsGEP(ptr._ptr, + llvm._extract_ptrs(indices), + name) + else: + ret = self._ptr.CreateGEP(ptr._ptr, + llvm._extract_ptrs(indices), + name) + return Value(ret) + + # casts and extensions + + def trunc(self, value, dest_ty, name=""): + return Value(self._ptr.CreateTrunc(value._ptr, dest_ty._ptr, name)) + + def zext(self, value, dest_ty, name=""): + return Value(self._ptr.CreateZext(value._ptr, dest_ty._ptr, name)) + + def sext(self, value, dest_ty, name=""): + return Value(self._ptr.CreateSext(value._ptr, dest_ty._ptr, name)) + + def fptoui(self, value, dest_ty, name=""): + return Value(self._ptr.CreateFPToUI(value._ptr, dest_ty._ptr, name)) + + def fptosi(self, value, dest_ty, name=""): + return Value(self._ptr.CreateFPToSI(value._ptr, dest_ty._ptr, name)) + + def uitofp(self, value, dest_ty, name=""): + return Value(self._ptr.CreateUIToFP(value._ptr, dest_ty._ptr, name)) + + def sitofp(self, value, dest_ty, name=""): + return Value(self._ptr.CreateSIToFP(value._ptr, dest_ty._ptr, name)) + + def fptrunc(self, value, dest_ty, name=""): + return Value(self._ptr.CreateFPTrunc(value._ptr, dest_ty._ptr, name)) + + def fpext(self, value, dest_ty, name=""): + return Value(self._ptr.CreateFPExt(value._ptr, dest_ty._ptr, name)) + + def ptrtoint(self, value, dest_ty, name=""): + return Value(self._ptr.CreatePtrToInt(value._ptr, dest_ty._ptr, name)) + + def inttoptr(self, value, dest_ty, name=""): + return Value(self._ptr.CreateIntToPtr(value._ptr, dest_ty._ptr, name)) + + def bitcast(self, value, dest_ty, name=""): + return Value(self._ptr.CreateBitCast(value._ptr, dest_ty._ptr, name)) + + # comparisons + + def icmp(self, ipred, lhs, rhs, name=""): + return Value(self._ptr.CreateICmp(ipred, lhs._ptr, rhs._ptr, name)) + + def fcmp(self, rpred, lhs, rhs, name=""): + return Value(self._ptr.CreateFCmp(rpred, lhs._ptr, rhs._ptr, name)) + + # misc + + def extract_value(self, retval, idx, name=""): + return Value(self._ptr.CreateExtractValue(retval._ptr, [idx], name)) + + # obsolete synonym for extract_value + getresult = extract_value + + def insert_value(self, retval, rhs, idx, name=""): + return Value(self._ptr.CreateInsertValue(retval._ptr, + rhs._ptr, + [idx], + name)) + + def phi(self, ty, name=""): + return Value(self._ptr.CreatePHI(ty._ptr, 2, name)) + + def call(self, fn, args, name=""): + err_template = 'Argument type mismatch: expected %s but got %s' + for i, (t, v) in enumerate(zip(fn.type.pointee.args, args)): + if t != v.type: + raise TypeError(err_template % (t, v.type)) + arg_ptrs = llvm._extract_ptrs(args) + return Value(self._ptr.CreateCall(fn._ptr, arg_ptrs, name)) + + def select(self, cond, then_value, else_value, name=""): + return Value(self._ptr.CreateSelect(cond._ptr, then_value._ptr, + else_value._ptr, name)) + + def vaarg(self, list_val, ty, name=""): + return Value(self._ptr.CreateVAArg(list_val._ptr, ty._ptr, name)) + + def extract_element(self, vec_val, idx_val, name=""): + return Value(self._ptr.CreateExtractElement(vec_val._ptr, + idx_val_.ptr, + name)) + + + def insert_element(self, vec_val, elt_val, idx_val, name=""): + return Value(self._ptr.CreateExtractElement(vec_val._ptr, + elt_val._ptr, + idx_val_.ptr, + name)) + + def shuffle_vector(self, vecA, vecB, mask, name=""): + return Value(self._ptr.CreateShuffleVector(vecA._ptr, + vecB._ptr, + mask._ptr, + name)) + # atomics + + def atomic_cmpxchg(self, ptr, old, new, ordering, crossthread=True): + return Value(self._ptr.CreateAtomicCmpXchg(ptr._ptr, + old._ptr, + new._ptr, + ordering, + _sync_scope(crossthread))) + + def atomic_rmw(self, op, ptr, val, ordering, crossthread=True): + op_dict = dict((k.lower(), v) + for k, v in vars(api.llvm.AtomicRMWInst.BinOp)) + op = op_dict[op] + return Value(self._ptr.CreateAtomicRMW(op, ptr._ptr, val._ptr, + ordering, + _sync_scope(crossthread))) + + def atomic_xchg(self, *args, **kwargs): + return self.atomic_rmw('xchg', *args, **kwargs) + + def atomic_add(self, *args, **kwargs): + return self.atomic_rmw('add', *args, **kwargs) + + def atomic_sub(self, *args, **kwargs): + return self.atomic_rmw('sub', *args, **kwargs) + + def atomic_and(self, *args, **kwargs): + return self.atomic_rmw('and', *args, **kwargs) + + def atomic_nand(self, *args, **kwargs): + return self.atomic_rmw('nand', *args, **kwargs) + + def atomic_or(self, *args, **kwargs): + return self.atomic_rmw('or', *args, **kwargs) + + def atomic_xor(self, *args, **kwargs): + return self.atomic_rmw('xor', *args, **kwargs) + + def atomic_max(self, *args, **kwargs): + return self.atomic_rmw('max', *args, **kwargs) + + def atomic_min(self, *args, **kwargs): + return self.atomic_rmw('min', *args, **kwargs) + + def atomic_umax(self, *args, **kwargs): + return self.atomic_rmw('umax', *args, **kwargs) + + def atomic_umin(self, *args, **kwargs): + return self.atomic_rmw('umin', *args, **kwargs) + + def atomic_load(self, ptr, ordering, align=1, crossthread=True, + volatile=False, name=""): + inst = self._ptr.load(ptr, align=align, volatile=volatile, name=name) + inst._ptr.setAtomic(ordering, _sync_scope(crossthread)) + return inst + + def atomic_store(self, value, ptr, ordering, align=1, crossthread=True, + volatile=False): + inst = self._ptr.store(ptr, value, align=align, volatile=volatile, + name=name) + inst._ptr.setAtomic(ordering, _sync_scope(crossthread)) + return inst + + + def fence(self, ordering, crossthread=True): + return Value(self._ptr.CreateFence(ordering, + _sync_scope(crossthread))) + +def _sync_scope(crossthread): + if crossthread: + scope = api.llvm.SynchronizationScope.CrossThread + else: + scope = api.llvm.SynchronizationScope.SingleThread + return scope + +def load_library_permanently(filename): + """Load a shared library. + + Load the given shared library (filename argument specifies the full + path of the .so file) using LLVM. Symbols from these are available + from the execution engine thereafter.""" + with contextlib.closing(StringIO()) as errmsg: + failed = _api.llvm.sys.LoadLibraryPermanently(filename, errmsg) + if failed: + raise llvm.LLVMException(errmsg.getvalue()) + +def inline_function(call): + info = _api.llvm.InlineFunctionInfo() + return _api.llvm.InlineFunction(call._ptr, info) + +def parse_environment_options(progname, envname): + _api.llvm.cl.ParseEnvironmentOptions(progname, envname) + +if _api.llvm.InitializeNativeTarget(): + raise llvm.LLVMException("No native target!?") +if _api.llvm.InitializeNativeTargetAsmPrinter(): + # should this be an optional feature? + # should user trigger the initialization? + raise llvm.LLVMException("No native asm printer!?") + +#===----------------------------------------------------------------------=== +# Initialization +#===----------------------------------------------------------------------=== + +HAS_PTX = HAS_NVPTX = False + +if True: # use PTX? + try: + _api.LLVMInitializePTXTarget() + _api.LLVMInitializePTXTargetInfo() + _api.LLVMInitializePTXTargetMC() + _api.LLVMInitializePTXAsmPrinter() + HAS_PTX = True + except AttributeError: + try: + _api.LLVMInitializeNVPTXTarget() + _api.LLVMInitializeNVPTXTargetInfo() + _api.LLVMInitializeNVPTXTargetMC() + _api.LLVMInitializeNVPTXAsmPrinter() + HAS_NVPTX = True + except AttributeError: + pass + - \ No newline at end of file From 230583f42ddec81bcea0f153c29f8e1930c7f900 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 8 Feb 2013 18:16:26 -0600 Subject: [PATCH 265/516] Fix bug with empty namespace --- newbinding/gen/binding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/newbinding/gen/binding.py b/newbinding/gen/binding.py index 51620a8..cfe4394 100644 --- a/newbinding/gen/binding.py +++ b/newbinding/gen/binding.py @@ -578,7 +578,7 @@ class Function(Method): with writer.function(self.name, varargs='args') as varargs: unwrapped = writer.unwrap_many(varargs) self.process_ownedptr_args(writer, unwrapped) - func = '.'.join([self.parent.py_name, self.name]) + func = '.'.join([self.parent.py_name, self.name]).lstrip('.') ret = writer.call('_api.%s' % func, varargs=unwrapped) wrapped = writer.wrap(ret, self.is_return_ownedptr()) writer.return_value(wrapped) From 0681d2f37eb4a67aa2e8b78403241bd2f7a7e03e Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 8 Feb 2013 18:22:53 -0600 Subject: [PATCH 266/516] Fixes various problem in llvm.core --- llvm/core.py | 70 ++++++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index 6d5f0d1..2f7adb5 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -318,7 +318,7 @@ class Module(llvm.Wrapper): ll = str(module_obj) print module_obj # same as `print ll' """ - return str(self.ptr) + return str(self._ptr) def __eq__(self, rhs): if isinstance(rhs, Module): @@ -331,20 +331,20 @@ class Module(llvm.Wrapper): def _get_target(self): - return self.ptr.getTargetTriple() + return self._ptr.getTargetTriple() def _set_target(self, value): - return self.ptr.setTargetTriple(value) + return self._ptr.setTargetTriple(value) target = property(_get_target, _set_target, doc="The target triple string describing the target host.") def _get_data_layout(self): - return self.ptr.getDataLayout() + return self._ptr.getDataLayout() def _set_data_layout(self, value): - return self.ptr.setDataLayout(value) + return self._ptr.setDataLayout(value) data_layout = property(_get_data_layout, _set_data_layout, doc = """The data layout string for the module's target platform. @@ -383,7 +383,7 @@ class Module(llvm.Wrapper): raise llvm.LLVMException(errmsg) def get_type_named(self, name): - typ = self.ptr.getTypeByName(name) + typ = self._ptr.getTypeByName(name) return StructType(typ) def add_global_variable(self, ty, name, addrspace=0): @@ -405,12 +405,12 @@ class Module(llvm.Wrapper): def get_global_variable_named(self, name): """Return a GlobalVariable object for the given name.""" - ptr = self.ptr.getNamedGlobal(name) + ptr = self._ptr.getNamedGlobal(name) return GlobalVariable(ptr) @property def global_variables(self): - return self.ptr.list_globals() + return self._ptr.list_globals() def add_function(self, ty, name): """Add a function of given type with given name.""" @@ -421,7 +421,7 @@ class Module(llvm.Wrapper): def get_function_named(self, name): """Return a Function object representing function with given name.""" - fn = self.ptr.getFunction(name) + fn = self._ptr.getFunction(name) if fn is None: return None return Function(fn) @@ -429,14 +429,14 @@ class Module(llvm.Wrapper): def get_or_insert_function(self, ty, name): """Like get_function_named(), but does add_function() first, if function is not present.""" - constant = self.ptr.getOrInsertFunction(name, ty._ptr) + constant = self._ptr.getOrInsertFunction(name, ty._ptr) fn = constant._downcast(api.llvm.Function) return Function(fn) @property def functions(self): """All functions in this module.""" - return map(Function, self.ptr.list_functions()) + return map(Function, self._ptr.list_functions()) def verify(self): """Verify module. @@ -445,7 +445,7 @@ class Module(llvm.Wrapper): error.""" action = api.llvm.VerifierFailureAction.ReturnStatusAction errio = StringIO() - broken = api.llvm.verifyModule(self.ptr, action, errio) + broken = api.llvm.verifyModule(self._ptr, action, errio) if broken: raise llvm.LLVMException(errio.getvalue()) @@ -463,15 +463,15 @@ class Module(llvm.Wrapper): if fileobj is None: ret = True fileobj = StringIO - api.llvm.WriteBitcodeToFile(self.ptr, fileobj) + api.llvm.WriteBitcodeToFile(self._ptr, fileobj) if ret: return fileobj.getvalue() def _get_id(self): - return self.ptr.getModuleIdentifier(self.ptr) + return self._ptr.getModuleIdentifier(self._ptr) def _set_id(self, string): - self.ptr.setModuleIdentifier(string) + self._ptr.setModuleIdentifier(string) id = property(_get_id, _set_id) @@ -508,13 +508,13 @@ class Module(llvm.Wrapper): return self._to_native_something(fileobj, CGFT.CGFT_AssemblyFile) def get_or_insert_named_metadata(self, name): - return NamedMetadata(self.ptr.getOrInsertNamedMetadata(name)) + return NamedMetadata(self._ptr.getOrInsertNamedMetadata(name)) def get_named_metadata(self, name): - return NamedMetadata(self.ptr.get_named_metadata(name)) + return NamedMetadata(self._ptr.get_named_metadata(name)) def clone(self): - return NamedMetadata(api.llvm.CloneModule(self.ptr)) + return NamedMetadata(api.llvm.CloneModule(self._ptr)) class Type(llvm.Wrapper): """Represents a type, like a 32-bit integer or an 80-bit x86 float. @@ -860,7 +860,7 @@ class User(Value): for i in range(self.operand_count)] def _get_operand(self, i): - return _make_value(_core.LLVMUserGetOperand(self.ptr, i)) + return _make_value(_core.LLVMUserGetOperand(self._ptr, i)) class Constant(User): @@ -1309,7 +1309,7 @@ class Function(GlobalValue): return self._ptr.viewCFG() def add_attribute(self, attr): - _core.LLVMAddFunctionAttr(self.ptr, attr) + _core.LLVMAddFunctionAttr(self._ptr, attr) def remove_attribute(self, attr): attrbldr = api.llvm.AttrBuilder() @@ -1589,7 +1589,7 @@ class Builder(llvm.Wrapper): context = api.llvm.getGlobalContext() ptr = api.llvm.IRBuilder.new(context) ptr.SetInsertPoint(basic_block._ptr) - return BasicBlock(ptr) + return Builder(ptr) def position_at_beginning(self, bblk): """Position the builder at the beginning of the given block. @@ -1970,20 +1970,20 @@ def load_library_permanently(filename): path of the .so file) using LLVM. Symbols from these are available from the execution engine thereafter.""" with contextlib.closing(StringIO()) as errmsg: - failed = _api.llvm.sys.LoadLibraryPermanently(filename, errmsg) + failed = api.llvm.sys.LoadLibraryPermanently(filename, errmsg) if failed: raise llvm.LLVMException(errmsg.getvalue()) def inline_function(call): - info = _api.llvm.InlineFunctionInfo() - return _api.llvm.InlineFunction(call._ptr, info) + info = api.llvm.InlineFunctionInfo() + return api.llvm.InlineFunction(call._ptr, info) def parse_environment_options(progname, envname): - _api.llvm.cl.ParseEnvironmentOptions(progname, envname) + api.llvm.cl.ParseEnvironmentOptions(progname, envname) -if _api.llvm.InitializeNativeTarget(): +if api.llvm.InitializeNativeTarget(): raise llvm.LLVMException("No native target!?") -if _api.llvm.InitializeNativeTargetAsmPrinter(): +if api.llvm.InitializeNativeTargetAsmPrinter(): # should this be an optional feature? # should user trigger the initialization? raise llvm.LLVMException("No native asm printer!?") @@ -1996,17 +1996,17 @@ HAS_PTX = HAS_NVPTX = False if True: # use PTX? try: - _api.LLVMInitializePTXTarget() - _api.LLVMInitializePTXTargetInfo() - _api.LLVMInitializePTXTargetMC() - _api.LLVMInitializePTXAsmPrinter() + api.LLVMInitializePTXTarget() + api.LLVMInitializePTXTargetInfo() + api.LLVMInitializePTXTargetMC() + api.LLVMInitializePTXAsmPrinter() HAS_PTX = True except AttributeError: try: - _api.LLVMInitializeNVPTXTarget() - _api.LLVMInitializeNVPTXTargetInfo() - _api.LLVMInitializeNVPTXTargetMC() - _api.LLVMInitializeNVPTXAsmPrinter() + api.LLVMInitializeNVPTXTarget() + api.LLVMInitializeNVPTXTargetInfo() + api.LLVMInitializeNVPTXTargetMC() + api.LLVMInitializeNVPTXAsmPrinter() HAS_NVPTX = True except AttributeError: pass From 3189be4d58a24d6a16bb02d38a89472806a89eaa Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 11 Feb 2013 09:59:15 -0600 Subject: [PATCH 267/516] Rename newbinding directory to llvmpy. --- {newbinding => llvmpy}/Makefile | 0 {newbinding => llvmpy}/README | 0 llvmpy/__init__.py | 0 {newbinding => llvmpy}/capsule.cpp | 0 {newbinding => llvmpy}/capsule.py | 0 {newbinding => llvmpy}/extra.py | 4 ++-- {newbinding => llvmpy}/gen/binding.py | 2 +- {newbinding => llvmpy}/gen/codegen.py | 0 {newbinding => llvmpy}/gen/gen.py | 0 .../include/llvm_binding/auto_pyobject.h | 0 .../include/llvm_binding/binding.h | 0 .../include/llvm_binding/capsule_context.h | 0 .../include/llvm_binding/conversion.h | 0 {newbinding => llvmpy}/include/llvm_binding/extra.h | 1 + {newbinding => llvmpy}/setup.py | 0 {newbinding => llvmpy}/src/ADT/SmallVector.py | 0 {newbinding => llvmpy}/src/ADT/StringRef.py | 0 {newbinding => llvmpy}/src/ADT/Triple.py | 0 {newbinding => llvmpy}/src/ADT/__init__.py | 0 {newbinding => llvmpy}/src/Analysis/Verifier.py | 0 {newbinding => llvmpy}/src/Analysis/__init__.py | 0 {newbinding => llvmpy}/src/Argument.py | 0 .../src/Assembly/AssemblyAnnotationWriter.py | 0 {newbinding => llvmpy}/src/Assembly/Parser.py | 0 {newbinding => llvmpy}/src/Assembly/__init__.py | 0 {newbinding => llvmpy}/src/Attributes.py | 0 {newbinding => llvmpy}/src/BasicBlock.py | 0 {newbinding => llvmpy}/src/Bitcode/ReaderWriter.py | 0 {newbinding => llvmpy}/src/Bitcode/__init__.py | 0 {newbinding => llvmpy}/src/CallingConv.py | 0 .../src/CodeGen/MachineCodeInfo.py | 0 {newbinding => llvmpy}/src/CodeGen/__init__.py | 0 {newbinding => llvmpy}/src/Constant.py | 6 +++--- {newbinding => llvmpy}/src/DataLayout.py | 2 +- {newbinding => llvmpy}/src/DerivedTypes.py | 2 +- {newbinding => llvmpy}/src/EngineBuilder.py | 0 .../src/ExecutionEngine/ExecutionEngine.py | 2 +- .../src/ExecutionEngine/__init__.py | 0 {newbinding => llvmpy}/src/Function.py | 0 {newbinding => llvmpy}/src/GenericValue.py | 0 {newbinding => llvmpy}/src/GlobalValue.py | 0 {newbinding => llvmpy}/src/GlobalVariable.py | 0 {newbinding => llvmpy}/src/IRBuilder.py | 12 ++++++------ {newbinding => llvmpy}/src/InlineAsm.py | 0 {newbinding => llvmpy}/src/Instruction.py | 0 {newbinding => llvmpy}/src/Intrinsics.py | 0 {newbinding => llvmpy}/src/JITMemoryManager.py | 0 {newbinding => llvmpy}/src/LLVMContext.py | 0 {newbinding => llvmpy}/src/Linker.py | 0 {newbinding => llvmpy}/src/Metadata.py | 2 +- {newbinding => llvmpy}/src/Module.py | 2 +- {newbinding => llvmpy}/src/Pass.py | 0 {newbinding => llvmpy}/src/PassManager.py | 0 {newbinding => llvmpy}/src/Support/CodeGen.py | 0 {newbinding => llvmpy}/src/Support/CommandLine.py | 0 {newbinding => llvmpy}/src/Support/DynamicLibrary.py | 0 .../src/Support/FormattedStream.py | 0 {newbinding => llvmpy}/src/Support/SourceMgr.py | 0 {newbinding => llvmpy}/src/Support/Target.py | 0 {newbinding => llvmpy}/src/Support/TargetSelect.py | 0 {newbinding => llvmpy}/src/Support/__init__.py | 0 {newbinding => llvmpy}/src/Support/raw_ostream.py | 0 .../src/Target/TargetLibraryInfo.py | 0 {newbinding => llvmpy}/src/Target/TargetMachine.py | 0 {newbinding => llvmpy}/src/Target/__init__.py | 0 {newbinding => llvmpy}/src/TargetTransformInfo.py | 0 {newbinding => llvmpy}/src/Transforms/IPO.py | 0 .../src/Transforms/PassManagerBuilder.py | 0 .../src/Transforms/Utils/Cloning.py | 0 .../src/Transforms/Utils/__init__.py | 0 {newbinding => llvmpy}/src/Transforms/__init__.py | 0 {newbinding => llvmpy}/src/Type.py | 2 +- {newbinding => llvmpy}/src/User.py | 0 {newbinding => llvmpy}/src/Value.py | 2 +- {newbinding => llvmpy}/src/__init__.py | 0 {newbinding => llvmpy}/src/namespace.py | 0 {newbinding => llvmpy}/test_binding.py | 11 +++++++---- 77 files changed, 27 insertions(+), 23 deletions(-) rename {newbinding => llvmpy}/Makefile (100%) rename {newbinding => llvmpy}/README (100%) create mode 100644 llvmpy/__init__.py rename {newbinding => llvmpy}/capsule.cpp (100%) rename {newbinding => llvmpy}/capsule.py (100%) rename {newbinding => llvmpy}/extra.py (89%) rename {newbinding => llvmpy}/gen/binding.py (99%) rename {newbinding => llvmpy}/gen/codegen.py (100%) rename {newbinding => llvmpy}/gen/gen.py (100%) rename {newbinding => llvmpy}/include/llvm_binding/auto_pyobject.h (100%) rename {newbinding => llvmpy}/include/llvm_binding/binding.h (100%) rename {newbinding => llvmpy}/include/llvm_binding/capsule_context.h (100%) rename {newbinding => llvmpy}/include/llvm_binding/conversion.h (100%) rename {newbinding => llvmpy}/include/llvm_binding/extra.h (99%) rename {newbinding => llvmpy}/setup.py (100%) rename {newbinding => llvmpy}/src/ADT/SmallVector.py (100%) rename {newbinding => llvmpy}/src/ADT/StringRef.py (100%) rename {newbinding => llvmpy}/src/ADT/Triple.py (100%) rename {newbinding => llvmpy}/src/ADT/__init__.py (100%) rename {newbinding => llvmpy}/src/Analysis/Verifier.py (100%) rename {newbinding => llvmpy}/src/Analysis/__init__.py (100%) rename {newbinding => llvmpy}/src/Argument.py (100%) rename {newbinding => llvmpy}/src/Assembly/AssemblyAnnotationWriter.py (100%) rename {newbinding => llvmpy}/src/Assembly/Parser.py (100%) rename {newbinding => llvmpy}/src/Assembly/__init__.py (100%) rename {newbinding => llvmpy}/src/Attributes.py (100%) rename {newbinding => llvmpy}/src/BasicBlock.py (100%) rename {newbinding => llvmpy}/src/Bitcode/ReaderWriter.py (100%) rename {newbinding => llvmpy}/src/Bitcode/__init__.py (100%) rename {newbinding => llvmpy}/src/CallingConv.py (100%) rename {newbinding => llvmpy}/src/CodeGen/MachineCodeInfo.py (100%) rename {newbinding => llvmpy}/src/CodeGen/__init__.py (100%) rename {newbinding => llvmpy}/src/Constant.py (98%) rename {newbinding => llvmpy}/src/DataLayout.py (99%) rename {newbinding => llvmpy}/src/DerivedTypes.py (96%) rename {newbinding => llvmpy}/src/EngineBuilder.py (100%) rename {newbinding => llvmpy}/src/ExecutionEngine/ExecutionEngine.py (99%) rename {newbinding => llvmpy}/src/ExecutionEngine/__init__.py (100%) rename {newbinding => llvmpy}/src/Function.py (100%) rename {newbinding => llvmpy}/src/GenericValue.py (100%) rename {newbinding => llvmpy}/src/GlobalValue.py (100%) rename {newbinding => llvmpy}/src/GlobalVariable.py (100%) rename {newbinding => llvmpy}/src/IRBuilder.py (98%) rename {newbinding => llvmpy}/src/InlineAsm.py (100%) rename {newbinding => llvmpy}/src/Instruction.py (100%) rename {newbinding => llvmpy}/src/Intrinsics.py (100%) rename {newbinding => llvmpy}/src/JITMemoryManager.py (100%) rename {newbinding => llvmpy}/src/LLVMContext.py (100%) rename {newbinding => llvmpy}/src/Linker.py (100%) rename {newbinding => llvmpy}/src/Metadata.py (98%) rename {newbinding => llvmpy}/src/Module.py (98%) rename {newbinding => llvmpy}/src/Pass.py (100%) rename {newbinding => llvmpy}/src/PassManager.py (100%) rename {newbinding => llvmpy}/src/Support/CodeGen.py (100%) rename {newbinding => llvmpy}/src/Support/CommandLine.py (100%) rename {newbinding => llvmpy}/src/Support/DynamicLibrary.py (100%) rename {newbinding => llvmpy}/src/Support/FormattedStream.py (100%) rename {newbinding => llvmpy}/src/Support/SourceMgr.py (100%) rename {newbinding => llvmpy}/src/Support/Target.py (100%) rename {newbinding => llvmpy}/src/Support/TargetSelect.py (100%) rename {newbinding => llvmpy}/src/Support/__init__.py (100%) rename {newbinding => llvmpy}/src/Support/raw_ostream.py (100%) rename {newbinding => llvmpy}/src/Target/TargetLibraryInfo.py (100%) rename {newbinding => llvmpy}/src/Target/TargetMachine.py (100%) rename {newbinding => llvmpy}/src/Target/__init__.py (100%) rename {newbinding => llvmpy}/src/TargetTransformInfo.py (100%) rename {newbinding => llvmpy}/src/Transforms/IPO.py (100%) rename {newbinding => llvmpy}/src/Transforms/PassManagerBuilder.py (100%) rename {newbinding => llvmpy}/src/Transforms/Utils/Cloning.py (100%) rename {newbinding => llvmpy}/src/Transforms/Utils/__init__.py (100%) rename {newbinding => llvmpy}/src/Transforms/__init__.py (100%) rename {newbinding => llvmpy}/src/Type.py (99%) rename {newbinding => llvmpy}/src/User.py (100%) rename {newbinding => llvmpy}/src/Value.py (98%) rename {newbinding => llvmpy}/src/__init__.py (100%) rename {newbinding => llvmpy}/src/namespace.py (100%) rename {newbinding => llvmpy}/test_binding.py (98%) diff --git a/newbinding/Makefile b/llvmpy/Makefile similarity index 100% rename from newbinding/Makefile rename to llvmpy/Makefile diff --git a/newbinding/README b/llvmpy/README similarity index 100% rename from newbinding/README rename to llvmpy/README diff --git a/llvmpy/__init__.py b/llvmpy/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/newbinding/capsule.cpp b/llvmpy/capsule.cpp similarity index 100% rename from newbinding/capsule.cpp rename to llvmpy/capsule.cpp diff --git a/newbinding/capsule.py b/llvmpy/capsule.py similarity index 100% rename from newbinding/capsule.py rename to llvmpy/capsule.py diff --git a/newbinding/extra.py b/llvmpy/extra.py similarity index 89% rename from newbinding/extra.py rename to llvmpy/extra.py index d65f84c..a2e744f 100644 --- a/newbinding/extra.py +++ b/llvmpy/extra.py @@ -2,8 +2,8 @@ Wrapped the extra functions in _api.so ''' -import capsule -import _api +from llvmpy import capsule +from llvmpy import _api # # Re-export the native API from the _api.extra and wrap the functions # diff --git a/newbinding/gen/binding.py b/llvmpy/gen/binding.py similarity index 99% rename from newbinding/gen/binding.py rename to llvmpy/gen/binding.py index cfe4394..6d73cd3 100644 --- a/newbinding/gen/binding.py +++ b/llvmpy/gen/binding.py @@ -135,7 +135,7 @@ class SubModule(object): filepath = os.path.join(rootdir, '%s.py' % name) with open(filepath, 'w') as pyfile: println = cg.wrap_println_from_file(pyfile) - println('import _api, capsule') + println('from llvmpy import _api, capsule') for ns in self.namespaces: println('from . import %s' % ns.localname) println() diff --git a/newbinding/gen/codegen.py b/llvmpy/gen/codegen.py similarity index 100% rename from newbinding/gen/codegen.py rename to llvmpy/gen/codegen.py diff --git a/newbinding/gen/gen.py b/llvmpy/gen/gen.py similarity index 100% rename from newbinding/gen/gen.py rename to llvmpy/gen/gen.py diff --git a/newbinding/include/llvm_binding/auto_pyobject.h b/llvmpy/include/llvm_binding/auto_pyobject.h similarity index 100% rename from newbinding/include/llvm_binding/auto_pyobject.h rename to llvmpy/include/llvm_binding/auto_pyobject.h diff --git a/newbinding/include/llvm_binding/binding.h b/llvmpy/include/llvm_binding/binding.h similarity index 100% rename from newbinding/include/llvm_binding/binding.h rename to llvmpy/include/llvm_binding/binding.h diff --git a/newbinding/include/llvm_binding/capsule_context.h b/llvmpy/include/llvm_binding/capsule_context.h similarity index 100% rename from newbinding/include/llvm_binding/capsule_context.h rename to llvmpy/include/llvm_binding/capsule_context.h diff --git a/newbinding/include/llvm_binding/conversion.h b/llvmpy/include/llvm_binding/conversion.h similarity index 100% rename from newbinding/include/llvm_binding/conversion.h rename to llvmpy/include/llvm_binding/conversion.h diff --git a/newbinding/include/llvm_binding/extra.h b/llvmpy/include/llvm_binding/extra.h similarity index 99% rename from newbinding/include/llvm_binding/extra.h rename to llvmpy/include/llvm_binding/extra.h index d045d5c..438f52c 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/llvmpy/include/llvm_binding/extra.h @@ -358,6 +358,7 @@ PyObject* ExecutionEngine_RunFunction(llvm::ExecutionEngine* EE, return NULL; } std::vector vec_args; + Py_ssize_t nargs = PyTuple_Size(Args); vec_args.reserve(nargs); for (Py_ssize_t i = 0; i < nargs; ++i) { diff --git a/newbinding/setup.py b/llvmpy/setup.py similarity index 100% rename from newbinding/setup.py rename to llvmpy/setup.py diff --git a/newbinding/src/ADT/SmallVector.py b/llvmpy/src/ADT/SmallVector.py similarity index 100% rename from newbinding/src/ADT/SmallVector.py rename to llvmpy/src/ADT/SmallVector.py diff --git a/newbinding/src/ADT/StringRef.py b/llvmpy/src/ADT/StringRef.py similarity index 100% rename from newbinding/src/ADT/StringRef.py rename to llvmpy/src/ADT/StringRef.py diff --git a/newbinding/src/ADT/Triple.py b/llvmpy/src/ADT/Triple.py similarity index 100% rename from newbinding/src/ADT/Triple.py rename to llvmpy/src/ADT/Triple.py diff --git a/newbinding/src/ADT/__init__.py b/llvmpy/src/ADT/__init__.py similarity index 100% rename from newbinding/src/ADT/__init__.py rename to llvmpy/src/ADT/__init__.py diff --git a/newbinding/src/Analysis/Verifier.py b/llvmpy/src/Analysis/Verifier.py similarity index 100% rename from newbinding/src/Analysis/Verifier.py rename to llvmpy/src/Analysis/Verifier.py diff --git a/newbinding/src/Analysis/__init__.py b/llvmpy/src/Analysis/__init__.py similarity index 100% rename from newbinding/src/Analysis/__init__.py rename to llvmpy/src/Analysis/__init__.py diff --git a/newbinding/src/Argument.py b/llvmpy/src/Argument.py similarity index 100% rename from newbinding/src/Argument.py rename to llvmpy/src/Argument.py diff --git a/newbinding/src/Assembly/AssemblyAnnotationWriter.py b/llvmpy/src/Assembly/AssemblyAnnotationWriter.py similarity index 100% rename from newbinding/src/Assembly/AssemblyAnnotationWriter.py rename to llvmpy/src/Assembly/AssemblyAnnotationWriter.py diff --git a/newbinding/src/Assembly/Parser.py b/llvmpy/src/Assembly/Parser.py similarity index 100% rename from newbinding/src/Assembly/Parser.py rename to llvmpy/src/Assembly/Parser.py diff --git a/newbinding/src/Assembly/__init__.py b/llvmpy/src/Assembly/__init__.py similarity index 100% rename from newbinding/src/Assembly/__init__.py rename to llvmpy/src/Assembly/__init__.py diff --git a/newbinding/src/Attributes.py b/llvmpy/src/Attributes.py similarity index 100% rename from newbinding/src/Attributes.py rename to llvmpy/src/Attributes.py diff --git a/newbinding/src/BasicBlock.py b/llvmpy/src/BasicBlock.py similarity index 100% rename from newbinding/src/BasicBlock.py rename to llvmpy/src/BasicBlock.py diff --git a/newbinding/src/Bitcode/ReaderWriter.py b/llvmpy/src/Bitcode/ReaderWriter.py similarity index 100% rename from newbinding/src/Bitcode/ReaderWriter.py rename to llvmpy/src/Bitcode/ReaderWriter.py diff --git a/newbinding/src/Bitcode/__init__.py b/llvmpy/src/Bitcode/__init__.py similarity index 100% rename from newbinding/src/Bitcode/__init__.py rename to llvmpy/src/Bitcode/__init__.py diff --git a/newbinding/src/CallingConv.py b/llvmpy/src/CallingConv.py similarity index 100% rename from newbinding/src/CallingConv.py rename to llvmpy/src/CallingConv.py diff --git a/newbinding/src/CodeGen/MachineCodeInfo.py b/llvmpy/src/CodeGen/MachineCodeInfo.py similarity index 100% rename from newbinding/src/CodeGen/MachineCodeInfo.py rename to llvmpy/src/CodeGen/MachineCodeInfo.py diff --git a/newbinding/src/CodeGen/__init__.py b/llvmpy/src/CodeGen/__init__.py similarity index 100% rename from newbinding/src/CodeGen/__init__.py rename to llvmpy/src/CodeGen/__init__.py diff --git a/newbinding/src/Constant.py b/llvmpy/src/Constant.py similarity index 98% rename from newbinding/src/Constant.py rename to llvmpy/src/Constant.py index 42541c4..5407d71 100644 --- a/newbinding/src/Constant.py +++ b/llvmpy/src/Constant.py @@ -227,7 +227,7 @@ class ConstantExpr: @CustomPythonStaticMethod def getGetElementPtr(*args): - import extra + from llvmpy import extra args = list(args) valuelist = args[1] args[1] = extra.make_small_vector_from_values(*valuelist) @@ -242,7 +242,7 @@ class ConstantExpr: @CustomPythonStaticMethod def getExtractValue(*args): - import extra + from llvmpy import extra args = list(args) valuelist = args[1] args[1] = extra.make_small_vector_from_unsigned(*valuelist) @@ -254,7 +254,7 @@ class ConstantExpr: @CustomPythonStaticMethod def getInsertValue(*args): - import extra + from llvmpy import extra args = list(args) valuelist = args[2] args[1] = extra.make_small_vector_from_unsigned(*valuelist) diff --git a/newbinding/src/DataLayout.py b/llvmpy/src/DataLayout.py similarity index 99% rename from newbinding/src/DataLayout.py rename to llvmpy/src/DataLayout.py index 704c4b1..d704723 100644 --- a/newbinding/src/DataLayout.py +++ b/llvmpy/src/DataLayout.py @@ -81,7 +81,7 @@ class DataLayout: @CustomPythonMethod def getIndexedOffset(self, *args): - import extra + from llvmpy import extra args = list(args) args[1] = extra.make_small_vector_from_values(args[1]) return self.getIndexedOffset(*args) diff --git a/newbinding/src/DerivedTypes.py b/llvmpy/src/DerivedTypes.py similarity index 96% rename from newbinding/src/DerivedTypes.py rename to llvmpy/src/DerivedTypes.py index e71f1a8..a34c2f1 100644 --- a/newbinding/src/DerivedTypes.py +++ b/llvmpy/src/DerivedTypes.py @@ -17,7 +17,7 @@ class FunctionType: @CustomPythonStaticMethod def get(*args): - import extra + from llvmpy import extra if len(args) == 3: typelist = args[1] sv = extra.make_small_vector_from_types(*typelist) diff --git a/newbinding/src/EngineBuilder.py b/llvmpy/src/EngineBuilder.py similarity index 100% rename from newbinding/src/EngineBuilder.py rename to llvmpy/src/EngineBuilder.py diff --git a/newbinding/src/ExecutionEngine/ExecutionEngine.py b/llvmpy/src/ExecutionEngine/ExecutionEngine.py similarity index 99% rename from newbinding/src/ExecutionEngine/ExecutionEngine.py rename to llvmpy/src/ExecutionEngine/ExecutionEngine.py index f4bdb14..1188de3 100644 --- a/newbinding/src/ExecutionEngine/ExecutionEngine.py +++ b/llvmpy/src/ExecutionEngine/ExecutionEngine.py @@ -88,7 +88,7 @@ class ExecutionEngine: @CustomPythonMethod def runFunction(self, fn, args): - import capsule + from llvmpy import capsule unwrapped = map(capsule.unwrap, args) return self._runFunction(fn, tuple(unwrapped)) diff --git a/newbinding/src/ExecutionEngine/__init__.py b/llvmpy/src/ExecutionEngine/__init__.py similarity index 100% rename from newbinding/src/ExecutionEngine/__init__.py rename to llvmpy/src/ExecutionEngine/__init__.py diff --git a/newbinding/src/Function.py b/llvmpy/src/Function.py similarity index 100% rename from newbinding/src/Function.py rename to llvmpy/src/Function.py diff --git a/newbinding/src/GenericValue.py b/llvmpy/src/GenericValue.py similarity index 100% rename from newbinding/src/GenericValue.py rename to llvmpy/src/GenericValue.py diff --git a/newbinding/src/GlobalValue.py b/llvmpy/src/GlobalValue.py similarity index 100% rename from newbinding/src/GlobalValue.py rename to llvmpy/src/GlobalValue.py diff --git a/newbinding/src/GlobalVariable.py b/llvmpy/src/GlobalVariable.py similarity index 100% rename from newbinding/src/GlobalVariable.py rename to llvmpy/src/GlobalVariable.py diff --git a/newbinding/src/IRBuilder.py b/llvmpy/src/IRBuilder.py similarity index 98% rename from newbinding/src/IRBuilder.py rename to llvmpy/src/IRBuilder.py index 2965367..095122f 100644 --- a/newbinding/src/IRBuilder.py +++ b/llvmpy/src/IRBuilder.py @@ -68,7 +68,7 @@ class IRBuilder: @CustomPythonMethod def CreateInvoke(self, *args): - import extra + from llvmpy import extra args = list(args) valuelist = args[3] args[3] = extra.make_small_vector_from_values(*valuelist) @@ -181,7 +181,7 @@ class IRBuilder: @CustomPythonMethod def CreateGEP(self, *args): - import extra + from llvmpy import extra args = list(args) valuelist = args[1] args[1] = extra.make_small_vector_from_values(*valuelist) @@ -194,7 +194,7 @@ class IRBuilder: @CustomPythonMethod def CreateInBoundsGEP(self, *args): - import extra + from llvmpy import extra args = list(args) valuelist = args[1] args[1] = extra.make_small_vector_from_values(*valuelist) @@ -241,7 +241,7 @@ class IRBuilder: @CustomPythonMethod def CreateCall(self, *args): - import extra + from llvmpy import extra args = list(args) valuelist = args[1] args[1] = extra.make_small_vector_from_values(*valuelist) @@ -282,7 +282,7 @@ class IRBuilder: @CustomPythonMethod def CreateExtractValue(self, args): - import extra + from llvmpy import extra args = list(args) valuelist = args[1] args[1] = extra.make_small_vector_from_unsigned(*valuelist) @@ -295,7 +295,7 @@ class IRBuilder: @CustomPythonMethod def CreateInsertValue(self, args): - import extra + from llvmpy import extra args = list(args) valuelist = args[2] args[1] = extra.make_small_vector_from_unsigned(*valuelist) diff --git a/newbinding/src/InlineAsm.py b/llvmpy/src/InlineAsm.py similarity index 100% rename from newbinding/src/InlineAsm.py rename to llvmpy/src/InlineAsm.py diff --git a/newbinding/src/Instruction.py b/llvmpy/src/Instruction.py similarity index 100% rename from newbinding/src/Instruction.py rename to llvmpy/src/Instruction.py diff --git a/newbinding/src/Intrinsics.py b/llvmpy/src/Intrinsics.py similarity index 100% rename from newbinding/src/Intrinsics.py rename to llvmpy/src/Intrinsics.py diff --git a/newbinding/src/JITMemoryManager.py b/llvmpy/src/JITMemoryManager.py similarity index 100% rename from newbinding/src/JITMemoryManager.py rename to llvmpy/src/JITMemoryManager.py diff --git a/newbinding/src/LLVMContext.py b/llvmpy/src/LLVMContext.py similarity index 100% rename from newbinding/src/LLVMContext.py rename to llvmpy/src/LLVMContext.py diff --git a/newbinding/src/Linker.py b/llvmpy/src/Linker.py similarity index 100% rename from newbinding/src/Linker.py rename to llvmpy/src/Linker.py diff --git a/newbinding/src/Metadata.py b/llvmpy/src/Metadata.py similarity index 98% rename from newbinding/src/Metadata.py rename to llvmpy/src/Metadata.py index 338cbbd..94088ca 100644 --- a/newbinding/src/Metadata.py +++ b/llvmpy/src/Metadata.py @@ -46,7 +46,7 @@ class NamedMDNode: @CustomPythonMethod def __str__(self): - import extra + from llvmpy import extra os = extra.make_raw_ostream_for_printing() self.print_(os, None) return os.str() \ No newline at end of file diff --git a/newbinding/src/Module.py b/llvmpy/src/Module.py similarity index 98% rename from newbinding/src/Module.py rename to llvmpy/src/Module.py index 7718cd6..d68be36 100644 --- a/newbinding/src/Module.py +++ b/llvmpy/src/Module.py @@ -77,7 +77,7 @@ class Module: @CustomPythonMethod def __str__(self): - import extra + from llvmpy import extra os = extra.make_raw_ostream_for_printing() self.print_(os, None) return os.str() diff --git a/newbinding/src/Pass.py b/llvmpy/src/Pass.py similarity index 100% rename from newbinding/src/Pass.py rename to llvmpy/src/Pass.py diff --git a/newbinding/src/PassManager.py b/llvmpy/src/PassManager.py similarity index 100% rename from newbinding/src/PassManager.py rename to llvmpy/src/PassManager.py diff --git a/newbinding/src/Support/CodeGen.py b/llvmpy/src/Support/CodeGen.py similarity index 100% rename from newbinding/src/Support/CodeGen.py rename to llvmpy/src/Support/CodeGen.py diff --git a/newbinding/src/Support/CommandLine.py b/llvmpy/src/Support/CommandLine.py similarity index 100% rename from newbinding/src/Support/CommandLine.py rename to llvmpy/src/Support/CommandLine.py diff --git a/newbinding/src/Support/DynamicLibrary.py b/llvmpy/src/Support/DynamicLibrary.py similarity index 100% rename from newbinding/src/Support/DynamicLibrary.py rename to llvmpy/src/Support/DynamicLibrary.py diff --git a/newbinding/src/Support/FormattedStream.py b/llvmpy/src/Support/FormattedStream.py similarity index 100% rename from newbinding/src/Support/FormattedStream.py rename to llvmpy/src/Support/FormattedStream.py diff --git a/newbinding/src/Support/SourceMgr.py b/llvmpy/src/Support/SourceMgr.py similarity index 100% rename from newbinding/src/Support/SourceMgr.py rename to llvmpy/src/Support/SourceMgr.py diff --git a/newbinding/src/Support/Target.py b/llvmpy/src/Support/Target.py similarity index 100% rename from newbinding/src/Support/Target.py rename to llvmpy/src/Support/Target.py diff --git a/newbinding/src/Support/TargetSelect.py b/llvmpy/src/Support/TargetSelect.py similarity index 100% rename from newbinding/src/Support/TargetSelect.py rename to llvmpy/src/Support/TargetSelect.py diff --git a/newbinding/src/Support/__init__.py b/llvmpy/src/Support/__init__.py similarity index 100% rename from newbinding/src/Support/__init__.py rename to llvmpy/src/Support/__init__.py diff --git a/newbinding/src/Support/raw_ostream.py b/llvmpy/src/Support/raw_ostream.py similarity index 100% rename from newbinding/src/Support/raw_ostream.py rename to llvmpy/src/Support/raw_ostream.py diff --git a/newbinding/src/Target/TargetLibraryInfo.py b/llvmpy/src/Target/TargetLibraryInfo.py similarity index 100% rename from newbinding/src/Target/TargetLibraryInfo.py rename to llvmpy/src/Target/TargetLibraryInfo.py diff --git a/newbinding/src/Target/TargetMachine.py b/llvmpy/src/Target/TargetMachine.py similarity index 100% rename from newbinding/src/Target/TargetMachine.py rename to llvmpy/src/Target/TargetMachine.py diff --git a/newbinding/src/Target/__init__.py b/llvmpy/src/Target/__init__.py similarity index 100% rename from newbinding/src/Target/__init__.py rename to llvmpy/src/Target/__init__.py diff --git a/newbinding/src/TargetTransformInfo.py b/llvmpy/src/TargetTransformInfo.py similarity index 100% rename from newbinding/src/TargetTransformInfo.py rename to llvmpy/src/TargetTransformInfo.py diff --git a/newbinding/src/Transforms/IPO.py b/llvmpy/src/Transforms/IPO.py similarity index 100% rename from newbinding/src/Transforms/IPO.py rename to llvmpy/src/Transforms/IPO.py diff --git a/newbinding/src/Transforms/PassManagerBuilder.py b/llvmpy/src/Transforms/PassManagerBuilder.py similarity index 100% rename from newbinding/src/Transforms/PassManagerBuilder.py rename to llvmpy/src/Transforms/PassManagerBuilder.py diff --git a/newbinding/src/Transforms/Utils/Cloning.py b/llvmpy/src/Transforms/Utils/Cloning.py similarity index 100% rename from newbinding/src/Transforms/Utils/Cloning.py rename to llvmpy/src/Transforms/Utils/Cloning.py diff --git a/newbinding/src/Transforms/Utils/__init__.py b/llvmpy/src/Transforms/Utils/__init__.py similarity index 100% rename from newbinding/src/Transforms/Utils/__init__.py rename to llvmpy/src/Transforms/Utils/__init__.py diff --git a/newbinding/src/Transforms/__init__.py b/llvmpy/src/Transforms/__init__.py similarity index 100% rename from newbinding/src/Transforms/__init__.py rename to llvmpy/src/Transforms/__init__.py diff --git a/newbinding/src/Type.py b/llvmpy/src/Type.py similarity index 99% rename from newbinding/src/Type.py rename to llvmpy/src/Type.py index 4078a9d..ec0bf88 100644 --- a/newbinding/src/Type.py +++ b/llvmpy/src/Type.py @@ -125,7 +125,7 @@ class Type: @CustomPythonMethod def __str__(self): - import extra + from llvmpy import extra os = extra.make_raw_ostream_for_printing() self.print_(os) return os.str() diff --git a/newbinding/src/User.py b/llvmpy/src/User.py similarity index 100% rename from newbinding/src/User.py rename to llvmpy/src/User.py diff --git a/newbinding/src/Value.py b/llvmpy/src/Value.py similarity index 98% rename from newbinding/src/Value.py rename to llvmpy/src/Value.py index 27bcda0..88f221c 100644 --- a/newbinding/src/Value.py +++ b/llvmpy/src/Value.py @@ -56,7 +56,7 @@ class Value: @CustomPythonMethod def __str__(self): - import extra + from llvmpy import extra os = extra.make_raw_ostream_for_printing() self.print_(os, None) return os.str() diff --git a/newbinding/src/__init__.py b/llvmpy/src/__init__.py similarity index 100% rename from newbinding/src/__init__.py rename to llvmpy/src/__init__.py diff --git a/newbinding/src/namespace.py b/llvmpy/src/namespace.py similarity index 100% rename from newbinding/src/namespace.py rename to llvmpy/src/namespace.py diff --git a/newbinding/test_binding.py b/llvmpy/test_binding.py similarity index 98% rename from newbinding/test_binding.py rename to llvmpy/test_binding.py index 7fa5e2c..e1e12e5 100644 --- a/newbinding/test_binding.py +++ b/llvmpy/test_binding.py @@ -1,8 +1,11 @@ -from api import llvm -import extra -import _capsule from StringIO import StringIO -llvm.capsule.set_debug(True) + +from llvmpy.api import llvm +from llvmpy import extra +from llvmpy import _capsule +import llvmpy.capsule +llvmpy.capsule.set_debug(True) + def test_basic_jit_use(): llvm.InitializeNativeTarget() From 2d8c6f0a410469ee0276c120e63414f0b3eb3e7f Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 11 Feb 2013 18:13:38 -0600 Subject: [PATCH 268/516] Add PassRegistry, PassSupport, TargetRegistry, TargetOptions, and functions in Host.h And a few other fixes --- llvmpy/.gitignore | 4 + llvmpy/capsule.py | 7 ++ llvmpy/include/llvm_binding/auto_pyobject.h | 3 +- llvmpy/include/llvm_binding/extra.h | 97 +++++++++++++++++++ llvmpy/src/Analysis/Verifier.py | 2 +- llvmpy/src/DataLayout.py | 15 ++- llvmpy/src/ExecutionEngine/ExecutionEngine.py | 15 ++- llvmpy/src/GlobalVariable.py | 2 +- llvmpy/src/Instruction.py | 12 ++- llvmpy/src/Pass.py | 8 +- llvmpy/src/PassManager.py | 2 +- llvmpy/src/PassRegistry.py | 21 ++++ llvmpy/src/PassSupport.py | 24 +++++ llvmpy/src/Support/Host.py | 25 +++++ llvmpy/src/Support/Target.py | 27 ------ llvmpy/src/Support/TargetRegistry.py | 68 +++++++++++++ llvmpy/src/Target/TargetLibraryInfo.py | 9 +- llvmpy/src/Target/TargetMachine.py | 21 ++-- llvmpy/src/Target/TargetOptions.py | 12 +++ llvmpy/test_binding.py | 41 +++++++- 20 files changed, 352 insertions(+), 63 deletions(-) create mode 100644 llvmpy/.gitignore create mode 100644 llvmpy/src/PassRegistry.py create mode 100644 llvmpy/src/PassSupport.py create mode 100644 llvmpy/src/Support/Host.py delete mode 100644 llvmpy/src/Support/Target.py create mode 100644 llvmpy/src/Support/TargetRegistry.py create mode 100644 llvmpy/src/Target/TargetOptions.py diff --git a/llvmpy/.gitignore b/llvmpy/.gitignore new file mode 100644 index 0000000..ab608aa --- /dev/null +++ b/llvmpy/.gitignore @@ -0,0 +1,4 @@ +api.cpp +api/*.py +api/*/*.py + diff --git a/llvmpy/capsule.py b/llvmpy/capsule.py index d98a23d..7a7ceaf 100644 --- a/llvmpy/capsule.py +++ b/llvmpy/capsule.py @@ -102,6 +102,13 @@ def release_ownership(old): _addr2dtor[addr] = None +def obtain_ownership(cap): + cls = cap.get_class() + if cls._has_dtor(): + addr = cap.pointer + assert _addr2dtor[addr] is None + _addr2dtor[addr] = cls._delete_ + def has_ownership(cap): addr = Capsule.getPointer(cap) return _addr2dtor.get(addr) is not None diff --git a/llvmpy/include/llvm_binding/auto_pyobject.h b/llvmpy/include/llvm_binding/auto_pyobject.h index 451f2d9..368e64f 100644 --- a/llvmpy/include/llvm_binding/auto_pyobject.h +++ b/llvmpy/include/llvm_binding/auto_pyobject.h @@ -34,5 +34,4 @@ private: void operator = (const auto_pyobject&); }; -#endif AUTO_PYOBJECT_H_ - +#endif // AUTO_PYOBJECT_H_ diff --git a/llvmpy/include/llvm_binding/extra.h b/llvmpy/include/llvm_binding/extra.h index 438f52c..2bbad42 100644 --- a/llvmpy/include/llvm_binding/extra.h +++ b/llvmpy/include/llvm_binding/extra.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -16,6 +17,9 @@ #include #include #include +#include +#include + #include "auto_pyobject.h" @@ -774,3 +778,96 @@ PyObject* DynamicLibrary_LoadLibraryPermanently(const char * Filename, } } +class PassRegistryEnumerator : public llvm::PassRegistrationListener{ +public: + PyObject* List; +public: + PassRegistryEnumerator(PyObject* list) : List(list) { } + + inline virtual void passEnumerate(const llvm::PassInfo * pass_info){ + PyObject* passArg = PyString_FromString(pass_info->getPassArgument()); + PyObject* passName = PyString_FromString(pass_info->getPassName()); + PyList_Append(List, Py_BuildValue("(OO)", passArg, passName)); + } +}; + +static +PyObject* PassRegistry_enumerate(llvm::PassRegistry* PR) +{ + using namespace llvm; + PassRegistryEnumerator PRE(PyList_New(0)); + PR->enumerateWith(&PRE); + return PRE.List; +} + +static +PyObject* TargetRegistry_lookupTarget(const std::string &Triple, + PyObject* Error) +{ + using namespace llvm; + std::string error; + const Target* target = TargetRegistry::lookupTarget(Triple, error); + if (!target) { + PyFile_WriteString(error.c_str(), Error); + Py_RETURN_NONE; + } else { + return pycapsule_new(const_cast(target), "llvm::Target"); + } +} + + +static +PyObject* TargetRegistry_lookupTarget(const std::string &Arch, + llvm::Triple &Triple, + PyObject* Error) +{ + using namespace llvm; + std::string error; + const Target* target = TargetRegistry::lookupTarget(Arch, Triple, error); + if (!target) { + PyFile_WriteString(error.c_str(), Error); + Py_RETURN_NONE; + } else { + return pycapsule_new(const_cast(target), "llvm::Target"); + } +} + + +static +PyObject* TargetRegistry_getClosestTargetForJIT(PyObject* Error) +{ + using namespace llvm; + std::string error; + const Target* target = TargetRegistry::getClosestTargetForJIT(error); + if (!target) { + PyFile_WriteString(error.c_str(), Error); + Py_RETURN_NONE; + } else { + return pycapsule_new(const_cast(target), "llvm::Target"); + } + +} + +static +PyObject* llvm_sys_getHostCPUFeatures(PyObject* Features) +{ + using namespace llvm::sys; + using namespace llvm; + typedef StringMap::iterator iterator; + StringMap features; + bool ok = getHostCPUFeatures(features); + if (ok) { + for (iterator it = features.begin(); it != features.end(); ++it) { + const char *key = it->getKey().data(); + PyObject *val = it->getValue() ? Py_True : Py_False; + Py_INCREF(val); + if (-1 == PyDict_SetItemString(Features, key, val)) { + return NULL; + } + } + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } +} + diff --git a/llvmpy/src/Analysis/Verifier.py b/llvmpy/src/Analysis/Verifier.py index 5b47740..3afa075 100644 --- a/llvmpy/src/Analysis/Verifier.py +++ b/llvmpy/src/Analysis/Verifier.py @@ -1,7 +1,7 @@ from binding import * from ..namespace import llvm from ..Module import Module -from ..Function import Function +from ..Value import Function llvm.includes.add('llvm/Analysis/Verifier.h') diff --git a/llvmpy/src/DataLayout.py b/llvmpy/src/DataLayout.py index d704723..9582d53 100644 --- a/llvmpy/src/DataLayout.py +++ b/llvmpy/src/DataLayout.py @@ -1,15 +1,17 @@ from binding import * from namespace import llvm +from Pass import ImmutablePass + +DataLayout = llvm.Class(ImmutablePass) +StructLayout = llvm.Class() + from LLVMContext import LLVMContext from ADT.StringRef import StringRef from Module import Module from Type import Type, IntegerType, StructType from ADT.SmallVector import SmallVector_Value from GlobalVariable import GlobalVariable -from Pass import ImmutablePass -DataLayout = llvm.Class(ImmutablePass) -StructLayout = llvm.Class() @DataLayout class DataLayout: @@ -93,4 +95,9 @@ class DataLayout: @StructLayout class StructLayout: - pass + getSizeInBytes = Method(cast(Uint64, int)) + getSizeInBits = Method(cast(Uint64, int)) + getAlignment = Method(cast(Unsigned, int)) + getElementContainingOffset = Method(cast(Unsigned, int), cast(int, Uint64)) + getElementOffset = Method(cast(Uint64, int), cast(int, Unsigned)) + getElementOffsetInBits = Method(cast(Uint64, int), cast(int, Unsigned)) diff --git a/llvmpy/src/ExecutionEngine/ExecutionEngine.py b/llvmpy/src/ExecutionEngine/ExecutionEngine.py index 1188de3..0bd4714 100644 --- a/llvmpy/src/ExecutionEngine/ExecutionEngine.py +++ b/llvmpy/src/ExecutionEngine/ExecutionEngine.py @@ -34,16 +34,25 @@ class ExecutionEngine: Reloc.Model, CodeModel.Model).require_only(1) - addModule = Method(Void, ptr(Module)) + addModule = Method(Void, ownedptr(Module)) getDataLayout = Method(const(ownedptr(DataLayout))) - removeModule = Method(cast(Bool, bool), ptr(Module)) + _removeModule = Method(cast(Bool, bool), ptr(Module)) + _removeModule.realname = 'removeModule' + @CustomPythonMethod + def removeModule(self, module): + if self._removeModule(module): + capsule.obtain_ownership(module._ptr) + return True + return False FindFunctionNamed = Method(ptr(Function), cast(str, ConstCharPtr)) getPointerToNamedFunction = Method(cast(VoidPtr, int), cast(str, StdString), cast(bool, Bool)).require_only(1) - runStaticConstructorsDestructors = Method(Void, cast(Bool, bool)) + runStaticConstructorsDestructors = Method(Void, + cast(Bool, bool), # is dtor + ) runStaticConstructorsDestructors |= Method(Void, ptr(Module), cast(Bool, bool)) diff --git a/llvmpy/src/GlobalVariable.py b/llvmpy/src/GlobalVariable.py index 4ee91fb..2280e24 100644 --- a/llvmpy/src/GlobalVariable.py +++ b/llvmpy/src/GlobalVariable.py @@ -4,10 +4,10 @@ from namespace import llvm from GlobalValue import GlobalValue GlobalVariable = llvm.Class(GlobalValue) -from Constant import Constant from Module import Module from Type import Type from ADT.StringRef import StringRef +from Value import Constant @GlobalVariable class GlobalVariable: diff --git a/llvmpy/src/Instruction.py b/llvmpy/src/Instruction.py index ca64072..b3fa701 100644 --- a/llvmpy/src/Instruction.py +++ b/llvmpy/src/Instruction.py @@ -1,11 +1,6 @@ from binding import * from namespace import llvm from Value import Value, MDNode, User, BasicBlock, Function -from ADT.StringRef import StringRef -from CallingConv import CallingConv -from Attributes import Attributes -from Constant import ConstantInt -from Type import Type Instruction = llvm.Class(User) @@ -68,6 +63,13 @@ SynchronizationScope = llvm.Enum('SynchronizationScope', +from ADT.StringRef import StringRef +from CallingConv import CallingConv +from Attributes import Attributes +from Constant import ConstantInt +from Type import Type + + @Instruction class Instruction: diff --git a/llvmpy/src/Pass.py b/llvmpy/src/Pass.py index 39e894b..f36856c 100644 --- a/llvmpy/src/Pass.py +++ b/llvmpy/src/Pass.py @@ -1,14 +1,14 @@ from binding import * from namespace import llvm -from ADT.StringRef import StringRef -from Module import Module -from Function import Function Pass = llvm.Class() ModulePass = llvm.Class(Pass) FunctionPass = llvm.Class(Pass) ImmutablePass = llvm.Class(ModulePass) +from ADT.StringRef import StringRef +from Module import Module +from Value import Function @Pass class Pass: @@ -16,7 +16,7 @@ class Pass: delete = Destructor() getPassName = Method(cast(StringRef, str)) - + dump = Method() @ModulePass class ModulePass: diff --git a/llvmpy/src/PassManager.py b/llvmpy/src/PassManager.py index f969192..91a98f4 100644 --- a/llvmpy/src/PassManager.py +++ b/llvmpy/src/PassManager.py @@ -2,7 +2,7 @@ from binding import * from namespace import llvm from Pass import Pass from Module import Module -from Function import Function +from Value import Function PassManagerBase = llvm.Class() PassManager = llvm.Class(PassManagerBase) diff --git a/llvmpy/src/PassRegistry.py b/llvmpy/src/PassRegistry.py new file mode 100644 index 0000000..495de51 --- /dev/null +++ b/llvmpy/src/PassRegistry.py @@ -0,0 +1,21 @@ +from binding import * +from namespace import llvm +from src.ADT.StringRef import StringRef + +PassRegistry = llvm.Class() + +from src.PassSupport import PassInfo + +@PassRegistry +class PassRegistry: + _include_ = 'llvm/PassRegistry.h' + + delete = Destructor() + + getPassRegistry = StaticMethod(ownedptr(PassRegistry)) + + getPassInfo = Method(const(ptr(PassInfo)), cast(str, StringRef)) + + # This is a custom method that wraps enumerateWith + # Returns list of tuples of (pass-arg, pass-name) + enumerate = CustomMethod('PassRegistry_enumerate', PyObjectPtr) \ No newline at end of file diff --git a/llvmpy/src/PassSupport.py b/llvmpy/src/PassSupport.py new file mode 100644 index 0000000..8dba872 --- /dev/null +++ b/llvmpy/src/PassSupport.py @@ -0,0 +1,24 @@ +from binding import * +from namespace import llvm + +PassInfo = llvm.Class() + +from src.Pass import Pass +from src.PassRegistry import PassRegistry + +@PassInfo +class PassInfo: + _include_ = 'llvm/PassSupport.h' + + createPass = Method(ptr(Pass)) + +llvm.Function('initializeCore', Void, ref(PassRegistry)) +llvm.Function('initializeScalarOpts', Void, ref(PassRegistry)) +llvm.Function('initializeVectorization', Void, ref(PassRegistry)) +llvm.Function('initializeIPO', Void, ref(PassRegistry)) +llvm.Function('initializeAnalysis', Void, ref(PassRegistry)) +llvm.Function('initializeIPA', Void, ref(PassRegistry)) +llvm.Function('initializeTransformUtils', Void, ref(PassRegistry)) +llvm.Function('initializeInstCombine', Void, ref(PassRegistry)) +llvm.Function('initializeInstrumentation', Void, ref(PassRegistry)) +llvm.Function('initializeTarget', Void, ref(PassRegistry)) diff --git a/llvmpy/src/Support/Host.py b/llvmpy/src/Support/Host.py new file mode 100644 index 0000000..8163ebe --- /dev/null +++ b/llvmpy/src/Support/Host.py @@ -0,0 +1,25 @@ +from binding import * +from src.namespace import sys + +isLittleEndianHost = sys.Function('isLittleEndianHost', + cast(Bool, bool)) + +isBigEndianHost = sys.Function('isBigEndianHost', + cast(Bool, bool)) + +getDefaultTargetTriple = sys.Function('getDefaultTargetTriple', + cast(ConstStdString, str)) + +# llvm 3.3 +#getProcessTriple = sys.Function('getProcessTriple', +# cast(ConstStdString, str)) + +getHostCPUName = sys.Function('getHostCPUName', + cast(ConstStdString, str)) + +getHostCPUFeatures = sys.CustomFunction('getHostCPUFeatures', + 'llvm_sys_getHostCPUFeatures', + PyObjectPtr, # bool: success? + PyObjectPtr, # dict: store feature map + ) + diff --git a/llvmpy/src/Support/Target.py b/llvmpy/src/Support/Target.py deleted file mode 100644 index bdaeff5..0000000 --- a/llvmpy/src/Support/Target.py +++ /dev/null @@ -1,27 +0,0 @@ -from binding import * -from ..namespace import llvm -from ..ADT.StringRef import StringRef -Target = llvm.Class() - -@Target -class Target: - _include_ = 'llvm/Support/TargetRegistry.h' - - getNext = Method(const(ptr(Target))) - - getName = Method(cast(StringRef, str)) - getShortDescription = Method(cast(StringRef, str)) - - def _has(): - return Method(cast(Bool, bool)) - - hasJIT = _has() - hasTargetMachine = _has() - hasMCAsmBackend = _has() - hasMCAsmParser = _has() - hasAsmPrinter = _has() - hasMCDisassembler = _has() - hasMCInstPrinter = _has() - hasMCCodeEmitter = _has() - hasMCObjectStreamer = _has() - hasAsmStreamer = _has() diff --git a/llvmpy/src/Support/TargetRegistry.py b/llvmpy/src/Support/TargetRegistry.py new file mode 100644 index 0000000..640364b --- /dev/null +++ b/llvmpy/src/Support/TargetRegistry.py @@ -0,0 +1,68 @@ +from binding import * +from src.namespace import llvm + +llvm.includes.add('llvm/Support/TargetRegistry.h') + +Target = llvm.Class() +TargetRegistry = llvm.Class() + +from src.ADT.Triple import Triple +from src.ADT.StringRef import StringRef +from src.Target.TargetMachine import TargetMachine +from src.Target.TargetOptions import TargetOptions +from src.Support.CodeGen import Reloc, CodeModel, CodeGenOpt + +@Target +class Target: + getNext = Method(const(ptr(Target))) + + getName = Method(cast(StringRef, str)) + getShortDescription = Method(cast(StringRef, str)) + + def _has(): + return Method(cast(Bool, bool)) + + hasJIT = _has() + hasTargetMachine = _has() + hasMCAsmBackend = _has() + hasMCAsmParser = _has() + hasAsmPrinter = _has() + hasMCDisassembler = _has() + hasMCInstPrinter = _has() + hasMCCodeEmitter = _has() + hasMCObjectStreamer = _has() + hasAsmStreamer = _has() + + createTargetMachine = Method(ptr(TargetMachine), + cast(str, StringRef), # triple + cast(str, StringRef), # cpu + cast(str, StringRef), # features + ref(TargetOptions), + Reloc.Model, # = Reloc::Default + CodeModel.Model, # = CodeModel.Default + CodeGenOpt.Level, # = CodeGenOpt.Default + ).require_only(4) + + +@TargetRegistry +class TargetRegistry: + printRegisteredTargetsForVersion = StaticMethod() + + lookupTarget = CustomStaticMethod('TargetRegistry_lookupTarget', + PyObjectPtr, # const Target* + cast(str, ConstCharPtr), # triple + PyObjectPtr, # std::string &Error + ) + + lookupTarget |= CustomStaticMethod('TargetRegistry_lookupTarget', + PyObjectPtr, # const Target* + cast(str, ConstCharPtr), # arch + ref(Triple), # triple + PyObjectPtr, # std::string &Error + ) + + getClosestTargetForJIT = CustomStaticMethod( + 'TargetRegistry_getClosestTargetForJIT', + PyObjectPtr, # const Target* + PyObjectPtr, # std::string &Error + ) diff --git a/llvmpy/src/Target/TargetLibraryInfo.py b/llvmpy/src/Target/TargetLibraryInfo.py index d98b00b..9c47814 100644 --- a/llvmpy/src/Target/TargetLibraryInfo.py +++ b/llvmpy/src/Target/TargetLibraryInfo.py @@ -1,8 +1,7 @@ from binding import * from ..namespace import llvm -from ..ADT.Triple import Triple -from ..Pass import ImmutablePass -from ..ADT.StringRef import StringRef + +from src.Pass import ImmutablePass TargetLibraryInfo = llvm.Class(ImmutablePass) @@ -54,6 +53,10 @@ LibFunc.Enum('Func', ''' # not in llvm-3.2 abs, ffs, ffsl, ffsll, fprintf, isascii, # isdigit, labs, llabs, printf, sprintf, toascii +from src.ADT.Triple import Triple +from src.ADT.StringRef import StringRef + + @TargetLibraryInfo class TargetLibraryInfo: _include_ = 'llvm/Target/TargetLibraryInfo.h' diff --git a/llvmpy/src/Target/TargetMachine.py b/llvmpy/src/Target/TargetMachine.py index e60ed5c..29960fa 100644 --- a/llvmpy/src/Target/TargetMachine.py +++ b/llvmpy/src/Target/TargetMachine.py @@ -1,17 +1,18 @@ from binding import * -from ..namespace import llvm -from ..ADT.StringRef import StringRef -from ..Support.CodeGen import CodeModel, TLSModel, CodeGenOpt, Reloc -from ..GlobalValue import GlobalValue -from ..Support.Target import Target -from ..DataLayout import DataLayout -from ..TargetTransformInfo import (ScalarTargetTransformInfo, - VectorTargetTransformInfo) -from ..PassManager import PassManagerBase -from ..Support.FormattedStream import formatted_raw_ostream +from src.namespace import llvm TargetMachine = llvm.Class() +from src.Support.TargetRegistry import Target +from src.ADT.StringRef import StringRef +from src.Support.CodeGen import CodeModel, TLSModel, CodeGenOpt, Reloc +from src.GlobalValue import GlobalValue +from src.DataLayout import DataLayout +from src.TargetTransformInfo import (ScalarTargetTransformInfo, + VectorTargetTransformInfo) +from src.PassManager import PassManagerBase +from src.Support.FormattedStream import formatted_raw_ostream + @TargetMachine class TargetMachine: _include_ = 'llvm/Target/TargetMachine.h' diff --git a/llvmpy/src/Target/TargetOptions.py b/llvmpy/src/Target/TargetOptions.py new file mode 100644 index 0000000..0e28677 --- /dev/null +++ b/llvmpy/src/Target/TargetOptions.py @@ -0,0 +1,12 @@ +from binding import * +from src.namespace import llvm + +llvm.includes.add('llvm/Target/TargetOptions.h') + +TargetOptions = llvm.Class() + +@TargetOptions +class TargetOptions: + new = Constructor() + delete = Destructor() + diff --git a/llvmpy/test_binding.py b/llvmpy/test_binding.py index e1e12e5..01e6c38 100644 --- a/llvmpy/test_binding.py +++ b/llvmpy/test_binding.py @@ -7,9 +7,10 @@ import llvmpy.capsule llvmpy.capsule.set_debug(True) +llvm.InitializeNativeTarget() +llvm.InitializeNativeTargetAsmPrinter() + def test_basic_jit_use(): - llvm.InitializeNativeTarget() - llvm.InitializeNativeTargetAsmPrinter() context = llvm.getGlobalContext() m = llvm.Module.new("modname", context) @@ -332,6 +333,42 @@ def test_intrinsic(): fn.eraseFromParent() assert 'llvm.sin.f32' not in str(m) +def test_passregistry(): + passreg = llvm.PassRegistry.getPassRegistry() + + llvm.initializeScalarOpts(passreg) + + passinfo = passreg.getPassInfo("dce") + dcepass = passinfo.createPass() + print dcepass.getPassName() + + print passreg.enumerate() + +def test_targetregistry(): + llvm.TargetRegistry.printRegisteredTargetsForVersion() + errmsg = StringIO() + + target = llvm.TargetRegistry.getClosestTargetForJIT(errmsg) + errmsg.close() + + print target.getName() + print target.getShortDescription() + assert target.hasJIT() + assert target.hasTargetMachine() + + next = target.getNext() + if next: + print next.getName() + print next.getShortDescription() + + triple = llvm.sys.getDefaultTargetTriple() + cpu = llvm.sys.getHostCPUName() + features = {} + assert not llvm.sys.getHostCPUFeatures(features), "Only for Linux and ARM?" + + targetoptions = llvm.TargetOptions.new() + tm = target.createTargetMachine(triple, cpu, "", targetoptions) + def main(): for name, value in globals().items(): if name.startswith('test_') and callable(value): From a97b26415e7e21d63abfe66ed9c31b3e9a1d1e7d Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 11 Feb 2013 18:15:22 -0600 Subject: [PATCH 269/516] Update old API to use the new binding. Have not run the testsuite yet. --- llvm/__init__.py | 4 + llvm/core.py | 30 ++++ llvm/ee.py | 334 ++++++++++++++++++++++++++++++++++++++++++ llvm/passes.py | 371 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 739 insertions(+) diff --git a/llvm/__init__.py b/llvm/__init__.py index 23f3f4d..4cf374c 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -1,5 +1,6 @@ class Wrapper(object): def __init__(self, ptr): + assert ptr self.__ptr = ptr @property @@ -9,3 +10,6 @@ class Wrapper(object): def _extract_ptrs(objs): return [x._ptr for x in objs] + +class LLVMException(Exception): + pass diff --git a/llvm/core.py b/llvm/core.py index 2f7adb5..3c3e027 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -1,3 +1,33 @@ +# +# Copyright (c) 2008-10, Mahadevan R All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of this software, nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + try: from cStringIO import StringIO except ImportError: diff --git a/llvm/ee.py b/llvm/ee.py index e69de29..8523998 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -0,0 +1,334 @@ +# +# Copyright (c) 2008-10, Mahadevan R All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of this software, nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +"Execution Engine and related classes." + +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO +import contextlib + +import llvm +from llvm import core +from llvmpy import api + +#===----------------------------------------------------------------------=== +# 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 + +#===----------------------------------------------------------------------=== +# Generic value +#===----------------------------------------------------------------------=== + +class GenericValue(llvm.Wrapper): + + @staticmethod + def int(ty, intval): + ptr = api.llvm.CreateInt(ty._ptr, intval, False) + return GenericValue(ptr) + + @staticmethod + def int_signed(ty, intval): + ptr = api.llvm.CreateInt(ty._ptr, intval, True) + return GenericValue(ptr) + + @staticmethod + def real(ty, floatval): + if str(ty) == 'float': + ptr = api.llvm.CreateFloat(floatval) + elif str(ty) == 'double': + ptr = api.llvm.CreateDouble(floatval) + else: + raise Exception('Unreachable') + return GenericValue(ptr) + + @staticmethod + def pointer(addr): + ''' + One argument version takes (addr). + Two argument version takes (ty, addr). [Deprecated] + + `ty` is unused. + `addr` is an integer representing an address. + + ''' + ptr = api.llvm.CreatePointer(addr) + return GenericValue(ptr) + + def as_int(self): + return self._ptr.toUnsignedInt() + + def as_int_signed(self): + return self._ptr.toSignedInt() + + def as_real(self, ty): + return self._ptr.toFloat() + + def as_pointer(self): + return self._ptr.toPointer() + +#===----------------------------------------------------------------------=== +# Engine builder +#===----------------------------------------------------------------------=== + +class EngineBuilder(llvm.Wrapper): + @staticmethod + def new(module): + ptr = api.llvm.EngineBuilder.new(module) + return EngineBuilder(ptr) + + def force_jit(self): + self._ptr.setEngineKind(api.llvm.EngineKind.Kind.JIT) + return self + + def force_interpreter(self): + self._ptr.setEngineKind(api.llvm.EngineKind.Kind.Interpreter) + return self + + def opt(self, level): + ''' + level valid [0, 1, 2, 3] -- [None, Less, Default, Aggressive] + ''' + assert 0 <= level <= 3 + self._ptr.setOptLevel = level + return self + + def mattrs(self, string): + '''set machine attributes as a comma/space separated string + + e.g: +sse,-3dnow + ''' + self._ptr.setMAttrs(string.split(',')) + return self + + def create(self, tm=None): + ''' + tm --- Optional. Provide a TargetMachine. Ownership is transfered + to the returned execution engine. + ''' + if tm is not None: + engine = self._ptr.create(tm._ptr) + else: + engine = self._ptr.create() + return ExecutionEngine(engine) + + def select_target(self, *args): + '''get the corresponding target machine + + Accept no arguments or (triple, march, mcpu, mattrs) + ''' + if args: + triple, march, mcpu, mattrs = args + ptr = self._ptr.select_target(triple, march, mcpu, + mattrs.split(',')) + else: + ptr = self._ptr.select_target() + return TargetMachine(ptr) + + +#===----------------------------------------------------------------------=== +# Execution engine +#===----------------------------------------------------------------------=== + +class ExecutionEngine(llvm.Wrapper): + + @staticmethod + def new(module, force_interpreter=False): + eb = EngineBuilder.new(module) + if force_interpreter: + eb.force_interpreter() + return eb.create() + + def disable_lazy_compilation(self, disabled=True): + self._ptr.DisableLazyCompilation(disabled) + + def run_function(self, fn, args): + return self._ptr.runFunction(fn._ptr, map(lambda x: x._ptr, args)) + + def get_pointer_to_function(self, fn): + return self._ptr.getPointerToFunction(fn._ptr) + + def get_pointer_to_global(self, val): + return self._ptr.getPointerToGlobal(val._ptr) + + def add_global_mapping(self, gvar, addr): + assert addr >= 0, "Address cannot not be negative" + self._ptr.addGlobalMapping(gvar._ptr, addr) + + def run_static_ctors(self): + self._ptr.runStaticConstructorDestructors(False) + + def run_static_dtors(self): + self._ptr.runStaticConstructorDestructors(True) + + def free_machine_code_for(self, fn): + self.freeMachineCodeForFunction(fn._ptr) + + def add_module(self, module): + self._ptr.addModule(module._ptr) + + def remove_module(self, module): + return self._ptr.removeModule(module._ptr) + + @property + def target_data(self): + ptr = self._ptr.getDataLayout() + return TargetData(ptr) + +#===----------------------------------------------------------------------=== +# Target machine +#===----------------------------------------------------------------------=== + +def print_registered_targets(): + ''' + Note: print directly to stdout + ''' + llvm.TargetRegistry.printRegisteredTargetsForVersion() + +def get_host_cpu_name(): + '''return the string name of the host CPU + ''' + return llvm.sys.getHostCPUName() + +def get_default_triple(): + '''return the target triple of the host in str-rep + ''' + return llvm.sys.getDefaultTargetTriple() + + +class TargetMachine(llvm.Wrapper): + + @staticmethod + def new(triple='', cpu='', features='', opt=2, cm=CM_DEFAULT): + if not triple: + triple = get_default_triple() + if not cpu: + cpu = get_host_cpu_name() + with contextlib.closing(StringIO) 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() + tm = target.createTargetMachine(triple, cpu, features, + target_options, + api.llvm.Reloc.Model.Default, + cm, opt) + if not tm: + raise llvm.LLVMException("Cannot create target machine") + return TargetMachine(ptr) + + @staticmethod + def lookup(arch, cpu='', features='', opt=2, cm=CM_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(StringIO) as error: + target = api.llvm.TargetMachine.lookupTarget(arch, 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() + tm = target.createTargetMachine(str(triple), cpu, features, + target_options, + api.llvm.Reloc.Model.Default, + cm, opt) + if not tm: + raise llvm.LLVMException("Cannot create target machine") + return TargetMachine(ptr) + + def _emit_file(self, module, cgft): + pm = api.llvm.PassManager.new() + os = api.extra.make_raw_ostream_for_printing() + failed = self._ptr.addPassesToEmitFile(pm, os, cgft) + pm.run(module) + 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, 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, 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() + diff --git a/llvm/passes.py b/llvm/passes.py index e69de29..545a19d 100644 --- a/llvm/passes.py +++ b/llvm/passes.py @@ -0,0 +1,371 @@ +# +# Copyright (c) 2008-10, Mahadevan R All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of this software, nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +"""Pass managers and passes. + +This module provides the LLVM pass managers and the passes themselves. +All transformation passes listed at http://www.llvm.org/docs/Passes.html +are available. +""" + +import llvm # top-level, for common stuff +import llvm.core as core # module, function etc. +from llvmpy import api + +#===----------------------------------------------------------------------=== +# Pass manager builder +#===----------------------------------------------------------------------=== + +class PassManagerBuilder(llvm.Wrapper): + @staticmethod + def new(): + return PassManagerBuilder(api.llvm.PassManagerBuilder()) + + def populate(self, pm): + if isinstance(pm, FunctionPassManager): + self._ptr.populateFunctionPassManager(pm._ptr) + else: + self._ptr.populateModulePassManager(pm._ptr) + + @property + def opt_level(self): + return self._ptr.OptLevel + + @opt_level.setter + def _set_opt_level(self, optlevel): + self._ptr.OptLevel = optlevel + + @property + def size_level(self): + return self._ptr.SizeLevel + + @size_level.setter + def _set_size_level(self, sizelevel): + self._ptr.SizeLevel = sizelevel + + @property + def vectorize(self): + return self._ptr.Vectorize + + @vectorize.setter + def _set_vectorize(self, enable): + self._ptr.Vectroize = enable + + @property + def loop_vectorize(self): + try: + return self._ptr.LoopVectorize + except AttributeError: + return False + + @loop_vectorize.setter + def loop_vectorize(self, enable): + if llvm.version >= (3, 2): + self._ptr.LoopVectorize = enable + elif enable: + warnings.warn("Ignored. LLVM-3.1 & prior do not support loop vectorizer.") + + @property + def disable_unit_at_a_time(self): + return self._ptr.DisableUnitAtATime + + @disable_unit_at_a_time.setter + def disable_unit_at_a_time(self, disable): + self._ptr.DisableUnitAtATime = disable + + @property + def disable_unroll_loops(self): + return self._ptr.DisableUnrollLoops + + @disable_unroll_loops.setter + def disable_unroll_loops(self, disable): + self._ptr.DisableUnrollLoops = disable + + @property + def disable_simplify_lib_calls(self): + return self._ptr.DisableSimplifyLibCalls + + @disable_simplify_lib_calls.setter + def disable_simplify_lib_calls(self, disable): + self._ptr.DisableSimplifyLibCalls = disable + + def use_inliner_with_threshold(self, threshold): + self._ptr.Inliner = api.llvm.createFunctionInliningPass(threshold) + + +#===----------------------------------------------------------------------=== +# Pass manager +#===----------------------------------------------------------------------=== + +class PassManager(llvm.Wrapper): + + @staticmethod + def new(): + return PassManager(api.llvm.PassManager.new()) + + def add(self, pass_obj): + '''Add a pass to the pass manager. + + pass_obj --- Either a Pass instance, a string name of a pass + ''' + if isinstance(pass_obj, Pass): + self._ptr.add(pass_obj._ptr) + else: + self._add_pass(str(pass_obj)) + + def _add_pass(self, pass_name): + passreg = api.llvm.PassRegistry.getPassRegistry() + a_pass = passreg.getPassInfo(pass_name) + if not a_pass: + assert pass_name not in PASSES, "Registered but not found?" + raise llvm.LLVMException('Invalid pass name "%s"' % pass_name) + self._ptr.add(a_pass) + + def run(self, module): + return self._ptr.run(module._ptr) + +class FunctionPassManager(PassManager): + + @staticmethod + def new(module): + ptr = api.llvm.FunctionPassManager.new(module) + return FunctionPassManager(ptr) + + def __init__(self, ptr): + PassManager.__init__(self, ptr) + + def initialize(self): + self._ptr.doInitization() + + def run(self, fn): + return self._ptr.run(fn) + + def finalize(self): + self._ptr.doFinalization() + +#===----------------------------------------------------------------------=== +# Passes +#===----------------------------------------------------------------------=== + +class Pass(llvm.Wrapper): + '''Pass Inferface + ''' + + @staticmethod + def new(name): + '''Create a new pass by name. + + Note: Not all pass has a default constructor. LLVM will kill + the process if an the pass requires arguments to construct. + The error cannot be caught. + ''' + passreg = api.llvm.PassRegistry.getPassRegistry() + a_pass = passreg.getPassInfo(pass_name) + p = Pass(a_pass) + p.__name = name + return p + + @property + def name(self): + '''The name used in PassRegistry. + ''' + return p.__name + + @property + def description(self): + return self._ptr.getPassName() + + def dump(self): + return self._ptr.dump() + +#===----------------------------------------------------------------------=== +# Target data +#===----------------------------------------------------------------------=== + +class TargetData(Pass): + + @staticmethod + def new(strrep): + ptr = api.llvm.DataLayout.new(strrep) + return TargetData(ptr) + + def clone(self): + return TargetData.new(str(self)) + + def __str__(self): + return self._ptr.getStringRepresentation() + + @property + def byte_order(self): + if self._ptr.isLittleEndian(): + return 1 + else: + return 0 + + @property + def pointer_size(self): + return self._ptr.getPointerSize() + + @property + def target_integer_type(self): + return self._ptr.core.IntegerType(core.Type.getInt32Ty()) + + def size(self, ty): + return self._ptr.getTypeSizeInBits(ty._ptr) + + def store_size(self, ty): + return self._ptr.getTypeStoreSize(ty._ptr) + + def abi_size(self, ty): + return self._ptr.getTypeAllocSize(ty._ptr) + + def abi_alignment(self, ty): + return self._ptr.getABITypeAlignment(ty._ptr) + + def callframe_alignment(self, ty): + return self._ptr.getCallFrameTypeAlignment(ty._ptr) + + def preferred_alignment(self, ty_or_gv): + if isinstance(ty_or_gv, core.Type): + return self._ptr.getPrefTypeAlignment(ty_or_gv._ptr) + elif isinstance(ty_or_gv, core.GlobalVariable): + return self._ptr._core.getPreferredAlignment(ty_or_gv._ptr) + else: + raise core.LLVMException("argument is neither a type nor a global variable") + + def element_at_offset(self, ty, ofs): + return self._ptr.getStructLayout(ty).getElementContainingOffset(ofs) + + def offset_of_element(self, ty, el): + return self._ptr.getStructLayout(ty).getElementOffset(el) + +#===----------------------------------------------------------------------=== +# Target Library Info +#===----------------------------------------------------------------------=== + +class TargetLibraryInfo(Pass): + @staticmethod + def new(triple): + triple = api.llvm.Triple.new(str(triple)) + ptr = api.llvm.TargetLibraryInfo.new(triple) + return TargetLibraryInfo(ptr) + +#===----------------------------------------------------------------------=== +# Helpers +#===----------------------------------------------------------------------=== + +def build_pass_managers(tm, opt=2, loop_vectorize=False, vectorize=False, + inline_threshold=2000, pm=True, fpm=True, mod=None): + ''' + tm --- The TargetMachine for which the passes are optimizing for. + The TargetMachine must stay alive until the pass managers + are removed. + opt --- [0-3] Optimization level. Default to 2. + loop_vectorize --- [boolean] Whether to use loop-vectorizer. + vectorize --- [boolean] Whether to use basic-block vectorizer. + inline_threshold --- [int] Threshold for the inliner. + features --- [str] CPU feature string. + pm --- [boolean] Whether to build a module-level pass-manager. + fpm --- [boolean] Whether to build a function-level pass-manager. + mod --- [Module] The module object for the FunctionPassManager. + ''' + if pm: + pm = PassManager.new() + if fpm: + if not mod: + raise TypeError("Keyword 'mod' must be defined") + fpm = FunctionPassManager.new(mod) + + # Populate PassManagers with target specific passes + pmb = PassManagerBuilder.new() + pmb.opt_level = opt + pmb.vectorize = vectorize + pmb.loop_vectorize = loop_vectorize + if inline_threshold: + pmb.use_inliner_with_threshold(inline_threshold) + if pm: + pm.add(tm.target_data.clone()) + pm.add(TargetLibraryInfo.new(tm.triple)) + if llvm.version >= (3, 2): + pm.add(TargetTransformInfo.new(tm)) + pmb.populate(pm) + + if fpm: + fpm.add(tm.target_data) + fpm.add(TargetLibraryInfo.new(tm.triple)) + if llvm.version >= (3, 2): + fpm.add(TargetTransformInfo.new(tm)) + pmb.populate(fpm) + fpm.initialize() + + from collections import namedtuple + return namedtuple('passmanagers', ['pm', 'fpm'])(pm=pm, fpm=fpm) + +#===----------------------------------------------------------------------=== +# Misc. +#===----------------------------------------------------------------------=== + +# Intialize passes +PASSES = None + +def _dump_all_passes(): + passreg = api.llvm.PassRegistry.getPassRegistry() + for name, desc in passreg.enumerate(): + yield name, desc + +def _initialize_passes(): + global PASSES + + passreg = api.llvm.PassRegistry.getPassRegistry() + + api.llvm.initializeCore(passreg) + api.llvm.initializeScalarOpts(passreg) + api.llvm.initializeVectorization(passreg) + api.llvm.initializeIPO(passreg) + api.llvm.initializeAnalysis(passreg) + api.llvm.initializeIPA(passreg) + api.llvm.initializeTransformUtils(passreg) + api.llvm.initializeInstCombine(passreg) + api.llvm.initializeInstrumentation(passreg) + api.llvm.initializeTarget(passreg) + + PASSES = dict(_dump_all_passes()) + + # build globals + def transform(name): + return "PASS_%s" % (name.upper().replace('-', '_')) + + global_symbols = globals() + for i in PASSES: + assert i not in global_symbols + global_symbols[transform(i)] = i + +_initialize_passes() + From b4f4483809c006918056d932f5f93639efd221e5 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Tue, 12 Feb 2013 11:24:36 -0600 Subject: [PATCH 270/516] Py3k fixes for Windows --- llvm-config-win32.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/llvm-config-win32.py b/llvm-config-win32.py index 595452c..2fbe662 100644 --- a/llvm-config-win32.py +++ b/llvm-config-win32.py @@ -1,4 +1,6 @@ -import sys, os +import sys +import os + def find_path_of(filename, envvar='PATH'): """Finds the path from $PATH where the file exists, returns None if not found.""" @@ -8,11 +10,12 @@ def find_path_of(filename, envvar='PATH'): return os.path.abspath(path) return None + if sys.argv[1] == '--version': cmd = 'llvm-tblgen --version' # Hardcoded extraction, only tested on llvm 3.1 result = os.popen(cmd).read().split('\n')[1].strip().split(' ')[2] - print result + print(result) elif sys.argv[1] == '--libs': # NOTE: instead of actually looking at the components requested, # we just spit out a bunch of libs @@ -70,7 +73,7 @@ elif sys.argv[1] == '--includedir': incdir = os.path.abspath(os.path.join(llvmbin, '../include')) if not os.path.exists(os.path.join(incdir, 'llvm/BasicBlock.h')): raise RuntimeError('Could not find LLVM include dir') - print incdir + print(incdir) elif sys.argv[1] == '--libdir': llvmbin = find_path_of('llvm-tblgen.exe') if llvmbin is None: @@ -78,6 +81,6 @@ elif sys.argv[1] == '--libdir': libdir = os.path.abspath(os.path.join(llvmbin, '../lib')) if not os.path.exists(os.path.join(libdir, 'LLVMCore.lib')): raise RuntimeError('Could not find LLVM lib dir') - print libdir + print(libdir) else: raise RuntimeError('Unrecognized llvm-config command %s' % sys.argv[1]) From 0036d55eead8782bd603e5202c22f8d5dde0b027 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Tue, 12 Feb 2013 11:55:04 -0600 Subject: [PATCH 271/516] remove excess whitespace --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 78079fd..c24aa66 100644 --- a/setup.py +++ b/setup.py @@ -42,7 +42,7 @@ def get_enabled_components(): return run_llvm_config(['--components']).split() def get_llvm_version(): - return run_llvm_config([' --version']) + return run_llvm_config(['--version']) def auto_intrinsic_gen(incdir): From a09394cacdcc841c22d205976ef3d059686cd716 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 13 Feb 2013 15:09:26 -0600 Subject: [PATCH 272/516] Fix a lots of bugs in the newbinding to pass all the tests. NOTE: debug info has not been implemented yet. --- llvm/__init__.py | 22 +- llvm/_version.py | 193 +++ llvm/core.py | 1065 ++++++++------ llvm/ee.py | 60 +- llvm/passes.py | 49 +- llvm/tbaa.py | 51 + llvm/test_llvmpy.py | 1243 +++++++++++++++++ llvmpy/capsule.py | 6 +- llvmpy/gen/binding.py | 17 +- llvmpy/include/llvm_binding/conversion.h | 21 +- llvmpy/include/llvm_binding/extra.h | 54 +- llvmpy/src/Argument.py | 4 +- llvmpy/src/Attributes.py | 2 +- llvmpy/src/BasicBlock.py | 4 +- llvmpy/src/Constant.py | 33 +- llvmpy/src/DerivedTypes.py | 1 + llvmpy/src/ExecutionEngine/ExecutionEngine.py | 2 +- llvmpy/src/Function.py | 4 +- llvmpy/src/GenericValue.py | 4 +- llvmpy/src/IRBuilder.py | 7 +- llvmpy/src/Instruction.py | 6 +- llvmpy/src/Metadata.py | 2 + llvmpy/src/Target/TargetMachine.py | 6 +- llvmpy/src/TargetTransformInfo.py | 10 +- llvmpy/src/Transforms/PassManagerBuilder.py | 11 +- llvmpy/src/Transforms/Utils/Cloning.py | 10 +- llvmpy/src/Type.py | 20 +- llvmpy/src/Value.py | 9 + test/constants.py | 2 - test/malloc.py | 16 + test/operands.py | 2 + test/testall.py | 29 +- 32 files changed, 2419 insertions(+), 546 deletions(-) create mode 100644 llvm/_version.py create mode 100644 llvm/tbaa.py create mode 100644 llvm/test_llvmpy.py create mode 100644 test/malloc.py diff --git a/llvm/__init__.py b/llvm/__init__.py index 4cf374c..c18d066 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -1,3 +1,12 @@ +from ._version import get_versions +__version__ = get_versions()['version'] +del get_versions + + +from llvmpy import extra +version = extra.get_llvm_version() +del extra + class Wrapper(object): def __init__(self, ptr): assert ptr @@ -9,7 +18,18 @@ class Wrapper(object): def _extract_ptrs(objs): - return [x._ptr for x in objs] + return [(x._ptr if x is not None else None) + for x in objs] class LLVMException(Exception): pass + +def test(verbosity=1): + """test(verbosity=1) -> TextTestResult + + Run self-test, and return unittest.runner.TextTestResult object. + """ + from llvm.test_llvmpy import run + + return run(verbosity=verbosity) + diff --git a/llvm/_version.py b/llvm/_version.py new file mode 100644 index 0000000..a90c5b8 --- /dev/null +++ b/llvm/_version.py @@ -0,0 +1,193 @@ + +IN_LONG_VERSION_PY = True +# This file helps to compute a version number in source trees obtained from +# git-archive tarball (such as those provided by github's download-from-tag +# feature). Distribution tarballs (build by setup.py sdist) and build +# directories (produced by setup.py build) will contain a much shorter file +# that just contains the computed version number. + +# This file is released into the public domain. Generated by +# versioneer-0.7+ (https://github.com/warner/python-versioneer) + +# these strings will be replaced by git during git-archive +git_refnames = "$Format:%d$" +git_full = "$Format:%H$" +GIT = "git" + +import subprocess +import sys + +def run_command(args, cwd=None, verbose=False): + try: + # remember shell=False, so use git.cmd on windows, not just git + p = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd) + except EnvironmentError: + e = sys.exc_info()[1] + if verbose: + print("unable to run %s" % args[0]) + print(e) + return None + stdout = p.communicate()[0].strip() + if sys.version >= '3': + stdout = stdout.decode() + if p.returncode != 0: + if verbose: + print("unable to run %s (error)" % args[0]) + return None + return stdout + + +import sys +import re +import os.path + +def get_expanded_variables(versionfile_source): + # the code embedded in _version.py can just fetch the value of these + # variables. When used from setup.py, we don't want to import + # _version.py, so we do it with a regexp instead. This function is not + # used from _version.py. + variables = {} + try: + for line in open(versionfile_source,"r").readlines(): + if line.strip().startswith("git_refnames ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + variables["refnames"] = mo.group(1) + if line.strip().startswith("git_full ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + variables["full"] = mo.group(1) + except EnvironmentError: + pass + return variables + +def versions_from_expanded_variables(variables, tag_prefix, verbose=False): + refnames = variables["refnames"].strip() + if refnames.startswith("$Format"): + if verbose: + print("variables are unexpanded, not using") + return {} # unexpanded, so not in an unpacked git-archive tarball + refs = set([r.strip() for r in refnames.strip("()").split(",")]) + for ref in list(refs): + if not re.search(r'\d', ref): + if verbose: + print("discarding '%s', no digits" % ref) + refs.discard(ref) + # Assume all version tags have a digit. git's %d expansion + # behaves like git log --decorate=short and strips out the + # refs/heads/ and refs/tags/ prefixes that would let us + # distinguish between branches and tags. By ignoring refnames + # without digits, we filter out many common branch names like + # "release" and "stabilization", as well as "HEAD" and "master". + if verbose: + print("remaining refs: %s" % ",".join(sorted(refs))) + for ref in sorted(refs): + # sorting will prefer e.g. "2.0" over "2.0rc1" + if ref.startswith(tag_prefix): + r = ref[len(tag_prefix):] + if verbose: + print("picking %s" % r) + return { "version": r, + "full": variables["full"].strip() } + # no suitable tags, so we use the full revision id + if verbose: + print("no suitable tags, using full revision id") + return { "version": variables["full"].strip(), + "full": variables["full"].strip() } + +def versions_from_vcs(tag_prefix, versionfile_source, verbose=False): + # this runs 'git' from the root of the source tree. That either means + # someone ran a setup.py command (and this code is in versioneer.py, so + # IN_LONG_VERSION_PY=False, thus the containing directory is the root of + # the source tree), or someone ran a project-specific entry point (and + # this code is in _version.py, so IN_LONG_VERSION_PY=True, thus the + # containing directory is somewhere deeper in the source tree). This only + # gets called if the git-archive 'subst' variables were *not* expanded, + # and _version.py hasn't already been rewritten with a short version + # string, meaning we're inside a checked out source tree. + + try: + here = os.path.abspath(__file__) + except NameError: + # some py2exe/bbfreeze/non-CPython implementations don't do __file__ + return {} # not always correct + + # versionfile_source is the relative path from the top of the source tree + # (where the .git directory might live) to this file. Invert this to find + # the root from __file__. + root = here + if IN_LONG_VERSION_PY: + for i in range(len(versionfile_source.split("/"))): + root = os.path.dirname(root) + else: + root = os.path.dirname(here) + if not os.path.exists(os.path.join(root, ".git")): + if verbose: + print("no .git in %s" % root) + return {} + + stdout = run_command([GIT, "describe", "--tags", "--dirty", "--always"], + cwd=root) + if stdout is None: + return {} + if not stdout.startswith(tag_prefix): + if verbose: + print("tag '%s' doesn't start with prefix '%s'" % (stdout, tag_prefix)) + return {} + tag = stdout[len(tag_prefix):] + stdout = run_command([GIT, "rev-parse", "HEAD"], cwd=root) + if stdout is None: + return {} + full = stdout.strip() + if tag.endswith("-dirty"): + full += "-dirty" + return {"version": tag, "full": full} + + +def versions_from_parentdir(parentdir_prefix, versionfile_source, verbose=False): + if IN_LONG_VERSION_PY: + # We're running from _version.py. If it's from a source tree + # (execute-in-place), we can work upwards to find the root of the + # tree, and then check the parent directory for a version string. If + # it's in an installed application, there's no hope. + try: + here = os.path.abspath(__file__) + except NameError: + # py2exe/bbfreeze/non-CPython don't have __file__ + return {} # without __file__, we have no hope + # versionfile_source is the relative path from the top of the source + # tree to _version.py. Invert this to find the root from __file__. + root = here + for i in range(len(versionfile_source.split("/"))): + root = os.path.dirname(root) + else: + # we're running from versioneer.py, which means we're running from + # the setup.py in a source tree. sys.argv[0] is setup.py in the root. + here = os.path.abspath(sys.argv[0]) + root = os.path.dirname(here) + + # Source tarballs conventionally unpack into a directory that includes + # both the project name and a version string. + dirname = os.path.basename(root) + if not dirname.startswith(parentdir_prefix): + if verbose: + print("guessing rootdir is '%s', but '%s' doesn't start with prefix '%s'" % + (root, dirname, parentdir_prefix)) + return None + return {"version": dirname[len(parentdir_prefix):], "full": ""} + +tag_prefix = "" +parentdir_prefix = "llvmpy-" +versionfile_source = "llvm/_version.py" + +def get_versions(default={"version": "unknown", "full": ""}, verbose=False): + variables = { "refnames": git_refnames, "full": git_full } + ver = versions_from_expanded_variables(variables, tag_prefix, verbose) + if not ver: + ver = versions_from_vcs(tag_prefix, versionfile_source, verbose) + if not ver: + ver = versions_from_parentdir(parentdir_prefix, versionfile_source, + verbose) + if not ver: + ver = default + return ver diff --git a/llvm/core.py b/llvm/core.py index 3c3e027..1c3184c 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -32,11 +32,12 @@ try: from cStringIO import StringIO except ImportError: from StringIO import StringIO -import contextlib +import contextlib, weakref import llvm +from llvm._intrinsic_ids import * -import api +from llvmpy import api #===----------------------------------------------------------------------=== # Enumerations @@ -88,167 +89,180 @@ VALUE_PSEUDO_SOURCE_VALUE = api.llvm.Value.ValueTy.PseudoSourceVal VALUE_FIXED_STACK_PSEUDO_SOURCE_VALUE = api.llvm.Value.ValueTy.FixedStackPseudoSourceValueVal VALUE_INSTRUCTION = api.llvm.Value.ValueTy.InstructionVal -## instruction opcodes (from include/llvm/Instruction.def) -#OPCODE_RET = 1 -#OPCODE_BR = 2 -#OPCODE_SWITCH = 3 -#OPCODE_INDIRECT_BR = 4 -#OPCODE_INVOKE = 5 -#OPCODE_RESUME = 6 -#OPCODE_UNREACHABLE = 7 -#OPCODE_ADD = 8 -#OPCODE_FADD = 9 -#OPCODE_SUB = 10 -#OPCODE_FSUB = 11 -#OPCODE_MUL = 12 -#OPCODE_FMUL = 13 -#OPCODE_UDIV = 14 -#OPCODE_SDIV = 15 -#OPCODE_FDIV = 16 -#OPCODE_UREM = 17 -#OPCODE_SREM = 18 -#OPCODE_FREM = 19 -#OPCODE_SHL = 20 -#OPCODE_LSHR = 21 -#OPCODE_ASHR = 22 -#OPCODE_AND = 23 -#OPCODE_OR = 24 -#OPCODE_XOR = 25 -#OPCODE_ALLOCA = 26 -#OPCODE_LOAD = 27 -#OPCODE_STORE = 28 -#OPCODE_GETELEMENTPTR = 29 -#OPCODE_FENCE = 30 -#OPCODE_ATOMICCMPXCHG = 31 -#OPCODE_ATOMICRMW = 32 -#OPCODE_TRUNC = 33 -#OPCODE_ZEXT = 34 -#OPCODE_SEXT = 35 -#OPCODE_FPTOUI = 36 -#OPCODE_FPTOSI = 37 -#OPCODE_UITOFP = 38 -#OPCODE_SITOFP = 39 -#OPCODE_FPTRUNC = 40 -#OPCODE_FPEXT = 41 -#OPCODE_PTRTOINT = 42 -#OPCODE_INTTOPTR = 43 -#OPCODE_BITCAST = 44 -#OPCODE_ICMP = 45 -#OPCODE_FCMP = 46 -#OPCODE_PHI = 47 -#OPCODE_CALL = 48 -#OPCODE_SELECT = 49 -#OPCODE_USEROP1 = 50 -#OPCODE_USEROP2 = 51 -#OPCODE_VAARG = 52 -#OPCODE_EXTRACTELEMENT = 53 -#OPCODE_INSERTELEMENT = 54 -#OPCODE_SHUFFLEVECTOR = 55 -#OPCODE_EXTRACTVALUE = 56 -#OPCODE_INSERTVALUE = 57 -#OPCODE_LANDINGPAD = 58 -# -## calling conventions -#CC_C = 0 -#CC_FASTCALL = 8 -#CC_COLDCALL = 9 -#CC_GHC = 10 -#CC_X86_STDCALL = 64 -#CC_X86_FASTCALL = 65 -#CC_ARM_APCS = 66 -#CC_ARM_AAPCS = 67 -#CC_ARM_AAPCS_VFP = 68 -#CC_MSP430_INTR = 69 -#CC_X86_THISCALL = 70 -#CC_PTX_KERNEL = 71 -#CC_PTX_DEVICE = 72 -#CC_MBLAZE_INTR = 73 -#CC_MBLAZE_SVOL = 74 -# -# -## int predicates -#ICMP_EQ = 32 -#ICMP_NE = 33 -#ICMP_UGT = 34 -#ICMP_UGE = 35 -#ICMP_ULT = 36 -#ICMP_ULE = 37 -#ICMP_SGT = 38 -#ICMP_SGE = 39 -#ICMP_SLT = 40 -#ICMP_SLE = 41 -# -## same as ICMP_xx, for backward compatibility -#IPRED_EQ = ICMP_EQ -#IPRED_NE = ICMP_NE -#IPRED_UGT = ICMP_UGT -#IPRED_UGE = ICMP_UGE -#IPRED_ULT = ICMP_ULT -#IPRED_ULE = ICMP_ULE -#IPRED_SGT = ICMP_SGT -#IPRED_SGE = ICMP_SGE -#IPRED_SLT = ICMP_SLT -#IPRED_SLE = ICMP_SLE -# -## real predicates -#FCMP_FALSE = 0 -#FCMP_OEQ = 1 -#FCMP_OGT = 2 -#FCMP_OGE = 3 -#FCMP_OLT = 4 -#FCMP_OLE = 5 -#FCMP_ONE = 6 -#FCMP_ORD = 7 -#FCMP_UNO = 8 -#FCMP_UEQ = 9 -#FCMP_UGT = 10 -#FCMP_UGE = 11 -#FCMP_ULT = 12 -#FCMP_ULE = 13 -#FCMP_UNE = 14 -#FCMP_TRUE = 15 -# -## real predicates -#RPRED_FALSE = FCMP_FALSE -#RPRED_OEQ = FCMP_OEQ -#RPRED_OGT = FCMP_OGT -#RPRED_OGE = FCMP_OGE -#RPRED_OLT = FCMP_OLT -#RPRED_OLE = FCMP_OLE -#RPRED_ONE = FCMP_ONE -#RPRED_ORD = FCMP_ORD -#RPRED_UNO = FCMP_UNO -#RPRED_UEQ = FCMP_UEQ -#RPRED_UGT = FCMP_UGT -#RPRED_UGE = FCMP_UGE -#RPRED_ULT = FCMP_ULT -#RPRED_ULE = FCMP_ULE -#RPRED_UNE = FCMP_UNE -#RPRED_TRUE = FCMP_TRUE -# -## linkages (see llvm-c/Core.h) -#LINKAGE_EXTERNAL = 0 -#LINKAGE_AVAILABLE_EXTERNALLY = 1 -#LINKAGE_LINKONCE_ANY = 2 -#LINKAGE_LINKONCE_ODR = 3 -#LINKAGE_WEAK_ANY = 4 -#LINKAGE_WEAK_ODR = 5 -#LINKAGE_APPENDING = 6 -#LINKAGE_INTERNAL = 7 -#LINKAGE_PRIVATE = 8 -#LINKAGE_DLLIMPORT = 9 -#LINKAGE_DLLEXPORT = 10 -#LINKAGE_EXTERNAL_WEAK = 11 -#LINKAGE_GHOST = 12 -#LINKAGE_COMMON = 13 -#LINKAGE_LINKER_PRIVATE = 14 -#LINKAGE_LINKER_PRIVATE_WEAK = 15 -#LINKAGE_LINKER_PRIVATE_WEAK_DEF_AUTO = 16 -# -## visibility (see llvm/GlobalValue.h) -#VISIBILITY_DEFAULT = 0 -#VISIBILITY_HIDDEN = 1 -#VISIBILITY_PROTECTED = 2 +# instruction opcodes (from include/llvm/Instruction.def) +OPCODE_RET = 1 +OPCODE_BR = 2 +OPCODE_SWITCH = 3 +OPCODE_INDIRECT_BR = 4 +OPCODE_INVOKE = 5 +OPCODE_RESUME = 6 +OPCODE_UNREACHABLE = 7 +OPCODE_ADD = 8 +OPCODE_FADD = 9 +OPCODE_SUB = 10 +OPCODE_FSUB = 11 +OPCODE_MUL = 12 +OPCODE_FMUL = 13 +OPCODE_UDIV = 14 +OPCODE_SDIV = 15 +OPCODE_FDIV = 16 +OPCODE_UREM = 17 +OPCODE_SREM = 18 +OPCODE_FREM = 19 +OPCODE_SHL = 20 +OPCODE_LSHR = 21 +OPCODE_ASHR = 22 +OPCODE_AND = 23 +OPCODE_OR = 24 +OPCODE_XOR = 25 +OPCODE_ALLOCA = 26 +OPCODE_LOAD = 27 +OPCODE_STORE = 28 +OPCODE_GETELEMENTPTR = 29 +OPCODE_FENCE = 30 +OPCODE_ATOMICCMPXCHG = 31 +OPCODE_ATOMICRMW = 32 +OPCODE_TRUNC = 33 +OPCODE_ZEXT = 34 +OPCODE_SEXT = 35 +OPCODE_FPTOUI = 36 +OPCODE_FPTOSI = 37 +OPCODE_UITOFP = 38 +OPCODE_SITOFP = 39 +OPCODE_FPTRUNC = 40 +OPCODE_FPEXT = 41 +OPCODE_PTRTOINT = 42 +OPCODE_INTTOPTR = 43 +OPCODE_BITCAST = 44 +OPCODE_ICMP = 45 +OPCODE_FCMP = 46 +OPCODE_PHI = 47 +OPCODE_CALL = 48 +OPCODE_SELECT = 49 +OPCODE_USEROP1 = 50 +OPCODE_USEROP2 = 51 +OPCODE_VAARG = 52 +OPCODE_EXTRACTELEMENT = 53 +OPCODE_INSERTELEMENT = 54 +OPCODE_SHUFFLEVECTOR = 55 +OPCODE_EXTRACTVALUE = 56 +OPCODE_INSERTVALUE = 57 +OPCODE_LANDINGPAD = 58 + +# calling conventions +CC_C = api.llvm.CallingConv.ID.C +CC_FASTCALL = api.llvm.CallingConv.ID.Fast +CC_COLDCALL = api.llvm.CallingConv.ID.Cold +CC_GHC = api.llvm.CallingConv.ID.GHC +CC_X86_STDCALL = api.llvm.CallingConv.ID.X86_StdCall +CC_X86_FASTCALL = api.llvm.CallingConv.ID.X86_FastCall +CC_ARM_APCS = api.llvm.CallingConv.ID.ARM_APCS +CC_ARM_AAPCS = api.llvm.CallingConv.ID.ARM_AAPCS +CC_ARM_AAPCS_VFP = api.llvm.CallingConv.ID.ARM_AAPCS_VFP +CC_MSP430_INTR = api.llvm.CallingConv.ID.MSP430_INTR +CC_X86_THISCALL = api.llvm.CallingConv.ID.X86_ThisCall +CC_PTX_KERNEL = api.llvm.CallingConv.ID.PTX_Kernel +CC_PTX_DEVICE = api.llvm.CallingConv.ID.PTX_Device +CC_MBLAZE_INTR = api.llvm.CallingConv.ID.MBLAZE_INTR +CC_MBLAZE_SVOL = api.llvm.CallingConv.ID.MBLAZE_SVOL + + +# int predicates +ICMP_EQ = api.llvm.CmpInst.Predicate.ICMP_EQ +ICMP_NE = api.llvm.CmpInst.Predicate.ICMP_NE +ICMP_UGT = api.llvm.CmpInst.Predicate.ICMP_UGT +ICMP_UGE = api.llvm.CmpInst.Predicate.ICMP_UGE +ICMP_ULT = api.llvm.CmpInst.Predicate.ICMP_ULT +ICMP_ULE = api.llvm.CmpInst.Predicate.ICMP_ULE +ICMP_SGT = api.llvm.CmpInst.Predicate.ICMP_SGT +ICMP_SGE = api.llvm.CmpInst.Predicate.ICMP_SGE +ICMP_SLT = api.llvm.CmpInst.Predicate.ICMP_SLT +ICMP_SLE = api.llvm.CmpInst.Predicate.ICMP_SLE + +# same as ICMP_xx, for backward compatibility +IPRED_EQ = ICMP_EQ +IPRED_NE = ICMP_NE +IPRED_UGT = ICMP_UGT +IPRED_UGE = ICMP_UGE +IPRED_ULT = ICMP_ULT +IPRED_ULE = ICMP_ULE +IPRED_SGT = ICMP_SGT +IPRED_SGE = ICMP_SGE +IPRED_SLT = ICMP_SLT +IPRED_SLE = ICMP_SLE + +# real predicates +FCMP_FALSE = api.llvm.CmpInst.Predicate.FCMP_FALSE +FCMP_OEQ = api.llvm.CmpInst.Predicate.FCMP_OEQ +FCMP_OGT = api.llvm.CmpInst.Predicate.FCMP_OGT +FCMP_OGE = api.llvm.CmpInst.Predicate.FCMP_OGE +FCMP_OLT = api.llvm.CmpInst.Predicate.FCMP_OLT +FCMP_OLE = api.llvm.CmpInst.Predicate.FCMP_OLE +FCMP_ONE = api.llvm.CmpInst.Predicate.FCMP_ONE +FCMP_ORD = api.llvm.CmpInst.Predicate.FCMP_ORD +FCMP_UNO = api.llvm.CmpInst.Predicate.FCMP_UNO +FCMP_UEQ = api.llvm.CmpInst.Predicate.FCMP_UEQ +FCMP_UGT = api.llvm.CmpInst.Predicate.FCMP_UGT +FCMP_UGE = api.llvm.CmpInst.Predicate.FCMP_UGE +FCMP_ULT = api.llvm.CmpInst.Predicate.FCMP_ULT +FCMP_ULE = api.llvm.CmpInst.Predicate.FCMP_ULE +FCMP_UNE = api.llvm.CmpInst.Predicate.FCMP_UNE +FCMP_TRUE = api.llvm.CmpInst.Predicate.FCMP_TRUE + +# real predicates +RPRED_FALSE = FCMP_FALSE +RPRED_OEQ = FCMP_OEQ +RPRED_OGT = FCMP_OGT +RPRED_OGE = FCMP_OGE +RPRED_OLT = FCMP_OLT +RPRED_OLE = FCMP_OLE +RPRED_ONE = FCMP_ONE +RPRED_ORD = FCMP_ORD +RPRED_UNO = FCMP_UNO +RPRED_UEQ = FCMP_UEQ +RPRED_UGT = FCMP_UGT +RPRED_UGE = FCMP_UGE +RPRED_ULT = FCMP_ULT +RPRED_ULE = FCMP_ULE +RPRED_UNE = FCMP_UNE +RPRED_TRUE = FCMP_TRUE + +# linkages (see llvm::GlobalValue::LinkageTypes) +LINKAGE_EXTERNAL = \ + api.llvm.GlobalValue.LinkageTypes.ExternalLinkage +LINKAGE_AVAILABLE_EXTERNALLY = \ + api.llvm.GlobalValue.LinkageTypes.AvailableExternallyLinkage +LINKAGE_LINKONCE_ANY = \ + api.llvm.GlobalValue.LinkageTypes.LinkOnceAnyLinkage +LINKAGE_LINKONCE_ODR = \ + api.llvm.GlobalValue.LinkageTypes.LinkOnceODRLinkage +LINKAGE_WEAK_ANY = \ + api.llvm.GlobalValue.LinkageTypes.WeakAnyLinkage +LINKAGE_WEAK_ODR = \ + api.llvm.GlobalValue.LinkageTypes.WeakODRLinkage +LINKAGE_APPENDING = \ + api.llvm.GlobalValue.LinkageTypes.AppendingLinkage +LINKAGE_INTERNAL = \ + api.llvm.GlobalValue.LinkageTypes.InternalLinkage +LINKAGE_PRIVATE = \ + api.llvm.GlobalValue.LinkageTypes.PrivateLinkage +LINKAGE_DLLIMPORT = \ + api.llvm.GlobalValue.LinkageTypes.DLLImportLinkage +LINKAGE_DLLEXPORT = \ + api.llvm.GlobalValue.LinkageTypes.DLLExportLinkage +LINKAGE_EXTERNAL_WEAK = \ + api.llvm.GlobalValue.LinkageTypes.ExternalWeakLinkage +LINKAGE_COMMON = \ + api.llvm.GlobalValue.LinkageTypes.CommonLinkage +LINKAGE_LINKER_PRIVATE = \ + api.llvm.GlobalValue.LinkageTypes.LinkerPrivateLinkage +LINKAGE_LINKER_PRIVATE_WEAK = \ + api.llvm.GlobalValue.LinkageTypes.LinkerPrivateWeakLinkage + +# visibility (see llvm/GlobalValue.h) +VISIBILITY_DEFAULT = api.llvm.GlobalValue.VisibilityTypes.DefaultVisibility +VISIBILITY_HIDDEN = api.llvm.GlobalValue.VisibilityTypes.HiddenVisibility +VISIBILITY_PROTECTED = api.llvm.GlobalValue.VisibilityTypes.ProtectedVisibility # parameter attributes llvm::Attributes::AttrVal (see llvm/Attributes.h) ATTR_NONE = api.llvm.Attributes.AttrVal.None_ @@ -291,6 +305,16 @@ class Module(llvm.Wrapper): module_obj = Module.new('my_module') """ + __cache = weakref.WeakValueDictionary() + + def __new__(cls, ptr): + cached = cls.__cache.get(ptr) + if cached: + return cached + obj = object.__new__(cls) + cls.__cache[ptr] = obj + return obj + @staticmethod def new(id): """Create a new Module instance. @@ -314,6 +338,7 @@ class Module(llvm.Wrapper): else: bc = fileobj_or_str.read() errbuf = StringIO() + context = api.llvm.getGlobalContext() m = api.llvm.ParseBitCodeFile(bc, context, errbuf) if not m: raise Exception(errbuf.getvalue()) @@ -335,7 +360,9 @@ class Module(llvm.Wrapper): else: ir = fileobj_or_str.read() errbuf = StringIO() - m = api.llvm.ParseAssemblyString(ir, None, api.llvm.SMDIagnostic.new(), context) + context = api.llvm.getGlobalContext() + m = api.llvm.ParseAssemblyString(ir, None, api.llvm.SMDiagnostic.new(), + context) errbuf.close() return Module(m) @@ -351,6 +378,7 @@ class Module(llvm.Wrapper): return str(self._ptr) def __eq__(self, rhs): + assert isinstance(rhs, Module), type(rhs) if isinstance(rhs, Module): return str(self) == str(rhs) else: @@ -386,7 +414,7 @@ class Module(llvm.Wrapper): @property def pointer_size(self): - return self.getPointerSize() + return self._ptr.getPointerSize() def link_in(self, other, preserve=False): """Link the `other' module into this one. @@ -401,20 +429,21 @@ class Module(llvm.Wrapper): Linker class. """ assert isinstance(other, Module) - enum_mode = api.llvm.Linker.LinkMode + enum_mode = api.llvm.Linker.LinkerMode mode = enum_mode.PreserveSource if preserve else enum_mode.DestroySource with contextlib.closing(StringIO()) as errmsg: - failed = api.llvm.Linker.LinkModule(self._ptr, - other._ptr, - mode, - errmsg) + failed = api.llvm.Linker.LinkModules(self._ptr, + other._ptr, + mode, + errmsg) if failed: raise llvm.LLVMException(errmsg) def get_type_named(self, name): typ = self._ptr.getTypeByName(name) - return StructType(typ) + if typ: + return StructType(typ) def add_global_variable(self, ty, name, addrspace=0): """Add a global variable of given type with given name.""" @@ -422,7 +451,7 @@ class Module(llvm.Wrapper): notthreadlocal = api.llvm.GlobalVariable.ThreadLocalMode.NotThreadLocal init = None insertbefore = None - ptr = api.llvm.GlobalVariable.new(self, + ptr = api.llvm.GlobalVariable.new(self._ptr, ty._ptr, False, external, @@ -431,16 +460,18 @@ class Module(llvm.Wrapper): insertbefore, notthreadlocal, addrspace) - return GlobalVariable(ptr) + return _make_value(ptr) def get_global_variable_named(self, name): """Return a GlobalVariable object for the given name.""" ptr = self._ptr.getNamedGlobal(name) - return GlobalVariable(ptr) + if ptr is None: + raise llvm.LLVMException("No global named: %s" % name) + return _make_value(ptr) @property def global_variables(self): - return self._ptr.list_globals() + return map(_make_value, self._ptr.list_globals()) def add_function(self, ty, name): """Add a function of given type with given name.""" @@ -452,21 +483,25 @@ class Module(llvm.Wrapper): def get_function_named(self, name): """Return a Function object representing function with given name.""" fn = self._ptr.getFunction(name) - if fn is None: - return None - return Function(fn) + if fn is not None: + return _make_value(fn) def get_or_insert_function(self, ty, name): """Like get_function_named(), but does add_function() first, if function is not present.""" constant = self._ptr.getOrInsertFunction(name, ty._ptr) - fn = constant._downcast(api.llvm.Function) - return Function(fn) + try: + fn = constant._downcast(api.llvm.Function) + except ValueError: + # bitcasted to function type + return _make_value(constant) + else: + return _make_value(fn) @property def functions(self): """All functions in this module.""" - return map(Function, self._ptr.list_functions()) + return map(_make_value, self._ptr.list_functions()) def verify(self): """Verify module. @@ -498,7 +533,7 @@ class Module(llvm.Wrapper): return fileobj.getvalue() def _get_id(self): - return self._ptr.getModuleIdentifier(self._ptr) + return self._ptr.getModuleIdentifier() def _set_id(self, string): self._ptr.setModuleIdentifier(string) @@ -506,13 +541,18 @@ class Module(llvm.Wrapper): id = property(_get_id, _set_id) def _to_native_something(self, fileobj, cgft): - ret = False - if fileobj is None: - ret = True - fileobj = StringIO() + cgft = api.llvm.TargetMachine.CodeGenFileType.CGFT_AssemblyFile cgft = api.llvm.TargetMachine.CodeGenFileType.CGFT_ObjectFile - failed = tm.addPassesToEmitFile(pm, formatted, cgft, False) + + from llvm.ee import TargetMachine + from llvm.passes import PassManager + from llvmpy import extra + tm = TargetMachine.new()._ptr + pm = PassManager.new()._ptr + formatted + failed = tm.addPassesToEmitFile(pm, fileobj, cgft, False) + if failed: raise llvm.LLVMException("Failed to write native object file") if ret: @@ -525,8 +565,16 @@ class Module(llvm.Wrapper): If a fileobj is given, the output is written to it; Otherwise, the output is returned ''' - CGFT = api.llvm.TargetMachine.CodeGenFileType - return self._to_native_something(fileobj, CGFT.CGFT_ObjectFile) + ret = False + if fileobj is None: + ret = True + fileobj = StringIO() + from llvm.ee import TargetMachine + tm = TargetMachine.new() + fileobj.write(tm.emit_object(self)) + if ret: + return fileobj.getvalue() + def to_native_assembly(self, fileobj=None): '''Outputs the byte string of the module as native assembly code @@ -534,17 +582,27 @@ class Module(llvm.Wrapper): If a fileobj is given, the output is written to it; Otherwise, the output is returned ''' - CGFT = api.llvm.TargetMachine.CodeGenFileType - return self._to_native_something(fileobj, CGFT.CGFT_AssemblyFile) + ret = False + if fileobj is None: + ret = True + fileobj = StringIO() + from llvm.ee import TargetMachine + tm = TargetMachine.new() + fileobj.write(tm.emit_assembly(self)) + if ret: + return fileobj.getvalue() + def get_or_insert_named_metadata(self, name): - return NamedMetadata(self._ptr.getOrInsertNamedMetadata(name)) + return NamedMetaData(self._ptr.getOrInsertNamedMetadata(name)) def get_named_metadata(self, name): - return NamedMetadata(self._ptr.get_named_metadata(name)) + md = self._ptr.getNamedMetadata(name) + if md: + return NamedMetaData(md) def clone(self): - return NamedMetadata(api.llvm.CloneModule(self._ptr)) + return Module(api.llvm.CloneModule(self._ptr)) class Type(llvm.Wrapper): """Represents a type, like a 32-bit integer or an 80-bit x86 float. @@ -552,6 +610,11 @@ class Type(llvm.Wrapper): Use one of the static methods to create an instance. Example: ty = Type.double() """ + _type_ = api.llvm.Type + + def __init__(self, ptr): + ptr = ptr._downcast(type(self)._type_) + super(Type, self).__init__(ptr) @staticmethod def int(bits=32): @@ -614,6 +677,8 @@ class Type(llvm.Wrapper): def opaque(name): """Create a opaque StructType""" context = api.llvm.getGlobalContext() + if not name: + raise llvm.LLVMException("Opaque type must have a non-empty name") ptr = api.llvm.StructType.create(context, name) return StructType(ptr) @@ -629,8 +694,15 @@ class Type(llvm.Wrapper): otherwise, creates a literal type.""" context = api.llvm.getGlobalContext() is_packed = False - ptr = api.llvm.StructType.create(context) - ptr.setBody(_extract_ptrs(element_tys), is_packed) + if name: + ptr = api.llvm.StructType.create(context, name) + ptr.setBody(llvm._extract_ptrs(element_tys), is_packed) + else: + ptr = api.llvm.StructType.get(context, + llvm._extract_ptrs(element_tys), + is_packed) + + return StructType(ptr) @staticmethod @@ -646,7 +718,7 @@ class Type(llvm.Wrapper): context = api.llvm.getGlobalContext() is_packed = True ptr = api.llvm.StructType.create(context) - ptr.setBody(_extract_ptrs(element_tys), is_packed) + ptr.setBody(llvm._extract_ptrs(element_tys), is_packed) return StructType(ptr) @staticmethod @@ -723,6 +795,7 @@ class Type(llvm.Wrapper): class IntegerType(Type): """Represents an integer type.""" + _type_ = api.llvm.IntegerType @property def width(self): @@ -731,6 +804,7 @@ class IntegerType(Type): class FunctionType(Type): """Represents a function type.""" + _type_ = api.llvm.FunctionType @property def return_type(self): @@ -746,7 +820,7 @@ class FunctionType(Type): def args(self): """An iterable that yields Type objects, representing the types of the arguments accepted by this function, in order.""" - tys = [Type(self._ptr.getParamType(i)) for i in range(self.arg_count)] + return [Type(self._ptr.getParamType(i)) for i in range(self.arg_count)] @property def arg_count(self): @@ -759,6 +833,7 @@ class FunctionType(Type): class StructType(Type): """Represents a structure type.""" + _type_ = api.llvm.StructType @property def element_count(self): @@ -798,18 +873,19 @@ class StructType(Type): @property def is_literal(self): - return self.isLiteral() + return self._ptr.isLiteral() @property def is_identified(self): - return not self.is_literal() + return not self.is_literal @property def is_opaque(self): - return self.isOpaque() + return self._ptr.isOpaque() class ArrayType(Type): """Represents an array type.""" + _type_ = api.llvm.ArrayType @property def element(self): @@ -820,6 +896,7 @@ class ArrayType(Type): return self._ptr.getNumElements() class PointerType(Type): + _type_ = api.llvm.PointerType @property def pointee(self): @@ -830,7 +907,8 @@ class PointerType(Type): return self._ptr.getAddressSpace() class VectorType(Type): - + _type_ = api.llvm.VectorType + @property def element(self): return self._ptr.getVectorElementType() @@ -840,6 +918,34 @@ class VectorType(Type): return self._ptr.getNumElements() class Value(llvm.Wrapper): + _type_ = api.llvm.Value + + + def __init__(self, builder, ptr): + assert builder is _ValueFactory + + if type(self._type_) is type: + if isinstance(ptr, self._type_): # is not downcast + casted = ptr + else: + casted = ptr._downcast(self._type_) + else: + try: + for ty in self._type_: + if isinstance(ptr, ty): # is not downcast + casted = ptr + else: + try: + casted = ptr._downcast(ty) + except ValueError: + pass + else: + break + else: + casted = ptr + except TypeError: + casted = ptr + super(Value, self).__init__(casted) def __str__(self): return str(self._ptr) @@ -875,9 +981,10 @@ class Value(llvm.Wrapper): @property def uses(self): - return map(User, self._ptr.list_use()) + return map(_make_value, self._ptr.list_use()) class User(Value): + _type_ = api.llvm.User @property def operand_count(self): @@ -886,193 +993,198 @@ class User(Value): @property def operands(self): """Yields operands of this instruction.""" - return [Value(self._ptr.getOperand(i)) + return [_make_value(self._ptr.getOperand(i)) for i in range(self.operand_count)] - def _get_operand(self, i): - return _make_value(_core.LLVMUserGetOperand(self._ptr, i)) class Constant(User): + _type_ = api.llvm.Constant @staticmethod def null(ty): - return Value(api.llvm.Constant.getNullValue(ty._ptr)) + return _make_value(api.llvm.Constant.getNullValue(ty._ptr)) @staticmethod def all_ones(ty): - return Value(api.llvm.Constant.getAllOnesValue(ty._ptr)) + return _make_value(api.llvm.Constant.getAllOnesValue(ty._ptr)) @staticmethod def undef(ty): - return Value(api.llvm.UndefValue.get(ty._ptr)) + return _make_value(api.llvm.UndefValue.get(ty._ptr)) @staticmethod def int(ty, value): - return Value(api.llvm.ConstantInt.get(ty._ptr, value, False)) + return _make_value(api.llvm.ConstantInt.get(ty._ptr, int(value), False)) @staticmethod def int_signextend(ty, value): - return Value(api.llvm.ConstantInt.get(ty._ptr, value, True)) + return _make_value(api.llvm.ConstantInt.get(ty._ptr, int(value), True)) @staticmethod def real(ty, value): - return Value(api.llvm.ConstantFP.get(ty._ptr, value)) + return _make_value(api.llvm.ConstantFP.get(ty._ptr, float(value))) @staticmethod def string(strval): # dont_null_terminate=True - return Value(api.llvm.ConstantDataArray.getString(strval, False)) + cxt = api.llvm.getGlobalContext() + return _make_value(api.llvm.ConstantDataArray.getString(cxt, strval, False)) @staticmethod def stringz(strval): # dont_null_terminate=False - return Value(api.llvm.ConstantDataArray.getString(strval, True)) + cxt = api.llvm.getGlobalContext() + return _make_value(api.llvm.ConstantDataArray.getString(cxt, strval, True)) @staticmethod def array(ty, consts): - return Value(api.llvm.ConstantArray.get(ty._ptr, consts)) + aryty = Type.array(ty, len(consts)) + return _make_value(api.llvm.ConstantArray.get(aryty._ptr, + llvm._extract_ptrs(consts))) @staticmethod def struct(consts): # not packed - return Value(api.llvm.ConstantStruct.getAnon(llvm._extract_ptrs(consts), + return _make_value(api.llvm.ConstantStruct.getAnon(llvm._extract_ptrs(consts), False)) @staticmethod def packed_struct(consts): - return Value(api.llvm.ConstantStruct.getAnon(llvm._extract_ptrs(consts), + return _make_value(api.llvm.ConstantStruct.getAnon(llvm._extract_ptrs(consts), False)) @staticmethod def vector(consts): - return Value(api.llvm.ConstantVector.get(llvm._extract_ptrs(consts))) + return _make_value(api.llvm.ConstantVector.get(llvm._extract_ptrs(consts))) @staticmethod def sizeof(ty): - return Value(api.llvm.ConstantExpr.getSizeOf(ty._ptr)) + return _make_value(api.llvm.ConstantExpr.getSizeOf(ty._ptr)) def neg(self): - return Value(api.llvm.ConstantExpr.getNeg(self._ptr)) + return _make_value(api.llvm.ConstantExpr.getNeg(self._ptr)) def not_(self): - return Value(api.llvm.ConstantExpr.getNot(self._ptr)) + return _make_value(api.llvm.ConstantExpr.getNot(self._ptr)) def add(self, rhs): - return Value(api.llvm.ConstantExpr.getAdd(self._ptr, rhs._ptr)) + return _make_value(api.llvm.ConstantExpr.getAdd(self._ptr, rhs._ptr)) def fadd(self, rhs): - return Value(api.llvm.ConstantExpr.getFAdd(self._ptr, rhs._ptr)) + return _make_value(api.llvm.ConstantExpr.getFAdd(self._ptr, rhs._ptr)) def sub(self, rhs): - return Value(api.llvm.ConstantExpr.getSub(self._ptr, rhs._ptr)) + return _make_value(api.llvm.ConstantExpr.getSub(self._ptr, rhs._ptr)) def fsub(self, rhs): - return Value(api.llvm.ConstantExpr.getFSub(self._ptr, rhs._ptr)) + return _make_value(api.llvm.ConstantExpr.getFSub(self._ptr, rhs._ptr)) def mul(self, rhs): - return Value(api.llvm.ConstantExpr.getMul(self._ptr, rhs._ptr)) + return _make_value(api.llvm.ConstantExpr.getMul(self._ptr, rhs._ptr)) def fmul(self, rhs): - return Value(api.llvm.ConstantExpr.getFMul(self._ptr, rhs._ptr)) + return _make_value(api.llvm.ConstantExpr.getFMul(self._ptr, rhs._ptr)) def udiv(self, rhs): - return Value(api.llvm.ConstantExpr.getUDiv(self._ptr, rhs._ptr)) + return _make_value(api.llvm.ConstantExpr.getUDiv(self._ptr, rhs._ptr)) def sdiv(self, rhs): - return Value(api.llvm.ConstantExpr.getSDiv(self._ptr, rhs._ptr)) + return _make_value(api.llvm.ConstantExpr.getSDiv(self._ptr, rhs._ptr)) def fdiv(self, rhs): - return Value(api.llvm.ConstantExpr.getFDiv(self._ptr, rhs._ptr)) + return _make_value(api.llvm.ConstantExpr.getFDiv(self._ptr, rhs._ptr)) def urem(self, rhs): - return Value(api.llvm.ConstantExpr.getURem(self._ptr, rhs._ptr)) + return _make_value(api.llvm.ConstantExpr.getURem(self._ptr, rhs._ptr)) def srem(self, rhs): - return Value(api.llvm.ConstantExpr.getSRem(self._ptr, rhs._ptr)) + return _make_value(api.llvm.ConstantExpr.getSRem(self._ptr, rhs._ptr)) def frem(self, rhs): - return Value(api.llvm.ConstantExpr.getFRem(self._ptr, rhs._ptr)) + return _make_value(api.llvm.ConstantExpr.getFRem(self._ptr, rhs._ptr)) def and_(self, rhs): - return Value(api.llvm.ConstantExpr.getAnd(self._ptr, rhs._ptr)) + return _make_value(api.llvm.ConstantExpr.getAnd(self._ptr, rhs._ptr)) def or_(self, rhs): - return Value(api.llvm.ConstantExpr.getOr(self._ptr, rhs._ptr)) + return _make_value(api.llvm.ConstantExpr.getOr(self._ptr, rhs._ptr)) def xor(self, rhs): - return Value(api.llvm.ConstantExpr.getXor(self._ptr, rhs._ptr)) + return _make_value(api.llvm.ConstantExpr.getXor(self._ptr, rhs._ptr)) def icmp(self, int_pred, rhs): - return Value(api.llvm.ConstantExpr.getICmp(int_pred, self._ptr, rhs._ptr)) + return _make_value(api.llvm.ConstantExpr.getICmp(int_pred, self._ptr, rhs._ptr)) def fcmp(self, real_pred, rhs): - return Value(api.llvm.ConstantExpr.getFCmp(real_pred, self._ptr, rhs._ptr)) + return _make_value(api.llvm.ConstantExpr.getFCmp(real_pred, self._ptr, rhs._ptr)) def shl(self, rhs): - return Value(api.llvm.ConstantExpr.getShl(self._ptr, rhs._ptr)) + return _make_value(api.llvm.ConstantExpr.getShl(self._ptr, rhs._ptr)) def lshr(self, rhs): - return Value(api.llvm.ConstantExpr.getLShr(self._ptr, rhs._ptr)) + return _make_value(api.llvm.ConstantExpr.getLShr(self._ptr, rhs._ptr)) def ashr(self, rhs): - return Value(api.llvm.ConstantExpr.getAShr(self._ptr, rhs._ptr)) + return _make_value(api.llvm.ConstantExpr.getAShr(self._ptr, rhs._ptr)) def gep(self, indices): indices = llvm._extract_ptrs(indices) - return Value(api.llvm.ConstantExpr.getGetElementPtr(self._ptr, indices)) + return _make_value(api.llvm.ConstantExpr.getGetElementPtr(self._ptr, indices)) def trunc(self, ty): - return Value(api.llvm.ConstantExpr.getTrunc(self._ptr, ty)) + return _make_value(api.llvm.ConstantExpr.getTrunc(self._ptr, ty._ptr)) def sext(self, ty): - return Value(api.llvm.ConstantExpr.getSExt(self._ptr, ty)) + return _make_value(api.llvm.ConstantExpr.getSExt(self._ptr, ty._ptr)) def zext(self, ty): - return Value(api.llvm.ConstantExpr.getZExt(self._ptr, ty)) + return _make_value(api.llvm.ConstantExpr.getZExt(self._ptr, ty._ptr)) def fptrunc(self, ty): - return Value(api.llvm.ConstantExpr.getFPTrunc(self._ptr, ty)) + return _make_value(api.llvm.ConstantExpr.getFPTrunc(self._ptr, ty._ptr)) def fpext(self, ty): - return Value(api.llvm.ConstantExpr.getFPExtend(self._ptr, ty)) + return _make_value(api.llvm.ConstantExpr.getFPExtend(self._ptr, ty._ptr)) def uitofp(self, ty): - return Value(api.llvm.ConstantExpr.getUIToFP(self._ptr, ty)) + return _make_value(api.llvm.ConstantExpr.getUIToFP(self._ptr, ty._ptr)) def sitofp(self, ty): - return Value(api.llvm.ConstantExpr.getSIToFP(self._ptr, ty)) + return _make_value(api.llvm.ConstantExpr.getSIToFP(self._ptr, ty._ptr)) def fptoui(self, ty): - return Value(api.llvm.ConstantExpr.getFPToUI(self._ptr, ty)) + return _make_value(api.llvm.ConstantExpr.getFPToUI(self._ptr, ty._ptr)) def fptosi(self, ty): - return Value(api.llvm.ConstantExpr.getFPToSI(self._ptr, ty)) + return _make_value(api.llvm.ConstantExpr.getFPToSI(self._ptr, ty._ptr)) def ptrtoint(self, ty): - return Value(api.llvm.ConstantExpr.getPtrToInt(self._ptr, ty)) + return _make_value(api.llvm.ConstantExpr.getPtrToInt(self._ptr, ty._ptr)) def inttoptr(self, ty): - return Value(api.llvm.ConstantExpr.getIntToPtr(self._ptr, ty)) + return _make_value(api.llvm.ConstantExpr.getIntToPtr(self._ptr, ty._ptr)) def bitcast(self, ty): - return Value(api.llvm.ConstantExpr.getBitCast(self._ptr, ty)) + return _make_value(api.llvm.ConstantExpr.getBitCast(self._ptr, ty._ptr)) def select(self, true_const, false_const): - return Value(api.llvm.ConstantExpr.getSelect(self._ptr, + return _make_value(api.llvm.ConstantExpr.getSelect(self._ptr, true_const._ptr, false_const._ptr)) def extract_element(self, index): # note: self must be a _vector_ constant - return Value(api.llvm.ConstantExpr.getExtractElement(self._ptr, index._ptr)) + return _make_value(api.llvm.ConstantExpr.getExtractElement(self._ptr, index._ptr)) def insert_element(self, value, index): - return Value(api.llvm.ConstantExpr.getExtractElement(self._ptr, + return _make_value(api.llvm.ConstantExpr.getExtractElement(self._ptr, value._ptr, index._ptr)) def shuffle_vector(self, vector_b, mask): - return Value(api.llvm.ConstantExpr.getShuffleVector(self._ptr, + return _make_value(api.llvm.ConstantExpr.getShuffleVector(self._ptr, vector_b._ptr, mask._ptr)) class ConstantExpr(Constant): + _type_ = api.llvm.ConstantExpr + @property def opcode(self): return self._ptr.getOpcode() @@ -1094,6 +1206,8 @@ class ConstantDataVector(Constant): class ConstantInt(Constant): + _type_ = api.llvm.ConstantInt + @property def z_ext_value(self): '''Obtain the zero extended value for an integer constant value.''' @@ -1130,8 +1244,8 @@ class ConstantPointerNull(Constant): class UndefValue(Constant): pass - class GlobalValue(Constant): + _type_ = api.llvm.GlobalValue def _get_linkage(self): return self._ptr.getLinkage() @@ -1176,6 +1290,7 @@ class GlobalValue(Constant): class GlobalVariable(GlobalValue): + _type_ = api.llvm.GlobalVariable @staticmethod def new(module, ty, name, addrspace=0): @@ -1183,7 +1298,7 @@ class GlobalVariable(GlobalValue): external_linkage = linkage.ExternalLinkage tlmode = api.llvm.GlobalVariable.ThreadLocalMode not_threadlocal = tlmode.NotThreadLocal - gv = api.llvm.GlobalVariablel.new(module._ptr, + gv = api.llvm.GlobalVariable.new(module._ptr, ty._ptr, False, # is constant external_linkage, @@ -1192,22 +1307,23 @@ class GlobalVariable(GlobalValue): None, # insert before not_threadlocal, addrspace) - return GlobalVariable(gv) + return _make_value(gv) @staticmethod def get(module, name): - gv = GlobalVariable(module._ptr.getNamedGlobal(name)) + gv = _make_value(module._ptr.getNamedGlobal(name)) if not gv: llvm.LLVMException("no global named `%s`" % name) return gv def delete(self): + _ValueFactory.delete(self._ptr) self._ptr.eraseFromParent() def _get_initializer(self): if not self._ptr.hasInitializer(): return None - return Constant(self._ptr.getInitializer()) + return _make_value(self._ptr.getInitializer()) def _set_initializer(self, const): self._ptr.setInitializer(const._ptr) @@ -1235,21 +1351,25 @@ class GlobalVariable(GlobalValue): thread_local = property(_get_thread_local, _set_thread_local) class Argument(Value): + _type_ = api.llvm.Argument def add_attribute(self, attr): - attrbldr = api.llvm.AttrBuilder() + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() attrbldr.addAttribute(attr) attrs = api.llvm.Attributes.get(context, attrbldr) self._ptr.addAttr(attrs) def remove_attribute(self, attr): - attrbldr = api.llvm.AttrBuilder() + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() attrbldr.addAttribute(attr) attrs = api.llvm.Attributes.get(context, attrbldr) self._ptr.removeAttr(attrs) def _set_alignment(self, align): - attrbldr = api.llvm.AttrBuilder() + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() attrbldr.addAlignmentAttr(align) attrs = api.llvm.Attributes.get(context, attrbldr) self._ptr.addAttr(attrs) @@ -1261,6 +1381,7 @@ class Argument(Value): _set_alignment) class Function(GlobalValue): + _type_ = api.llvm.Function @staticmethod def new(module, func_ty, name): @@ -1277,11 +1398,12 @@ class Function(GlobalValue): @staticmethod def intrinsic(module, intrinsic_id, types): fn = api.llvm.Intrinsic.getDeclaration(module._ptr, - intrinsic_id, - types) - return Function(fn) + intrinsic_id, + llvm._extract_ptrs(types)) + return _make_value(fn) def delete(self): + _ValueFactory.delete(self._ptr) self._ptr.eraseFromParent() @property @@ -1310,13 +1432,14 @@ class Function(GlobalValue): def _set_does_not_throw(self,value): assert value - self._ptr.setDoesNotThow() + self._ptr.setDoesNotThrow() does_not_throw = property(_get_does_not_throw, _set_does_not_throw) @property def args(self): - return self._ptr.getArgumentList() + args = self._ptr.getArgumentList() + return map(_make_value, args) @property def basic_block_count(self): @@ -1324,25 +1447,27 @@ class Function(GlobalValue): @property def entry_basic_block(self): - return self._ptr.getEntryBlock() + assert self.basic_block_count + return _make_value(self._ptr.getEntryBlock()) def append_basic_block(self, name): context = api.llvm.getGlobalContext() bb = api.llvm.BasicBlock.Create(context, name, self._ptr, None) - return BasicBlock(bb) + return _make_value(bb) @property def basic_blocks(self): - return self._ptr.getBasicBlockList() + return map(_make_value, self._ptr.getBasicBlockList()) def viewCFG(self): return self._ptr.viewCFG() def add_attribute(self, attr): - _core.LLVMAddFunctionAttr(self._ptr, attr) + self._ptr.addFnAttr(attr) def remove_attribute(self, attr): - attrbldr = api.llvm.AttrBuilder() + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() attrbldr.addAttribute(attr) attrs = api.llvm.Attributes.get(context, attrbldr) self._ptr.removeFnAttr(attrs) @@ -1356,25 +1481,30 @@ class Function(GlobalValue): # Note: LLVM has a bug in preverifier that will always abort # the process upon failure. - return api.llvm.verifyFunction() + actions = api.llvm.VerifierFailureAction + return api.llvm.verifyFunction(self._ptr, actions.PrintMessageAction) #===----------------------------------------------------------------------=== # InlineAsm #===----------------------------------------------------------------------=== class InlineAsm(Value): + _type_ = api.llvm.InlineAsm + @staticmethod def get(functype, asm, constrains, side_effect=False, align_stack=False, dialect=api.llvm.InlineAsm.AsmDialect.AD_ATT): - ilasm = api.llvm.InlineAsm.get(functype._ptr, asm, contrains, side_effect, - align_stack, dialect) - return InlineAsm(ilasm) + ilasm = api.llvm.InlineAsm.get(functype._ptr, asm, constrains, + side_effect, align_stack, dialect) + return _make_value(ilasm) #===----------------------------------------------------------------------=== # MetaData #===----------------------------------------------------------------------=== class MetaData(Value): + _type_ = api.llvm.MDNode + @staticmethod def get(module, values): ''' @@ -1382,13 +1512,15 @@ class MetaData(Value): ''' context = api.llvm.getGlobalContext() ptr = api.llvm.MDNode.get(context, llvm._extract_ptrs(values)) - return MetaData(ptr) + return _make_value(ptr) @staticmethod def get_named_operands(module, name): - namedmd = module.get_named_metadata(name)._ptr - return [MetaData(namedmd.getOperand(i)) - for i in namedmd.getNumOperands()] + namedmd = module.get_named_metadata(name) + if not namedmd: + return [] + return [_make_value(namedmd._ptr.getOperand(i)) + for i in range(namedmd._ptr.getNumOperands())] @staticmethod def add_named_operand(module, name, operand): @@ -1397,20 +1529,28 @@ class MetaData(Value): @property def operand_count(self): - return self._ptr.getOperand() + return self._ptr.getNumOperands() @property def operands(self): """Yields operands of this metadata.""" - return [Value(self._ptr.getOperand(i)) for i in self.operand_count] - + res = [] + for i in range(self.operand_count): + op = self._ptr.getOperand(i) + if op is None: + res.append(None) + else: + res.append(_make_value(op)) + return res class MetaDataString(Value): + _type_ = api.llvm.MDString + @staticmethod def get(module, s): context = api.llvm.getGlobalContext() ptr = api.llvm.MDString.get(context, s) - return MetaDataString(ptr) + return _make_value(ptr) @property def string(self): @@ -1419,6 +1559,7 @@ class MetaDataString(Value): class NamedMetaData(llvm.Wrapper): + @staticmethod def get_or_insert(mod, name): return mod.get_or_insert_named_metadata(name) @@ -1446,10 +1587,11 @@ class NamedMetaData(llvm.Wrapper): #===----------------------------------------------------------------------=== class Instruction(User): + _type_ = api.llvm.Instruction @property def basic_block(self): - return BasicBlock(self._ptr.getParent()) + return _make_value(self._ptr.getParent()) @property def is_terminator(self): @@ -1517,6 +1659,7 @@ class Instruction(User): class CallOrInvokeInstruction(Instruction): + _type_ = api.llvm.CallInst, api.llvm.InvokeInst def _get_cc(self): return self._ptr.getCallingConv() @@ -1527,19 +1670,22 @@ class CallOrInvokeInstruction(Instruction): calling_convention = property(_get_cc, _set_cc) def add_parameter_attribute(self, idx, attr): - attrbldr = api.llvm.AttrBuilder() + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() attrbldr.addAttribute(attr) attrs = api.llvm.Attributes.get(context, attrbldr) self._ptr.addAttribute(idx, attrs) def remove_parameter_attribute(self, idx, attr): - attrbldr = api.llvm.AttrBuilder() + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() attrbldr.addAttribute(attr) attrs = api.llvm.Attributes.get(context, attrbldr) self._ptr.removeAttribute(idx, attrs) def set_parameter_alignment(self, idx, align): - attrbldr = api.llvm.AttrBuilder() + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() attrbldr.addAlignmentAttr(align) attrs = api.llvm.Attributes.get(context, attrbldr) self._ptr.addAttribute(idx, attrs) @@ -1547,7 +1693,7 @@ class CallOrInvokeInstruction(Instruction): def _get_called_function(self): function = self._ptr.getCalledFunction() if function: # Return value can be None on indirect call/invoke - return Value(function) + return _make_value(function) def _set_called_function(self, function): self._ptr.setCalledFunction(function) @@ -1556,6 +1702,7 @@ class CallOrInvokeInstruction(Instruction): class PHINode(Instruction): + _type_ = api.llvm.PHINode @property def incoming_count(self): @@ -1565,10 +1712,10 @@ class PHINode(Instruction): self._ptr.addIncoming(value._ptr, block._ptr) def get_incoming_value(self, idx): - return self._ptr.getIncomingValue(idx) + return _make_value(self._ptr.getIncomingValue(idx)) def get_incoming_block(self, idx): - return self._ptr.getIncomingBlock(idx) + return _make_value(self._ptr.getIncomingBlock(idx)) class SwitchInstruction(Instruction): @@ -1582,36 +1729,108 @@ class CompareInstruction(Instruction): @property def predicate(self): return self._ptr.getPredicate() - - #===----------------------------------------------------------------------=== # Basic block #===----------------------------------------------------------------------=== class BasicBlock(Value): + _type_ = api.llvm.BasicBlock def insert_before(self, name): context = api.llvm.getGlobalContext() ptr = api.llvm.BasicBlock.Create(context, name, self.function._ptr, self._ptr) - return BasicBlock(ptr) + return _make_value(ptr) def delete(self): + _ValueFactory.delete(self._ptr) self._ptr.eraseFromParent() @property def function(self): - return Function(self._ptr.getParent()) + return _make_value(self._ptr.getParent()) @property def instructions(self): - return map(Value, self._ptr.getInstList()) + return map(_make_value, self._ptr.getInstList()) +#===----------------------------------------------------------------------=== +# Value factory method +#===----------------------------------------------------------------------=== + + +class _ValueFactory(object): + cache = weakref.WeakValueDictionary() + + # value ID -> class map + class_for_valueid = { + VALUE_ARGUMENT : Argument, + VALUE_BASIC_BLOCK : BasicBlock, + VALUE_FUNCTION : Function, + VALUE_GLOBAL_ALIAS : GlobalValue, + VALUE_GLOBAL_VARIABLE : GlobalVariable, + VALUE_UNDEF_VALUE : UndefValue, + VALUE_CONSTANT_EXPR : ConstantExpr, + VALUE_CONSTANT_AGGREGATE_ZERO : ConstantAggregateZero, + VALUE_CONSTANT_DATA_ARRAY : ConstantDataArray, + VALUE_CONSTANT_DATA_VECTOR : ConstantDataVector, + VALUE_CONSTANT_INT : ConstantInt, + VALUE_CONSTANT_FP : ConstantFP, + VALUE_CONSTANT_ARRAY : ConstantArray, + VALUE_CONSTANT_STRUCT : ConstantStruct, + VALUE_CONSTANT_VECTOR : ConstantVector, + VALUE_CONSTANT_POINTER_NULL : ConstantPointerNull, + VALUE_MD_NODE : MetaData, + VALUE_MD_STRING : MetaDataString, + VALUE_INLINE_ASM : InlineAsm, + VALUE_INSTRUCTION + OPCODE_PHI : PHINode, + VALUE_INSTRUCTION + OPCODE_CALL : CallOrInvokeInstruction, + VALUE_INSTRUCTION + OPCODE_INVOKE : CallOrInvokeInstruction, + VALUE_INSTRUCTION + OPCODE_SWITCH : SwitchInstruction, + VALUE_INSTRUCTION + OPCODE_ICMP : CompareInstruction, + VALUE_INSTRUCTION + OPCODE_FCMP : CompareInstruction + } + + @classmethod + def build(cls, ptr): + # try to look in the cache + addr = ptr._capsule.pointer + try: + obj = cls.cache[addr] + return obj + except KeyError: + pass + # find class by value id + id = ptr.getValueID() + ctorcls = cls.class_for_valueid.get(id) + if not ctorcls: + if id > VALUE_INSTRUCTION: # "generic" instruction + ctorcls = Instruction + else: # "generic" value + ctorcls = Value + # cache the obj + obj = ctorcls(_ValueFactory, ptr) + cls.cache[addr] = obj + return obj + + @classmethod + def delete(cls, ptr): + del cls.cache[ptr._capsule.pointer] + +def _make_value(ptr): + return _ValueFactory.build(ptr) #===----------------------------------------------------------------------=== # Builder #===----------------------------------------------------------------------=== +_atomic_orderings = { 'unordered' : api.llvm.AtomicOrdering.Unordered, + 'monotonic' : api.llvm.AtomicOrdering.Monotonic, + 'acquire' : api.llvm.AtomicOrdering.Acquire, + 'release' : api.llvm.AtomicOrdering.Release, + 'acq_rel' : api.llvm.AtomicOrdering.AcquireRelease, + 'seq_cst' : api.llvm.AtomicOrdering.SequentiallyConsistent} + class Builder(llvm.Wrapper): @staticmethod @@ -1628,7 +1847,7 @@ class Builder(llvm.Wrapper): # Instruction list won't be long anyway, # Does not matter much to build a list of all instructions - instrs = bblk._ptr.getInstList() + instrs = bblk.instructions if instrs: self.position_before(instrs[0]) else: @@ -1650,150 +1869,163 @@ class Builder(llvm.Wrapper): @property def basic_block(self): """The basic block where the builder is positioned.""" - return BasicBlock(self._ptr.GetInsertBlock()) + return _make_value(self._ptr.GetInsertBlock()) # terminator instructions + def _guard_terminators(self): + if __debug__: + import warnings + for instr in self.basic_block.instructions: + if instr.is_terminator: + warnings.warn("BasicBlock can only have one terminator") def ret_void(self): - return Value(self._ptr.CreateRetVoid()) + self._guard_terminators() + return _make_value(self._ptr.CreateRetVoid()) def ret(self, value): - return Value(self._ptr.CreateRet(value._ptr)) + self._guard_terminators() + return _make_value(self._ptr.CreateRet(value._ptr)) def ret_many(self, values): + self._guard_terminators() values = llvm._extract_ptrs(values) - return Value(self._ptr.CreateAggregateRet(values, len(values))) + return _make_value(self._ptr.CreateAggregateRet(values, len(values))) def branch(self, bblk): - if __debug__: - for instr in self.basic_block.instructions: - assert not instr.is_terminator, "BasicBlock can only have one terminator" - return Value(self._ptr.CreateBr(bblk._ptr)) + self._guard_terminators() + return _make_value(self._ptr.CreateBr(bblk._ptr)) def cbranch(self, if_value, then_blk, else_blk): - return Value(self._ptr.CreateCondBr(if_value._ptr, + self._guard_terminators() + return _make_value(self._ptr.CreateCondBr(if_value._ptr, then_blk._ptr, else_blk._ptr)) def switch(self, value, else_blk, n=10): - return Value(self._ptr.CreateSwitch(self.value._ptr, - self.else_blk._ptr, - n)) + self._guard_terminators() + return _make_value(self._ptr.CreateSwitch(value._ptr, + else_blk._ptr, + n)) def invoke(self, func, args, then_blk, catch_blk, name=""): - return Value(self._ptr.CreateInvoke(self.func._ptr, - self.then_blk._ptr, - self.catch_blk._ptr, - args)) + self._guard_terminators() + return _make_value(self._ptr.CreateInvoke(func._ptr, + then_blk._ptr, + catch_blk._ptr, + llvm._extract_ptrs(args))) def unreachable(self): - return Value(self._ptr.CreateUnreachable()) + self._guard_terminators() + return _make_value(self._ptr.CreateUnreachable()) # arithmethic, bitwise and logical def add(self, lhs, rhs, name=""): - return Value(self._ptr.CreateAdd(lhs._ptr, rhs._ptr, name)) + return _make_value(self._ptr.CreateAdd(lhs._ptr, rhs._ptr, name)) def fadd(self, lhs, rhs, name=""): - return Value(self._ptr.CreateFAdd(lhs._ptr, rhs._ptr, name)) + return _make_value(self._ptr.CreateFAdd(lhs._ptr, rhs._ptr, name)) def sub(self, lhs, rhs, name=""): - return Value(self._ptr.CreateSub(lhs._ptr, rhs._ptr, name)) + return _make_value(self._ptr.CreateSub(lhs._ptr, rhs._ptr, name)) def fsub(self, lhs, rhs, name=""): - return Value(self._ptr.CreateFSub(lhs._ptr, rhs._ptr, name)) + return _make_value(self._ptr.CreateFSub(lhs._ptr, rhs._ptr, name)) def mul(self, lhs, rhs, name=""): - return Value(self._ptr.CreateMul(lhs._ptr, rhs._ptr, name)) + return _make_value(self._ptr.CreateMul(lhs._ptr, rhs._ptr, name)) def fmul(self, lhs, rhs, name=""): - return Value(self._ptr.CreateFMul(lhs._ptr, rhs._ptr, name)) + return _make_value(self._ptr.CreateFMul(lhs._ptr, rhs._ptr, name)) def udiv(self, lhs, rhs, name=""): - return Value(self._ptr.CreateUDiv(lhs._ptr, rhs._ptr, name)) + return _make_value(self._ptr.CreateUDiv(lhs._ptr, rhs._ptr, name)) def sdiv(self, lhs, rhs, name=""): - return Value(self._ptr.CreateSDiv(lhs._ptr, rhs._ptr, name)) + return _make_value(self._ptr.CreateSDiv(lhs._ptr, rhs._ptr, name)) def fdiv(self, lhs, rhs, name=""): - return Value(self._ptr.CreateFDiv(lhs._ptr, rhs._ptr, name)) + return _make_value(self._ptr.CreateFDiv(lhs._ptr, rhs._ptr, name)) def urem(self, lhs, rhs, name=""): - return Value(self._ptr.CreateURem(lhs._ptr, rhs._ptr, name)) + return _make_value(self._ptr.CreateURem(lhs._ptr, rhs._ptr, name)) def srem(self, lhs, rhs, name=""): - return Value(self._ptr.CreateSRem(lhs._ptr, rhs._ptr, name)) + return _make_value(self._ptr.CreateSRem(lhs._ptr, rhs._ptr, name)) def frem(self, lhs, rhs, name=""): - return Value(self._ptr.CreateFRem(lhs._ptr, rhs._ptr, name)) + return _make_value(self._ptr.CreateFRem(lhs._ptr, rhs._ptr, name)) def shl(self, lhs, rhs, name=""): - return Value(self._ptr.CreateShl(lhs._ptr, rhs._ptr, name)) + return _make_value(self._ptr.CreateShl(lhs._ptr, rhs._ptr, name)) def lshr(self, lhs, rhs, name=""): - return Value(self._ptr.CreateLShr(lhs._ptr, rhs._ptr, name)) + return _make_value(self._ptr.CreateLShr(lhs._ptr, rhs._ptr, name)) def ashr(self, lhs, rhs, name=""): - return Value(self._ptr.CreateAShr(lhs._ptr, rhs._ptr, name)) + return _make_value(self._ptr.CreateAShr(lhs._ptr, rhs._ptr, name)) def and_(self, lhs, rhs, name=""): - return Value(self._ptr.CreateAnd(lhs._ptr, rhs._ptr, name)) + return _make_value(self._ptr.CreateAnd(lhs._ptr, rhs._ptr, name)) def or_(self, lhs, rhs, name=""): - return Value(self._ptr.CreateOr(lhs._ptr, rhs._ptr, name)) + return _make_value(self._ptr.CreateOr(lhs._ptr, rhs._ptr, name)) def xor(self, lhs, rhs, name=""): - return Value(self._ptr.CreateXor(lhs._ptr, rhs._ptr, name)) + return _make_value(self._ptr.CreateXor(lhs._ptr, rhs._ptr, name)) def neg(self, val, name=""): - return Value(self._ptr.CreateNeg(val._ptr, name)) + return _make_value(self._ptr.CreateNeg(val._ptr, name)) def not_(self, val, name=""): - return Value(self._ptr.CreateNot(val._ptr, name)) + return _make_value(self._ptr.CreateNot(val._ptr, name)) # memory def malloc(self, ty, name=""): context = api.llvm.getGlobalContext() - intty = api.llvm.Type.getInt32Ty(context) - sizeof = api.llvm.ConstantExpr.getSizeOf(ty) - zero = api.llvm.ConstantInt.get(intty, 0) - # XXX: how do I know when to insert? - # assume to end of block for now - inst = api.llvm.CallInst.CreateMalloc(self.basic_block._ptr, - intty, - ty._ptr, - sizeof, - zero, - None, - name) - return Value(inst) - + allocsz = api.llvm.ConstantExpr.getSizeOf(ty._ptr) + ity = allocsz.getType() + malloc = api.llvm.CallInst.CreateMalloc(self.basic_block._ptr, + ity, + ty._ptr, + allocsz, + None, + None, + "") + inst = self._ptr.Insert(malloc, name) + return _make_value(inst) + def malloc_array(self, ty, size, name=""): - sizeof = api.llvm.ConstantExpr.getSizeOf(ty) - # XXX: how do I know when to insert? - # assume to end of block for now - inst = api.llvm.CallInst.CreateMalloc(self.basic_block._ptr, - size.type._ptr, - ty._ptr, - sizeof, - size._ptr, - None, - name) - return Value(inst) + context = api.llvm.getGlobalContext() + allocsz = api.llvm.ConstantExpr.getSizeOf(ty._ptr) + ity = allocsz.getType() + malloc = api.llvm.CallInst.CreateMalloc(self.basic_block._ptr, + ity, + ty._ptr, + allocsz, + size._ptr, + None, + "") + inst = self._ptr.Insert(malloc, name) + return _make_value(inst) def alloca(self, ty, name=""): - zero = api.llvm.ConstantInt.get(intty, 0) - return Value(self._ptr.CreateAlloca(ty._ptr, zero, name)) + intty = Type.int() + zero = api.llvm.ConstantInt.get(intty._ptr, 0) + return _make_value(self._ptr.CreateAlloca(ty._ptr, zero, name)) def alloca_array(self, ty, size, name=""): - return Value(self._ptr.CreateAlloca(ty._ptr, size._ptr, name)) + return _make_value(self._ptr.CreateAlloca(ty._ptr, size._ptr, name)) def free(self, ptr): - return Value(api.llvm.CallInst.CreateFree(ptr._ptr, self.basic_block._ptr)) + free = api.llvm.CallInst.CreateFree(ptr._ptr, self.basic_block._ptr) + inst = self._ptr.Insert(free) + return _make_value(inst) def load(self, ptr, name="", align=0, volatile=False, invariant=False): - inst = Value(self._ptr.CreateLoad(ptr._ptr, name)) + inst = _make_value(self._ptr.CreateLoad(ptr._ptr, name)) if align: inst._ptr.setAlignment(align) if volatile: @@ -1805,7 +2037,7 @@ class Builder(llvm.Wrapper): return inst def store(self, value, ptr, align=0, volatile=False): - inst = Value(self._ptr.CreateStore(value._ptr, ptr._ptr)) + inst = _make_value(self._ptr.CreateStore(value._ptr, ptr._ptr)) if align: inst._ptr.setAlignment(align) if volatile: @@ -1821,118 +2053,119 @@ class Builder(llvm.Wrapper): ret = self._ptr.CreateGEP(ptr._ptr, llvm._extract_ptrs(indices), name) - return Value(ret) + return _make_value(ret) # casts and extensions def trunc(self, value, dest_ty, name=""): - return Value(self._ptr.CreateTrunc(value._ptr, dest_ty._ptr, name)) + return _make_value(self._ptr.CreateTrunc(value._ptr, dest_ty._ptr, name)) def zext(self, value, dest_ty, name=""): - return Value(self._ptr.CreateZext(value._ptr, dest_ty._ptr, name)) + return _make_value(self._ptr.CreateZExt(value._ptr, dest_ty._ptr, name)) def sext(self, value, dest_ty, name=""): - return Value(self._ptr.CreateSext(value._ptr, dest_ty._ptr, name)) + return _make_value(self._ptr.CreateSExt(value._ptr, dest_ty._ptr, name)) def fptoui(self, value, dest_ty, name=""): - return Value(self._ptr.CreateFPToUI(value._ptr, dest_ty._ptr, name)) + return _make_value(self._ptr.CreateFPToUI(value._ptr, dest_ty._ptr, name)) def fptosi(self, value, dest_ty, name=""): - return Value(self._ptr.CreateFPToSI(value._ptr, dest_ty._ptr, name)) + return _make_value(self._ptr.CreateFPToSI(value._ptr, dest_ty._ptr, name)) def uitofp(self, value, dest_ty, name=""): - return Value(self._ptr.CreateUIToFP(value._ptr, dest_ty._ptr, name)) + return _make_value(self._ptr.CreateUIToFP(value._ptr, dest_ty._ptr, name)) def sitofp(self, value, dest_ty, name=""): - return Value(self._ptr.CreateSIToFP(value._ptr, dest_ty._ptr, name)) + return _make_value(self._ptr.CreateSIToFP(value._ptr, dest_ty._ptr, name)) def fptrunc(self, value, dest_ty, name=""): - return Value(self._ptr.CreateFPTrunc(value._ptr, dest_ty._ptr, name)) + return _make_value(self._ptr.CreateFPTrunc(value._ptr, dest_ty._ptr, name)) def fpext(self, value, dest_ty, name=""): - return Value(self._ptr.CreateFPExt(value._ptr, dest_ty._ptr, name)) + return _make_value(self._ptr.CreateFPExt(value._ptr, dest_ty._ptr, name)) def ptrtoint(self, value, dest_ty, name=""): - return Value(self._ptr.CreatePtrToInt(value._ptr, dest_ty._ptr, name)) + return _make_value(self._ptr.CreatePtrToInt(value._ptr, dest_ty._ptr, name)) def inttoptr(self, value, dest_ty, name=""): - return Value(self._ptr.CreateIntToPtr(value._ptr, dest_ty._ptr, name)) + return _make_value(self._ptr.CreateIntToPtr(value._ptr, dest_ty._ptr, name)) def bitcast(self, value, dest_ty, name=""): - return Value(self._ptr.CreateBitCast(value._ptr, dest_ty._ptr, name)) + return _make_value(self._ptr.CreateBitCast(value._ptr, dest_ty._ptr, name)) # comparisons def icmp(self, ipred, lhs, rhs, name=""): - return Value(self._ptr.CreateICmp(ipred, lhs._ptr, rhs._ptr, name)) + return _make_value(self._ptr.CreateICmp(ipred, lhs._ptr, rhs._ptr, name)) def fcmp(self, rpred, lhs, rhs, name=""): - return Value(self._ptr.CreateFCmp(rpred, lhs._ptr, rhs._ptr, name)) + return _make_value(self._ptr.CreateFCmp(rpred, lhs._ptr, rhs._ptr, name)) # misc def extract_value(self, retval, idx, name=""): - return Value(self._ptr.CreateExtractValue(retval._ptr, [idx], name)) + return _make_value(self._ptr.CreateExtractValue(retval._ptr, [idx], name)) # obsolete synonym for extract_value getresult = extract_value def insert_value(self, retval, rhs, idx, name=""): - return Value(self._ptr.CreateInsertValue(retval._ptr, + return _make_value(self._ptr.CreateInsertValue(retval._ptr, rhs._ptr, [idx], name)) def phi(self, ty, name=""): - return Value(self._ptr.CreatePHI(ty._ptr, 2, name)) + return _make_value(self._ptr.CreatePHI(ty._ptr, 2, name)) def call(self, fn, args, name=""): err_template = 'Argument type mismatch: expected %s but got %s' + for i, (t, v) in enumerate(zip(fn.type.pointee.args, args)): if t != v.type: raise TypeError(err_template % (t, v.type)) arg_ptrs = llvm._extract_ptrs(args) - return Value(self._ptr.CreateCall(fn._ptr, arg_ptrs, name)) + return _make_value(self._ptr.CreateCall(fn._ptr, arg_ptrs, name)) def select(self, cond, then_value, else_value, name=""): - return Value(self._ptr.CreateSelect(cond._ptr, then_value._ptr, + return _make_value(self._ptr.CreateSelect(cond._ptr, then_value._ptr, else_value._ptr, name)) def vaarg(self, list_val, ty, name=""): - return Value(self._ptr.CreateVAArg(list_val._ptr, ty._ptr, name)) + return _make_value(self._ptr.CreateVAArg(list_val._ptr, ty._ptr, name)) def extract_element(self, vec_val, idx_val, name=""): - return Value(self._ptr.CreateExtractElement(vec_val._ptr, - idx_val_.ptr, - name)) + return _make_value(self._ptr.CreateExtractElement(vec_val._ptr, + idx_val._ptr, + name)) def insert_element(self, vec_val, elt_val, idx_val, name=""): - return Value(self._ptr.CreateExtractElement(vec_val._ptr, - elt_val._ptr, - idx_val_.ptr, - name)) + return _make_value(self._ptr.CreateInsertElement(vec_val._ptr, + elt_val._ptr, + idx_val._ptr, + name)) def shuffle_vector(self, vecA, vecB, mask, name=""): - return Value(self._ptr.CreateShuffleVector(vecA._ptr, - vecB._ptr, - mask._ptr, - name)) + return _make_value(self._ptr.CreateShuffleVector(vecA._ptr, + vecB._ptr, + mask._ptr, + name)) # atomics def atomic_cmpxchg(self, ptr, old, new, ordering, crossthread=True): - return Value(self._ptr.CreateAtomicCmpXchg(ptr._ptr, + return _make_value(self._ptr.CreateAtomicCmpXchg(ptr._ptr, old._ptr, new._ptr, - ordering, + _atomic_orderings[ordering], _sync_scope(crossthread))) def atomic_rmw(self, op, ptr, val, ordering, crossthread=True): op_dict = dict((k.lower(), v) - for k, v in vars(api.llvm.AtomicRMWInst.BinOp)) + for k, v in vars(api.llvm.AtomicRMWInst.BinOp).items()) op = op_dict[op] - return Value(self._ptr.CreateAtomicRMW(op, ptr._ptr, val._ptr, - ordering, + return _make_value(self._ptr.CreateAtomicRMW(op, ptr._ptr, val._ptr, + _atomic_orderings[ordering], _sync_scope(crossthread))) def atomic_xchg(self, *args, **kwargs): @@ -1970,21 +2203,22 @@ class Builder(llvm.Wrapper): def atomic_load(self, ptr, ordering, align=1, crossthread=True, volatile=False, name=""): - inst = self._ptr.load(ptr, align=align, volatile=volatile, name=name) - inst._ptr.setAtomic(ordering, _sync_scope(crossthread)) + inst = self.load(ptr, align=align, volatile=volatile, name=name) + inst._ptr.setAtomic(_atomic_orderings[ordering], + _sync_scope(crossthread)) return inst def atomic_store(self, value, ptr, ordering, align=1, crossthread=True, volatile=False): - inst = self._ptr.store(ptr, value, align=align, volatile=volatile, - name=name) - inst._ptr.setAtomic(ordering, _sync_scope(crossthread)) + inst = self.store(value, ptr, align=align, volatile=volatile) + inst._ptr.setAtomic(_atomic_orderings[ordering], + _sync_scope(crossthread)) return inst def fence(self, ordering, crossthread=True): - return Value(self._ptr.CreateFence(ordering, - _sync_scope(crossthread))) + return _make_value(self._ptr.CreateFence(_atomic_orderings[ordering], + _sync_scope(crossthread))) def _sync_scope(crossthread): if crossthread: @@ -2000,12 +2234,13 @@ def load_library_permanently(filename): path of the .so file) using LLVM. Symbols from these are available from the execution engine thereafter.""" with contextlib.closing(StringIO()) as errmsg: - failed = api.llvm.sys.LoadLibraryPermanently(filename, errmsg) + failed = api.llvm.sys.DynamicLibrary.LoadPermanentLibrary(filename, + errmsg) if failed: raise llvm.LLVMException(errmsg.getvalue()) def inline_function(call): - info = api.llvm.InlineFunctionInfo() + info = api.llvm.InlineFunctionInfo.new() return api.llvm.InlineFunction(call._ptr, info) def parse_environment_options(progname, envname): diff --git a/llvm/ee.py b/llvm/ee.py index 8523998..8598ad9 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -38,8 +38,8 @@ import contextlib import llvm from llvm import core -from llvmpy import api - +from llvm.passes import TargetData, TargetTransformInfo +from llvmpy import api, extra #===----------------------------------------------------------------------=== # Enumerations #===----------------------------------------------------------------------=== @@ -63,20 +63,20 @@ class GenericValue(llvm.Wrapper): @staticmethod def int(ty, intval): - ptr = api.llvm.CreateInt(ty._ptr, intval, False) + ptr = api.llvm.GenericValue.CreateInt(ty._ptr, int(intval), False) return GenericValue(ptr) @staticmethod def int_signed(ty, intval): - ptr = api.llvm.CreateInt(ty._ptr, intval, True) + ptr = api.llvm.GenericValue.CreateInt(ty._ptr, int(intval), True) return GenericValue(ptr) @staticmethod def real(ty, floatval): if str(ty) == 'float': - ptr = api.llvm.CreateFloat(floatval) + ptr = api.llvm.GenericValue.CreateFloat(float(floatval)) elif str(ty) == 'double': - ptr = api.llvm.CreateDouble(floatval) + ptr = api.llvm.GenericValue.CreateDouble(float(floatval)) else: raise Exception('Unreachable') return GenericValue(ptr) @@ -91,7 +91,7 @@ class GenericValue(llvm.Wrapper): `addr` is an integer representing an address. ''' - ptr = api.llvm.CreatePointer(addr) + ptr = api.llvm.GenericValue.CreatePointer(int(addr)) return GenericValue(ptr) def as_int(self): @@ -101,7 +101,7 @@ class GenericValue(llvm.Wrapper): return self._ptr.toSignedInt() def as_real(self, ty): - return self._ptr.toFloat() + return self._ptr.toFloat(ty._ptr) def as_pointer(self): return self._ptr.toPointer() @@ -113,7 +113,7 @@ class GenericValue(llvm.Wrapper): class EngineBuilder(llvm.Wrapper): @staticmethod def new(module): - ptr = api.llvm.EngineBuilder.new(module) + ptr = api.llvm.EngineBuilder.new(module._ptr) return EngineBuilder(ptr) def force_jit(self): @@ -158,10 +158,10 @@ class EngineBuilder(llvm.Wrapper): ''' if args: triple, march, mcpu, mattrs = args - ptr = self._ptr.select_target(triple, march, mcpu, + ptr = self._ptr.selectTarget(triple, march, mcpu, mattrs.split(',')) else: - ptr = self._ptr.select_target() + ptr = self._ptr.selectTarget() return TargetMachine(ptr) @@ -182,7 +182,8 @@ class ExecutionEngine(llvm.Wrapper): self._ptr.DisableLazyCompilation(disabled) def run_function(self, fn, args): - return self._ptr.runFunction(fn._ptr, map(lambda x: x._ptr, args)) + ptr = self._ptr.runFunction(fn._ptr, map(lambda x: x._ptr, args)) + return GenericValue(ptr) def get_pointer_to_function(self, fn): return self._ptr.getPointerToFunction(fn._ptr) @@ -195,13 +196,13 @@ class ExecutionEngine(llvm.Wrapper): self._ptr.addGlobalMapping(gvar._ptr, addr) def run_static_ctors(self): - self._ptr.runStaticConstructorDestructors(False) + self._ptr.runStaticConstructorsDestructors(False) def run_static_dtors(self): - self._ptr.runStaticConstructorDestructors(True) + self._ptr.runStaticConstructorsDestructors(True) def free_machine_code_for(self, fn): - self.freeMachineCodeForFunction(fn._ptr) + self._ptr.freeMachineCodeForFunction(fn._ptr) def add_module(self, module): self._ptr.addModule(module._ptr) @@ -222,17 +223,17 @@ def print_registered_targets(): ''' Note: print directly to stdout ''' - llvm.TargetRegistry.printRegisteredTargetsForVersion() + api.llvm.TargetRegistry.printRegisteredTargetsForVersion() def get_host_cpu_name(): '''return the string name of the host CPU ''' - return llvm.sys.getHostCPUName() + return api.llvm.sys.getHostCPUName() def get_default_triple(): '''return the target triple of the host in str-rep ''' - return llvm.sys.getDefaultTargetTriple() + return api.llvm.sys.getDefaultTargetTriple() class TargetMachine(llvm.Wrapper): @@ -243,20 +244,20 @@ class TargetMachine(llvm.Wrapper): triple = get_default_triple() if not cpu: cpu = get_host_cpu_name() - with contextlib.closing(StringIO) as error: + with contextlib.closing(StringIO()) 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() + target_options = api.llvm.TargetOptions.new() tm = target.createTargetMachine(triple, cpu, features, target_options, api.llvm.Reloc.Model.Default, cm, opt) if not tm: raise llvm.LLVMException("Cannot create target machine") - return TargetMachine(ptr) + return TargetMachine(tm) @staticmethod def lookup(arch, cpu='', features='', opt=2, cm=CM_DEFAULT): @@ -272,24 +273,25 @@ class TargetMachine(llvm.Wrapper): use: `llvm-as < /dev/null | llc -march=xyz -mattr=help` ''' triple = api.llvm.Triple.new() - with contextlib.closing(StringIO) as error: - target = api.llvm.TargetMachine.lookupTarget(arch, triple, error) + with contextlib.closing(StringIO()) as error: + target = api.llvm.TargetRegistry.lookupTarget(arch, 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() + target_options = api.llvm.TargetOptions.new() tm = target.createTargetMachine(str(triple), cpu, features, target_options, api.llvm.Reloc.Model.Default, cm, opt) if not tm: raise llvm.LLVMException("Cannot create target machine") - return TargetMachine(ptr) + return TargetMachine(tm) def _emit_file(self, module, cgft): pm = api.llvm.PassManager.new() - os = api.extra.make_raw_ostream_for_printing() + 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) return os.str() @@ -298,19 +300,19 @@ class TargetMachine(llvm.Wrapper): '''returns byte string of the module as assembly code of the target machine ''' CGFT = api.llvm.TargetMachine.CodeGenFileType - return self._emit_file(module, CGFT.CGFT_AssemblyFile) + 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, CGFT.CGFT_ObjectFile) + 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) + return TargetData(self._ptr.getDataLayout()) @property def target_name(self): diff --git a/llvm/passes.py b/llvm/passes.py index 545a19d..36e7d97 100644 --- a/llvm/passes.py +++ b/llvm/passes.py @@ -46,7 +46,7 @@ from llvmpy import api class PassManagerBuilder(llvm.Wrapper): @staticmethod def new(): - return PassManagerBuilder(api.llvm.PassManagerBuilder()) + return PassManagerBuilder(api.llvm.PassManagerBuilder.new()) def populate(self, pm): if isinstance(pm, FunctionPassManager): @@ -59,7 +59,7 @@ class PassManagerBuilder(llvm.Wrapper): return self._ptr.OptLevel @opt_level.setter - def _set_opt_level(self, optlevel): + def opt_level(self, optlevel): self._ptr.OptLevel = optlevel @property @@ -67,7 +67,7 @@ class PassManagerBuilder(llvm.Wrapper): return self._ptr.SizeLevel @size_level.setter - def _set_size_level(self, sizelevel): + def size_level(self, sizelevel): self._ptr.SizeLevel = sizelevel @property @@ -75,8 +75,9 @@ class PassManagerBuilder(llvm.Wrapper): return self._ptr.Vectorize @vectorize.setter - def _set_vectorize(self, enable): - self._ptr.Vectroize = enable + def vectorize(self, enable): + self._ptr.Vectorize = enable + @property def loop_vectorize(self): @@ -142,10 +143,11 @@ class PassManager(llvm.Wrapper): def _add_pass(self, pass_name): passreg = api.llvm.PassRegistry.getPassRegistry() - a_pass = passreg.getPassInfo(pass_name) + a_pass = passreg.getPassInfo(pass_name).createPass() if not a_pass: assert pass_name not in PASSES, "Registered but not found?" raise llvm.LLVMException('Invalid pass name "%s"' % pass_name) + print a_pass self._ptr.add(a_pass) def run(self, module): @@ -155,17 +157,17 @@ class FunctionPassManager(PassManager): @staticmethod def new(module): - ptr = api.llvm.FunctionPassManager.new(module) + ptr = api.llvm.FunctionPassManager.new(module._ptr) return FunctionPassManager(ptr) def __init__(self, ptr): PassManager.__init__(self, ptr) def initialize(self): - self._ptr.doInitization() + self._ptr.doInitialization() def run(self, fn): - return self._ptr.run(fn) + return self._ptr.run(fn._ptr) def finalize(self): self._ptr.doFinalization() @@ -187,7 +189,7 @@ class Pass(llvm.Wrapper): The error cannot be caught. ''' passreg = api.llvm.PassRegistry.getPassRegistry() - a_pass = passreg.getPassInfo(pass_name) + a_pass = passreg.getPassInfo(name).createPass() p = Pass(a_pass) p.__name = name return p @@ -196,7 +198,10 @@ class Pass(llvm.Wrapper): def name(self): '''The name used in PassRegistry. ''' - return p.__name + try: + return self.__name + except AttributeError: + return @property def description(self): @@ -235,7 +240,8 @@ class TargetData(Pass): @property def target_integer_type(self): - return self._ptr.core.IntegerType(core.Type.getInt32Ty()) + context = api.llvm.getGlobalContext() + return api.llvm.IntegerType(api.llvm.Type.getInt32Ty(context)) def size(self, ty): return self._ptr.getTypeSizeInBits(ty._ptr) @@ -256,15 +262,15 @@ class TargetData(Pass): if isinstance(ty_or_gv, core.Type): return self._ptr.getPrefTypeAlignment(ty_or_gv._ptr) elif isinstance(ty_or_gv, core.GlobalVariable): - return self._ptr._core.getPreferredAlignment(ty_or_gv._ptr) + return self._ptr.getPreferredAlignment(ty_or_gv._ptr) else: raise core.LLVMException("argument is neither a type nor a global variable") def element_at_offset(self, ty, ofs): - return self._ptr.getStructLayout(ty).getElementContainingOffset(ofs) + return self._ptr.getStructLayout(ty._ptr).getElementContainingOffset(ofs) def offset_of_element(self, ty, el): - return self._ptr.getStructLayout(ty).getElementOffset(el) + return self._ptr.getStructLayout(ty._ptr).getElementOffset(el) #===----------------------------------------------------------------------=== # Target Library Info @@ -277,6 +283,19 @@ class TargetLibraryInfo(Pass): ptr = api.llvm.TargetLibraryInfo.new(triple) return TargetLibraryInfo(ptr) +#===----------------------------------------------------------------------=== +# Target Transformation Info +#===----------------------------------------------------------------------=== + +class TargetTransformInfo(Pass): + @staticmethod + def new(targetmachine): + scalartti = targetmachine._ptr.getScalarTargetTransformInfo() + vectortti = targetmachine._ptr.getVectorTargetTransformInfo() + ptr = api.llvm.TargetTransformInfo.new(scalartti, vectortti) + return TargetTransformInfo(ptr) + + #===----------------------------------------------------------------------=== # Helpers #===----------------------------------------------------------------------=== diff --git a/llvm/tbaa.py b/llvm/tbaa.py new file mode 100644 index 0000000..b510ce2 --- /dev/null +++ b/llvm/tbaa.py @@ -0,0 +1,51 @@ +from llvm.core import * + +class TBAABuilder(object): + '''Simplify creation of TBAA metadata. + + Each TBAABuidler object operates on a module. + User can create multiple TBAABuilder on a module + ''' + + def __init__(self, module, rootid): + ''' + module --- the module to use. + root --- string name to identify the TBAA root. + ''' + self.__module = module + self.__rootid = rootid + self.__rootmd = self.__new_md(rootid) + + @classmethod + def new(cls, module, rootid): + return cls(module, rootid) + + def get_node(self, name, parent=None, const=False): + '''Returns a MetaData object representing a TBAA node. + + Use loadstore_instruction.set_metadata('tbaa', node) to + bind a type to a memory. + ''' + parent = parent or self.root + const = Constant.int(Type.int(), int(bool(const))) + return self.__new_md(name, parent, const) + + @property + def module(self): + return self.__module + + @property + def root(self): + return self.__rootmd + + @property + def root_name(self): + return self.__rootid + + def __new_md(self, *args): + contents = list(args) + for i, v in enumerate(contents): + if isinstance(v, str): + contents[i] = MetaDataString.get(self.module, v) + return MetaData.get(self.module, contents) + diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py new file mode 100644 index 0000000..5b26e39 --- /dev/null +++ b/llvm/test_llvmpy.py @@ -0,0 +1,1243 @@ +""" +LLVM tests +""" +import os +import sys +import math +import shutil +import unittest +import subprocess +import tempfile +import contextlib + +is_py3k = bool(sys.version_info[0] == 3) +BITS = tuple.__itemsize__ * 8 + +if is_py3k: + from io import StringIO +else: + from cStringIO import StringIO + + +import llvm +from llvm.core import (Module, Type, GlobalVariable, Function, Builder, + Constant, MetaData, MetaDataString, inline_function) +from llvm.ee import EngineBuilder +import llvm.core as lc +import llvm.passes as lp +import llvm.ee as le +import llvmpy + + +tests = [] + + +# --------------------------------------------------------------------------- + +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 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 ''. + 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 ''. + m2.id = m.id # Copy the name from `m` + + self.assertEqual(str(m2).strip(), asm.strip()) + +tests.append(TestAsm) + +# --------------------------------------------------------------------------- + +class TestAttr(TestCase): + def make_module(self): + test_module = """ + define void @sum(i32*, i32*) { + entry: + ret void + } + """ + return Module.from_assembly(StringIO(test_module)) + + 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) + +# --------------------------------------------------------------------------- + +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()) + + old = bldr.load(ptr) + 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()) + + val = Constant.int(Type.int(), 1234) + + 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) + +# --------------------------------------------------------------------------- + +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) + +# --------------------------------------------------------------------------- + +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) + +# --------------------------------------------------------------------------- + +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) + 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) + +# --------------------------------------------------------------------------- + +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) + +# --------------------------------------------------------------------------- + +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) +# --------------------------------------------------------------------------- + +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) + +# --------------------------------------------------------------------------- + +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).decode('utf-8')) + self.assertTrue(le.get_host_cpu_name()) + + def test_ptx(self): + if lc.HAS_PTX: + arch = 'ptx64' + elif lc.HAS_NVPTX: + arch = 'nvptx64' + else: + return # skip this test + 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).decode('utf-8') + self.assertIn('foo', ptxasm) + if lc.HAS_NVPTX: + self.assertIn('.address_size 64', ptxasm) + self.assertIn('sm_20', ptxasm) + + def _build_module(self): + m = 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 + + def _build_bad_archname(self): + with self.assertRaises(RuntimeError): + tm = TargetMachine.lookup("ain't no arch name") + +tests.append(TestTargetMachines) + +# --------------------------------------------------------------------------- + +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): + 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: + fout.write(output) + + self._compile(src) + + def test_object(self): + if sys.platform == 'darwin': + # skip this test on MacOSX for now + return + + 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) + +if sys.platform != 'win32': + tests.append(TestNative) + +# --------------------------------------------------------------------------- + +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) + +tests.append(TestNativeAsm) + +# --------------------------------------------------------------------------- + +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) + +# --------------------------------------------------------------------------- + +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) + +# --------------------------------------------------------------------------- + +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) + +# --------------------------------------------------------------------------- + +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) + +# --------------------------------------------------------------------------- + +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) + +# --------------------------------------------------------------------------- +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) + + def test_cpu_support6(self): + features = [] + mattrs = ','.join(map(lambda s: '-%s' % s, features)) + print 'disable mattrs', mattrs + self._template(mattrs) + +tests.append(TestCPUSupport) + +# --------------------------------------------------------------------------- +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 + ee = le.ExecutionEngine.new(mod) + 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) + +# --------------------------------------------------------------------------- + +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 ) ; :0 [#uses +# } +# +# declare i32 @llvm.bswap.i32(i32) nounwind readnone +# +# define float @mysin(float %x) { +# entry: +# %cosx = call float @llvm.cos.f32( float %x ) ; [#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 + ee = le.ExecutionEngine.new(mod) + 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) + +# --------------------------------------------------------------------------- + +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) + +# --------------------------------------------------------------------------- + +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) + +# --------------------------------------------------------------------------- + +def run(verbosity=1): + print('llvmpy is installed in: ' + os.path.dirname(__file__)) + print('llvmpy version: ' + llvm.__version__) + print(sys.version) + + suite = unittest.TestSuite() + for cls in tests: + suite.addTest(unittest.makeSuite(cls)) + + # The default stream fails in IPython qtconsole on Windows, + # so just using sys.stdout + runner = unittest.TextTestRunner(verbosity=verbosity, stream=sys.stdout) + return runner.run(suite) + + +if __name__ == '__main__': + run() diff --git a/llvmpy/capsule.py b/llvmpy/capsule.py index 7a7ceaf..03aa286 100644 --- a/llvmpy/capsule.py +++ b/llvmpy/capsule.py @@ -196,4 +196,8 @@ def downcast(obj, cls): old = unwrap(obj) new = caster(old) used_to_own = has_ownership(old) - return wrap(new, owned=not used_to_own) + res = wrap(new, owned=not used_to_own) + if not res: + raise ValueError("Downcast failed") + return res + diff --git a/llvmpy/gen/binding.py b/llvmpy/gen/binding.py index 6d73cd3..aaa33e4 100644 --- a/llvmpy/gen/binding.py +++ b/llvmpy/gen/binding.py @@ -719,13 +719,26 @@ class cast(_Type): def wrap(self, writer, val): dst = self.python_type.__name__ - return writer.call('py_%(dst)s_from' % locals(), 'PyObject*', val) + if dst == 'int': + unsigned = set([Unsigned, UnsignedLongLong, Uint64, + Size_t, VoidPtr]) + signed = set([LongLong, Int64, Int]) + assert self.binding_type in unsigned|signed + if self.binding_type in signed: + signflag = 'signed' + else: + signflag = 'unsigned' + fn = 'py_%(dst)s_from_%(signflag)s' % locals() + else: + fn = 'py_%(dst)s_from' % locals() + return writer.call(fn, 'PyObject*', val) def unwrap(self, writer, val): src = self.python_type.__name__ dst = self.binding_type.fullname ret = writer.declare(dst) - status = writer.call('py_%(src)s_to' % locals(), 'int', val, ret) + fn = 'py_%(src)s_to' % locals() + status = writer.call(fn, 'int', val, ret) writer.die_if_false(status) return ret diff --git a/llvmpy/include/llvm_binding/conversion.h b/llvmpy/include/llvm_binding/conversion.h index cf4e639..7b8e6df 100644 --- a/llvmpy/include/llvm_binding/conversion.h +++ b/llvmpy/include/llvm_binding/conversion.h @@ -67,7 +67,7 @@ int py_str_to(PyObject *strobj, const char* &strref){ static int py_int_to(PyObject *intobj, int64_t & val){ - if (!PyInt_Check(intobj)) { + if (!PyInt_Check(intobj) and !PyLong_Check(intobj)) { // raise TypeError PyErr_SetString(PyExc_TypeError, "Expecting an int"); return 0; @@ -88,7 +88,7 @@ int py_int_to(PyObject *intobj, int64_t & val){ static int py_int_to(PyObject *intobj, unsigned & val){ - if (!PyInt_Check(intobj)) { + if (!PyInt_Check(intobj) and !PyLong_Check(intobj)) { // raise TypeError PyErr_SetString(PyExc_TypeError, "Expecting an int"); return 0; @@ -100,9 +100,8 @@ int py_int_to(PyObject *intobj, unsigned & val){ static int py_int_to(PyObject *intobj, unsigned long long & val){ - if (!PyInt_Check(intobj)) { + if (!PyInt_Check(intobj) and !PyLong_Check(intobj)) { // raise TypeError - puts(PyString_AsString(PyObject_Str(PyObject_Type(intobj)))); PyErr_SetString(PyExc_TypeError, "Expecting an int 2"); return 0; } @@ -126,12 +125,12 @@ int py_int_to(PyObject *intobj, size_t & val){ static int py_int_to(PyObject *intobj, void* & val){ - if (!PyLong_Check(intobj)) { + if (!PyInt_Check(intobj) and !PyLong_Check(intobj)) { // raise TypeError PyErr_SetString(PyExc_TypeError, "Expecting an int"); return 0; } - val = PyLong_FromVoidPtr(intobj); + val = PyLong_AsVoidPtr(intobj); // success return 1; } @@ -202,13 +201,19 @@ PyObject* py_bool_from(bool val){ } } + static -PyObject* py_int_from(const long long & val){ +PyObject* py_int_from_signed(const long long & val){ return PyLong_FromLongLong(val); } static -PyObject* py_int_from(void * addr){ +PyObject* py_int_from_unsigned(const unsigned long long & val){ + return PyLong_FromUnsignedLongLong(val); +} + +static +PyObject* py_int_from_unsigned(void * addr){ return PyLong_FromVoidPtr(addr); } diff --git a/llvmpy/include/llvm_binding/extra.h b/llvmpy/include/llvm_binding/extra.h index 2bbad42..76c8a16 100644 --- a/llvmpy/include/llvm_binding/extra.h +++ b/llvmpy/include/llvm_binding/extra.h @@ -137,12 +137,19 @@ PyObject* make_small_vector_from_unsigned(PyObject* self, PyObject* args) return pycapsule_new(SV, "llvm::SmallVector"); } +static +PyObject* get_llvm_version(PyObject* self, PyObject* args) +{ + return Py_BuildValue("(ii)", LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR); +} + static PyMethodDef extra_methodtable[] = { #define method(func) { #func, (PyCFunction)func, METH_VARARGS, NULL } method( make_raw_ostream_for_printing ), method( make_small_vector_from_types ), method( make_small_vector_from_values ), method( make_small_vector_from_unsigned ), + method( get_llvm_version ), #undef method { NULL } }; @@ -185,7 +192,8 @@ struct extract { template static - bool from_py_sequence(VecTy& vec, PyObject* seq, const char *capsuleName) + bool from_py_sequence(VecTy& vec, PyObject* seq, const char *capsuleName, + bool accept_null=false) { Py_ssize_t N = PySequence_Size(seq); for (Py_ssize_t i = 0; i < N; ++i) { @@ -193,15 +201,23 @@ struct extract { if (!item) { return false; } - auto_pyobject capsule = PyObject_GetAttrString(*item, "_ptr"); - if (!capsule) { - return false; + if (accept_null and Py_None == *item) { + vec.push_back(NULL); + } else { + auto_pyobject capsule = PyObject_GetAttrString(*item, "_ptr"); + if (!capsule) { + return false; + } + void* ptr = PyCapsule_GetPointer(*capsule, capsuleName); + if (!ptr) { + return false; + } + ElemTy* res = typecast::from(ptr); + if (!res) { + return false; + } + vec.push_back(res); } - void* ptr = PyCapsule_GetPointer(*capsule, capsuleName); - if (!ptr) { - return false; - } - vec.push_back(static_cast(ptr)); } return true; } @@ -609,6 +625,18 @@ PyObject* StructType_setBody(llvm::StructType* Self, Py_RETURN_NONE; } +static +PyObject* StructType_get(llvm::LLVMContext& Cxt, + PyObject* Elems, + bool isPacked=false) +{ + using namespace llvm; + std::vector elements; + extract::from_py_sequence(elements, Elems, "llvm::Type"); + StructType *sty = StructType::get(Cxt, elements, isPacked); + return pycapsule_new(sty, "llvm::Type", "llvm::StructType"); +} + static PyObject* Module_list_globals(llvm::Module* Mod) { @@ -656,7 +684,7 @@ PyObject* ConstantArray_get(llvm::ArrayType* Ty, PyObject* Consts) std::vector vec_consts; bool ok = extract::from_py_sequence(vec_consts, Consts, - "llvm::Value"); + "llvm::Value"); if (not ok) return NULL; Constant* ary = ConstantArray::get(Ty, vec_consts); return pycapsule_new(ary, "llvm::Value", "llvm::Constant"); @@ -724,7 +752,9 @@ static PyObject* MDNode_get(llvm::LLVMContext &Cxt, PyObject* Vals) { std::vector vals; - bool ok = extract::from_py_sequence(vals, Vals, "llvm::Value"); + bool accept_null = true; + bool ok = extract::from_py_sequence(vals, Vals, "llvm::Value", + accept_null); if (not ok) return NULL; llvm::MDNode* md = llvm::MDNode::get(Cxt, vals); return pycapsule_new(md, "llvm::Value", "llvm::MDNode"); @@ -750,7 +780,7 @@ PyObject* IRBuilder_CreateAggregateRet(llvm::IRBuilder<>* builder, if (not ok) return NULL; Value** ptr_values = &vec_values[0]; ReturnInst* inst = builder->CreateAggregateRet(ptr_values, N); - return pycapsule_new(inst, "llvm::Value", "llvm:ReturnInst"); + return pycapsule_new(inst, "llvm::Value", "llvm::ReturnInst"); } static diff --git a/llvmpy/src/Argument.py b/llvmpy/src/Argument.py index eac4b07..64db072 100644 --- a/llvmpy/src/Argument.py +++ b/llvmpy/src/Argument.py @@ -1,12 +1,14 @@ from binding import * from namespace import llvm -from Value import Argument +from Value import Argument, Value from Attributes import Attributes @Argument class Argument: _include_ = 'llvm/Argument.h' + _downcast_ = Value + addAttr = Method(Void, ref(Attributes)) removeAttr = Method(Void, ref(Attributes)) getParamAlignment = Method(cast(Unsigned, int)) diff --git a/llvmpy/src/Attributes.py b/llvmpy/src/Attributes.py index 235d2c8..c6a8d97 100644 --- a/llvmpy/src/Attributes.py +++ b/llvmpy/src/Attributes.py @@ -20,7 +20,7 @@ class Attributes: delete = Destructor() - get = Method(Attributes, ref(LLVMContext), ref(AttrBuilder)) + get = StaticMethod(Attributes, ref(LLVMContext), ref(AttrBuilder)) @AttrBuilder diff --git a/llvmpy/src/BasicBlock.py b/llvmpy/src/BasicBlock.py index 81edf37..4ed4f66 100644 --- a/llvmpy/src/BasicBlock.py +++ b/llvmpy/src/BasicBlock.py @@ -21,4 +21,6 @@ class BasicBlock: removePredecessor = Method(Void, ptr(BasicBlock), cast(bool, Bool)) removePredecessor |= Method(Void, ptr(BasicBlock)) - getInstList = CustomMethod('BasicBlock_getInstList', PyObjectPtr) \ No newline at end of file + getInstList = CustomMethod('BasicBlock_getInstList', PyObjectPtr) + + eraseFromParent = Method() diff --git a/llvmpy/src/Constant.py b/llvmpy/src/Constant.py index 5407d71..0a79bd3 100644 --- a/llvmpy/src/Constant.py +++ b/llvmpy/src/Constant.py @@ -1,18 +1,9 @@ from binding import * from namespace import llvm - -from Value import Constant, Value - -UndefValue = llvm.Class(Constant) -ConstantInt = llvm.Class(Constant) -ConstantFP = llvm.Class(Constant) -ConstantArray = llvm.Class(Constant) -ConstantStruct = llvm.Class(Constant) -ConstantVector = llvm.Class(Constant) -ConstantDataSequential = llvm.Class(Constant) -ConstantDataArray = llvm.Class(ConstantDataSequential) -ConstantExpr = llvm.Class(Constant) - +from Value import Value +from Value import Constant, UndefValue, ConstantInt, ConstantFP, ConstantArray +from Value import ConstantStruct, ConstantVector, ConstantVector +from Value import ConstantDataSequential, ConstantDataArray, ConstantExpr from LLVMContext import LLVMContext from ADT.StringRef import StringRef from ADT.SmallVector import SmallVector_Value, SmallVector_Unsigned @@ -81,6 +72,8 @@ class UndefValue: @ConstantInt class ConstantInt: + _downcast_ = Constant, Value + get = StaticMethod(ptr(ConstantInt), ptr(IntegerType), cast(int, Unsigned), @@ -95,6 +88,8 @@ class ConstantInt: @ConstantFP class ConstantFP: + _downcast_ = Constant, Value + get = StaticMethod(ptr(Constant), ptr(Type), cast(float, Double)) getNegativeZero = StaticMethod(ptr(ConstantFP), ptr(Type)) getInfinity = StaticMethod(ptr(ConstantFP), ptr(Type), cast(bool, Bool)) @@ -107,6 +102,8 @@ class ConstantFP: @ConstantArray class ConstantArray: + _downcast_ = Constant, Value + get = CustomStaticMethod('ConstantArray_get', PyObjectPtr, # ptr(Constant), ptr(ArrayType), @@ -116,6 +113,8 @@ class ConstantArray: @ConstantStruct class ConstantStruct: + _downcast_ = Constant, Value + get = CustomStaticMethod('ConstantStruct_get', PyObjectPtr, # ptr(Constant) ptr(StructType), @@ -130,6 +129,8 @@ class ConstantStruct: @ConstantVector class ConstantVector: + _downcast_ = Constant, Value + get = CustomStaticMethod('ConstantVector_get', PyObjectPtr, # ptr(Constant) PyObjectPtr, # constants @@ -138,11 +139,13 @@ class ConstantVector: @ConstantDataSequential class ConstantDataSequential: - pass + _downcast_ = Constant, Value @ConstantDataArray class ConstantDataArray: + _downcast_ = Constant, Value + getString = StaticMethod(ptr(Constant), ref(LLVMContext), cast(str, StringRef), @@ -174,6 +177,8 @@ def _factory_const_type(): @ConstantExpr class ConstantExpr: + _downcast_ = Constant, Value + getAlignOf = _factory(ptr(Type)) getSizeOf = _factory(ptr(Type)) getOffsetOf = _factory(ptr(Type), ptr(Constant)) diff --git a/llvmpy/src/DerivedTypes.py b/llvmpy/src/DerivedTypes.py index a34c2f1..40724e0 100644 --- a/llvmpy/src/DerivedTypes.py +++ b/llvmpy/src/DerivedTypes.py @@ -9,6 +9,7 @@ FunctionType = llvm.Class(Type) @FunctionType class FunctionType: _include_ = 'llvm/DerivedTypes.h' + _downcast_ = Type _get = StaticMethod(ptr(FunctionType), ptr(Type), cast(bool, Bool)) _get |= StaticMethod(ptr(FunctionType), ptr(Type), ref(SmallVector_Type), diff --git a/llvmpy/src/ExecutionEngine/ExecutionEngine.py b/llvmpy/src/ExecutionEngine/ExecutionEngine.py index 0bd4714..bcf66fd 100644 --- a/llvmpy/src/ExecutionEngine/ExecutionEngine.py +++ b/llvmpy/src/ExecutionEngine/ExecutionEngine.py @@ -41,7 +41,7 @@ class ExecutionEngine: @CustomPythonMethod def removeModule(self, module): if self._removeModule(module): - capsule.obtain_ownership(module._ptr) + capsule.obtain_ownership(module._capsule) return True return False diff --git a/llvmpy/src/Function.py b/llvmpy/src/Function.py index d82b5d3..52db622 100644 --- a/llvmpy/src/Function.py +++ b/llvmpy/src/Function.py @@ -1,6 +1,6 @@ from binding import * from namespace import llvm -from Value import GlobalValue, Constant, Function, Argument +from Value import GlobalValue, Constant, Function, Argument, Value from BasicBlock import BasicBlock from Attributes import Attributes from Type import Type @@ -11,7 +11,7 @@ from CallingConv import CallingConv @Function class Function: _include_ = 'llvm/Function.h' - _downcast_ = GlobalValue, Constant + _downcast_ = GlobalValue, Constant, Value getReturnType = Method(ptr(Type)) getFunctionType = Method(ptr(FunctionType)) diff --git a/llvmpy/src/GenericValue.py b/llvmpy/src/GenericValue.py index 74587ba..73a3709 100644 --- a/llvmpy/src/GenericValue.py +++ b/llvmpy/src/GenericValue.py @@ -26,8 +26,8 @@ class GenericValue: valueIntWidth = _accessor('ValueIntWidth', cast(Unsigned, int)) - toSignedInt = _accessor('ToSignedInt', cast(UnsignedLongLong, int)) - toUnsignedInt = _accessor('ToUnsignedInt', cast(LongLong, int)) + toSignedInt = _accessor('ToSignedInt', cast(LongLong, int)) + toUnsignedInt = _accessor('ToUnsignedInt', cast(UnsignedLongLong, int)) toFloat = _accessor('ToFloat', cast(Double, float), ptr(Type)) diff --git a/llvmpy/src/IRBuilder.py b/llvmpy/src/IRBuilder.py index 095122f..445ff11 100644 --- a/llvmpy/src/IRBuilder.py +++ b/llvmpy/src/IRBuilder.py @@ -281,7 +281,7 @@ class IRBuilder: _CreateExtractValue.realname = 'CreateExtractValue' @CustomPythonMethod - def CreateExtractValue(self, args): + def CreateExtractValue(self, *args): from llvmpy import extra args = list(args) valuelist = args[1] @@ -316,3 +316,8 @@ class IRBuilder: # New in llvm 3.3 #CreateVectorSplat = Method(ptr(Value), cast(int, Unsigned), ptr(Value), # cast(str, StringRef)) + + + Insert = Method(ptr(Instruction), + ptr(Instruction), + cast(str, StringRef)).require_only(1) diff --git a/llvmpy/src/Instruction.py b/llvmpy/src/Instruction.py index b3fa701..9763e7c 100644 --- a/llvmpy/src/Instruction.py +++ b/llvmpy/src/Instruction.py @@ -1,6 +1,6 @@ from binding import * from namespace import llvm -from Value import Value, MDNode, User, BasicBlock, Function +from Value import Value, MDNode, User, BasicBlock, Function, ConstantInt Instruction = llvm.Class(User) @@ -66,13 +66,14 @@ SynchronizationScope = llvm.Enum('SynchronizationScope', from ADT.StringRef import StringRef from CallingConv import CallingConv from Attributes import Attributes -from Constant import ConstantInt from Type import Type @Instruction class Instruction: + _downcast_ = Value, User + removeFromParent = Method() eraseFromParent = Method() eraseFromParent.disowning = True @@ -133,6 +134,7 @@ class BinaryOperator: @CallInst class CallInst: _downcast_ = Value, Instruction + getCallingConv = Method(CallingConv.ID) setCallingConv = Method(Void, CallingConv.ID) getParamAlignment = Method(cast(Unsigned, int), cast(int, Unsigned)) diff --git a/llvmpy/src/Metadata.py b/llvmpy/src/Metadata.py index 94088ca..d5cc4b1 100644 --- a/llvmpy/src/Metadata.py +++ b/llvmpy/src/Metadata.py @@ -10,6 +10,7 @@ from Assembly.AssemblyAnnotationWriter import AssemblyAnnotationWriter @MDNode class MDNode: + _downcast_ = Value replaceOperandWith = Method(Void, cast(int, Unsigned), ptr(Value)) getOperand = Method(ptr(Value), cast(int, Unsigned)) getNumOperands = Method(cast(Unsigned, int)) @@ -24,6 +25,7 @@ class MDNode: @MDString class MDString: + _downcast_ = Value get = StaticMethod(ptr(MDString), ref(LLVMContext), cast(str, StringRef)) getString = Method(cast(StringRef, str)) getLength = Method(cast(int, Unsigned)) diff --git a/llvmpy/src/Target/TargetMachine.py b/llvmpy/src/Target/TargetMachine.py index 29960fa..1bd6843 100644 --- a/llvmpy/src/Target/TargetMachine.py +++ b/llvmpy/src/Target/TargetMachine.py @@ -9,7 +9,7 @@ from src.Support.CodeGen import CodeModel, TLSModel, CodeGenOpt, Reloc from src.GlobalValue import GlobalValue from src.DataLayout import DataLayout from src.TargetTransformInfo import (ScalarTargetTransformInfo, - VectorTargetTransformInfo) + VectorTargetTransformInfo) from src.PassManager import PassManagerBase from src.Support.FormattedStream import formatted_raw_ostream @@ -40,9 +40,9 @@ class TargetMachine: getDataLayout = Method(const(ownedptr(DataLayout))) getScalarTargetTransformInfo = Method(const( - ownedptr(ScalarTargetTransformInfo))) + ownedptr(ScalarTargetTransformInfo))) getVectorTargetTransformInfo = Method(const( - ownedptr(VectorTargetTransformInfo))) + ownedptr(VectorTargetTransformInfo))) addPassesToEmitFile = Method(cast(bool, Bool), ref(PassManagerBase), diff --git a/llvmpy/src/TargetTransformInfo.py b/llvmpy/src/TargetTransformInfo.py index 5761281..1208050 100644 --- a/llvmpy/src/TargetTransformInfo.py +++ b/llvmpy/src/TargetTransformInfo.py @@ -1,11 +1,14 @@ from binding import * -from namespace import llvm +from src.namespace import llvm +from src.Pass import ImmutablePass llvm.includes.add('llvm/TargetTransformInfo.h') +TargetTransformInfo = llvm.Class(ImmutablePass) ScalarTargetTransformInfo = llvm.Class() VectorTargetTransformInfo = llvm.Class() + @ScalarTargetTransformInfo class ScalarTargetTransformInfo: delete = Destructor() @@ -14,3 +17,8 @@ class ScalarTargetTransformInfo: class VectorTargetTransformInfo: delete = Destructor() +@TargetTransformInfo +class TargetTransformInfo: + new = Constructor(ptr(ScalarTargetTransformInfo), + ptr(VectorTargetTransformInfo)) + diff --git a/llvmpy/src/Transforms/PassManagerBuilder.py b/llvmpy/src/Transforms/PassManagerBuilder.py index a95b6df..c940062 100644 --- a/llvmpy/src/Transforms/PassManagerBuilder.py +++ b/llvmpy/src/Transforms/PassManagerBuilder.py @@ -1,10 +1,13 @@ from binding import * from ..namespace import llvm -from ..PassManager import PassManagerBase, FunctionPassManager -from ..Target.TargetLibraryInfo import TargetLibraryInfo -from ..Pass import Pass -@llvm.Class() +PassManagerBuilder = llvm.Class() + +from src.PassManager import PassManagerBase, FunctionPassManager +from src.Target.TargetLibraryInfo import TargetLibraryInfo +from src.Pass import Pass + +@PassManagerBuilder class PassManagerBuilder: _include_ = 'llvm/Transforms/IPO/PassManagerBuilder.h' diff --git a/llvmpy/src/Transforms/Utils/Cloning.py b/llvmpy/src/Transforms/Utils/Cloning.py index 1971177..c6eaf0a 100644 --- a/llvmpy/src/Transforms/Utils/Cloning.py +++ b/llvmpy/src/Transforms/Utils/Cloning.py @@ -1,11 +1,15 @@ from binding import * from src.namespace import llvm -from src.Module import Module -from src.Instruction import CallInst llvm.includes.add('llvm/Transforms/Utils/Cloning.h') -@llvm.Class() +InlineFunctionInfo = llvm.Class() + + +from src.Module import Module +from src.Instruction import CallInst + +@InlineFunctionInfo class InlineFunctionInfo: new = Constructor() delete = Destructor() diff --git a/llvmpy/src/Type.py b/llvmpy/src/Type.py index ec0bf88..8e62137 100644 --- a/llvmpy/src/Type.py +++ b/llvmpy/src/Type.py @@ -146,25 +146,27 @@ class Type: @IntegerType class IntegerType: - pass + _downcast_ = Type @CompositeType class CompositeType: - pass + _downcast_ = Type @SequentialType class SequentialType: - pass + _downcast_ = Type @ArrayType class ArrayType: + _downcast_ = Type getNumElements = Method(cast(Uint64, int)) get = StaticMethod(ptr(ArrayType), ptr(Type), cast(int, Uint64)) isValidElementType = StaticMethod(cast(Bool, bool), ptr(Type)) @PointerType class PointerType: + _downcast_ = Type getAddressSpace = Method(cast(Unsigned, int)) get = StaticMethod(ptr(PointerType), ptr(Type), cast(int, Unsigned)) getUnqual = StaticMethod(ptr(PointerType), ptr(Type)) @@ -172,6 +174,7 @@ class PointerType: @VectorType class VectorType: + _downcast_ = Type getNumElements = Method(cast(Unsigned, int)) getBitWidth = Method(cast(Unsigned, int)) get = StaticMethod(ptr(VectorType), ptr(Type), cast(int, Unsigned)) @@ -184,6 +187,7 @@ class VectorType: @StructType class StructType: + _downcast_ = Type isPacked = Method(cast(Bool, bool)) isLiteral = Method(cast(Bool, bool)) isOpaque = Method(cast(Bool, bool)) @@ -203,10 +207,12 @@ class StructType: cast(str, StringRef), ).require_only(1) - get = StaticMethod(ptr(StructType), - ref(LLVMContext), - cast(bool, Bool), # is packed - ).require_only(1) + get = CustomStaticMethod('StructType_get', + PyObjectPtr, # StructType* + ref(LLVMContext), + PyObjectPtr, # ArrayRef elements + cast(bool, Bool), # is packed + ).require_only(2) isValidElementType = StaticMethod(cast(Bool, bool), ptr(Type)) diff --git a/llvmpy/src/Value.py b/llvmpy/src/Value.py index 88f221c..b10807a 100644 --- a/llvmpy/src/Value.py +++ b/llvmpy/src/Value.py @@ -11,6 +11,15 @@ BasicBlock = llvm.Class(Value) Constant = llvm.Class(User) GlobalValue = llvm.Class(Constant) Function = llvm.Class(GlobalValue) +UndefValue = llvm.Class(Constant) +ConstantInt = llvm.Class(Constant) +ConstantFP = llvm.Class(Constant) +ConstantArray = llvm.Class(Constant) +ConstantStruct = llvm.Class(Constant) +ConstantVector = llvm.Class(Constant) +ConstantDataSequential = llvm.Class(Constant) +ConstantDataArray = llvm.Class(ConstantDataSequential) +ConstantExpr = llvm.Class(Constant) from Support.raw_ostream import raw_ostream from Assembly.AssemblyAnnotationWriter import AssemblyAnnotationWriter diff --git a/test/constants.py b/test/constants.py index afe1020..90a5a53 100644 --- a/test/constants.py +++ b/test/constants.py @@ -21,8 +21,6 @@ def _build_test_module(datatype, constants): bb_entry = func_subject.append_basic_block('entry') builder = Builder.new(bb_entry) - - for k in constants: builder.call(func_subject.args[0], [k]) diff --git a/test/malloc.py b/test/malloc.py new file mode 100644 index 0000000..1613a36 --- /dev/null +++ b/test/malloc.py @@ -0,0 +1,16 @@ +from llvm.core import * + +def test(): + m = Module.new('sdf') + f = m.add_function(Type.function(Type.void(), []), 'foo') + bb = f.append_basic_block('entry') + b = Builder.new(bb) + alloc = b.malloc(Type.int(), 'ha') + inst = b.free(alloc) + alloc = b.malloc_array(Type.int(), Constant.int(Type.int(), 10), 'hee') + inst = b.free(alloc) + b.ret_void() + print m + +if __name__ == '__main__': + test() diff --git a/test/operands.py b/test/operands.py index 674bc9e..32fb811 100644 --- a/test/operands.py +++ b/test/operands.py @@ -49,6 +49,7 @@ class TestOperands(unittest.TestCase): i1 = test_func.basic_blocks[0].instructions[0] i2 = test_func.basic_blocks[0].instructions[1] + logging.debug("Testing User.operand_count ..") self.assertEqual(i1.operand_count, 3) @@ -61,6 +62,7 @@ class TestOperands(unittest.TestCase): 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) diff --git a/test/testall.py b/test/testall.py index 3b5f0c3..231bca3 100644 --- a/test/testall.py +++ b/test/testall.py @@ -18,16 +18,6 @@ def do_llvmexception(): e = LLVMException() -def do_ownable(): - print(" Testing class Ownable") - o = Ownable(None, lambda x: None) - try: - o._own(None) - o._disown() - except LLVMException: - pass - - def do_misc(): print(" Testing miscellaneous functions") try: @@ -44,7 +34,6 @@ def do_misc(): def do_llvm(): print(" Testing module llvm") do_llvmexception() - do_ownable() do_misc() @@ -208,7 +197,9 @@ def do_constant(): Constant.struct([Constant.int(ti,42)]*10) Constant.packed_struct([Constant.int(ti,42)]*10) Constant.vector([Constant.int(ti,42)]*10) + Constant.sizeof(ti) + k = Constant.int(ti, 10) f = Constant.real(Type.float(), 3.1415) k.neg().not_().add(k).sub(k).mul(k).udiv(k).sdiv(k).urem(k) @@ -271,7 +262,8 @@ def do_global_variable(): def do_argument(): print(" Testing class Argument") m = Module.new('a') - ft = Type.function(ti, [ti]) + tip = Type.pointer(ti) + ft = Type.function(tip, [tip]) f = Function.new(m, ft, 'func') a = f.args[0] a.add_attribute(ATTR_ZEXT) @@ -301,13 +293,14 @@ def do_function(): c = f.collector a = list(f.args) g = f.basic_block_count - g = f.get_entry_basic_block() - g = f.append_basic_block('a') - g = f.get_entry_basic_block() +# g = f.entry_basic_block +# g = f.append_basic_block('a') +# g = f.entry_basic_block g = list(f.basic_blocks) f.add_attribute(ATTR_NO_RETURN) f.add_attribute(ATTR_ALWAYS_INLINE) f.remove_attribute(ATTR_NO_RETURN) + # LLVM misbehaves: #try: # f.verify() @@ -414,7 +407,7 @@ def do_builder(): b.position_at_beginning(blk) b.position_at_end(blk) b.position_before(blk.instructions[0]) - blk2 = b.block + blk2 = b.basic_block b.ret_void() b.ret(Constant.int(ti, 10)) _do_builder_mrv() @@ -552,7 +545,7 @@ def do_genericvalue(): def do_executionengine(): print(" Testing class ExecutionEngine") m = Module.new('a') - ee = ExecutionEngine.new(m, True) + ee = ExecutionEngine.new(m, False) # True) ft = Type.function(ti, []) f = m.add_function(ft, 'func') bb = f.append_basic_block('entry') @@ -573,7 +566,7 @@ def do_executionengine(): ee3 = ExecutionEngine.new(m4, False) ee3.add_module(m5) x = ee3.remove_module(m5) - check_is_module(x) + isinstance(x, Module) def do_llvm_ee(): From d2dc34cdd3f5d772be398efdbcd222ad6b1df826 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 13 Feb 2013 17:12:54 -0600 Subject: [PATCH 273/516] Try to fix invalid dtor call --- llvm/core.py | 72 +++++++++++++++++++++++++------------ llvmpy/capsule.py | 20 ++++++----- llvmpy/gen/binding.py | 2 +- llvmpy/gen/codegen.py | 4 ++- llvmpy/src/IRBuilder.py | 2 +- llvmpy/src/Instruction.py | 75 +++++++++++++++++++++------------------ 6 files changed, 108 insertions(+), 67 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index 1c3184c..f2af943 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -475,28 +475,31 @@ class Module(llvm.Wrapper): def add_function(self, ty, name): """Add a function of given type with given name.""" - fn = self.get_function_named(name) - if fn is not None: - raise llvm.LLVMException("Duplicated function %s" % name) - return self.get_or_insert_function(ty, name) + return Function.new(self, ty, name) +# fn = self.get_function_named(name) +# if fn is not None: +# raise llvm.LLVMException("Duplicated function %s" % name) +# return self.get_or_insert_function(ty, name) def get_function_named(self, name): """Return a Function object representing function with given name.""" - fn = self._ptr.getFunction(name) - if fn is not None: - return _make_value(fn) + return Function.get(self, name) +# fn = self._ptr.getFunction(name) +# if fn is not None: +# return _make_value(fn) def get_or_insert_function(self, ty, name): """Like get_function_named(), but does add_function() first, if function is not present.""" - constant = self._ptr.getOrInsertFunction(name, ty._ptr) - try: - fn = constant._downcast(api.llvm.Function) - except ValueError: - # bitcasted to function type - return _make_value(constant) - else: - return _make_value(fn) + return Function.get_or_insert(self, ty, name) +# constant = self._ptr.getOrInsertFunction(name, ty._ptr) +# try: +# fn = constant._downcast(api.llvm.Function) +# except ValueError: +# # bitcasted to function type +# return _make_value(constant) +# else: +# return _make_value(fn) @property def functions(self): @@ -616,6 +619,10 @@ class Type(llvm.Wrapper): ptr = ptr._downcast(type(self)._type_) super(Type, self).__init__(ptr) + @property + def kind(self): + return self._ptr.getTypeID() + @staticmethod def int(bits=32): """Create an integer type having the given bit width.""" @@ -830,7 +837,6 @@ class FunctionType(Type): return self._ptr.getNumParams() - class StructType(Type): """Represents a structure type.""" _type_ = api.llvm.StructType @@ -1385,15 +1391,32 @@ class Function(GlobalValue): @staticmethod def new(module, func_ty, name): - return module.add_function(func_ty, name) + try: + fn = Function.get(module, name) + except llvm.LLVMException: + return Function.get_or_insert(module, func_ty, name) + else: + raise llvm.LLVMException("Duplicated function %s" % name) + @staticmethod def get_or_insert(module, func_ty, name): - return module.get_or_insert_function(func_ty, name) + constant = module._ptr.getOrInsertFunction(name, func_ty._ptr) + try: + fn = constant._downcast(api.llvm.Function) + except ValueError: + # bitcasted to function type + return _make_value(constant) + else: + return _make_value(fn) @staticmethod def get(module, name): - return module.get_function_named(name) + fn = module._ptr.getFunction(name) + if fn is None: + raise llvm.LLVMException("no function named `%s`" % name) + else: + return _make_value(fn) @staticmethod def intrinsic(module, intrinsic_id, types): @@ -1450,6 +1473,10 @@ class Function(GlobalValue): assert self.basic_block_count return _make_value(self._ptr.getEntryBlock()) + def get_entry_basic_block(self): + "Deprecated. Use entry_basic_block instead" + return self.entry_basic_block + def append_basic_block(self, name): context = api.llvm.getGlobalContext() bb = api.llvm.BasicBlock.Create(context, name, self._ptr, None) @@ -1857,6 +1884,7 @@ class Builder(llvm.Wrapper): """Position the builder at the end of the given block. Next instruction inserted will be last one in the block.""" + self._ptr.SetInsertPoint(bblk._ptr) def position_before(self, instr): @@ -2111,9 +2139,9 @@ class Builder(llvm.Wrapper): def insert_value(self, retval, rhs, idx, name=""): return _make_value(self._ptr.CreateInsertValue(retval._ptr, - rhs._ptr, - [idx], - name)) + rhs._ptr, + [idx], + name)) def phi(self, ty, name=""): return _make_value(self._ptr.CreatePHI(ty._ptr, 2, name)) diff --git a/llvmpy/capsule.py b/llvmpy/capsule.py index 03aa286..0b1f203 100644 --- a/llvmpy/capsule.py +++ b/llvmpy/capsule.py @@ -19,13 +19,14 @@ def set_debug(enabled): 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(addr, None) + dtor = _addr2dtor.pop((name, addr), None) if dtor is not None: - logger.debug('Destroy %s %s', item.name, hex(item.pointer)) + logger.debug('Destroy %s %s', name, hex(addr)) dtor(item.capsule) class Capsule(object): @@ -92,26 +93,28 @@ _cache = defaultdict(WeakValueDictionary) def release_ownership(old): logger.debug('Release %s', old) addr = Capsule.getPointer(old) - - if _addr2dtor.get(addr) is None: + name = Capsule.getName(old) + if _addr2dtor.get((name, addr)) is None: clsname = Capsule.getClassName(old) if not _pyclasses[clsname]._has_dtor(): return # Guard duplicated release raise Exception("Already released") - _addr2dtor[addr] = None + _addr2dtor[(name, addr)] = None def obtain_ownership(cap): cls = cap.get_class() if cls._has_dtor(): addr = cap.pointer + name = cap.name assert _addr2dtor[addr] is None - _addr2dtor[addr] = cls._delete_ + _addr2dtor[(name, addr)] = cls._delete_ def has_ownership(cap): addr = Capsule.getPointer(cap) - return _addr2dtor.get(addr) is not None + name = Capsule.getName(cap) + return _addr2dtor.get((name, addr)) is not None def wrap(cap, owned=False): '''Wrap a PyCapsule with the corresponding Wrapper class. @@ -125,11 +128,12 @@ def wrap(cap, owned=False): 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[addr] = cls._delete_ + _addr2dtor[(name, addr)] = cls._delete_ obj = cap.instantiate() _cache[cls][addr] = obj # cache it return obj diff --git a/llvmpy/gen/binding.py b/llvmpy/gen/binding.py index aaa33e4..4454d72 100644 --- a/llvmpy/gen/binding.py +++ b/llvmpy/gen/binding.py @@ -329,7 +329,7 @@ class Class(SubModule, _Type): fmt = 'PyCapsule_GetPointer(%(val)s, "%(name)s")' name = self.capsule_name raw = writer.declare('void*', fmt % locals()) - writer.die_if_false(raw) + writer.die_if_false(raw, verbose=name) ptrty = ptr(self).fullname ty = self.fullname fmt = 'typecast< %(ty)s >::from(%(raw)s)' diff --git a/llvmpy/gen/codegen.py b/llvmpy/gen/codegen.py index dd499d6..abde437 100644 --- a/llvmpy/gen/codegen.py +++ b/llvmpy/gen/codegen.py @@ -208,8 +208,10 @@ class CppCodeWriter(CodeWriterBase): self.return_null() return ret - def die_if_false(self, val): + def die_if_false(self, val, verbose=None): with self.block('if(!%(val)s)' % locals()): + if verbose: + self.println('puts("Error: %s");' % verbose) self.return_null() def raises(self, exccls, msg): diff --git a/llvmpy/src/IRBuilder.py b/llvmpy/src/IRBuilder.py index 445ff11..8590430 100644 --- a/llvmpy/src/IRBuilder.py +++ b/llvmpy/src/IRBuilder.py @@ -294,7 +294,7 @@ class IRBuilder: _CreateInsertValue.realname = 'CreateInsertValue' @CustomPythonMethod - def CreateInsertValue(self, args): + def CreateInsertValue(self, *args): from llvmpy import extra args = list(args) valuelist = args[2] diff --git a/llvmpy/src/Instruction.py b/llvmpy/src/Instruction.py index 9763e7c..4761e16 100644 --- a/llvmpy/src/Instruction.py +++ b/llvmpy/src/Instruction.py @@ -120,16 +120,17 @@ class Instruction: @AtomicCmpXchgInst class AtomicCmpXchgInst: - pass + _downcast_ = Value, Instruction @AtomicRMWInst class AtomicRMWInst: + _downcast_ = Value, Instruction BinOp = Enum('Xchg', 'Add', 'Sub', 'And', 'Nand', 'Or', 'Xor', 'Max', 'Min', 'UMax', 'UMin', 'FIRST_BINOP', 'LAST_BINOP', 'BAD_BINOP') @BinaryOperator class BinaryOperator: - pass + _downcast_ = Value, Instruction @CallInst class CallInst: @@ -159,6 +160,7 @@ class CallInst: @CmpInst class CmpInst: + _downcast_ = Value, Instruction Predicate = Enum('FCMP_FALSE', 'FCMP_OEQ', 'FCMP_OGT', 'FCMP_OGE', 'FCMP_OLT', 'FCMP_OLE', 'FCMP_ONE', 'FCMP_ORD', 'FCMP_UNO', 'FCMP_UEQ', 'FCMP_UGT', 'FCMP_UGE', 'FCMP_ULT', 'FCMP_ULE', @@ -175,30 +177,31 @@ class CmpInst: @ExtractElementInst class ExtractElementInst: - pass + _downcast_ = Value, Instruction @FenceInst class FenceInst: - pass + _downcast_ = Value, Instruction @GetElementPtrInst class GetElementPtrInst: - pass + _downcast_ = Value, Instruction @InsertElementInst class InsertElementInst: - pass + _downcast_ = Value, Instruction @InsertValueInst class InsertValueInst: - pass + _downcast_ = Value, Instruction @LandingPadInst class LandingPadInst: - pass + _downcast_ = Value, Instruction @PHINode class PHINode: + _downcast_ = Value, Instruction getNumIncomingValues = Method(cast(Unsigned, int)) getIncomingValue = Method(ptr(Value), cast(int, Unsigned)) setIncomingValue = Method(Void, cast(int, Unsigned), ptr(Value)) @@ -210,15 +213,15 @@ class PHINode: @SelectInst class SelectInst: - pass + _downcast_ = Value, Instruction @ShuffleVectorInst class ShuffleVectorInst: - pass + _downcast_ = Value, Instruction @StoreInst class StoreInst: - _downcast_ = Instruction + _downcast_ = Value, Instruction isVolatile = Method(cast(Bool, bool)) isSimple = Method(cast(Bool, bool)) isUnordered = Method(cast(Bool, bool)) @@ -237,38 +240,40 @@ class StoreInst: @TerminatorInst class TerminatorInst: + _downcast_ = Value, Instruction getNumSuccessors = Method(cast(Unsigned, int)) getSuccessor = Method(ptr(BasicBlock), cast(int, Unsigned)) setSuccessor = Method(Void, cast(int, Unsigned), ptr(BasicBlock)) @UnaryInstruction class UnaryInstruction: - pass + _downcast_ = Value, Instruction #call @IntrinsicInst class IntrinsicInst: - pass + _include_ = 'llvm/IntrinsicInst.h' + _downcast_ = Value, Instruction #compare @FCmpInst class FCmpInst: - pass + _downcast_ = Value, Instruction @ICmpInst class ICmpInst: - pass + _downcast_ = Value, Instruction # terminator @BranchInst class BranchInst: - pass + _downcast_ = Value, Instruction @IndirectBrInst class IndirectBrInst: - pass + _downcast_ = Value, Instruction @InvokeInst class InvokeInst: @@ -284,14 +289,16 @@ class InvokeInst: @ResumeInst class ResumeInst: - pass + _downcast_ = Value, Instruction @ReturnInst class ReturnInst: - pass + _downcast_ = Value, Instruction @SwitchInst class SwitchInst: + _downcast_ = Value, Instruction + getCondition = Method(ptr(Value)) setCondition = Method(Void, ptr(Value)) getDefaultDest = Method(ptr(BasicBlock)) @@ -302,20 +309,20 @@ class SwitchInst: @UnreachableInst class UnreachableInst: - pass + _downcast_ = Value, Instruction # unary @AllocaInst class AllocaInst: - pass + _downcast_ = Value, Instruction @CastInst class CastInst: - pass + _downcast_ = Value, Instruction @ExtractValueInst class ExtractValueInst: - pass + _downcast_ = Value, Instruction @LoadInst class LoadInst: @@ -338,46 +345,46 @@ class LoadInst: @VAArgInst class VAArgInst: - pass + _downcast_ = Value, Instruction # intrinsic @DbgInfoIntrinsic class DbgInfoIntrinsic: - pass + _downcast_ = Value, Instruction @MemIntrinsic class MemIntrinsic: - pass + _downcast_ = Value, Instruction @VACopyInst class VACopyInst: - pass + _downcast_ = Value, Instruction @VAEndInst class VAEndInst: - pass + _downcast_ = Value, Instruction @VAStartInst class VAStartInst: - pass + _downcast_ = Value, Instruction @BitCastInst class BitCastInst: - pass + _downcast_ = Value, Instruction @FPExtInst class FPExtInst: - pass + _downcast_ = Value, Instruction @FPToSIInst class FPToSIInst: - pass + _downcast_ = Value, Instruction @FPToUIInst class FPToUIInst: - pass + _downcast_ = Value, Instruction @FPTruncInst class FPTruncInst: - pass + _downcast_ = Value, Instruction From cb00dcc52c4ddf390a3ef51b33726babbf5e769c Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 13 Feb 2013 18:12:45 -0600 Subject: [PATCH 274/516] Fix a bug in CreatInsertValue and one in ConstantInt. --- llvm/core.py | 3 +-- llvmpy/src/Constant.py | 2 +- llvmpy/src/IRBuilder.py | 11 +++++++---- llvmpy/test_binding.py | 5 +++++ 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index f2af943..60c05fa 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -2041,8 +2041,7 @@ class Builder(llvm.Wrapper): def alloca(self, ty, name=""): intty = Type.int() - zero = api.llvm.ConstantInt.get(intty._ptr, 0) - return _make_value(self._ptr.CreateAlloca(ty._ptr, zero, name)) + return _make_value(self._ptr.CreateAlloca(ty._ptr, None, name)) def alloca_array(self, ty, size, name=""): return _make_value(self._ptr.CreateAlloca(ty._ptr, size._ptr, name)) diff --git a/llvmpy/src/Constant.py b/llvmpy/src/Constant.py index 0a79bd3..3cbb40b 100644 --- a/llvmpy/src/Constant.py +++ b/llvmpy/src/Constant.py @@ -76,7 +76,7 @@ class ConstantInt: get = StaticMethod(ptr(ConstantInt), ptr(IntegerType), - cast(int, Unsigned), + cast(int, Uint64), cast(bool, Bool), ).require_only(2) isValueValidForType = StaticMethod(cast(Bool, bool), diff --git a/llvmpy/src/IRBuilder.py b/llvmpy/src/IRBuilder.py index 8590430..efdf453 100644 --- a/llvmpy/src/IRBuilder.py +++ b/llvmpy/src/IRBuilder.py @@ -288,9 +288,12 @@ class IRBuilder: args[1] = extra.make_small_vector_from_unsigned(*valuelist) return self._CreateExtractValue(*args) - _CreateInsertValue = Method(ptr(Value), ptr(Value), ptr(Value), - ref(SmallVector_Unsigned), cast(str, StringRef)) - _CreateInsertValue.require_only(3) + _CreateInsertValue = Method(ptr(Value), + ptr(Value), # Agg + ptr(Value), # Val + ref(SmallVector_Unsigned), # ArrayRef + cast(str, StringRef), # name + ).require_only(3) _CreateInsertValue.realname = 'CreateInsertValue' @CustomPythonMethod @@ -298,7 +301,7 @@ class IRBuilder: from llvmpy import extra args = list(args) valuelist = args[2] - args[1] = extra.make_small_vector_from_unsigned(*valuelist) + args[2] = extra.make_small_vector_from_unsigned(*valuelist) return self._CreateInsertValue(*args) CreateLandingPad = Method(ptr(LandingPadInst), ptr(Type), ptr(Value), diff --git a/llvmpy/test_binding.py b/llvmpy/test_binding.py index 01e6c38..8eb56f6 100644 --- a/llvmpy/test_binding.py +++ b/llvmpy/test_binding.py @@ -323,6 +323,11 @@ def test_constants(): aryconst = llvm.ConstantArray.get(ary_int32x4, [intconst] * 4) assert str(aryconst.getAggregateElement(0)) == str(intconst) + bignum = 4415104608 + int64ty = llvm.Type.getInt64Ty(context) + const_bignum = llvm.ConstantInt.get(int64ty, 4415104608) + assert str(bignum) in str(const_bignum) + def test_intrinsic(): context = llvm.getGlobalContext() m = llvm.Module.new("modname", context) From bf121485ad4d9c564cc6f6ed3ad033187ca03e2e Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 15 Feb 2013 11:18:51 -0600 Subject: [PATCH 275/516] Fix problem with caching llvm.core.Value objects. --- llvm/__init__.py | 9 ++++++++- llvm/core.py | 17 ++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/llvm/__init__.py b/llvm/__init__.py index c18d066..e3e785f 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -14,7 +14,14 @@ class Wrapper(object): @property def _ptr(self): - return self.__ptr + try: + return self.__ptr + except AttributeError: + raise AttributeError("_ptr resource has been removed") + + @_ptr.deleter + def _ptr(self): + del self.__ptr def _extract_ptrs(objs): diff --git a/llvm/core.py b/llvm/core.py index 60c05fa..66f7c5f 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -926,7 +926,6 @@ class VectorType(Type): class Value(llvm.Wrapper): _type_ = api.llvm.Value - def __init__(self, builder, ptr): assert builder is _ValueFactory @@ -1596,6 +1595,7 @@ class NamedMetaData(llvm.Wrapper): return mod.get_named_metadata(name) def delete(self): + _ValueFactory.delete(self._ptr) self._ptr.eraseFromParent() @property @@ -1822,13 +1822,14 @@ class _ValueFactory(object): def build(cls, ptr): # try to look in the cache addr = ptr._capsule.pointer + id = ptr.getValueID() + key = id, addr try: - obj = cls.cache[addr] + obj = cls.cache[key] return obj except KeyError: pass # find class by value id - id = ptr.getValueID() ctorcls = cls.class_for_valueid.get(id) if not ctorcls: if id > VALUE_INSTRUCTION: # "generic" instruction @@ -1837,12 +1838,12 @@ class _ValueFactory(object): ctorcls = Value # cache the obj obj = ctorcls(_ValueFactory, ptr) - cls.cache[addr] = obj + cls.cache[key] = obj return obj @classmethod def delete(cls, ptr): - del cls.cache[ptr._capsule.pointer] + del cls.cache[(ptr.getValueID(), ptr._capsule.pointer)] def _make_value(ptr): return _ValueFactory.build(ptr) @@ -1851,12 +1852,14 @@ def _make_value(ptr): # Builder #===----------------------------------------------------------------------=== -_atomic_orderings = { 'unordered' : api.llvm.AtomicOrdering.Unordered, +_atomic_orderings = { + 'unordered' : api.llvm.AtomicOrdering.Unordered, 'monotonic' : api.llvm.AtomicOrdering.Monotonic, 'acquire' : api.llvm.AtomicOrdering.Acquire, 'release' : api.llvm.AtomicOrdering.Release, 'acq_rel' : api.llvm.AtomicOrdering.AcquireRelease, - 'seq_cst' : api.llvm.AtomicOrdering.SequentiallyConsistent} + 'seq_cst' : api.llvm.AtomicOrdering.SequentiallyConsistent +} class Builder(llvm.Wrapper): From 26c4380c2b24d4016b0a427c7c1730ebe90b22d5 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Sat, 16 Feb 2013 00:14:43 -0600 Subject: [PATCH 276/516] cleanup run_2to3 in setup.py --- setup.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/setup.py b/setup.py index c24aa66..9bd73b9 100644 --- a/setup.py +++ b/setup.py @@ -158,19 +158,16 @@ kwds = dict( def run_2to3(): import lib2to3.refactor - from distutils.command.build_py import build_py_2to3 as build_py + from distutils.command.build_py import build_py_2to3 + print("Installing 2to3 fixers") - # need to convert sources to Py3 on installation fixes = lib2to3.refactor.get_fixers_from_package("lib2to3.fixes") - #fixes = [fix for fix in fixes - # if fix.split('fix_')[-1] not in ('next',) - #] + kwds["cmdclass"]['build_py'] = build_py_2to3 - kwds["cmdclass"].update(dict(build_py=build_py)) - -if sys.version_info[0] >= 3: +if sys.version_info[0] == 3: run_2to3() + kwds['long_description'] = open('README.rst').read() setup( From 7813bec6e98bfb5d9485e6271e07553521367073 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Sat, 16 Feb 2013 01:14:06 -0600 Subject: [PATCH 277/516] add error handling --- setup.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 9bd73b9..cd13654 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,6 @@ -import sys import os +import sys +from subprocess import Popen, PIPE from distutils.core import setup, Extension import versioneer @@ -19,9 +20,16 @@ else: llvm_config = os.environ.get('LLVM_CONFIG_PATH', default_llvm_config) -def run_llvm_config(args): - cmd = llvm_config + ' ' + ' '.join(args) - return os.popen(cmd).read().rstrip() + +def run_llvm_config(extra_args): + args = llvm_config.split() + args.extend(extra_args) + p = Popen(args, stdout=PIPE, stderr=PIPE) + stdout, stderr = p.communicate() + if stderr: + raise Exception("%r:\n%s" % (args, stderr.decode())) + return stdout.decode().strip() + if run_llvm_config(['--version']) == '': sys.exit("Cannot invoke llvm-config.\n" @@ -59,7 +67,7 @@ libdir = run_llvm_config(['--libdir']) ldflags = run_llvm_config(['--ldflags']) llvm_version = get_llvm_version() -print('LLVM version = %s' % llvm_version) +print('LLVM version = %r' % llvm_version) auto_intrinsic_gen(incdir) From 079e31c474cbefbf4e5a79de112c374c0047fa1e Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Sat, 16 Feb 2013 01:15:37 -0600 Subject: [PATCH 278/516] remove unused code --- setup.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/setup.py b/setup.py index cd13654..6e7013e 100644 --- a/setup.py +++ b/setup.py @@ -164,16 +164,10 @@ kwds = dict( cmdclass = versioneer.get_cmdclass(), ) -def run_2to3(): - import lib2to3.refactor - from distutils.command.build_py import build_py_2to3 - - print("Installing 2to3 fixers") - fixes = lib2to3.refactor.get_fixers_from_package("lib2to3.fixes") - kwds["cmdclass"]['build_py'] = build_py_2to3 if sys.version_info[0] == 3: - run_2to3() + from distutils.command.build_py import build_py_2to3 + kwds["cmdclass"]['build_py'] = build_py_2to3 kwds['long_description'] = open('README.rst').read() From a7c650a458df47fdcef17f16fd884d340adab333 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Sat, 16 Feb 2013 01:24:27 -0600 Subject: [PATCH 279/516] simplified checking for valid llvm-config command --- setup.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/setup.py b/setup.py index 6e7013e..52e176f 100644 --- a/setup.py +++ b/setup.py @@ -30,9 +30,10 @@ def run_llvm_config(extra_args): raise Exception("%r:\n%s" % (args, stderr.decode())) return stdout.decode().strip() - -if run_llvm_config(['--version']) == '': - sys.exit("Cannot invoke llvm-config.\n" +llvm_version = run_llvm_config(['--version']) +print('LLVM version = %r' % llvm_version) +if not llvm_version: + sys.exit("Error: could invoke llvm-config --version\n" "Try setting LLVM_CONFIG_PATH=/path/to/llvm-config") def get_libs_and_objs(components): @@ -49,10 +50,6 @@ def get_libs_and_objs(components): def get_enabled_components(): return run_llvm_config(['--components']).split() -def get_llvm_version(): - return run_llvm_config(['--version']) - - def auto_intrinsic_gen(incdir): # let's do auto intrinsic generation print("Generate intrinsic IDs") @@ -66,8 +63,7 @@ incdir = run_llvm_config(['--includedir']) libdir = run_llvm_config(['--libdir']) ldflags = run_llvm_config(['--ldflags']) -llvm_version = get_llvm_version() -print('LLVM version = %r' % llvm_version) + auto_intrinsic_gen(incdir) From ffa713e3329199989f2c2e69c000efe2dc7a72e8 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Sat, 16 Feb 2013 01:34:51 -0600 Subject: [PATCH 280/516] improve error handling --- setup.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 52e176f..6802391 100644 --- a/setup.py +++ b/setup.py @@ -24,17 +24,18 @@ llvm_config = os.environ.get('LLVM_CONFIG_PATH', default_llvm_config) def run_llvm_config(extra_args): args = llvm_config.split() args.extend(extra_args) - p = Popen(args, stdout=PIPE, stderr=PIPE) + try: + p = Popen(args, stdout=PIPE, stderr=PIPE) + except OSError: + sys.exit("Error: could invoke %r\n" + "Try setting LLVM_CONFIG_PATH=/path/to/llvm-config" % args) stdout, stderr = p.communicate() if stderr: - raise Exception("%r:\n%s" % (args, stderr.decode())) + raise Exception("%r stderr is:\n%s" % (args, stderr.decode())) return stdout.decode().strip() llvm_version = run_llvm_config(['--version']) print('LLVM version = %r' % llvm_version) -if not llvm_version: - sys.exit("Error: could invoke llvm-config --version\n" - "Try setting LLVM_CONFIG_PATH=/path/to/llvm-config") def get_libs_and_objs(components): parts = run_llvm_config(['--libs'] + components).split() From 013c7d2009803f67245815724eb2a17139fccda5 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Sat, 16 Feb 2013 10:54:25 -0600 Subject: [PATCH 281/516] add impoved version of llvm-config for Windows --- llvm-config-win.py | 108 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 llvm-config-win.py diff --git a/llvm-config-win.py b/llvm-config-win.py new file mode 100644 index 0000000..25dbc43 --- /dev/null +++ b/llvm-config-win.py @@ -0,0 +1,108 @@ +import re +import sys +from distutils.spawn import find_executable +from os.path import abspath, dirname, isfile, join +from subprocess import Popen, PIPE + + +def find_llvm_tblgen(): + path = find_executable('llvm-tblgen') + if path is None: + sys.exit('Error: could not locate llvm-tblgen') + return path + +def find_llvm_prefix(): + return abspath(dirname(dirname(find_llvm_tblgen()))) + +def get_llvm_version(): + args = [find_llvm_tblgen(), '--version'] + p = Popen(args, stdout=PIPE, stderr=PIPE) + stdout, stderr = p.communicate() + if stderr: + raise Exception("%r stderr is:\n%s" % (args, stderr.decode())) + out = stdout.decode().strip() + pat = re.compile(r'llvm\s+version\s+(\d+\.\d+\S*)', re.I) + m = pat.search(out) + if m is None: + sys.exit('Error: could not parse version in:' + out) + return m.group(1) + +def main(): + try: + option = sys.argv[1] + except IndexError: + sys.exit('Error: option missing') + + if option == '--version': + print(get_llvm_version()) + + elif option == '--libs': + # NOTE: instead of actually looking at the components requested, + # we just print out a bunch of libs + 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 +LLVMX86Info +LLVMX86Utils +Advapi32 +Shell32 +""".split(): + print('-l%s' % lib) + if isfile(join(find_llvm_prefix(), 'lib', 'LLVMPTXCodeGen.lib')): + print('-lLLVMPTXAsmPrinter') + print('-lLLVMPTXCodeGen') + print('-lLLVMPTXDesc') + print('-lLLVMPTXInfo') + elif isfile(join(find_llvm_prefix(), 'lib', 'LLVMNVPTXCodeGen.lib')): + print('-lLLVMNVPTXAsmPrinter') + print('-lLLVMNVPTXCodeGen') + print('-lLLVMNVPTXDesc') + print('-lLLVMNVPTXInfo') + + elif option == '--includedir': + incdir = join(find_llvm_prefix(), 'include') + path = join(incdir, 'llvm' , 'BasicBlock.h') + if not isfile(path): + sys.exit('Error: no file: %r' % path) + print(incdir) + + elif option == '--libdir': + libdir = join(find_llvm_prefix(), 'lib') + path = join(libdir, ' LLVMCore.lib') + if not isfile(path): + sys.exit('Error: no file: %r' % path) + print(libdir) + + else: + sys.exit('Unrecognized llvm-config option %r' % option) + + +if __name__ == '__main__': + main() From 92c9813b3e39cdf02b54565278e22eda9e551b09 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Sat, 16 Feb 2013 12:50:22 -0600 Subject: [PATCH 282/516] fix library name --- llvm-config-win.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm-config-win.py b/llvm-config-win.py index 25dbc43..479fa2e 100644 --- a/llvm-config-win.py +++ b/llvm-config-win.py @@ -95,7 +95,7 @@ Shell32 elif option == '--libdir': libdir = join(find_llvm_prefix(), 'lib') - path = join(libdir, ' LLVMCore.lib') + path = join(libdir, 'LLVMCore.lib') if not isfile(path): sys.exit('Error: no file: %r' % path) print(libdir) From 0cc2e516acea4c562701d00efdab093b28d553f8 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Sat, 16 Feb 2013 14:29:43 -0600 Subject: [PATCH 283/516] enable new llvm-config on Windows and update changelog --- CHANGELOG | 5 ++ llvm-config-win.py | 108 ------------------------------------------- llvm-config-win32.py | 104 ++++++++++++++++++++++++++--------------- 3 files changed, 73 insertions(+), 144 deletions(-) delete mode 100644 llvm-config-win.py diff --git a/CHANGELOG b/CHANGELOG index 3d19ab8..6c2cd14 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +2013-02-XX 0.11.0: +-------------------- + * fix Python 3 support on Windows + + 2013-02-01 0.10.2: -------------------- * change default to link dynamically to LLVM use: diff --git a/llvm-config-win.py b/llvm-config-win.py deleted file mode 100644 index 479fa2e..0000000 --- a/llvm-config-win.py +++ /dev/null @@ -1,108 +0,0 @@ -import re -import sys -from distutils.spawn import find_executable -from os.path import abspath, dirname, isfile, join -from subprocess import Popen, PIPE - - -def find_llvm_tblgen(): - path = find_executable('llvm-tblgen') - if path is None: - sys.exit('Error: could not locate llvm-tblgen') - return path - -def find_llvm_prefix(): - return abspath(dirname(dirname(find_llvm_tblgen()))) - -def get_llvm_version(): - args = [find_llvm_tblgen(), '--version'] - p = Popen(args, stdout=PIPE, stderr=PIPE) - stdout, stderr = p.communicate() - if stderr: - raise Exception("%r stderr is:\n%s" % (args, stderr.decode())) - out = stdout.decode().strip() - pat = re.compile(r'llvm\s+version\s+(\d+\.\d+\S*)', re.I) - m = pat.search(out) - if m is None: - sys.exit('Error: could not parse version in:' + out) - return m.group(1) - -def main(): - try: - option = sys.argv[1] - except IndexError: - sys.exit('Error: option missing') - - if option == '--version': - print(get_llvm_version()) - - elif option == '--libs': - # NOTE: instead of actually looking at the components requested, - # we just print out a bunch of libs - 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 -LLVMX86Info -LLVMX86Utils -Advapi32 -Shell32 -""".split(): - print('-l%s' % lib) - if isfile(join(find_llvm_prefix(), 'lib', 'LLVMPTXCodeGen.lib')): - print('-lLLVMPTXAsmPrinter') - print('-lLLVMPTXCodeGen') - print('-lLLVMPTXDesc') - print('-lLLVMPTXInfo') - elif isfile(join(find_llvm_prefix(), 'lib', 'LLVMNVPTXCodeGen.lib')): - print('-lLLVMNVPTXAsmPrinter') - print('-lLLVMNVPTXCodeGen') - print('-lLLVMNVPTXDesc') - print('-lLLVMNVPTXInfo') - - elif option == '--includedir': - incdir = join(find_llvm_prefix(), 'include') - path = join(incdir, 'llvm' , 'BasicBlock.h') - if not isfile(path): - sys.exit('Error: no file: %r' % path) - print(incdir) - - elif option == '--libdir': - libdir = join(find_llvm_prefix(), 'lib') - path = join(libdir, 'LLVMCore.lib') - if not isfile(path): - sys.exit('Error: no file: %r' % path) - print(libdir) - - else: - sys.exit('Unrecognized llvm-config option %r' % option) - - -if __name__ == '__main__': - main() diff --git a/llvm-config-win32.py b/llvm-config-win32.py index 2fbe662..96cc867 100644 --- a/llvm-config-win32.py +++ b/llvm-config-win32.py @@ -1,24 +1,43 @@ +import re import sys -import os +from distutils.spawn import find_executable +from os.path import abspath, dirname, isfile, join +from subprocess import Popen, PIPE -def find_path_of(filename, envvar='PATH'): - """Finds the path from $PATH where the file exists, returns None if not found.""" - pathlist = os.getenv(envvar).split(os.pathsep) - for path in pathlist: - if os.path.exists(os.path.join(path, filename)): - return os.path.abspath(path) - return None +def find_llvm_tblgen(): + path = find_executable('llvm-tblgen') + if path is None: + sys.exit('Error: could not locate llvm-tblgen') + return path -if sys.argv[1] == '--version': - cmd = 'llvm-tblgen --version' - # Hardcoded extraction, only tested on llvm 3.1 - result = os.popen(cmd).read().split('\n')[1].strip().split(' ')[2] - print(result) -elif sys.argv[1] == '--libs': +def find_llvm_prefix(): + return abspath(dirname(dirname(find_llvm_tblgen()))) + + +def ensure_file(path): + if not isfile(path): + sys.exit('Error: no file: %r' % path) + + +def get_llvm_version(): + args = [find_llvm_tblgen(), '--version'] + p = Popen(args, stdout=PIPE, stderr=PIPE) + stdout, stderr = p.communicate() + if stderr: + raise Exception("%r stderr is:\n%s" % (args, stderr.decode())) + out = stdout.decode().strip() + pat = re.compile(r'llvm\s+version\s+(\d+\.\d+\S*)', re.I) + m = pat.search(out) + if m is None: + sys.exit('Error: could not parse version in:' + out) + return m.group(1) + + +def libs_options(): # NOTE: instead of actually looking at the components requested, - # we just spit out a bunch of libs + # we just print out a bunch of libs for lib in """ LLVMAnalysis LLVMAsmParser @@ -55,32 +74,45 @@ Advapi32 Shell32 """.split(): print('-l%s' % lib) - llvmbin = find_path_of('llvm-tblgen.exe') - if os.path.exists(os.path.join(llvmbin, '../lib/LLVMPTXCodeGen.lib')): + + if isfile(join(find_llvm_prefix(), 'lib', 'LLVMPTXCodeGen.lib')): print('-lLLVMPTXAsmPrinter') print('-lLLVMPTXCodeGen') print('-lLLVMPTXDesc') print('-lLLVMPTXInfo') - elif os.path.exists(os.path.join(llvmbin, '../lib/LLVMNVPTXCodeGen.lib')): + + elif isfile(join(find_llvm_prefix(), 'lib', 'LLVMNVPTXCodeGen.lib')): print('-lLLVMNVPTXAsmPrinter') print('-lLLVMNVPTXCodeGen') print('-lLLVMNVPTXDesc') print('-lLLVMNVPTXInfo') -elif sys.argv[1] == '--includedir': - llvmbin = find_path_of('llvm-tblgen.exe') - if llvmbin is None: - raise RuntimeError('Could not find LLVM') - incdir = os.path.abspath(os.path.join(llvmbin, '../include')) - if not os.path.exists(os.path.join(incdir, 'llvm/BasicBlock.h')): - raise RuntimeError('Could not find LLVM include dir') - print(incdir) -elif sys.argv[1] == '--libdir': - llvmbin = find_path_of('llvm-tblgen.exe') - if llvmbin is None: - raise RuntimeError('Could not find LLVM') - libdir = os.path.abspath(os.path.join(llvmbin, '../lib')) - if not os.path.exists(os.path.join(libdir, 'LLVMCore.lib')): - raise RuntimeError('Could not find LLVM lib dir') - print(libdir) -else: - raise RuntimeError('Unrecognized llvm-config command %s' % sys.argv[1]) + + +def main(): + try: + option = sys.argv[1] + except IndexError: + sys.exit('Error: option missing') + + if option == '--version': + print(get_llvm_version()) + + elif option == '--libs': + libs_options() + + elif option == '--includedir': + incdir = join(find_llvm_prefix(), 'include') + ensure_file(join(incdir, 'llvm' , 'BasicBlock.h')) + print(incdir) + + elif option == '--libdir': + libdir = join(find_llvm_prefix(), 'lib') + ensure_file(join(libdir, 'LLVMCore.lib')) + print(libdir) + + else: + sys.exit('Unrecognized llvm-config option %r' % option) + + +if __name__ == '__main__': + main() From acd6ab685b9ce0cb77d482a3c7e0ff693ed47231 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Sat, 16 Feb 2013 19:20:06 -0600 Subject: [PATCH 284/516] enhance setup error messages --- llvm-config-win32.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm-config-win32.py b/llvm-config-win32.py index 96cc867..9d3915a 100644 --- a/llvm-config-win32.py +++ b/llvm-config-win32.py @@ -26,7 +26,7 @@ def get_llvm_version(): p = Popen(args, stdout=PIPE, stderr=PIPE) stdout, stderr = p.communicate() if stderr: - raise Exception("%r stderr is:\n%s" % (args, stderr.decode())) + sys.exit("Error: %r stderr is:\n%s" % (args, stderr.decode())) out = stdout.decode().strip() pat = re.compile(r'llvm\s+version\s+(\d+\.\d+\S*)', re.I) m = pat.search(out) @@ -111,7 +111,7 @@ def main(): print(libdir) else: - sys.exit('Unrecognized llvm-config option %r' % option) + sys.exit('Error: Unrecognized llvm-config option %r' % option) if __name__ == '__main__': From 1647580a4172fdc46b8ea2396acdf90fd20fcaf3 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sat, 16 Feb 2013 21:54:12 -0600 Subject: [PATCH 285/516] LinkModules should release ownership of the other module when not preserving --- llvmpy/src/Linker.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/llvmpy/src/Linker.py b/llvmpy/src/Linker.py index 0b846d6..acca503 100644 --- a/llvmpy/src/Linker.py +++ b/llvmpy/src/Linker.py @@ -41,7 +41,7 @@ class Linker: PyObjectPtr, # errmsg ) - LinkModules = CustomStaticMethod('Linker_LinkModules', + _LinkModules = CustomStaticMethod('Linker_LinkModules', PyObjectPtr, # boolean ptr(Module), ptr(Module), @@ -49,3 +49,10 @@ class Linker: PyObjectPtr, # errsg ) + @CustomPythonStaticMethod + def LinkModules(module, other, mode, errmsg): + failed = Linker._LinkModules(module, other, mode, errmsg) + if not failed and mode != Linker.LinkerMode.PreserveSource: + capsule.release_ownership(other._ptr) + return failed + From 20d0bf9f2a8419f27abae471b7de6818be2502e8 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Sun, 17 Feb 2013 16:37:57 -0600 Subject: [PATCH 286/516] add missing dummy options --- llvm-config-win32.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/llvm-config-win32.py b/llvm-config-win32.py index 9d3915a..915871e 100644 --- a/llvm-config-win32.py +++ b/llvm-config-win32.py @@ -110,6 +110,9 @@ def main(): ensure_file(join(libdir, 'LLVMCore.lib')) print(libdir) + elif option in ('--ldflags', '--components'): + pass + else: sys.exit('Error: Unrecognized llvm-config option %r' % option) From bf484aa2163d5b88b09e1732975bc430d69bcf4d Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 19 Feb 2013 08:36:52 +0200 Subject: [PATCH 287/516] Correct if-then-else LLVM asm example. As was present vividly breaks LLVM IR constraints on SSA and basic-blocks: same var being assigned twice, no control transfer at the end of basic block. Compare with the original: http://www.mdevan.org/llvm-py/kaleidoscope/PythonLangImpl5.html --- docs/source/doc/kaleidoscope/PythonLangImpl5.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl5.rst b/docs/source/doc/kaleidoscope/PythonLangImpl5.rst index 5a096da..33edba2 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl5.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl5.rst @@ -217,7 +217,8 @@ Kaleidoscope looks something like this: br i1 %ifcond, label %then, label %else then: ; preds = %entry - %calltmp1 = call double @bar() + %calltmp = call double @foo() + br label %ifcont else: ; preds = %entry %calltmp1 = call double @bar() From 081b41db60609923db192d96b3861e4baf070b77 Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Tue, 19 Feb 2013 15:24:54 +0000 Subject: [PATCH 288/516] Allow casting pointers to ints in cbuilder --- llvm_cbuilder/builder.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 64083b1..917b37e 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -1153,6 +1153,10 @@ class PointerCasting(OperatorMixin): if _is_pointer(ty): return self._temp(self.parent.builder.bitcast(self.value, ty)) + + if _is_int(ty): + return self._temp(self.parent.builder.ptrtoint(self.value, ty)) + raise CastError(self.type, ty) From 175f558ce06f3b78cdc9e4e6370b16ca703b4c25 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 19 Feb 2013 10:54:31 -0600 Subject: [PATCH 289/516] Add error checking for common mistake in Builder.call --- llvm/core.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/llvm/core.py b/llvm/core.py index fa9dc77..fafaa22 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -2192,6 +2192,10 @@ class Builder(object): if t != v.type: raise TypeError(err_template % (t, v.type)) arg_ptrs = unpack_values(args) + + if (isinstance(fn, Function) and \ + fn.module is not self.basic_block.function.module): + raise ValueError("Intermodule function call") return _make_value( _core.LLVMBuildCall(self.ptr, fn.ptr, arg_ptrs, name)) From 42f7219c3f571cecf265ff723f0240b5edccad1b Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 22 Feb 2013 10:43:11 -0600 Subject: [PATCH 290/516] Allow function.verify to raise exception on error. --- llvm/core.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/llvm/core.py b/llvm/core.py index 66f7c5f..bc1ff45 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -1508,7 +1508,13 @@ class Function(GlobalValue): # Note: LLVM has a bug in preverifier that will always abort # the process upon failure. actions = api.llvm.VerifierFailureAction - return api.llvm.verifyFunction(self._ptr, actions.PrintMessageAction) + broken = api.llvm.verifyFunction(self._ptr, + actions.ReturnStatusAction) + if broken: + # If broken, then re-run to print the message + api.llvm.verifyFunction(self._ptr, actions.PrintMessageAction) + raise llvm.LLVMException("Function %s failed verification" % + self.name) #===----------------------------------------------------------------------=== # InlineAsm From d270e885cc37b86e66cf08fce2b7045251409c58 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 22 Feb 2013 10:43:34 -0600 Subject: [PATCH 291/516] Add ptrtoint cast in cbuilder --- llvm_cbuilder/builder.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 64083b1..917b37e 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -1153,6 +1153,10 @@ class PointerCasting(OperatorMixin): if _is_pointer(ty): return self._temp(self.parent.builder.bitcast(self.value, ty)) + + if _is_int(ty): + return self._temp(self.parent.builder.ptrtoint(self.value, ty)) + raise CastError(self.type, ty) From 435b92b4a49fc9974e3aed40d2cd67e21c7553cd Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 22 Feb 2013 10:50:18 -0600 Subject: [PATCH 292/516] Fix VectorType.element --- llvm/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/core.py b/llvm/core.py index bc1ff45..f38028b 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -917,7 +917,7 @@ class VectorType(Type): @property def element(self): - return self._ptr.getVectorElementType() + return Type(self._ptr.getVectorElementType()) @property def count(self): From 74982d6fefe23c42544ce89591fb8e2cda971a26 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 22 Feb 2013 13:42:05 -0600 Subject: [PATCH 293/516] Adapt to work in python2.6 --- llvmpy/capsule.cpp | 4 +- llvmpy/gen/gen.py | 2 + llvmpy/include/capsulethunk.h | 108 ++++++++++++++++++ llvmpy/include/llvm_binding/capsule_context.h | 20 +++- llvmpy/src/ADT/__init__.py | 12 +- llvmpy/src/Analysis/__init__.py | 12 +- llvmpy/src/Assembly/__init__.py | 12 +- llvmpy/src/Bitcode/__init__.py | 12 +- llvmpy/src/CodeGen/__init__.py | 12 +- llvmpy/src/ExecutionEngine/__init__.py | 12 +- llvmpy/src/Support/__init__.py | 12 +- llvmpy/src/Target/__init__.py | 12 +- llvmpy/src/Transforms/Utils/__init__.py | 17 +-- llvmpy/src/Transforms/__init__.py | 17 +-- llvmpy/src/__init__.py | 9 +- 15 files changed, 154 insertions(+), 119 deletions(-) create mode 100644 llvmpy/include/capsulethunk.h diff --git a/llvmpy/capsule.cpp b/llvmpy/capsule.cpp index e7e4932..b7fa81b 100644 --- a/llvmpy/capsule.cpp +++ b/llvmpy/capsule.cpp @@ -1,4 +1,5 @@ #include +#include #include static @@ -53,12 +54,13 @@ CapsuleContext* getContext(PyObject* self, PyObject* args) { PyErr_SetString(PyExc_TypeError, "PyCapsule has no context."); return NULL; } - return (CapsuleContext*)context; + return static_cast(context); } static PyObject* getClassName(PyObject* self, PyObject* args) { CapsuleContext* context = getContext(self, args); + //Assert(context->_magic == 0xdead); if (!context) { return NULL; } else { diff --git a/llvmpy/gen/gen.py b/llvmpy/gen/gen.py index c5d30de..066ed23 100644 --- a/llvmpy/gen/gen.py +++ b/llvmpy/gen/gen.py @@ -40,6 +40,8 @@ populate_submodules(module, submodule_%(ns)s); def populate_headers(println): includes = [ 'cstring', + 'Python.h', + 'capsulethunk.h', 'llvm_binding/conversion.h', 'llvm_binding/binding.h', 'llvm_binding/capsule_context.h', diff --git a/llvmpy/include/capsulethunk.h b/llvmpy/include/capsulethunk.h new file mode 100644 index 0000000..9061782 --- /dev/null +++ b/llvmpy/include/capsulethunk.h @@ -0,0 +1,108 @@ +/** + + This is a modified version of capsulethunk.h for use in llvmpy + +**/ + +#ifndef __CAPSULETHUNK_H +#define __CAPSULETHUNK_H + +//#define Assert(X) do_assert(!!(X), #X, __FILE__, __LINE__) +#define Assert(X) + +static +void do_assert(int cond, const char * msg, const char *file, unsigned line){ + if (not cond) { + fprintf(stderr, "Assertion failed %s:%d\n%s\n", file, line, msg); + exit(1); + } +} + +#if ( (PY_VERSION_HEX < 0x02070000) \ + || ((PY_VERSION_HEX >= 0x03000000) \ + && (PY_VERSION_HEX < 0x03010000)) ) + +typedef void (*PyCapsule_Destructor)(PyObject *); + +struct FakePyCapsule_Desc { + const char *name; + void *context; + PyCapsule_Destructor dtor; + PyObject *parent; + + FakePyCapsule_Desc() : name(0), context(0), dtor(0) {} +}; + +static +FakePyCapsule_Desc* get_pycobj_desc(PyObject *p){ + void *desc = ((PyCObject*)p)->desc; + Assert(desc && "No desc in PyCObject"); + return static_cast(desc); +} + +static +void pycobject_pycapsule_dtor(void *p, void *desc){ + Assert(desc); + Assert(p); + FakePyCapsule_Desc *fpc_desc = static_cast(desc); + Assert(fpc_desc->parent); + Assert(PyCObject_Check(fpc_desc->parent)); + fpc_desc->dtor(static_cast(fpc_desc->parent)); + delete fpc_desc; +} + +static +PyObject* PyCapsule_New(void* ptr, const char *name, PyCapsule_Destructor dtor) +{ + FakePyCapsule_Desc *desc = new FakePyCapsule_Desc; + desc->name = name; + desc->context = NULL; + desc->dtor = dtor; + PyObject *p = PyCObject_FromVoidPtrAndDesc(ptr, desc, + pycobject_pycapsule_dtor); + desc->parent = p; + return p; +} + +static +int PyCapsule_CheckExact(PyObject *p) +{ + return PyCObject_Check(p); +} + +static +void* PyCapsule_GetPointer(PyObject *p, const char *name) +{ + Assert(PyCapsule_CheckExact(p)); + if (strcmp(get_pycobj_desc(p)->name, name) != 0) { + PyErr_SetString(PyExc_ValueError, "Invalid PyCapsule object"); + } + return PyCObject_AsVoidPtr(p); +} + +static +void* PyCapsule_GetContext(PyObject *p) +{ + Assert(p); + Assert(PyCapsule_CheckExact(p)); + return get_pycobj_desc(p)->context; +} + +static +int PyCapsule_SetContext(PyObject *p, void *context) +{ + Assert(PyCapsule_CheckExact(p)); + get_pycobj_desc(p)->context = context; + return 0; +} + +static +const char * PyCapsule_GetName(PyObject *p) +{ +// Assert(PyCapsule_CheckExact(p)); + return get_pycobj_desc(p)->name; +} + +#endif /* #if PY_VERSION_HEX < 0x02070000 */ + +#endif /* __CAPSULETHUNK_H */ diff --git a/llvmpy/include/llvm_binding/capsule_context.h b/llvmpy/include/llvm_binding/capsule_context.h index 6ed1381..0256088 100644 --- a/llvmpy/include/llvm_binding/capsule_context.h +++ b/llvmpy/include/llvm_binding/capsule_context.h @@ -3,10 +3,10 @@ #include #include - -typedef PyObject* Destructor_Fn; +#include "capsulethunk.h" struct CapsuleContext { + //const unsigned _magic; const char* className; CapsuleContext(const char* cn) @@ -14,6 +14,17 @@ struct CapsuleContext { { } }; +static +void pycapsule_dtor_free_context(PyObject *pycap) +{ + void * context = PyCapsule_GetContext(pycap); + Assert(context); + CapsuleContext* cc = static_cast(context); + //Assert(cc->_magic == 0xdead); + delete cc; +} + + static PyObject* pycapsule_new(void* ptr, @@ -26,15 +37,16 @@ PyObject* pycapsule_new(void* ptr, if (!ptr) { Py_RETURN_NONE; } - PyObject* cap = PyCapsule_New(ptr, basename, NULL); + PyObject* cap = PyCapsule_New(ptr, basename, pycapsule_dtor_free_context); if (!cap) { PyErr_SetString(PyExc_TypeError, "Error creating new PyCapsule"); return NULL; } CapsuleContext* context = new CapsuleContext(classname); - if (PyCapsule_SetContext(cap, context)) { + if (0 != PyCapsule_SetContext(cap, context)) { return NULL; } + //Assert(context->_magic == 0xdead); return cap; } diff --git a/llvmpy/src/ADT/__init__.py b/llvmpy/src/ADT/__init__.py index da0beed..944426e 100644 --- a/llvmpy/src/ADT/__init__.py +++ b/llvmpy/src/ADT/__init__.py @@ -1,10 +1,2 @@ -import os.path, importlib - -def _init(): - for fname in os.listdir(os.path.dirname(__file__)): - if ((fname.endswith('.py') or fname.endswith('.pyc')) and - not fname.startswith('__init__')): - modname = os.path.basename(fname).rsplit('.', 1)[0] - importlib.import_module('.' + modname, __name__) - -_init() +from src import _init +_init(__name__, __file__) diff --git a/llvmpy/src/Analysis/__init__.py b/llvmpy/src/Analysis/__init__.py index da0beed..944426e 100644 --- a/llvmpy/src/Analysis/__init__.py +++ b/llvmpy/src/Analysis/__init__.py @@ -1,10 +1,2 @@ -import os.path, importlib - -def _init(): - for fname in os.listdir(os.path.dirname(__file__)): - if ((fname.endswith('.py') or fname.endswith('.pyc')) and - not fname.startswith('__init__')): - modname = os.path.basename(fname).rsplit('.', 1)[0] - importlib.import_module('.' + modname, __name__) - -_init() +from src import _init +_init(__name__, __file__) diff --git a/llvmpy/src/Assembly/__init__.py b/llvmpy/src/Assembly/__init__.py index da0beed..944426e 100644 --- a/llvmpy/src/Assembly/__init__.py +++ b/llvmpy/src/Assembly/__init__.py @@ -1,10 +1,2 @@ -import os.path, importlib - -def _init(): - for fname in os.listdir(os.path.dirname(__file__)): - if ((fname.endswith('.py') or fname.endswith('.pyc')) and - not fname.startswith('__init__')): - modname = os.path.basename(fname).rsplit('.', 1)[0] - importlib.import_module('.' + modname, __name__) - -_init() +from src import _init +_init(__name__, __file__) diff --git a/llvmpy/src/Bitcode/__init__.py b/llvmpy/src/Bitcode/__init__.py index da0beed..944426e 100644 --- a/llvmpy/src/Bitcode/__init__.py +++ b/llvmpy/src/Bitcode/__init__.py @@ -1,10 +1,2 @@ -import os.path, importlib - -def _init(): - for fname in os.listdir(os.path.dirname(__file__)): - if ((fname.endswith('.py') or fname.endswith('.pyc')) and - not fname.startswith('__init__')): - modname = os.path.basename(fname).rsplit('.', 1)[0] - importlib.import_module('.' + modname, __name__) - -_init() +from src import _init +_init(__name__, __file__) diff --git a/llvmpy/src/CodeGen/__init__.py b/llvmpy/src/CodeGen/__init__.py index da0beed..944426e 100644 --- a/llvmpy/src/CodeGen/__init__.py +++ b/llvmpy/src/CodeGen/__init__.py @@ -1,10 +1,2 @@ -import os.path, importlib - -def _init(): - for fname in os.listdir(os.path.dirname(__file__)): - if ((fname.endswith('.py') or fname.endswith('.pyc')) and - not fname.startswith('__init__')): - modname = os.path.basename(fname).rsplit('.', 1)[0] - importlib.import_module('.' + modname, __name__) - -_init() +from src import _init +_init(__name__, __file__) diff --git a/llvmpy/src/ExecutionEngine/__init__.py b/llvmpy/src/ExecutionEngine/__init__.py index da0beed..944426e 100644 --- a/llvmpy/src/ExecutionEngine/__init__.py +++ b/llvmpy/src/ExecutionEngine/__init__.py @@ -1,10 +1,2 @@ -import os.path, importlib - -def _init(): - for fname in os.listdir(os.path.dirname(__file__)): - if ((fname.endswith('.py') or fname.endswith('.pyc')) and - not fname.startswith('__init__')): - modname = os.path.basename(fname).rsplit('.', 1)[0] - importlib.import_module('.' + modname, __name__) - -_init() +from src import _init +_init(__name__, __file__) diff --git a/llvmpy/src/Support/__init__.py b/llvmpy/src/Support/__init__.py index da0beed..944426e 100644 --- a/llvmpy/src/Support/__init__.py +++ b/llvmpy/src/Support/__init__.py @@ -1,10 +1,2 @@ -import os.path, importlib - -def _init(): - for fname in os.listdir(os.path.dirname(__file__)): - if ((fname.endswith('.py') or fname.endswith('.pyc')) and - not fname.startswith('__init__')): - modname = os.path.basename(fname).rsplit('.', 1)[0] - importlib.import_module('.' + modname, __name__) - -_init() +from src import _init +_init(__name__, __file__) diff --git a/llvmpy/src/Target/__init__.py b/llvmpy/src/Target/__init__.py index da0beed..944426e 100644 --- a/llvmpy/src/Target/__init__.py +++ b/llvmpy/src/Target/__init__.py @@ -1,10 +1,2 @@ -import os.path, importlib - -def _init(): - for fname in os.listdir(os.path.dirname(__file__)): - if ((fname.endswith('.py') or fname.endswith('.pyc')) and - not fname.startswith('__init__')): - modname = os.path.basename(fname).rsplit('.', 1)[0] - importlib.import_module('.' + modname, __name__) - -_init() +from src import _init +_init(__name__, __file__) diff --git a/llvmpy/src/Transforms/Utils/__init__.py b/llvmpy/src/Transforms/Utils/__init__.py index 98c06fc..944426e 100644 --- a/llvmpy/src/Transforms/Utils/__init__.py +++ b/llvmpy/src/Transforms/Utils/__init__.py @@ -1,15 +1,2 @@ -import os.path, importlib - -def _init(): - base = os.path.dirname(__file__) - for fname in os.listdir(base): - print fname - is_python_script = fname.endswith('.py') or fname.endswith('.pyc') - is_init_script = fname.startswith('__init__') - is_directory = os.path.isdir(os.path.join(base, fname)) - if (is_directory or is_python_script) and not is_init_script : - modname = os.path.basename(fname).rsplit('.', 1)[0] - importlib.import_module('.' + modname, __name__) - -_init() - +from src import _init +_init(__name__, __file__) diff --git a/llvmpy/src/Transforms/__init__.py b/llvmpy/src/Transforms/__init__.py index 98c06fc..944426e 100644 --- a/llvmpy/src/Transforms/__init__.py +++ b/llvmpy/src/Transforms/__init__.py @@ -1,15 +1,2 @@ -import os.path, importlib - -def _init(): - base = os.path.dirname(__file__) - for fname in os.listdir(base): - print fname - is_python_script = fname.endswith('.py') or fname.endswith('.pyc') - is_init_script = fname.startswith('__init__') - is_directory = os.path.isdir(os.path.join(base, fname)) - if (is_directory or is_python_script) and not is_init_script : - modname = os.path.basename(fname).rsplit('.', 1)[0] - importlib.import_module('.' + modname, __name__) - -_init() - +from src import _init +_init(__name__, __file__) diff --git a/llvmpy/src/__init__.py b/llvmpy/src/__init__.py index 98c06fc..ed34608 100644 --- a/llvmpy/src/__init__.py +++ b/llvmpy/src/__init__.py @@ -1,7 +1,7 @@ -import os.path, importlib +import os.path -def _init(): - base = os.path.dirname(__file__) +def _init(root=__name__, file=__file__): + base = os.path.dirname(file) for fname in os.listdir(base): print fname is_python_script = fname.endswith('.py') or fname.endswith('.pyc') @@ -9,7 +9,8 @@ def _init(): is_directory = os.path.isdir(os.path.join(base, fname)) if (is_directory or is_python_script) and not is_init_script : modname = os.path.basename(fname).rsplit('.', 1)[0] - importlib.import_module('.' + modname, __name__) + #importlib.import_module('.' + modname, __name__) + __import__('.'.join([root, modname])) _init() From a275068193c87c5a27758c17d7699e963a0bdfa8 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 22 Feb 2013 17:58:38 -0600 Subject: [PATCH 294/516] Fix formatted_raw_ostream ownership error with the underlying stream. --- llvmpy/src/Support/FormattedStream.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/llvmpy/src/Support/FormattedStream.py b/llvmpy/src/Support/FormattedStream.py index 17c259b..26f906d 100644 --- a/llvmpy/src/Support/FormattedStream.py +++ b/llvmpy/src/Support/FormattedStream.py @@ -5,5 +5,11 @@ from raw_ostream import raw_ostream @llvm.Class(raw_ostream) class formatted_raw_ostream: _include_ = 'llvm/Support/FormattedStream.h' - new = Constructor(ref(raw_ostream), cast(bool, Bool)) + _new = Constructor(ref(raw_ostream), cast(bool, Bool)) + + @CustomPythonStaticMethod + def new(stream, destroy=False): + inst = formatted_raw_ostream._new(stream, destroy) + inst.__underlying_stream = stream # to prevent it being freed first + return inst From 45e70333fd70ec2449a0a95a7a7f4f68c47a36d5 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 22 Feb 2013 19:17:56 -0600 Subject: [PATCH 295/516] Adapt to python 3.3 --- llvmpy/capsule.cpp | 1 + llvmpy/capsule.py | 12 ++- llvmpy/extra.py | 2 +- llvmpy/gen/binding.py | 2 +- llvmpy/gen/codegen.py | 2 +- llvmpy/gen/gen.py | 1 + llvmpy/include/llvm_binding/conversion.h | 23 ++++++ llvmpy/include/llvm_binding/extra.h | 8 +- llvmpy/include/python3adapt.h | 32 ++++++++ llvmpy/src/ADT/Triple.py | 2 +- llvmpy/src/Argument.py | 6 +- llvmpy/src/Attributes.py | 4 +- llvmpy/src/BasicBlock.py | 10 +-- llvmpy/src/Bitcode/ReaderWriter.py | 2 +- llvmpy/src/CallingConv.py | 2 +- llvmpy/src/Constant.py | 20 ++--- llvmpy/src/DataLayout.py | 16 ++-- llvmpy/src/DerivedTypes.py | 8 +- llvmpy/src/EngineBuilder.py | 16 ++-- llvmpy/src/ExecutionEngine/ExecutionEngine.py | 2 +- llvmpy/src/Function.py | 16 ++-- llvmpy/src/GenericValue.py | 4 +- llvmpy/src/GlobalValue.py | 8 +- llvmpy/src/GlobalVariable.py | 12 +-- llvmpy/src/IRBuilder.py | 28 +++---- llvmpy/src/InlineAsm.py | 8 +- llvmpy/src/Instruction.py | 12 +-- llvmpy/src/Intrinsics.py | 6 +- llvmpy/src/JITMemoryManager.py | 2 +- llvmpy/src/LLVMContext.py | 2 +- llvmpy/src/Linker.py | 8 +- llvmpy/src/Metadata.py | 16 ++-- llvmpy/src/Module.py | 22 +++--- llvmpy/src/Pass.py | 8 +- llvmpy/src/PassManager.py | 8 +- llvmpy/src/PassRegistry.py | 2 +- llvmpy/src/PassSupport.py | 2 +- llvmpy/src/Support/FormattedStream.py | 2 +- llvmpy/src/Type.py | 8 +- llvmpy/src/User.py | 4 +- llvmpy/src/Value.py | 12 +-- llvmpy/src/__init__.py | 5 +- llvmpy/test_binding.py | 73 ++++++++++--------- 43 files changed, 251 insertions(+), 188 deletions(-) create mode 100644 llvmpy/include/python3adapt.h diff --git a/llvmpy/capsule.cpp b/llvmpy/capsule.cpp index b7fa81b..561b28a 100644 --- a/llvmpy/capsule.cpp +++ b/llvmpy/capsule.cpp @@ -1,4 +1,5 @@ #include +#include #include #include diff --git a/llvmpy/capsule.py b/llvmpy/capsule.py index 0b1f203..ec6fdde 100644 --- a/llvmpy/capsule.py +++ b/llvmpy/capsule.py @@ -32,7 +32,7 @@ def _capsule_weakref_dtor(item): class Capsule(object): "Wraps PyCapsule so that we can build weakref of it." - from _capsule import check, getClassName, getName, getPointer + from ._capsule import check, getClassName, getName, getPointer def __init__(self, capsule): assert Capsule.valid(capsule) @@ -75,6 +75,9 @@ class Capsule(object): else: return False + def __hash__(self): + return super(Capsule, self).__hash__() + def __ne__(self, other): return not (self == other) @@ -122,7 +125,7 @@ def wrap(cap, owned=False): ''' if not Capsule.valid(cap): if isinstance(cap, list): - return map(wrap, cap) + return list(map(wrap, cap)) return cap # bypass if cap is not a PyCapsule and not a list cap = Capsule(cap) @@ -170,6 +173,9 @@ class Wrapper(object): def _ptr(self): return self._capsule.capsule + def __hash__(self): + return super(Wrapper, self).__hash__() + def __eq__(self, other): return self._capsule == other._capsule @@ -184,7 +190,7 @@ class Wrapper(object): return hasattr(cls, '_delete_') def downcast(obj, cls): - import _api + from . import _api if type(obj) is cls: return obj fromty = obj._llvm_type_ diff --git a/llvmpy/extra.py b/llvmpy/extra.py index a2e744f..99035a7 100644 --- a/llvmpy/extra.py +++ b/llvmpy/extra.py @@ -11,7 +11,7 @@ from llvmpy import _api def _wrapper(func): "Wrap the re-exported functions" def _core(*args): - unwrapped = map(capsule.unwrap, args) + unwrapped = list(map(capsule.unwrap, args)) ret = func(*unwrapped) return capsule.wrap(ret) return _core diff --git a/llvmpy/gen/binding.py b/llvmpy/gen/binding.py index 4454d72..0f5c4fd 100644 --- a/llvmpy/gen/binding.py +++ b/llvmpy/gen/binding.py @@ -348,7 +348,7 @@ class Enum(object): def __init__(self, *value_names): self.parent = None if len(value_names) == 1: - value_names = filter(bool, value_names[0].replace(',', ' ').split()) + value_names = list(filter(bool, value_names[0].replace(',', ' ').split())) self.value_names = value_names self.includes = set() diff --git a/llvmpy/gen/codegen.py b/llvmpy/gen/codegen.py index abde437..f9585fd 100644 --- a/llvmpy/gen/codegen.py +++ b/llvmpy/gen/codegen.py @@ -259,7 +259,7 @@ class PyCodeWriter(CodeWriterBase): def unwrap_many(self, args): unwrapped = self.new_symbol('unwrapped') - self.println('%(unwrapped)s = map(capsule.unwrap, %(args)s)' % locals()) + self.println('%(unwrapped)s = list(map(capsule.unwrap, %(args)s))' % locals()) return unwrapped def unwrap(self, val): diff --git a/llvmpy/gen/gen.py b/llvmpy/gen/gen.py index 066ed23..263c289 100644 --- a/llvmpy/gen/gen.py +++ b/llvmpy/gen/gen.py @@ -41,6 +41,7 @@ def populate_headers(println): includes = [ 'cstring', 'Python.h', + 'python3adapt.h', 'capsulethunk.h', 'llvm_binding/conversion.h', 'llvm_binding/binding.h', diff --git a/llvmpy/include/llvm_binding/conversion.h b/llvmpy/include/llvm_binding/conversion.h index 7b8e6df..abc3749 100644 --- a/llvmpy/include/llvm_binding/conversion.h +++ b/llvmpy/include/llvm_binding/conversion.h @@ -4,6 +4,29 @@ // python object unwrapper +static +int py_bytes_to(PyObject *bytesobj, llvm::StringRef &strref){ + // type check + if (!PyBytes_Check(bytesobj)) { + // raises TypeError + PyErr_SetString(PyExc_TypeError, "Expecting a str"); + return 0; + } + // get len and buffer + const Py_ssize_t len = PyBytes_Size(bytesobj); + const char * buf = PyBytes_AsString(bytesobj); + if (!buf) { + // raises TypeError + return 0; + } + // set output + strref = llvm::StringRef(buf, len); + // success + return 1; +} + + + static int py_str_to(PyObject *strobj, llvm::StringRef &strref){ // type check diff --git a/llvmpy/include/llvm_binding/extra.h b/llvmpy/include/llvm_binding/extra.h index 76c8a16..3874bb3 100644 --- a/llvmpy/include/llvm_binding/extra.h +++ b/llvmpy/include/llvm_binding/extra.h @@ -497,11 +497,9 @@ PyObject* llvm_WriteBitcodeToFile(const llvm::Module *M, PyObject* FObj) llvm::WriteBitcodeToFile(M, rso); rso.flush(); StringRef ref = rso.str(); - PyObject* buf = PyString_FromStringAndSize(ref.data(), ref.size()); - if (-1 == PyFile_WriteObject(buf, FObj, Py_PRINT_RAW)){ - return NULL; - } - Py_RETURN_NONE; + PyObject* buf = PyBytes_FromStringAndSize(ref.data(), ref.size()); + puts(PyString_AsString(PyObject_Str(PyObject_Type(buf)))); + return PyObject_CallMethod(FObj, "write", "O", buf); } static diff --git a/llvmpy/include/python3adapt.h b/llvmpy/include/python3adapt.h new file mode 100644 index 0000000..5b19ebe --- /dev/null +++ b/llvmpy/include/python3adapt.h @@ -0,0 +1,32 @@ +#ifndef PYTHON3ADAPT_H +#define PYTHON3ADAPT_H + +#if (PY_VERSION_HEX < 0x03000000) + +#define PyBytes_Check PyString_Check +#define PyBytes_Size PyString_Size +#define PyBytes_AsString PyString_AsString +#define PyBytes_FromStringAndSize PyString_FromStringAndSize +#define PyBytes_FromString PyString_FromString + +#endif + +#if (PY_VERSION_HEX >= 0x03000000) + +#define PyString_Check PyUnicode_Check +#define PyString_Size PyUnicode_GET_SIZE +#define PyString_AsString PyUnicode_AsUTF8 +#define PyString_FromStringAndSize PyUnicode_FromStringAndSize +#define PyString_FromString PyUnicode_FromString + +#define PyInt_Check PyLong_Check +#define PyInt_FromLong PyLong_FromLong +#define PyInt_AsLong PyLong_AsLong +#define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask +#define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask + +#define PyFile_Check(x) (1) + +#endif + +#endif //PYTHON3ADAPT_H \ No newline at end of file diff --git a/llvmpy/src/ADT/Triple.py b/llvmpy/src/ADT/Triple.py index 82de57e..1615c1c 100644 --- a/llvmpy/src/ADT/Triple.py +++ b/llvmpy/src/ADT/Triple.py @@ -1,6 +1,6 @@ from binding import * from ..namespace import llvm -from StringRef import StringRef +from .StringRef import StringRef Triple = llvm.Class() diff --git a/llvmpy/src/Argument.py b/llvmpy/src/Argument.py index 64db072..4f0b7a4 100644 --- a/llvmpy/src/Argument.py +++ b/llvmpy/src/Argument.py @@ -1,7 +1,7 @@ from binding import * -from namespace import llvm -from Value import Argument, Value -from Attributes import Attributes +from .namespace import llvm +from .Value import Argument, Value +from .Attributes import Attributes @Argument class Argument: diff --git a/llvmpy/src/Attributes.py b/llvmpy/src/Attributes.py index c6a8d97..4fe7651 100644 --- a/llvmpy/src/Attributes.py +++ b/llvmpy/src/Attributes.py @@ -1,6 +1,6 @@ from binding import * -from namespace import llvm -from LLVMContext import LLVMContext +from .namespace import llvm +from .LLVMContext import LLVMContext llvm.includes.add('llvm/Attributes.h') diff --git a/llvmpy/src/BasicBlock.py b/llvmpy/src/BasicBlock.py index 4ed4f66..77eaf01 100644 --- a/llvmpy/src/BasicBlock.py +++ b/llvmpy/src/BasicBlock.py @@ -1,9 +1,9 @@ from binding import * -from namespace import llvm -from Value import Function, BasicBlock -from Instruction import Instruction, TerminatorInst -from LLVMContext import LLVMContext -from ADT.StringRef import StringRef +from .namespace import llvm +from .Value import Function, BasicBlock +from .Instruction import Instruction, TerminatorInst +from .LLVMContext import LLVMContext +from .ADT.StringRef import StringRef @BasicBlock class BasicBlock: diff --git a/llvmpy/src/Bitcode/ReaderWriter.py b/llvmpy/src/Bitcode/ReaderWriter.py index a8e8c43..b950ba4 100644 --- a/llvmpy/src/Bitcode/ReaderWriter.py +++ b/llvmpy/src/Bitcode/ReaderWriter.py @@ -9,7 +9,7 @@ llvm.includes.add('llvm/Bitcode/ReaderWriter.h') ParseBitCodeFile = llvm.CustomFunction('ParseBitCodeFile', 'llvm_ParseBitCodeFile', PyObjectPtr, # returns Module* - cast(str, StringRef), + cast(bytes, StringRef), ref(LLVMContext), PyObjectPtr, # file-like object ).require_only(2) diff --git a/llvmpy/src/CallingConv.py b/llvmpy/src/CallingConv.py index 71b4ad3..efca1fc 100644 --- a/llvmpy/src/CallingConv.py +++ b/llvmpy/src/CallingConv.py @@ -1,5 +1,5 @@ from binding import * -from namespace import llvm +from .namespace import llvm CallingConv = llvm.Namespace('CallingConv') ID = CallingConv.Enum('ID', ''' diff --git a/llvmpy/src/Constant.py b/llvmpy/src/Constant.py index 3cbb40b..70dc3bf 100644 --- a/llvmpy/src/Constant.py +++ b/llvmpy/src/Constant.py @@ -1,14 +1,14 @@ from binding import * -from namespace import llvm -from Value import Value -from Value import Constant, UndefValue, ConstantInt, ConstantFP, ConstantArray -from Value import ConstantStruct, ConstantVector, ConstantVector -from Value import ConstantDataSequential, ConstantDataArray, ConstantExpr -from LLVMContext import LLVMContext -from ADT.StringRef import StringRef -from ADT.SmallVector import SmallVector_Value, SmallVector_Unsigned -from Type import Type, IntegerType, ArrayType, StructType -from Instruction import CmpInst +from .namespace import llvm +from .Value import Value +from .Value import Constant, UndefValue, ConstantInt, ConstantFP, ConstantArray +from .Value import ConstantStruct, ConstantVector, ConstantVector +from .Value import ConstantDataSequential, ConstantDataArray, ConstantExpr +from .LLVMContext import LLVMContext +from .ADT.StringRef import StringRef +from .ADT.SmallVector import SmallVector_Value, SmallVector_Unsigned +from .Type import Type, IntegerType, ArrayType, StructType +from .Instruction import CmpInst @Constant class Constant: diff --git a/llvmpy/src/DataLayout.py b/llvmpy/src/DataLayout.py index 9582d53..7085f52 100644 --- a/llvmpy/src/DataLayout.py +++ b/llvmpy/src/DataLayout.py @@ -1,16 +1,16 @@ from binding import * -from namespace import llvm -from Pass import ImmutablePass +from .namespace import llvm +from .Pass import ImmutablePass DataLayout = llvm.Class(ImmutablePass) StructLayout = llvm.Class() -from LLVMContext import LLVMContext -from ADT.StringRef import StringRef -from Module import Module -from Type import Type, IntegerType, StructType -from ADT.SmallVector import SmallVector_Value -from GlobalVariable import GlobalVariable +from .LLVMContext import LLVMContext +from .ADT.StringRef import StringRef +from .Module import Module +from .Type import Type, IntegerType, StructType +from .ADT.SmallVector import SmallVector_Value +from .GlobalVariable import GlobalVariable @DataLayout diff --git a/llvmpy/src/DerivedTypes.py b/llvmpy/src/DerivedTypes.py index 40724e0..02eec8c 100644 --- a/llvmpy/src/DerivedTypes.py +++ b/llvmpy/src/DerivedTypes.py @@ -1,8 +1,8 @@ from binding import * -from namespace import llvm -from LLVMContext import LLVMContext -from Type import Type -from ADT.SmallVector import SmallVector_Type +from .namespace import llvm +from .LLVMContext import LLVMContext +from .Type import Type +from .ADT.SmallVector import SmallVector_Type FunctionType = llvm.Class(Type) diff --git a/llvmpy/src/EngineBuilder.py b/llvmpy/src/EngineBuilder.py index c3feafe..4e8ed12 100644 --- a/llvmpy/src/EngineBuilder.py +++ b/llvmpy/src/EngineBuilder.py @@ -1,12 +1,12 @@ from binding import * -from namespace import llvm -from Module import Module -from JITMemoryManager import JITMemoryManager -from Support.CodeGen import CodeGenOpt, Reloc, CodeModel -from ADT.StringRef import StringRef -from ExecutionEngine.ExecutionEngine import ExecutionEngine -from Target.TargetMachine import TargetMachine -from ADT.Triple import Triple +from .namespace import llvm +from .Module import Module +from .JITMemoryManager import JITMemoryManager +from .Support.CodeGen import CodeGenOpt, Reloc, CodeModel +from .ADT.StringRef import StringRef +from .ExecutionEngine.ExecutionEngine import ExecutionEngine +from .Target.TargetMachine import TargetMachine +from .ADT.Triple import Triple EngineBuilder = llvm.Class() diff --git a/llvmpy/src/ExecutionEngine/ExecutionEngine.py b/llvmpy/src/ExecutionEngine/ExecutionEngine.py index bcf66fd..038d344 100644 --- a/llvmpy/src/ExecutionEngine/ExecutionEngine.py +++ b/llvmpy/src/ExecutionEngine/ExecutionEngine.py @@ -98,6 +98,6 @@ class ExecutionEngine: @CustomPythonMethod def runFunction(self, fn, args): from llvmpy import capsule - unwrapped = map(capsule.unwrap, args) + unwrapped = list(map(capsule.unwrap, args)) return self._runFunction(fn, tuple(unwrapped)) diff --git a/llvmpy/src/Function.py b/llvmpy/src/Function.py index 52db622..55a50d9 100644 --- a/llvmpy/src/Function.py +++ b/llvmpy/src/Function.py @@ -1,12 +1,12 @@ from binding import * -from namespace import llvm -from Value import GlobalValue, Constant, Function, Argument, Value -from BasicBlock import BasicBlock -from Attributes import Attributes -from Type import Type -from DerivedTypes import FunctionType -from LLVMContext import LLVMContext -from CallingConv import CallingConv +from .namespace import llvm +from .Value import GlobalValue, Constant, Function, Argument, Value +from .BasicBlock import BasicBlock +from .Attributes import Attributes +from .Type import Type +from .DerivedTypes import FunctionType +from .LLVMContext import LLVMContext +from .CallingConv import CallingConv @Function class Function: diff --git a/llvmpy/src/GenericValue.py b/llvmpy/src/GenericValue.py index 73a3709..e587b5f 100644 --- a/llvmpy/src/GenericValue.py +++ b/llvmpy/src/GenericValue.py @@ -1,6 +1,6 @@ from binding import * -from namespace import llvm -from Type import Type +from .namespace import llvm +from .Type import Type GenericValue = llvm.Class() diff --git a/llvmpy/src/GlobalValue.py b/llvmpy/src/GlobalValue.py index f21d5af..2583c6a 100644 --- a/llvmpy/src/GlobalValue.py +++ b/llvmpy/src/GlobalValue.py @@ -1,8 +1,8 @@ from binding import * -from namespace import llvm -from Value import GlobalValue -from Module import Module -from ADT.StringRef import StringRef +from .namespace import llvm +from .Value import GlobalValue +from .Module import Module +from .ADT.StringRef import StringRef @GlobalValue class GlobalValue: diff --git a/llvmpy/src/GlobalVariable.py b/llvmpy/src/GlobalVariable.py index 2280e24..c38df27 100644 --- a/llvmpy/src/GlobalVariable.py +++ b/llvmpy/src/GlobalVariable.py @@ -1,13 +1,13 @@ from binding import * -from namespace import llvm +from .namespace import llvm -from GlobalValue import GlobalValue +from .GlobalValue import GlobalValue GlobalVariable = llvm.Class(GlobalValue) -from Module import Module -from Type import Type -from ADT.StringRef import StringRef -from Value import Constant +from .Module import Module +from .Type import Type +from .ADT.StringRef import StringRef +from .Value import Constant @GlobalVariable class GlobalVariable: diff --git a/llvmpy/src/IRBuilder.py b/llvmpy/src/IRBuilder.py index efdf453..afd78a0 100644 --- a/llvmpy/src/IRBuilder.py +++ b/llvmpy/src/IRBuilder.py @@ -1,18 +1,18 @@ from binding import * -from namespace import llvm -from LLVMContext import LLVMContext -from BasicBlock import BasicBlock -from Instruction import Instruction -from Instruction import ReturnInst, CallInst, BranchInst, SwitchInst -from Instruction import IndirectBrInst, InvokeInst, ResumeInst, PHINode -from Instruction import UnreachableInst, AllocaInst, LoadInst, StoreInst -from Instruction import FenceInst, AtomicCmpXchgInst, AtomicRMWInst, CmpInst -from Instruction import LandingPadInst, VAArgInst -from Instruction import AtomicOrdering, SynchronizationScope -from ADT.SmallVector import SmallVector_Value, SmallVector_Unsigned -from ADT.StringRef import StringRef -from Value import Value, MDNode -from Type import Type, IntegerType +from .namespace import llvm +from .LLVMContext import LLVMContext +from .BasicBlock import BasicBlock +from .Instruction import Instruction +from .Instruction import ReturnInst, CallInst, BranchInst, SwitchInst +from .Instruction import IndirectBrInst, InvokeInst, ResumeInst, PHINode +from .Instruction import UnreachableInst, AllocaInst, LoadInst, StoreInst +from .Instruction import FenceInst, AtomicCmpXchgInst, AtomicRMWInst, CmpInst +from .Instruction import LandingPadInst, VAArgInst +from .Instruction import AtomicOrdering, SynchronizationScope +from .ADT.SmallVector import SmallVector_Value, SmallVector_Unsigned +from .ADT.StringRef import StringRef +from .Value import Value, MDNode +from .Type import Type, IntegerType IRBuilder = llvm.Class() diff --git a/llvmpy/src/InlineAsm.py b/llvmpy/src/InlineAsm.py index a4ce16b..8793343 100644 --- a/llvmpy/src/InlineAsm.py +++ b/llvmpy/src/InlineAsm.py @@ -1,8 +1,8 @@ from binding import * -from namespace import llvm -from Value import Value -from DerivedTypes import FunctionType -from ADT.StringRef import StringRef +from .namespace import llvm +from .Value import Value +from .DerivedTypes import FunctionType +from .ADT.StringRef import StringRef llvm.includes.add('llvm/InlineAsm.h') diff --git a/llvmpy/src/Instruction.py b/llvmpy/src/Instruction.py index 4761e16..1974aad 100644 --- a/llvmpy/src/Instruction.py +++ b/llvmpy/src/Instruction.py @@ -1,6 +1,6 @@ from binding import * -from namespace import llvm -from Value import Value, MDNode, User, BasicBlock, Function, ConstantInt +from .namespace import llvm +from .Value import Value, MDNode, User, BasicBlock, Function, ConstantInt Instruction = llvm.Class(User) @@ -63,10 +63,10 @@ SynchronizationScope = llvm.Enum('SynchronizationScope', -from ADT.StringRef import StringRef -from CallingConv import CallingConv -from Attributes import Attributes -from Type import Type +from .ADT.StringRef import StringRef +from .CallingConv import CallingConv +from .Attributes import Attributes +from .Type import Type diff --git a/llvmpy/src/Intrinsics.py b/llvmpy/src/Intrinsics.py index 5314112..7e1decd 100644 --- a/llvmpy/src/Intrinsics.py +++ b/llvmpy/src/Intrinsics.py @@ -1,8 +1,8 @@ from binding import * -from namespace import llvm +from .namespace import llvm -from Module import Module -from Function import Function +from .Module import Module +from .Function import Function Intrinsic = llvm.Namespace('Intrinsic') diff --git a/llvmpy/src/JITMemoryManager.py b/llvmpy/src/JITMemoryManager.py index f134735..e34e678 100644 --- a/llvmpy/src/JITMemoryManager.py +++ b/llvmpy/src/JITMemoryManager.py @@ -1,5 +1,5 @@ from binding import * -from namespace import llvm +from .namespace import llvm @llvm.Class() class JITMemoryManager: diff --git a/llvmpy/src/LLVMContext.py b/llvmpy/src/LLVMContext.py index f2526db..4a6b49a 100644 --- a/llvmpy/src/LLVMContext.py +++ b/llvmpy/src/LLVMContext.py @@ -1,5 +1,5 @@ from binding import * -from namespace import llvm +from .namespace import llvm @llvm.Class() class LLVMContext: diff --git a/llvmpy/src/Linker.py b/llvmpy/src/Linker.py index acca503..960bd90 100644 --- a/llvmpy/src/Linker.py +++ b/llvmpy/src/Linker.py @@ -1,8 +1,8 @@ from binding import * -from namespace import llvm -from ADT.StringRef import StringRef -from Module import Module -from LLVMContext import LLVMContext +from .namespace import llvm +from .ADT.StringRef import StringRef +from .Module import Module +from .LLVMContext import LLVMContext llvm.includes.add('llvm/Linker.h') diff --git a/llvmpy/src/Metadata.py b/llvmpy/src/Metadata.py index d5cc4b1..cfeb6ce 100644 --- a/llvmpy/src/Metadata.py +++ b/llvmpy/src/Metadata.py @@ -1,12 +1,12 @@ from binding import * -from namespace import llvm -from Value import Value, MDNode, MDString -from LLVMContext import LLVMContext -from ADT.StringRef import StringRef -from Module import Module -from Function import Function -from Support.raw_ostream import raw_ostream -from Assembly.AssemblyAnnotationWriter import AssemblyAnnotationWriter +from .namespace import llvm +from .Value import Value, MDNode, MDString +from .LLVMContext import LLVMContext +from .ADT.StringRef import StringRef +from .Module import Module +from .Function import Function +from .Support.raw_ostream import raw_ostream +from .Assembly.AssemblyAnnotationWriter import AssemblyAnnotationWriter @MDNode class MDNode: diff --git a/llvmpy/src/Module.py b/llvmpy/src/Module.py index d68be36..46fad5a 100644 --- a/llvmpy/src/Module.py +++ b/llvmpy/src/Module.py @@ -1,18 +1,18 @@ from binding import * -from namespace import llvm +from .namespace import llvm Module = llvm.Class() -from LLVMContext import LLVMContext -from ADT.StringRef import StringRef -from Constant import Constant -from GlobalVariable import GlobalVariable -from Function import Function -from DerivedTypes import FunctionType -from Support.raw_ostream import raw_ostream -from Assembly.AssemblyAnnotationWriter import AssemblyAnnotationWriter -from Type import Type, StructType -from Metadata import NamedMDNode +from .LLVMContext import LLVMContext +from .ADT.StringRef import StringRef +from .Constant import Constant +from .GlobalVariable import GlobalVariable +from .Function import Function +from .DerivedTypes import FunctionType +from .Support.raw_ostream import raw_ostream +from .Assembly.AssemblyAnnotationWriter import AssemblyAnnotationWriter +from .Type import Type, StructType +from .Metadata import NamedMDNode @Module class Module: diff --git a/llvmpy/src/Pass.py b/llvmpy/src/Pass.py index f36856c..ad03d9a 100644 --- a/llvmpy/src/Pass.py +++ b/llvmpy/src/Pass.py @@ -1,14 +1,14 @@ from binding import * -from namespace import llvm +from .namespace import llvm Pass = llvm.Class() ModulePass = llvm.Class(Pass) FunctionPass = llvm.Class(Pass) ImmutablePass = llvm.Class(ModulePass) -from ADT.StringRef import StringRef -from Module import Module -from Value import Function +from .ADT.StringRef import StringRef +from .Module import Module +from .Value import Function @Pass class Pass: diff --git a/llvmpy/src/PassManager.py b/llvmpy/src/PassManager.py index 91a98f4..4d59e9f 100644 --- a/llvmpy/src/PassManager.py +++ b/llvmpy/src/PassManager.py @@ -1,8 +1,8 @@ from binding import * -from namespace import llvm -from Pass import Pass -from Module import Module -from Value import Function +from .namespace import llvm +from .Pass import Pass +from .Module import Module +from .Value import Function PassManagerBase = llvm.Class() PassManager = llvm.Class(PassManagerBase) diff --git a/llvmpy/src/PassRegistry.py b/llvmpy/src/PassRegistry.py index 495de51..ede026c 100644 --- a/llvmpy/src/PassRegistry.py +++ b/llvmpy/src/PassRegistry.py @@ -1,5 +1,5 @@ from binding import * -from namespace import llvm +from .namespace import llvm from src.ADT.StringRef import StringRef PassRegistry = llvm.Class() diff --git a/llvmpy/src/PassSupport.py b/llvmpy/src/PassSupport.py index 8dba872..d239a6d 100644 --- a/llvmpy/src/PassSupport.py +++ b/llvmpy/src/PassSupport.py @@ -1,5 +1,5 @@ from binding import * -from namespace import llvm +from .namespace import llvm PassInfo = llvm.Class() diff --git a/llvmpy/src/Support/FormattedStream.py b/llvmpy/src/Support/FormattedStream.py index 26f906d..3e9159b 100644 --- a/llvmpy/src/Support/FormattedStream.py +++ b/llvmpy/src/Support/FormattedStream.py @@ -1,6 +1,6 @@ from binding import * from ..namespace import llvm -from raw_ostream import raw_ostream +from .raw_ostream import raw_ostream @llvm.Class(raw_ostream) class formatted_raw_ostream: diff --git a/llvmpy/src/Type.py b/llvmpy/src/Type.py index 8e62137..ea1f0e5 100644 --- a/llvmpy/src/Type.py +++ b/llvmpy/src/Type.py @@ -1,8 +1,8 @@ from binding import * -from namespace import llvm -from LLVMContext import LLVMContext -from Support.raw_ostream import raw_ostream -from ADT.StringRef import StringRef +from .namespace import llvm +from .LLVMContext import LLVMContext +from .Support.raw_ostream import raw_ostream +from .ADT.StringRef import StringRef Type = llvm.Class() IntegerType = llvm.Class(Type) diff --git a/llvmpy/src/User.py b/llvmpy/src/User.py index 9a077c1..1d3cc1f 100644 --- a/llvmpy/src/User.py +++ b/llvmpy/src/User.py @@ -1,6 +1,6 @@ from binding import * -from namespace import llvm -from Value import Value, User +from .namespace import llvm +from .Value import Value, User @User class User: diff --git a/llvmpy/src/Value.py b/llvmpy/src/Value.py index b10807a..669ed80 100644 --- a/llvmpy/src/Value.py +++ b/llvmpy/src/Value.py @@ -1,5 +1,5 @@ from binding import * -from namespace import llvm +from .namespace import llvm # forward declarations Value = llvm.Class() @@ -21,11 +21,11 @@ ConstantDataSequential = llvm.Class(Constant) ConstantDataArray = llvm.Class(ConstantDataSequential) ConstantExpr = llvm.Class(Constant) -from Support.raw_ostream import raw_ostream -from Assembly.AssemblyAnnotationWriter import AssemblyAnnotationWriter -from Type import Type -from LLVMContext import LLVMContext -from ADT.StringRef import StringRef +from .Support.raw_ostream import raw_ostream +from .Assembly.AssemblyAnnotationWriter import AssemblyAnnotationWriter +from .Type import Type +from .LLVMContext import LLVMContext +from .ADT.StringRef import StringRef @Value diff --git a/llvmpy/src/__init__.py b/llvmpy/src/__init__.py index ed34608..36bc12f 100644 --- a/llvmpy/src/__init__.py +++ b/llvmpy/src/__init__.py @@ -3,11 +3,12 @@ import os.path def _init(root=__name__, file=__file__): base = os.path.dirname(file) for fname in os.listdir(base): - print fname is_python_script = fname.endswith('.py') or fname.endswith('.pyc') is_init_script = fname.startswith('__init__') is_directory = os.path.isdir(os.path.join(base, fname)) - if (is_directory or is_python_script) and not is_init_script : + is_python_module = is_directory and not fname.startswith('__') + if (is_python_module or is_python_script) and not is_init_script: + print(fname) modname = os.path.basename(fname).rsplit('.', 1)[0] #importlib.import_module('.' + modname, __name__) __import__('.'.join([root, modname])) diff --git a/llvmpy/test_binding.py b/llvmpy/test_binding.py index 8eb56f6..c7ceb49 100644 --- a/llvmpy/test_binding.py +++ b/llvmpy/test_binding.py @@ -1,9 +1,10 @@ -from StringIO import StringIO +from io import BytesIO, StringIO from llvmpy.api import llvm from llvmpy import extra from llvmpy import _capsule import llvmpy.capsule +import collections llvmpy.capsule.set_debug(True) @@ -14,19 +15,19 @@ def test_basic_jit_use(): context = llvm.getGlobalContext() m = llvm.Module.new("modname", context) - print m.getModuleIdentifier() + print(m.getModuleIdentifier()) m.setModuleIdentifier('modname2') - print m.getModuleIdentifier() - print 'endianness', m.getEndianness() + print(m.getModuleIdentifier()) + print('endianness', m.getEndianness()) assert m.getEndianness() == llvm.Module.Endianness.AnyEndianness - print 'pointer-size', m.getPointerSize() + print('pointer-size', m.getPointerSize()) assert m.getPointerSize() == llvm.Module.PointerSize.AnyPointerSize m.dump() os = extra.make_raw_ostream_for_printing() m.print_(os, None) - print os.str() + print(os.str()) int1ty = llvm.Type.getInt1Ty(context) @@ -40,11 +41,11 @@ def test_basic_jit_use(): types = [llvm.Type.getIntNTy(context, 8), llvm.Type.getIntNTy(context, 32)] fnty = llvm.FunctionType.get(llvm.Type.getIntNTy(context, 8), types, False) - print fnty + print(fnty) const = m.getOrInsertFunction("foo", fnty) fn = const._downcast(llvm.Function) - print fn + print(fn) assert fn.hasName() assert 'foo' == fn.getName() fn.setName('bar') @@ -63,7 +64,7 @@ def test_basic_jit_use(): assert len(fn_uselist) == 0 builder = llvm.IRBuilder.new(context) - print builder + print(builder) bb = llvm.BasicBlock.Create(context, "entry", fn, None) assert bb.empty() @@ -72,19 +73,19 @@ def test_basic_jit_use(): assert bb.getTerminator() is None arg0, arg1 = fn.getArgumentList() - print arg0, arg1 + print(arg0, arg1) extended = builder.CreateZExt(arg0, arg1.getType()) result = builder.CreateAdd(extended, arg1) ret = builder.CreateTrunc(result, fn.getReturnType()) builder.CreateRet(ret) - print arg0.list_use() + print(arg0.list_use()) - print fn + print(fn) errio = StringIO() - print m + print(m) # verifier action = llvm.VerifierFailureAction.ReturnStatusAction @@ -92,7 +93,7 @@ def test_basic_jit_use(): corrupted = llvm.verifyFunction(fn, action) assert not corrupted corrupted = llvm.verifyModule(m, action, errio) - print corrupted + print(corrupted) assert not corrupted, errio.getvalue() # build pass manager @@ -114,13 +115,13 @@ def test_basic_jit_use(): pm.run(m) - print m + print(m) # build engine ee = llvm.ExecutionEngine.createJIT(m, errio) - print ee, errio.getvalue() - print ee.getDataLayout().getStringRepresentation() + print(ee, errio.getvalue()) + print(ee.getDataLayout().getStringRepresentation()) datalayout_str = 'e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64' @@ -149,7 +150,7 @@ def test_basic_jit_use(): assert 44 == gvR.toUnsignedInt() # write bitcode - bc_buffer = StringIO() + bc_buffer = BytesIO() llvm.WriteBitcodeToFile(m, bc_buffer) bc = bc_buffer.getvalue() bc_buffer.close() @@ -187,7 +188,7 @@ def test_engine_builder(): builder.SetInsertPoint(bb) builder.CreateRet(fn.getArgumentList()[0]) - print fn + print(fn) eb = llvm.EngineBuilder.new(m) eb2 = eb.setEngineKind(llvm.EngineKind.Kind.JIT) @@ -196,13 +197,13 @@ def test_engine_builder(): tm = eb.selectTarget() - print 'target triple:', tm.getTargetTriple() - print 'target cpu:', tm.getTargetCPU() - print 'target feature string:', tm.getTargetFeatureString() + print('target triple:', tm.getTargetTriple()) + print('target cpu:', tm.getTargetCPU()) + print('target feature string:', tm.getTargetFeatureString()) target = tm.getTarget() - print 'target name:', target.getName() - print 'target short description:', target.getShortDescription() + print('target name:', target.getName()) + print('target short description:', target.getShortDescription()) assert target.hasJIT() assert target.hasTargetMachine() @@ -218,7 +219,7 @@ def test_engine_builder(): triple_32variant = triple.get32BitArchVariant() assert triple_32variant.isArch32Bit() - print tm.getDataLayout() + print(tm.getDataLayout()) pm = llvm.PassManager.new() pm.add(llvm.DataLayout.new(str(tm.getDataLayout()))) @@ -240,7 +241,7 @@ def test_engine_builder(): formatted.flush() raw.flush() asm = raw.str() - print asm + print(asm) assert 'foo' in asm @@ -301,7 +302,7 @@ def test_globalvariable(): gvar2 = m.getNamedGlobal('apple') assert gvar2 is gvar - print m.list_globals() + print(m.list_globals()) def test_sequentialtypes(): @@ -345,9 +346,9 @@ def test_passregistry(): passinfo = passreg.getPassInfo("dce") dcepass = passinfo.createPass() - print dcepass.getPassName() + print(dcepass.getPassName()) - print passreg.enumerate() + print(passreg.enumerate()) def test_targetregistry(): llvm.TargetRegistry.printRegisteredTargetsForVersion() @@ -356,15 +357,15 @@ def test_targetregistry(): target = llvm.TargetRegistry.getClosestTargetForJIT(errmsg) errmsg.close() - print target.getName() - print target.getShortDescription() + print(target.getName()) + print(target.getShortDescription()) assert target.hasJIT() assert target.hasTargetMachine() next = target.getNext() if next: - print next.getName() - print next.getShortDescription() + print(next.getName()) + print(next.getShortDescription()) triple = llvm.sys.getDefaultTargetTriple() cpu = llvm.sys.getHostCPUName() @@ -375,9 +376,9 @@ def test_targetregistry(): tm = target.createTargetMachine(triple, cpu, "", targetoptions) def main(): - for name, value in globals().items(): - if name.startswith('test_') and callable(value): - print name.center(80, '-') + for name, value in list(globals().items()): + if name.startswith('test_') and isinstance(value, collections.Callable): + print(name.center(80, '-')) value() From 6c07747a3b906e649a09aacd3f3b2f90b2ddc10d Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 23 Feb 2013 21:52:23 +0200 Subject: [PATCH 296/516] Typo fix - could *not* invoke llvm-config. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6802391..3757770 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ def run_llvm_config(extra_args): try: p = Popen(args, stdout=PIPE, stderr=PIPE) except OSError: - sys.exit("Error: could invoke %r\n" + sys.exit("Error: could not invoke %r\n" "Try setting LLVM_CONFIG_PATH=/path/to/llvm-config" % args) stdout, stderr = p.communicate() if stderr: From fccf439117016e605a8b763b3dffcd94a35506ad Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 23 Feb 2013 23:08:30 +0200 Subject: [PATCH 297/516] Add missing titles to few docs to make sure they're rendered in docs. --- docs/source/doc/llvm.core.Constant.rst | 3 +++ docs/source/doc/llvm.core.GlobalVariable.rst | 3 +++ docs/source/doc/llvm.core.Module.rst | 4 +++- docs/source/doc/llvm.core.StructType.rst | 3 +++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/source/doc/llvm.core.Constant.rst b/docs/source/doc/llvm.core.Constant.rst index 4f2ed08..9b479c2 100644 --- a/docs/source/doc/llvm.core.Constant.rst +++ b/docs/source/doc/llvm.core.Constant.rst @@ -4,6 +4,9 @@ | title: Constant (llvm.core) | +-------------------------------+ +llvm.core.Constant +================== + ``Constant``-s represents constants that appear within the code. The values of such objects are known at creation time. Constants can be created from Python constants. A constant expression is also a constant diff --git a/docs/source/doc/llvm.core.GlobalVariable.rst b/docs/source/doc/llvm.core.GlobalVariable.rst index 392a6a0..48c8255 100644 --- a/docs/source/doc/llvm.core.GlobalVariable.rst +++ b/docs/source/doc/llvm.core.GlobalVariable.rst @@ -4,6 +4,9 @@ | title: GlobalVariable (llvm.core) | +-------------------------------------+ +llvm.core.GlobalVariable +======================== + Global variables (``llvm.core.GlobalVariable``) are subclasses of `llvm.core.GlobalValue `_ and represent module-level variables. These can have optional initializers and can be diff --git a/docs/source/doc/llvm.core.Module.rst b/docs/source/doc/llvm.core.Module.rst index 3dbd5c8..824b6cd 100644 --- a/docs/source/doc/llvm.core.Module.rst +++ b/docs/source/doc/llvm.core.Module.rst @@ -4,11 +4,13 @@ | title: Module (llvm.core) | +-----------------------------+ +llvm.core.Module +================ + Modules are top-level container objects. You need to create a module object first, before you can add global variables, aliases or functions. Modules are created using the static method ``Module.new``: - .. code-block:: python #!/usr/bin/env python diff --git a/docs/source/doc/llvm.core.StructType.rst b/docs/source/doc/llvm.core.StructType.rst index e69de29..0ac3ce6 100644 --- a/docs/source/doc/llvm.core.StructType.rst +++ b/docs/source/doc/llvm.core.StructType.rst @@ -0,0 +1,3 @@ +llvm.core.StructType +==================== + From 650a49dcab6d4b5836fa7daa62be5c3ec4b94770 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 23 Feb 2013 23:13:23 +0200 Subject: [PATCH 298/516] Fix import statements. --- docs/source/doc/llvm.core.Module.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/doc/llvm.core.Module.rst b/docs/source/doc/llvm.core.Module.rst index 824b6cd..4052a4f 100644 --- a/docs/source/doc/llvm.core.Module.rst +++ b/docs/source/doc/llvm.core.Module.rst @@ -15,7 +15,8 @@ Modules are created using the static method ``Module.new``: #!/usr/bin/env python - from llvm import \* from llvm.core import \* + from llvm import * + from llvm.core import * # create a module my_module = Module.new('my_module') From 769376b0556cc7e2daea138723c9dfc3c2e3da1f Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 24 Feb 2013 00:03:26 +0200 Subject: [PATCH 299/516] Sublists must have blank lines before and after. --- docs/source/doc/llvm_concepts.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/doc/llvm_concepts.rst b/docs/source/doc/llvm_concepts.rst index c642994..8690e49 100644 --- a/docs/source/doc/llvm_concepts.rst +++ b/docs/source/doc/llvm_concepts.rst @@ -28,6 +28,7 @@ follow these steps: - add a *basic block* to the function - using a helper object called an *instruction builder*, add two instructions into the basic block: + - an instruction to add the two arguments and store the result into a temporary variable - a return From 8086487ab742a743d02bbb9b3b9fd2104162da77 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 24 Feb 2013 00:08:28 +0200 Subject: [PATCH 300/516] Fix "title underline too short" warnings. --- docs/source/doc/examples/JITTutorial2.rst | 2 +- docs/source/doc/kaleidoscope/PythonLangImpl1.rst | 2 +- docs/source/doc/kaleidoscope/PythonLangImpl8.rst | 10 +++++----- docs/source/doc/llvm_cbuilder.rst | 2 +- docs/source/index.rst | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/source/doc/examples/JITTutorial2.rst b/docs/source/doc/examples/JITTutorial2.rst index a9a9979..6e76150 100644 --- a/docs/source/doc/examples/JITTutorial2.rst +++ b/docs/source/doc/examples/JITTutorial2.rst @@ -1,5 +1,5 @@ A More Complicated Function -==================== +=========================== .. code-block:: python diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl1.rst b/docs/source/doc/kaleidoscope/PythonLangImpl1.rst index 00b16fb..ae4b80d 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl1.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl1.rst @@ -6,7 +6,7 @@ Written by `Chris Lattner `_ and `Max Shawabkeh `_ Introduction -========= +============ Welcome to the "Implementing a language with LLVM" tutorial. This tutorial runs through the implementation of a simple language, showing diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl8.rst b/docs/source/doc/kaleidoscope/PythonLangImpl8.rst index dd4abc1..eb13dd0 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl8.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl8.rst @@ -1,6 +1,6 @@ -************************************************* +*************************************************** Chapter 8: Conclusion and other useful LLVM tidbits -************************************************* +*************************************************** Written by Chris Lattner @@ -106,7 +106,7 @@ generating LLVM IR. These are some of the more subtle things that may not be obv but are very useful if you want to take advantage of LLVM's capabilities. Properties of the LLVM IR -======================== +========================= We have a couple common questions about code in the LLVM IR form - let's just get these out of the way right now, shall we? @@ -164,7 +164,7 @@ This can make sense for specialized domains such as an in-kernel language. -------------- Safety Guarantees ----------------- +----------------- Many of the languages above are also "safe" languages: it is impossible for a program written in Java to corrupt its address space and @@ -236,7 +236,7 @@ you desire in your front-end, on the language-specific AST. -------------- Tips and Tricks -============== +=============== There is a variety of useful tips and tricks that you come to know after working on/with LLVM that aren't obvious at first glance. diff --git a/docs/source/doc/llvm_cbuilder.rst b/docs/source/doc/llvm_cbuilder.rst index 990bfb0..c8623c2 100644 --- a/docs/source/doc/llvm_cbuilder.rst +++ b/docs/source/doc/llvm_cbuilder.rst @@ -1,5 +1,5 @@ llvm_cbuilder -========= +============= llvm_cbuilder is a set of Python-contexts you can use to write C-like constructs in Python which generates llvmpy code directly. diff --git a/docs/source/index.rst b/docs/source/index.rst index 9f86b32..7798b77 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -4,7 +4,7 @@ contain the root `toctree` directive. Documentation for llvmpy -================= +======================== Contents: From d74ff4dc2bebee2a7ceabaafaebc6dd5c5db8538 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 24 Feb 2013 00:22:54 +0200 Subject: [PATCH 301/516] Fill in required explicit argument for code-block. --- docs/source/doc/kaleidoscope/PythonLangImpl7.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl7.rst b/docs/source/doc/kaleidoscope/PythonLangImpl7.rst index 629608c..7e86ee4 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl7.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl7.rst @@ -295,7 +295,7 @@ variables is a useful thing regardless of whether you will be mutating them. Here's a motivating example that shows how we could use these: -.. code-block:: +.. code-block:: none # Define ':' for sequencing: as a low-precedence operator that ignores operands # and just returns the RHS. @@ -352,7 +352,7 @@ function that ensures that the allocas are created in the entry block of the function: -.. code-block:: +.. code-block:: python # Creates an alloca instruction in the entry block of the function. This is used # for mutable variables. @@ -475,7 +475,7 @@ It is interesting to see what the code looks like before and after the mem2reg optimization runs. For example, this is the before/after code for our recursive fib function. Before the optimization: -.. code-block:: +.. code-block:: llvm define double @fib(double %x) { entry: @@ -515,7 +515,7 @@ still just make the PHI. Here is the code after the mem2reg pass runs: -.. code-block:: +.. code-block:: llvm define double @fib(double %x) { entry: @@ -651,7 +651,7 @@ Now that we have an assignment operator, we can mutate loop variables and arguments. For example, we can now run code like this: -.. code-block:: +.. code-block:: none # Function to print a double. extern printd(x) From d36cd1dbc7786b714da54a9cfd781f02045023c0 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 24 Feb 2013 00:40:25 +0200 Subject: [PATCH 302/516] Add docstring documentation to all llvm.core classes. Some classes have docstrings, and lack rST docs (e.g. Module), few others vice versa. It's unclear what is the best way to deal with this. IMHO, docstrings should prevail, i.e. existing docs would rather be moved to docstings. Anyway, for now just make sure that users don't miss documentation, even if it's just list of classmembers. --- docs/source/doc/llvm.core.Argument.rst | 7 +++++++ docs/source/doc/llvm.core.ArrayType.rst | 7 +++++++ docs/source/doc/llvm.core.BasicBlock.rst | 7 +++++++ docs/source/doc/llvm.core.Builder.rst | 7 +++++++ docs/source/doc/llvm.core.Constant.rst | 6 ++++++ docs/source/doc/llvm.core.Function.rst | 7 +++++++ docs/source/doc/llvm.core.FunctionType.rst | 7 +++++++ docs/source/doc/llvm.core.GlobalValue.rst | 6 ++++++ docs/source/doc/llvm.core.GlobalVariable.rst | 7 +++++++ docs/source/doc/llvm.core.Instruction.rst | 7 +++++++ docs/source/doc/llvm.core.IntegerType.rst | 7 +++++++ docs/source/doc/llvm.core.Module.rst | 7 +++++++ docs/source/doc/llvm.core.PointerType.rst | 7 +++++++ docs/source/doc/llvm.core.StructType.rst | 5 +++++ docs/source/doc/llvm.core.Type.rst | 7 +++++++ docs/source/doc/llvm.core.User.rst | 7 +++++++ docs/source/doc/llvm.core.Value.rst | 7 +++++++ docs/source/doc/llvm.core.VectorType.rst | 7 +++++++ 18 files changed, 122 insertions(+) diff --git a/docs/source/doc/llvm.core.Argument.rst b/docs/source/doc/llvm.core.Argument.rst index 2481665..a2ffbfa 100644 --- a/docs/source/doc/llvm.core.Argument.rst +++ b/docs/source/doc/llvm.core.Argument.rst @@ -56,3 +56,10 @@ Add an attribute ``attr`` to the argument, from the set listed above. ~~~~~~~~~~~~~~~~~~~~~~~~~~ Remove the attribute ``attr`` of the argument. + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.Argument + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.ArrayType.rst b/docs/source/doc/llvm.core.ArrayType.rst index f8b5e0c..3a4e645 100644 --- a/docs/source/doc/llvm.core.ArrayType.rst +++ b/docs/source/doc/llvm.core.ArrayType.rst @@ -28,3 +28,10 @@ A ``Type`` object representing the type of the element of the array. [read-only] The number of elements in the array. + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.ArrayType + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.BasicBlock.rst b/docs/source/doc/llvm.core.BasicBlock.rst index 74806a6..eb10be3 100644 --- a/docs/source/doc/llvm.core.BasicBlock.rst +++ b/docs/source/doc/llvm.core.BasicBlock.rst @@ -42,3 +42,10 @@ The parent function of this basicblock. ~~~~~~~~~~~~~~~~ A list of instructions in this basicblock. + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.BasicBlock + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.Builder.rst b/docs/source/doc/llvm.core.Builder.rst index 1e90908..24b9361 100644 --- a/docs/source/doc/llvm.core.Builder.rst +++ b/docs/source/doc/llvm.core.Builder.rst @@ -409,3 +409,10 @@ positioned. ~~~~~~~~~ Deprecated. Same as ``basic_block`` + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.Builder + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.Constant.rst b/docs/source/doc/llvm.core.Constant.rst index 9b479c2..ae67fa4 100644 --- a/docs/source/doc/llvm.core.Constant.rst +++ b/docs/source/doc/llvm.core.Constant.rst @@ -354,3 +354,9 @@ some examples: assert isinstance(k1, ConstantInt) assert isinstance(k2, ConstantArray) + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.Constant + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.Function.rst b/docs/source/doc/llvm.core.Function.rst index 1d6070c..cda101e 100644 --- a/docs/source/doc/llvm.core.Function.rst +++ b/docs/source/doc/llvm.core.Function.rst @@ -149,3 +149,10 @@ function bodies. Verifies the function. See `LLVM docs `_. + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.Function + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.FunctionType.rst b/docs/source/doc/llvm.core.FunctionType.rst index 8d40009..7b728a8 100644 --- a/docs/source/doc/llvm.core.FunctionType.rst +++ b/docs/source/doc/llvm.core.FunctionType.rst @@ -46,3 +46,10 @@ the function. Used like this: Type.int(), Type.int() ] ) for arg in func_type.args: assert arg.kind == TYPE_INTEGER assert arg == Type.int() assert func_type.arg_count == len(func_type.args) + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.FunctionType + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.GlobalValue.rst b/docs/source/doc/llvm.core.GlobalValue.rst index 70dee7b..a5c2383 100644 --- a/docs/source/doc/llvm.core.GlobalValue.rst +++ b/docs/source/doc/llvm.core.GlobalValue.rst @@ -95,3 +95,9 @@ A power-of-2 integer indicating the boundary to align to. The module object to which this global belongs to. + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.GlobalValue + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.GlobalVariable.rst b/docs/source/doc/llvm.core.GlobalVariable.rst index 48c8255..1ba69d8 100644 --- a/docs/source/doc/llvm.core.GlobalVariable.rst +++ b/docs/source/doc/llvm.core.GlobalVariable.rst @@ -40,3 +40,10 @@ class, or by using the static method ``GlobalVariable.new``. # list all global variables in a module for gv in module_obj.global_variables: print gv.name, "of type", gv.type + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.GlobalVariable + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.Instruction.rst b/docs/source/doc/llvm.core.Instruction.rst index 95aeb81..67c43f0 100644 --- a/docs/source/doc/llvm.core.Instruction.rst +++ b/docs/source/doc/llvm.core.Instruction.rst @@ -240,3 +240,10 @@ Properties The predicate of the compare instruction, one of the ``ICMP_*`` or ``FCMP_*`` constants. + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.Instruction + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.IntegerType.rst b/docs/source/doc/llvm.core.IntegerType.rst index f62907c..6f1e2b1 100644 --- a/docs/source/doc/llvm.core.IntegerType.rst +++ b/docs/source/doc/llvm.core.IntegerType.rst @@ -21,3 +21,10 @@ Properties [read-only] The width of the integer type, in number of bits. + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.IntegerType + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.Module.rst b/docs/source/doc/llvm.core.Module.rst index 4052a4f..75cc174 100644 --- a/docs/source/doc/llvm.core.Module.rst +++ b/docs/source/doc/llvm.core.Module.rst @@ -20,3 +20,10 @@ Modules are created using the static method ``Module.new``: # create a module my_module = Module.new('my_module') + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.Module + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.PointerType.rst b/docs/source/doc/llvm.core.PointerType.rst index a869fba..cc65139 100644 --- a/docs/source/doc/llvm.core.PointerType.rst +++ b/docs/source/doc/llvm.core.PointerType.rst @@ -29,3 +29,10 @@ The address space of the pointer. A `Type `_ object representing the type of the value pointed to. + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.PointerType + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.StructType.rst b/docs/source/doc/llvm.core.StructType.rst index 0ac3ce6..f3b0786 100644 --- a/docs/source/doc/llvm.core.StructType.rst +++ b/docs/source/doc/llvm.core.StructType.rst @@ -1,3 +1,8 @@ llvm.core.StructType ==================== +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.StructType + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.Type.rst b/docs/source/doc/llvm.core.Type.rst index 58883d7..b1eb354 100644 --- a/docs/source/doc/llvm.core.Type.rst +++ b/docs/source/doc/llvm.core.Type.rst @@ -126,3 +126,10 @@ Example: assert Type.int().kind == TYPE_INTEGER assert Type.void().kind == TYPE_VOID + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.Type + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.User.rst b/docs/source/doc/llvm.core.User.rst index 0762729..12d40c5 100644 --- a/docs/source/doc/llvm.core.User.rst +++ b/docs/source/doc/llvm.core.User.rst @@ -37,3 +37,10 @@ The list of operands (values, of type The number of operands that this value referes to. Same as ``len(uses.operands)`` but faster if you just want the count. + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.User + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.Value.rst b/docs/source/doc/llvm.core.Value.rst index fdff4cc..081d328 100644 --- a/docs/source/doc/llvm.core.Value.rst +++ b/docs/source/doc/llvm.core.Value.rst @@ -63,3 +63,10 @@ representation. ``Value`` objects can be compared for equality. Internally, this converts both arguments into their LLVM assembly representations and compares the resultant strings. + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.Value + :members: + :undoc-members: diff --git a/docs/source/doc/llvm.core.VectorType.rst b/docs/source/doc/llvm.core.VectorType.rst index 19b98e6..a18f6ea 100644 --- a/docs/source/doc/llvm.core.VectorType.rst +++ b/docs/source/doc/llvm.core.VectorType.rst @@ -29,3 +29,10 @@ element of the vector. [read-only] The number of elements in the vector. + + +Automatically Generated Documentation +------------------------------------- +.. autoclass:: llvm.core.VectorType + :members: + :undoc-members: From 4e87b5170aa027f71301556d5b60b3b12a7d40ed Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 24 Feb 2013 00:43:43 +0200 Subject: [PATCH 303/516] Allow Sphinx build docs with docstrings without installing module. --- docs/source/conf.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 5c5c38d..830f1ad 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -11,12 +11,22 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys, os +import sys, os, glob # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +#sys.path.insert(0, os.path.abspath('../..')) + +# Support sphinx.ext.autodoc to extract docstrings from modules without installing +# complete package. +# The python modules depend on _core, so we must build entire package first though. +built_lib = glob.glob('../../build/lib.*/') +if not built_lib: + print "WARNING: To build complete documentation you must build package first" +else: + # lib dir has platform suffix + sys.path.insert(0, os.path.abspath(built_lib[0])) # -- General configuration ----------------------------------------------------- From d270f47328820bfa7da6477a142555d4ebb646b9 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sun, 24 Feb 2013 13:21:42 -0600 Subject: [PATCH 304/516] Fix writing to file-like obj in python3.3 --- llvmpy/include/llvm_binding/conversion.h | 2 +- llvmpy/include/llvm_binding/extra.h | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/llvmpy/include/llvm_binding/conversion.h b/llvmpy/include/llvm_binding/conversion.h index abc3749..1c629b7 100644 --- a/llvmpy/include/llvm_binding/conversion.h +++ b/llvmpy/include/llvm_binding/conversion.h @@ -9,7 +9,7 @@ int py_bytes_to(PyObject *bytesobj, llvm::StringRef &strref){ // type check if (!PyBytes_Check(bytesobj)) { // raises TypeError - PyErr_SetString(PyExc_TypeError, "Expecting a str"); + PyErr_SetString(PyExc_TypeError, "Expecting a bytes"); return 0; } // get len and buffer diff --git a/llvmpy/include/llvm_binding/extra.h b/llvmpy/include/llvm_binding/extra.h index 3874bb3..b33a8a0 100644 --- a/llvmpy/include/llvm_binding/extra.h +++ b/llvmpy/include/llvm_binding/extra.h @@ -477,9 +477,13 @@ PyObject* llvm_ParseBitCodeFile(llvm::StringRef Buf, llvm::LLVMContext& Ctx, if (FObj) { std::string ErrStr; M = ParseBitcodeFile(MB, Ctx, &ErrStr); - if (-1 == PyFile_WriteString(ErrStr.c_str(), FObj)) { + auto_pyobject buf = PyBytes_FromString(ErrStr.c_str()); + if (NULL == PyObject_CallMethod(FObj, "write", "O", *buf)){ return NULL; } +// if (-1 == PyFile_WriteString(ErrStr.c_str(), FObj)) { +// return NULL; +// } } else { M = ParseBitcodeFile(MB, Ctx); } @@ -497,9 +501,8 @@ PyObject* llvm_WriteBitcodeToFile(const llvm::Module *M, PyObject* FObj) llvm::WriteBitcodeToFile(M, rso); rso.flush(); StringRef ref = rso.str(); - PyObject* buf = PyBytes_FromStringAndSize(ref.data(), ref.size()); - puts(PyString_AsString(PyObject_Str(PyObject_Type(buf)))); - return PyObject_CallMethod(FObj, "write", "O", buf); + auto_pyobject buf = PyBytes_FromStringAndSize(ref.data(), ref.size()); + return PyObject_CallMethod(FObj, "write", "O", *buf); } static From c1b46e4384958a37493dc9130710f2eecac7624d Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 25 Feb 2013 10:02:49 -0600 Subject: [PATCH 305/516] Fix test --- llvmpy/test_binding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvmpy/test_binding.py b/llvmpy/test_binding.py index c7ceb49..aee0167 100644 --- a/llvmpy/test_binding.py +++ b/llvmpy/test_binding.py @@ -156,7 +156,7 @@ def test_basic_jit_use(): bc_buffer.close() # read bitcode - errbuf = StringIO() + errbuf = BytesIO() m2 = llvm.ParseBitCodeFile(bc, context, errbuf) if not m2: raise Exception(errbuf.getvalue()) From 894539681b92314c6255bf6154fb9232cef2d313 Mon Sep 17 00:00:00 2001 From: Jon Riehl Date: Tue, 26 Feb 2013 15:48:00 -0600 Subject: [PATCH 306/516] Modified documentation configuration to search for build specific to Python version. Updated copyright. First attempt at using llvm._version to set documentation version. --- docs/source/conf.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 830f1ad..701ef80 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -21,9 +21,10 @@ import sys, os, glob # Support sphinx.ext.autodoc to extract docstrings from modules without installing # complete package. # The python modules depend on _core, so we must build entire package first though. -built_lib = glob.glob('../../build/lib.*/') +built_lib = glob.glob('../../build/lib.*-%d.%d/' % sys.version_info[:2]) if not built_lib: - print "WARNING: To build complete documentation you must build package first" + sys.stderr.write("WARNING: To build complete documentation you must build " + "package first\n") else: # lib dir has platform suffix sys.path.insert(0, os.path.abspath(built_lib[0])) @@ -51,16 +52,22 @@ master_doc = 'index' # General information about the project. project = u'llvmpy' -copyright = u'2012, Mahadevan R (2008-2010), Continuum Analytics (2012)' +copyright = u'2013, Mahadevan R (2008-2010), Continuum Analytics (2012-2013)' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # -# The short X.Y version. -version = '0.9' -# The full version, including alpha/beta/rc tags. -release = '0.9.0' +try: + import llvm + version_strs = llvm.__version__.split('.') + # The short X.Y version. + version = '.'.join(version_strs[:2]) + # The full version, including alpha/beta/rc tags. + release = '%s.%s' % (version, '-'.join(version_strs[2].split('-')[:2])) +except ImportError: + version = 'unknown-version' + release = 'unknown-release' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. From dd9ba65328f18c881318ebeddcee73d2b48217b2 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 26 Feb 2013 18:43:49 -0600 Subject: [PATCH 307/516] Bug fixes --- llvm/core.py | 2 +- llvmpy/include/llvm_binding/conversion.h | 4 ++-- llvmpy/src/Instruction.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index f38028b..268318a 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -1729,7 +1729,7 @@ class CallOrInvokeInstruction(Instruction): return _make_value(function) def _set_called_function(self, function): - self._ptr.setCalledFunction(function) + self._ptr.setCalledFunction(function._ptr) called_function = property(_get_called_function, _set_called_function) diff --git a/llvmpy/include/llvm_binding/conversion.h b/llvmpy/include/llvm_binding/conversion.h index 1c629b7..5395a3f 100644 --- a/llvmpy/include/llvm_binding/conversion.h +++ b/llvmpy/include/llvm_binding/conversion.h @@ -124,8 +124,8 @@ int py_int_to(PyObject *intobj, unsigned & val){ static int py_int_to(PyObject *intobj, unsigned long long & val){ if (!PyInt_Check(intobj) and !PyLong_Check(intobj)) { - // raise TypeError - PyErr_SetString(PyExc_TypeError, "Expecting an int 2"); + // raise TypeError; + PyErr_SetString(PyExc_TypeError, "Expecting an int"); return 0; } val = PyInt_AsUnsignedLongLongMask(intobj); diff --git a/llvmpy/src/Instruction.py b/llvmpy/src/Instruction.py index 1974aad..beb94f1 100644 --- a/llvmpy/src/Instruction.py +++ b/llvmpy/src/Instruction.py @@ -134,7 +134,7 @@ class BinaryOperator: @CallInst class CallInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction getCallingConv = Method(CallingConv.ID) setCallingConv = Method(Void, CallingConv.ID) @@ -277,7 +277,7 @@ class IndirectBrInst: @InvokeInst class InvokeInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction getCallingConv = Method(CallingConv.ID) setCallingConv = Method(Void, CallingConv.ID) getParamAlignment = Method(cast(Unsigned, int), cast(int, Unsigned)) From c3a08a446fead9268a136aeac4f853097ca4bf78 Mon Sep 17 00:00:00 2001 From: cuda Date: Wed, 27 Feb 2013 11:28:07 -0600 Subject: [PATCH 308/516] Fix import and Makefile on Linux --- llvmpy/Makefile | 3 +-- llvmpy/src/PassManager.py | 8 +++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/llvmpy/Makefile b/llvmpy/Makefile index 9de1fb0..e9cc1c3 100644 --- a/llvmpy/Makefile +++ b/llvmpy/Makefile @@ -10,8 +10,7 @@ api.cpp api/__init__.py: src/*.py include/llvm_binding/*.h gen/gen.py gen/bindin clean: cleantemp rm -f _api.so _capsule.so - rm -rf api - py_clean + rm -rf api cleantemp: rm -f api.cpp diff --git a/llvmpy/src/PassManager.py b/llvmpy/src/PassManager.py index 4d59e9f..760f080 100644 --- a/llvmpy/src/PassManager.py +++ b/llvmpy/src/PassManager.py @@ -1,13 +1,15 @@ from binding import * from .namespace import llvm -from .Pass import Pass -from .Module import Module -from .Value import Function PassManagerBase = llvm.Class() PassManager = llvm.Class(PassManagerBase) FunctionPassManager = llvm.Class(PassManagerBase) +from .Pass import Pass +from .Module import Module +from .Value import Function + + @PassManagerBase class PassManagerBase: _include_ = 'llvm/PassManager.h' From 740d2595eeae16592b0ae7d2dbdd43e0b6d0ef18 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 27 Feb 2013 13:25:19 -0600 Subject: [PATCH 309/516] Replace StringIO with BytesIO --- llvm/core.py | 21 +++++++++------------ llvm/ee.py | 9 +++------ llvm/test_llvmpy.py | 15 +++++---------- 3 files changed, 17 insertions(+), 28 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index 268318a..49b5561 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -28,10 +28,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO +from io import BytesIO import contextlib, weakref import llvm @@ -337,7 +334,7 @@ class Module(llvm.Wrapper): bc = fileobj_or_str else: bc = fileobj_or_str.read() - errbuf = StringIO() + errbuf = BytesIO() context = api.llvm.getGlobalContext() m = api.llvm.ParseBitCodeFile(bc, context, errbuf) if not m: @@ -359,7 +356,7 @@ class Module(llvm.Wrapper): ir = fileobj_or_str else: ir = fileobj_or_str.read() - errbuf = StringIO() + errbuf = BytesIO() context = api.llvm.getGlobalContext() m = api.llvm.ParseAssemblyString(ir, None, api.llvm.SMDiagnostic.new(), context) @@ -432,7 +429,7 @@ class Module(llvm.Wrapper): enum_mode = api.llvm.Linker.LinkerMode mode = enum_mode.PreserveSource if preserve else enum_mode.DestroySource - with contextlib.closing(StringIO()) as errmsg: + with contextlib.closing(BytesIO()) as errmsg: failed = api.llvm.Linker.LinkModules(self._ptr, other._ptr, mode, @@ -512,7 +509,7 @@ class Module(llvm.Wrapper): Checks module for errors. Raises `llvm.LLVMException' on any error.""" action = api.llvm.VerifierFailureAction.ReturnStatusAction - errio = StringIO() + errio = BytesIO() broken = api.llvm.verifyModule(self._ptr, action, errio) if broken: raise llvm.LLVMException(errio.getvalue()) @@ -530,7 +527,7 @@ class Module(llvm.Wrapper): ret = False if fileobj is None: ret = True - fileobj = StringIO + fileobj = BytesIO api.llvm.WriteBitcodeToFile(self._ptr, fileobj) if ret: return fileobj.getvalue() @@ -571,7 +568,7 @@ class Module(llvm.Wrapper): ret = False if fileobj is None: ret = True - fileobj = StringIO() + fileobj = BytesIO() from llvm.ee import TargetMachine tm = TargetMachine.new() fileobj.write(tm.emit_object(self)) @@ -588,7 +585,7 @@ class Module(llvm.Wrapper): ret = False if fileobj is None: ret = True - fileobj = StringIO() + fileobj = BytesIO() from llvm.ee import TargetMachine tm = TargetMachine.new() fileobj.write(tm.emit_assembly(self)) @@ -2269,7 +2266,7 @@ def load_library_permanently(filename): Load the given shared library (filename argument specifies the full path of the .so file) using LLVM. Symbols from these are available from the execution engine thereafter.""" - with contextlib.closing(StringIO()) as errmsg: + with contextlib.closing(BytesIO()) as errmsg: failed = api.llvm.sys.DynamicLibrary.LoadPermanentLibrary(filename, errmsg) if failed: diff --git a/llvm/ee.py b/llvm/ee.py index 8598ad9..030eacb 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -30,10 +30,7 @@ "Execution Engine and related classes." -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO +from io import BytesIO import contextlib import llvm @@ -244,7 +241,7 @@ class TargetMachine(llvm.Wrapper): triple = get_default_triple() if not cpu: cpu = get_host_cpu_name() - with contextlib.closing(StringIO()) as error: + with contextlib.closing(BytesIO()) as error: target = api.llvm.TargetRegistry.lookupTarget(triple, error) if not target: raise llvm.LLVMException(error) @@ -273,7 +270,7 @@ class TargetMachine(llvm.Wrapper): use: `llvm-as < /dev/null | llc -march=xyz -mattr=help` ''' triple = api.llvm.Triple.new() - with contextlib.closing(StringIO()) as error: + with contextlib.closing(BytesIO()) as error: target = api.llvm.TargetRegistry.lookupTarget(arch, triple, error) if not target: raise llvm.LLVMException(error) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 5b26e39..8c9b800 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -10,13 +10,8 @@ import subprocess import tempfile import contextlib -is_py3k = bool(sys.version_info[0] == 3) BITS = tuple.__itemsize__ * 8 - -if is_py3k: - from io import StringIO -else: - from cStringIO import StringIO +from io import BytesIO import llvm @@ -123,7 +118,7 @@ class TestAttr(TestCase): ret void } """ - return Module.from_assembly(StringIO(test_module)) + return Module.from_assembly(BytesIO(test_module)) def test_align(self): m = self.make_module() @@ -255,7 +250,7 @@ entry: } """ def test_operands(self): - m = Module.from_assembly(StringIO(self.test_module)) + m = Module.from_assembly(BytesIO(self.test_module)) test_func = m.get_function_named("test_func") prod = m.get_function_named("prod") @@ -317,7 +312,7 @@ entry: } """ def test_passes(self): - m = Module.from_assembly(StringIO(self.asm)) + m = Module.from_assembly(BytesIO(self.asm)) fn_test1 = m.get_function_named('test1') fn_test2 = m.get_function_named('test2') @@ -365,7 +360,7 @@ entry: self.assertNotEqual(str(fn_test1).strip(), original_test1.strip()) def test_passes_with_pmb(self): - m = Module.from_assembly(StringIO(self.asm)) + m = Module.from_assembly(BytesIO(self.asm)) fn_test1 = m.get_function_named('test1') fn_test2 = m.get_function_named('test2') From 93cd20e9336e337016e0c73faf1172d017ba3e0b Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 27 Feb 2013 13:48:08 -0600 Subject: [PATCH 310/516] Fix for python 3 --- llvm/core.py | 25 +++++++++++++++++-------- llvm/ee.py | 2 +- llvm/passes.py | 1 - llvm/test_llvmpy.py | 33 +++++++++++++++++++-------------- test/inlineasm.py | 2 +- test/malloc.py | 2 +- test/tbaa.py | 2 +- test/test_debuginfo.py | 2 +- 8 files changed, 41 insertions(+), 28 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index 49b5561..bed5763 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -29,6 +29,14 @@ # from io import BytesIO +try: + from StringIO import StringIO +except ImportError: + try: + from cStringIO import StringIO + except ImportError: + from io import StringIO + import contextlib, weakref import llvm @@ -468,7 +476,7 @@ class Module(llvm.Wrapper): @property def global_variables(self): - return map(_make_value, self._ptr.list_globals()) + return list(map(_make_value, self._ptr.list_globals())) def add_function(self, ty, name): """Add a function of given type with given name.""" @@ -501,7 +509,7 @@ class Module(llvm.Wrapper): @property def functions(self): """All functions in this module.""" - return map(_make_value, self._ptr.list_functions()) + return list(map(_make_value, self._ptr.list_functions())) def verify(self): """Verify module. @@ -585,10 +593,11 @@ class Module(llvm.Wrapper): ret = False if fileobj is None: ret = True - fileobj = BytesIO() + fileobj = StringIO() from llvm.ee import TargetMachine tm = TargetMachine.new() - fileobj.write(tm.emit_assembly(self)) + asm = tm.emit_assembly(self) + fileobj.write(asm) if ret: return fileobj.getvalue() @@ -983,7 +992,7 @@ class Value(llvm.Wrapper): @property def uses(self): - return map(_make_value, self._ptr.list_use()) + return list(map(_make_value, self._ptr.list_use())) class User(Value): _type_ = api.llvm.User @@ -1458,7 +1467,7 @@ class Function(GlobalValue): @property def args(self): args = self._ptr.getArgumentList() - return map(_make_value, args) + return list(map(_make_value, args)) @property def basic_block_count(self): @@ -1480,7 +1489,7 @@ class Function(GlobalValue): @property def basic_blocks(self): - return map(_make_value, self._ptr.getBasicBlockList()) + return list(map(_make_value, self._ptr.getBasicBlockList())) def viewCFG(self): return self._ptr.viewCFG() @@ -1782,7 +1791,7 @@ class BasicBlock(Value): @property def instructions(self): - return map(_make_value, self._ptr.getInstList()) + return list(map(_make_value, self._ptr.getInstList())) #===----------------------------------------------------------------------=== # Value factory method diff --git a/llvm/ee.py b/llvm/ee.py index 030eacb..672a0b6 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -179,7 +179,7 @@ class ExecutionEngine(llvm.Wrapper): self._ptr.DisableLazyCompilation(disabled) def run_function(self, fn, args): - ptr = self._ptr.runFunction(fn._ptr, map(lambda x: x._ptr, args)) + ptr = self._ptr.runFunction(fn._ptr, list(map(lambda x: x._ptr, args))) return GenericValue(ptr) def get_pointer_to_function(self, fn): diff --git a/llvm/passes.py b/llvm/passes.py index 36e7d97..9f706d8 100644 --- a/llvm/passes.py +++ b/llvm/passes.py @@ -147,7 +147,6 @@ class PassManager(llvm.Wrapper): if not a_pass: assert pass_name not in PASSES, "Registered but not found?" raise llvm.LLVMException('Invalid pass name "%s"' % pass_name) - print a_pass self._ptr.add(a_pass) def run(self, module): diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 8c9b800..3656621 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -11,7 +11,11 @@ import tempfile import contextlib BITS = tuple.__itemsize__ * 8 -from io import BytesIO + +try: + from StringIO import StringIO +except ImportError: + from io import StringIO import llvm @@ -118,7 +122,8 @@ class TestAttr(TestCase): ret void } """ - return Module.from_assembly(BytesIO(test_module)) + buf = StringIO(test_module) + return Module.from_assembly(buf) def test_align(self): m = self.make_module() @@ -250,7 +255,7 @@ entry: } """ def test_operands(self): - m = Module.from_assembly(BytesIO(self.test_module)) + m = Module.from_assembly(StringIO(self.test_module)) test_func = m.get_function_named("test_func") prod = m.get_function_named("prod") @@ -312,7 +317,7 @@ entry: } """ def test_passes(self): - m = Module.from_assembly(BytesIO(self.asm)) + m = Module.from_assembly(StringIO(self.asm)) fn_test1 = m.get_function_named('test1') fn_test2 = m.get_function_named('test2') @@ -360,7 +365,7 @@ entry: self.assertNotEqual(str(fn_test1).strip(), original_test1.strip()) def test_passes_with_pmb(self): - m = Module.from_assembly(BytesIO(self.asm)) + m = Module.from_assembly(StringIO(self.asm)) fn_test1 = m.get_function_named('test1') fn_test2 = m.get_function_named('test2') @@ -626,7 +631,7 @@ class TestTargetMachines(TestCase): self.assertTrue(tm.target_data) self.assertTrue(tm.target_short_description) self.assertTrue(tm.triple) - self.assertIn('foo', tm.emit_assembly(m).decode('utf-8')) + self.assertIn('foo', tm.emit_assembly(m)) self.assertTrue(le.get_host_cpu_name()) def test_ptx(self): @@ -636,13 +641,13 @@ class TestTargetMachines(TestCase): arch = 'nvptx64' else: return # skip this test - print 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).decode('utf-8') + ptxasm = ptxtm.emit_assembly(m) self.assertIn('foo', ptxasm) if lc.HAS_NVPTX: self.assertIn('.address_size 64', ptxasm) @@ -936,31 +941,31 @@ class TestCPUSupport(TestCase): def test_cpu_support2(self): features = 'sse3', 'sse41', 'sse42', 'avx' mattrs = ','.join(map(lambda s: '-%s' % s, features)) - print 'disable mattrs', mattrs + 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 + 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 + 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 + print('disable mattrs', mattrs) self._template(mattrs) def test_cpu_support6(self): features = [] mattrs = ','.join(map(lambda s: '-%s' % s, features)) - print 'disable mattrs', mattrs + print('disable mattrs', mattrs) self._template(mattrs) tests.append(TestCPUSupport) @@ -1235,4 +1240,4 @@ def run(verbosity=1): if __name__ == '__main__': - run() + unittest.main() diff --git a/test/inlineasm.py b/test/inlineasm.py index df91d71..64a4cbe 100644 --- a/test/inlineasm.py +++ b/test/inlineasm.py @@ -20,7 +20,7 @@ class TestInlineAsm(TestCase): inlineasm = InlineAsm.get(iaty, "bswap $0", "=r,r") self.assertIn('asm "bswap $0", "=r,r"', str(inlineasm)) builder.ret(builder.call(inlineasm, [fn.args[0]])) - print fn + print(fn) if __name__ == '__main__': unittest.main() diff --git a/test/malloc.py b/test/malloc.py index 1613a36..be37dcd 100644 --- a/test/malloc.py +++ b/test/malloc.py @@ -10,7 +10,7 @@ def test(): alloc = b.malloc_array(Type.int(), Constant.int(Type.int(), 10), 'hee') inst = b.free(alloc) b.ret_void() - print m + print(m) if __name__ == '__main__': test() diff --git a/test/tbaa.py b/test/tbaa.py index 242ed19..ad11081 100644 --- a/test/tbaa.py +++ b/test/tbaa.py @@ -29,7 +29,7 @@ class TestTBAABuilder(TestCase): bldr.ret_void() - print mod + print(mod) if __name__ == '__main__': unittest.main() diff --git a/test/test_debuginfo.py b/test/test_debuginfo.py index 33dbbdb..b6a5d6f 100644 --- a/test/test_debuginfo.py +++ b/test/test_debuginfo.py @@ -122,7 +122,7 @@ def debug_in_gdb(lfunc): # Now let's compile and run! retval = ee.run_function(lfunc, [arg1]) - print retval.as_real(float_type) + print(retval.as_real(float_type)) if __name__ == '__main__': From 5d83d626f6ff22fc3c74d18e45fad392ad5fd75f Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 27 Feb 2013 14:20:45 -0600 Subject: [PATCH 311/516] Update setup script --- llvmpy/build.py | 8 ++++++++ setup.py | 33 +++++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 10 deletions(-) create mode 100644 llvmpy/build.py diff --git a/llvmpy/build.py b/llvmpy/build.py new file mode 100644 index 0000000..1021927 --- /dev/null +++ b/llvmpy/build.py @@ -0,0 +1,8 @@ +from os import chdir +from os.path import dirname +import sys, subprocess + +scriptdir = dirname(__file__) +chdir(scriptdir) + +subprocess.check_call([sys.executable, 'gen/gen.py', 'api', 'src']) diff --git a/setup.py b/setup.py index 3757770..9bcd9f0 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ import os import sys -from subprocess import Popen, PIPE +from subprocess import Popen, PIPE, check_call from distutils.core import setup, Extension import versioneer @@ -141,22 +141,30 @@ if sys.platform == 'win32': else: macros.append(('_GNU_SOURCE', None)) +# auto generate bindings +check_call([sys.executable, 'llvmpy/build.py']) + extra_link_args = ldflags.split() kwds = dict( ext_modules = [ Extension( - name='llvm._core', - sources=['llvm/_core.cpp', 'llvm/wrap.cpp', 'llvm/extra.cpp'], + name='llvmpy._api', + sources=['llvmpy/api.cpp'], define_macros = macros, - include_dirs = ['/usr/include', incdir], + include_dirs = [incdir, 'llvmpy/include'], library_dirs = [libdir], libraries = libs_core, extra_objects = objs_core, extra_link_args = extra_link_args), - Extension(name='llvm._dwarf', - sources=['llvm/_dwarf.cpp'], - include_dirs=[incdir]) + Extension( + name='llvmpy._capsule', + sources=['llvmpy/capsule.cpp'], + include_dirs=['llvmpy/include'], + ) +# Extension(name='llvm._dwarf', +# sources=['llvm/_dwarf.cpp'], +# include_dirs=[incdir]) ], cmdclass = versioneer.get_cmdclass(), ) @@ -173,12 +181,17 @@ setup( name = 'llvmpy', version=versioneer.get_version(), description = 'Python bindings for LLVM', - author = 'R Mahadevan', + author = 'R Mahadevan, Siu Kwan Lam', maintainer = 'Continuum Analytics, Inc.', maintainer_email = 'llvmpy@continuum.io', url = 'http://www.llvmpy.org/', - packages = ['llvm', 'llvm_cbuilder', 'llpython'], - py_modules = ['llvm.core'], + packages = ['llvm', 'llvm_cbuilder', 'llpython', + 'llvmpy.api', 'llvmpy.api.llvm'], + py_modules = ['llvmpy', + 'llvmpy._capsule', + 'llvmpy._api', + 'llvmpy.capsule', + 'llvmpy.extra'], license = "BSD", classifiers = [ "Intended Audience :: Developers", From ae6dab8e509d54fc35f73b3a5924e182038aed91 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 27 Feb 2013 14:53:49 -0600 Subject: [PATCH 312/516] Pass llvm version and ptx support to wrapper generator through environ --- llvmpy/gen/binding.py | 14 ++++++++++++++ llvmpy/src/Support/TargetSelect.py | 18 ++++++++++-------- setup.py | 12 ++++++++---- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/llvmpy/gen/binding.py b/llvmpy/gen/binding.py index 0f5c4fd..ab8e7aa 100644 --- a/llvmpy/gen/binding.py +++ b/llvmpy/gen/binding.py @@ -838,3 +838,17 @@ class Attr(object): writer.println() +# +# Pick-up environ var +# +PTX_SUPPORT = os.environ['LLVMPY_PTX_SUPPORT'] + +def _parse_llvm_version(ver): + import re + m = re.compile(r'(\d+)\.(\d+)').match(ver) + assert m + major, minor = m.groups() + return int(major), int(minor) + +LLVM_VERSION = _parse_llvm_version(os.environ['LLVMPY_LLVM_VERSION']) + diff --git a/llvmpy/src/Support/TargetSelect.py b/llvmpy/src/Support/TargetSelect.py index ca97c24..85e1d74 100644 --- a/llvmpy/src/Support/TargetSelect.py +++ b/llvmpy/src/Support/TargetSelect.py @@ -17,12 +17,14 @@ InitializeNativeTargetDisassembler = llvm.Function( #InitializeAllTargetMCs = llvm.Function('InitializeAllTargetMCs') #InitializeAllAsmPrinters = llvm.Function('InitializeAllAsmPrinters') -#LLVMInitializePTXTarget = default.Function('LLVMInitializePTXTarget') -#LLVMInitializePTXTargetInfo = default.Function('LLVMInitializePTXTargetInfo') -#LLVMInitializePTXTargetMC = default.Function('LLVMInitializePTXTargetMC') -#LLVMInitializePTXAsmPrinter = default.Function('LLVMInitializePTXAsmPrinter') +if PTX_SUPPORT == 'PTX': + LLVMInitializePTXTarget = default.Function('LLVMInitializePTXTarget') + LLVMInitializePTXTargetInfo = default.Function('LLVMInitializePTXTargetInfo') + LLVMInitializePTXTargetMC = default.Function('LLVMInitializePTXTargetMC') + LLVMInitializePTXAsmPrinter = default.Function('LLVMInitializePTXAsmPrinter') -LLVMInitializeNVPTXTarget = default.Function('LLVMInitializeNVPTXTarget') -LLVMInitializeNVPTXTargetInfo = default.Function('LLVMInitializeNVPTXTargetInfo') -LLVMInitializeNVPTXTargetMC = default.Function('LLVMInitializeNVPTXTargetMC') -LLVMInitializeNVPTXAsmPrinter = default.Function('LLVMInitializeNVPTXAsmPrinter') +if PTX_SUPPORT == 'NVPTX': + LLVMInitializeNVPTXTarget = default.Function('LLVMInitializeNVPTXTarget') + LLVMInitializeNVPTXTargetInfo = default.Function('LLVMInitializeNVPTXTargetInfo') + LLVMInitializeNVPTXTargetMC = default.Function('LLVMInitializeNVPTXTargetMC') + LLVMInitializeNVPTXAsmPrinter = default.Function('LLVMInitializeNVPTXAsmPrinter') diff --git a/setup.py b/setup.py index 9bcd9f0..6fa6653 100644 --- a/setup.py +++ b/setup.py @@ -97,7 +97,7 @@ def determine_to_use_dynlink(libdir, llvm_version): dynlink = determine_to_use_dynlink(libdir, llvm_version) - +ptx_support = '' if dynlink: print('Using dynamic linking') @@ -120,12 +120,13 @@ else: if (nvptx_components & enabled_components) == nvptx_components: print("Using NVPTX") extra_components.extend(nvptx_components) + ptx_support = 'NVPTX' elif (ptx_components & enabled_components) == ptx_components: print("Using PTX") extra_components.extend(ptx_components) + ptx_support = 'PTX' else: print("No CUDA support") - macros.append(('LLVM_DISABLE_PTX', None)) libs_core, objs_core = get_libs_and_objs( ['core', 'analysis', 'scalaropts', 'executionengine', @@ -136,14 +137,17 @@ else: if sys.platform == 'win32': # If no PTX lib got added, disable PTX in the build - if 'LLVMPTXCodeGen' not in libs_core: - macros.append(('LLVM_DISABLE_PTX', None)) + if 'LLVMPTXCodeGen' in libs_core: + ptx_support = 'ptx' else: macros.append(('_GNU_SOURCE', None)) # auto generate bindings +os.environ['LLVMPY_PTX_SUPPORT'] = ptx_support +os.environ['LLVMPY_LLVM_VERSION'] = llvm_version check_call([sys.executable, 'llvmpy/build.py']) +# generate shared objects extra_link_args = ldflags.split() kwds = dict( ext_modules = [ From d485c22b0870f75d429eea6a546d8479e4946b2d Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 27 Feb 2013 16:32:00 -0600 Subject: [PATCH 313/516] Add llvm.workaround package --- llvm/workaround/__init__.py | 0 llvm/workaround/avx_support.py | 60 ++++++++++++++++++++++++++++++++++ setup.py | 4 ++- 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 llvm/workaround/__init__.py create mode 100644 llvm/workaround/avx_support.py diff --git a/llvm/workaround/__init__.py b/llvm/workaround/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/llvm/workaround/avx_support.py b/llvm/workaround/avx_support.py new file mode 100644 index 0000000..81cb936 --- /dev/null +++ b/llvm/workaround/avx_support.py @@ -0,0 +1,60 @@ +""" +Auto-detect avx and xsave + +According to Intel manual [0], both AVX and XSAVE features must be present to +use AVX instructions. + +References: + +[0] Intel Architecture Instruction Set Extensions Programming Reference + +http://software.intel.com/sites/default/files/m/a/b/3/4/d/41604-319433-012a.pdf + +""" + +import sys, os, subprocess + +def detect_avx_support(option='detect'): + '''Detect AVX support''' + option = os.environ.get('LLVMPY_AVX_SUPPORT', option).lower() + if option in ('disable', '0', 'false'): + return False + elif option in ('enable', '1', 'true'): + return True + else: # do detection + plat = sys.platform + if plat.startswith('darwin'): + return detect_osx_like() + elif plat.startswith('win32'): + return False # don't know how to detect in windows + else: + return detect_unix_like() + +def detect_unix_like(): + try: + info = open('/proc/cpuinfo') + except IOError: + return False + + for line in info: + if line.lstrip().startswith('flags'): + features = line.split() + if 'avx' in features and 'xsave' in features: + # enable AVX if flags contain AVX + return True + return False + +def detect_osx_like(): + try: + info = subprocess.Popen(['sysctl', '-n', 'machdep.cpu.features'], + stdout=subprocess.PIPE) + except OSError: + return False + + features = info.stdout.read() + features = features.split() + return 'AVX1.0' in features and 'OSXSAVE' in features and 'XSAVE' in features + + +if __name__ == '__main__': + print("AVX support: %s" % detect_avx_support()) diff --git a/setup.py b/setup.py index 6fa6653..ea7edb6 100644 --- a/setup.py +++ b/setup.py @@ -189,7 +189,9 @@ setup( maintainer = 'Continuum Analytics, Inc.', maintainer_email = 'llvmpy@continuum.io', url = 'http://www.llvmpy.org/', - packages = ['llvm', 'llvm_cbuilder', 'llpython', + packages = ['llvm', 'llvm.workaround', + 'llvm_cbuilder', + 'llpython', 'llvmpy.api', 'llvmpy.api.llvm'], py_modules = ['llvmpy', 'llvmpy._capsule', From f3e7b39bc926a17ff4537fafb02e416492657a47 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 27 Feb 2013 16:36:21 -0600 Subject: [PATCH 314/516] Update changelog --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 6c2cd14..d2e2263 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ 2013-02-XX 0.11.0: -------------------- * fix Python 3 support on Windows + * New llvm binding 2013-02-01 0.10.2: From 8073b67c96defdbee148b329a8f9bb2447487cfe Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 27 Feb 2013 18:28:15 -0600 Subject: [PATCH 315/516] Fix test related to AVX instructions. --- llvm/test_llvmpy.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 3656621..509629c 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -964,9 +964,13 @@ class TestCPUSupport(TestCase): def test_cpu_support6(self): features = [] - mattrs = ','.join(map(lambda s: '-%s' % s, features)) - print('disable mattrs', mattrs) - self._template(mattrs) + from llvm.workaround.avx_support import detect_avx_support + if not detect_avx_support(): + print 'Skipping: no AVX' + else: + mattrs = ','.join(map(lambda s: '-%s' % s, features)) + print('disable mattrs', mattrs) + self._template(mattrs) tests.append(TestCPUSupport) From 9f9d5a6081c790e26ef6065d95ea1a6fb2496a8a Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 27 Feb 2013 18:31:54 -0600 Subject: [PATCH 316/516] More fixes to disable AVX in tests --- llvm/test_llvmpy.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 509629c..27fd59c 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -923,7 +923,6 @@ class TestCPUSupport(TestCase): 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]) @@ -987,7 +986,12 @@ class TestIntrinsicBasic(TestCase): def _template(self, mod, func, pyfunc): float = func.type.pointee.return_type - ee = le.ExecutionEngine.new(mod) + + 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) From cd8d622fc9005cca8be10a633834ccbfac64bb2f Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 27 Feb 2013 18:34:00 -0600 Subject: [PATCH 317/516] Fix mysin test for AVX support --- llvm/test_llvmpy.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 27fd59c..04170b4 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -1152,7 +1152,13 @@ class TestIntrinsic(TestCase): # declare float @llvm.cos.f32(float) nounwind readnone # let's run the function - ee = le.ExecutionEngine.new(mod) + + 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]) From 9df508f7c0e3bba40e64431ff030df64a8e6f107 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 27 Feb 2013 18:43:57 -0600 Subject: [PATCH 318/516] Fix test with unicode problem in py3k --- llvm/test_llvmpy.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 04170b4..02bb386 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -10,6 +10,7 @@ import subprocess import tempfile import contextlib +is_py3k = sys.version_info[0] >= 3 BITS = tuple.__itemsize__ * 8 try: @@ -711,7 +712,10 @@ class TestNative(TestCase): src = os.path.join(self.tmpdir, 'llvmasm.s') with open(src, 'wb') as fout: - fout.write(output) + if is_py3k: + fout.write(output.encode('utf-8')) + else: + fout.write(output) self._compile(src) @@ -725,7 +729,11 @@ class TestNative(TestCase): src = os.path.join(self.tmpdir, 'llvmobj.o') with open(src, 'wb') as fout: - fout.write(output) + if is_py3k: + fout.write(output.encode('utf-8')) + else: + fout.write(output) + self._compile(src) @@ -965,7 +973,7 @@ class TestCPUSupport(TestCase): features = [] from llvm.workaround.avx_support import detect_avx_support if not detect_avx_support(): - print 'Skipping: no AVX' + print('Skipping: no AVX') else: mattrs = ','.join(map(lambda s: '-%s' % s, features)) print('disable mattrs', mattrs) From 0cccb3dec9e1a70107a09a43398caea87a2f01de Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 27 Feb 2013 19:03:44 -0600 Subject: [PATCH 319/516] Attempt to fix object code printing problem due to unicode --- llvm/ee.py | 8 +++++++- llvm/test_llvmpy.py | 6 +----- llvmpy/include/llvm_binding/conversion.h | 6 ++++++ llvmpy/src/Support/raw_ostream.py | 2 ++ 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/llvm/ee.py b/llvm/ee.py index 672a0b6..18cef78 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -291,7 +291,13 @@ class TargetMachine(llvm.Wrapper): pm.add(api.llvm.DataLayout.new(str(self.target_data))) failed = self._ptr.addPassesToEmitFile(pm, os, cgft) pm.run(module) - return os.str() + + + 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 diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 02bb386..c96f471 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -729,11 +729,7 @@ class TestNative(TestCase): src = os.path.join(self.tmpdir, 'llvmobj.o') with open(src, 'wb') as fout: - if is_py3k: - fout.write(output.encode('utf-8')) - else: - fout.write(output) - + fout.write(output) self._compile(src) diff --git a/llvmpy/include/llvm_binding/conversion.h b/llvmpy/include/llvm_binding/conversion.h index 5395a3f..cdc0350 100644 --- a/llvmpy/include/llvm_binding/conversion.h +++ b/llvmpy/include/llvm_binding/conversion.h @@ -209,6 +209,12 @@ static PyObject* py_str_from(const std::string &str){ return PyString_FromStringAndSize(str.c_str(), str.size()); } + + +static +PyObject* py_bytes_from(const std::string &str){ + return PyBytes_FromStringAndSize(str.c_str(), str.size()); +} // //static //PyObject* py_str_from(const llvm::StringRef *str){ diff --git a/llvmpy/src/Support/raw_ostream.py b/llvmpy/src/Support/raw_ostream.py index dcce73f..02765aa 100644 --- a/llvmpy/src/Support/raw_ostream.py +++ b/llvmpy/src/Support/raw_ostream.py @@ -15,4 +15,6 @@ class raw_svector_ostream: _base_ = raw_ostream str = Method(cast(str, StringRef)) + bytes = Method(cast(bytes, StringRef)) + bytes.realname = 'str' From 268dc2466a9f34c55c19fca7e95bef5a08a81700 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 27 Feb 2013 19:12:23 -0600 Subject: [PATCH 320/516] Fix build on win32 due to missing environ variable --- llvmpy/gen/binding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvmpy/gen/binding.py b/llvmpy/gen/binding.py index ab8e7aa..1b9c799 100644 --- a/llvmpy/gen/binding.py +++ b/llvmpy/gen/binding.py @@ -841,7 +841,7 @@ class Attr(object): # # Pick-up environ var # -PTX_SUPPORT = os.environ['LLVMPY_PTX_SUPPORT'] +PTX_SUPPORT = os.environ.get('LLVMPY_PTX_SUPPORT', '') def _parse_llvm_version(ver): import re From 4bf0fa65ef3099b8bac9286873019606a837da04 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 27 Feb 2013 19:22:32 -0600 Subject: [PATCH 321/516] Attempt to fix build on 32-bit linux --- llvmpy/include/llvm_binding/conversion.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvmpy/include/llvm_binding/conversion.h b/llvmpy/include/llvm_binding/conversion.h index cdc0350..8c9e3fc 100644 --- a/llvmpy/include/llvm_binding/conversion.h +++ b/llvmpy/include/llvm_binding/conversion.h @@ -135,10 +135,10 @@ int py_int_to(PyObject *intobj, unsigned long long & val){ } static -int py_int_to(PyObject *intobj, size_t & val){ +int py_int_to(PyObject *intobj, unsigned long & val){ unsigned long long ull; if (py_int_to(intobj, ull)) { - val = (size_t)ull; + val = (unsigned long)ull; return 1; } else { return 0; From 1a34e412a5c706cf097c783e3150f079b5397fed Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 27 Feb 2013 19:27:34 -0600 Subject: [PATCH 322/516] Fix: "not" is not available on some compiler. --- llvmpy/include/capsulethunk.h | 2 +- llvmpy/include/llvm_binding/extra.h | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/llvmpy/include/capsulethunk.h b/llvmpy/include/capsulethunk.h index 9061782..6b1aba7 100644 --- a/llvmpy/include/capsulethunk.h +++ b/llvmpy/include/capsulethunk.h @@ -12,7 +12,7 @@ static void do_assert(int cond, const char * msg, const char *file, unsigned line){ - if (not cond) { + if (!cond) { fprintf(stderr, "Assertion failed %s:%d\n%s\n", file, line, msg); exit(1); } diff --git a/llvmpy/include/llvm_binding/extra.h b/llvmpy/include/llvm_binding/extra.h index b33a8a0..5838ae1 100644 --- a/llvmpy/include/llvm_binding/extra.h +++ b/llvmpy/include/llvm_binding/extra.h @@ -586,7 +586,7 @@ PyObject* Linker_LinkInModule(llvm::Linker* Linker, { std::string errmsg; bool failed = Linker->LinkInModule(Mod, &errmsg); - if (not failed) { + if (! failed) { Py_RETURN_FALSE; } else { if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) { @@ -604,7 +604,7 @@ PyObject* Linker_LinkModules(llvm::Module* Dest, { std::string errmsg; bool failed = llvm::Linker::LinkModules(Dest, Src, Mode, &errmsg); - if (not failed) { + if (! failed) { Py_RETURN_FALSE; } else { if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) { @@ -686,7 +686,7 @@ PyObject* ConstantArray_get(llvm::ArrayType* Ty, PyObject* Consts) std::vector vec_consts; bool ok = extract::from_py_sequence(vec_consts, Consts, "llvm::Value"); - if (not ok) return NULL; + if (! ok) return NULL; Constant* ary = ConstantArray::get(Ty, vec_consts); return pycapsule_new(ary, "llvm::Value", "llvm::Constant"); } @@ -699,7 +699,7 @@ PyObject* ConstantStruct_get(llvm::StructType* Ty, PyObject* Elems) std::vector vec_consts; bool ok = extract::from_py_sequence(vec_consts, Elems, "llvm::Value"); - if (not ok) return NULL; + if (! ok) return NULL; Constant* ary = ConstantStruct::get(Ty, vec_consts); return pycapsule_new(ary, "llvm::Value", "llvm::Constant"); } @@ -713,7 +713,7 @@ PyObject* ConstantStruct_getAnon(PyObject* Elems, std::vector vec_consts; bool ok = extract::from_py_sequence(vec_consts, Elems, "llvm::Value"); - if (not ok) return NULL; + if (! ok) return NULL; Constant* ary = ConstantStruct::getAnon(vec_consts, isPacked); return pycapsule_new(ary, "llvm::Value", "llvm::Constant"); } @@ -726,7 +726,7 @@ PyObject* ConstantVector_get(PyObject* Elems) std::vector vec_consts; bool ok = extract::from_py_sequence(vec_consts, Elems, "llvm::Value"); - if (not ok) return NULL; + if (! ok) return NULL; Constant* ary = ConstantVector::get(vec_consts); return pycapsule_new(ary, "llvm::Value", "llvm::Constant"); } @@ -756,7 +756,7 @@ PyObject* MDNode_get(llvm::LLVMContext &Cxt, PyObject* Vals) bool accept_null = true; bool ok = extract::from_py_sequence(vals, Vals, "llvm::Value", accept_null); - if (not ok) return NULL; + if (! ok) return NULL; llvm::MDNode* md = llvm::MDNode::get(Cxt, vals); return pycapsule_new(md, "llvm::Value", "llvm::MDNode"); } @@ -778,7 +778,7 @@ PyObject* IRBuilder_CreateAggregateRet(llvm::IRBuilder<>* builder, using namespace llvm; std::vector vec_values; bool ok = extract::from_py_sequence(vec_values, Vals, "llvm::Value"); - if (not ok) return NULL; + if (! ok) return NULL; Value** ptr_values = &vec_values[0]; ReturnInst* inst = builder->CreateAggregateRet(ptr_values, N); return pycapsule_new(inst, "llvm::Value", "llvm::ReturnInst"); From d9c2ec696dde230a2a6fd562c048f9f63cf1122c Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 27 Feb 2013 19:31:26 -0600 Subject: [PATCH 323/516] Fix: "and" is not available in all compilers. --- llvmpy/include/llvm_binding/conversion.h | 8 ++++---- llvmpy/include/llvm_binding/extra.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/llvmpy/include/llvm_binding/conversion.h b/llvmpy/include/llvm_binding/conversion.h index 8c9e3fc..0d65fa9 100644 --- a/llvmpy/include/llvm_binding/conversion.h +++ b/llvmpy/include/llvm_binding/conversion.h @@ -90,7 +90,7 @@ int py_str_to(PyObject *strobj, const char* &strref){ static int py_int_to(PyObject *intobj, int64_t & val){ - if (!PyInt_Check(intobj) and !PyLong_Check(intobj)) { + if (!PyInt_Check(intobj) && !PyLong_Check(intobj)) { // raise TypeError PyErr_SetString(PyExc_TypeError, "Expecting an int"); return 0; @@ -111,7 +111,7 @@ int py_int_to(PyObject *intobj, int64_t & val){ static int py_int_to(PyObject *intobj, unsigned & val){ - if (!PyInt_Check(intobj) and !PyLong_Check(intobj)) { + if (!PyInt_Check(intobj) && !PyLong_Check(intobj)) { // raise TypeError PyErr_SetString(PyExc_TypeError, "Expecting an int"); return 0; @@ -123,7 +123,7 @@ int py_int_to(PyObject *intobj, unsigned & val){ static int py_int_to(PyObject *intobj, unsigned long long & val){ - if (!PyInt_Check(intobj) and !PyLong_Check(intobj)) { + if (!PyInt_Check(intobj) && !PyLong_Check(intobj)) { // raise TypeError; PyErr_SetString(PyExc_TypeError, "Expecting an int"); return 0; @@ -148,7 +148,7 @@ int py_int_to(PyObject *intobj, unsigned long & val){ static int py_int_to(PyObject *intobj, void* & val){ - if (!PyInt_Check(intobj) and !PyLong_Check(intobj)) { + if (!PyInt_Check(intobj) && !PyLong_Check(intobj)) { // raise TypeError PyErr_SetString(PyExc_TypeError, "Expecting an int"); return 0; diff --git a/llvmpy/include/llvm_binding/extra.h b/llvmpy/include/llvm_binding/extra.h index 5838ae1..0e2d0a0 100644 --- a/llvmpy/include/llvm_binding/extra.h +++ b/llvmpy/include/llvm_binding/extra.h @@ -201,7 +201,7 @@ struct extract { if (!item) { return false; } - if (accept_null and Py_None == *item) { + if (accept_null && Py_None == *item) { vec.push_back(NULL); } else { auto_pyobject capsule = PyObject_GetAttrString(*item, "_ptr"); From 61d8105e2cffbdd415ff485d3e029a2f8abfcd9d Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Wed, 27 Feb 2013 19:26:25 -0600 Subject: [PATCH 324/516] add missing static library (Windows) --- llvm-config-win32.py | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm-config-win32.py b/llvm-config-win32.py index 915871e..05fc94f 100644 --- a/llvm-config-win32.py +++ b/llvm-config-win32.py @@ -68,6 +68,7 @@ LLVMX86AsmParser LLVMX86AsmPrinter LLVMX86CodeGen LLVMX86Desc +LLVMX86Disassembler LLVMX86Info LLVMX86Utils Advapi32 From 75b7d11fb1aad8506418468e1906e2867b250d79 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 27 Feb 2013 20:00:40 -0600 Subject: [PATCH 325/516] Add prints to help debug. --- llvmpy/include/llvm_binding/conversion.h | 1 + 1 file changed, 1 insertion(+) diff --git a/llvmpy/include/llvm_binding/conversion.h b/llvmpy/include/llvm_binding/conversion.h index 0d65fa9..da90de6 100644 --- a/llvmpy/include/llvm_binding/conversion.h +++ b/llvmpy/include/llvm_binding/conversion.h @@ -207,6 +207,7 @@ int py_bool_to(PyObject *boolobj, bool & val){ static PyObject* py_str_from(const std::string &str){ + puts(str.c_str()); return PyString_FromStringAndSize(str.c_str(), str.size()); } From 91d2740fbf29163bdcf27f6c8fea96cce2be1c93 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Wed, 27 Feb 2013 20:00:42 -0600 Subject: [PATCH 326/516] disable lib2to3 conversion --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index ea7edb6..4ed5c56 100644 --- a/setup.py +++ b/setup.py @@ -174,9 +174,9 @@ kwds = dict( ) -if sys.version_info[0] == 3: - from distutils.command.build_py import build_py_2to3 - kwds["cmdclass"]['build_py'] = build_py_2to3 +#if sys.version_info[0] == 3: +# from distutils.command.build_py import build_py_2to3 +# kwds["cmdclass"]['build_py'] = build_py_2to3 kwds['long_description'] = open('README.rst').read() From f172e82f1032f365a80ac8ccb4d7673702945c63 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 27 Feb 2013 20:28:30 -0600 Subject: [PATCH 327/516] Use .data() instead of .c_str() --- llvmpy/include/llvm_binding/conversion.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/llvmpy/include/llvm_binding/conversion.h b/llvmpy/include/llvm_binding/conversion.h index da90de6..a9f073c 100644 --- a/llvmpy/include/llvm_binding/conversion.h +++ b/llvmpy/include/llvm_binding/conversion.h @@ -207,14 +207,13 @@ int py_bool_to(PyObject *boolobj, bool & val){ static PyObject* py_str_from(const std::string &str){ - puts(str.c_str()); - return PyString_FromStringAndSize(str.c_str(), str.size()); + return PyString_FromStringAndSize(str.data(), str.size()); } static PyObject* py_bytes_from(const std::string &str){ - return PyBytes_FromStringAndSize(str.c_str(), str.size()); + return PyBytes_FromStringAndSize(str.data(), str.size()); } // //static From e89c19ee60fed56ed43d243a69e540e3b9ff7f79 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 28 Feb 2013 00:00:25 -0600 Subject: [PATCH 328/516] Ensure order of imported modules --- llvmpy/src/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvmpy/src/__init__.py b/llvmpy/src/__init__.py index 36bc12f..69b6609 100644 --- a/llvmpy/src/__init__.py +++ b/llvmpy/src/__init__.py @@ -2,7 +2,7 @@ import os.path def _init(root=__name__, file=__file__): base = os.path.dirname(file) - for fname in os.listdir(base): + for fname in sorted(os.listdir(base)): is_python_script = fname.endswith('.py') or fname.endswith('.pyc') is_init_script = fname.startswith('__init__') is_directory = os.path.isdir(os.path.join(base, fname)) From 51ff879a070553b3628b49099f12995ec1c35263 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 28 Feb 2013 00:01:03 -0600 Subject: [PATCH 329/516] Fix incorrect use of StringRef in return value --- llvmpy/src/DataLayout.py | 2 +- llvmpy/src/Pass.py | 2 +- llvmpy/src/Support/TargetRegistry.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/llvmpy/src/DataLayout.py b/llvmpy/src/DataLayout.py index 7085f52..812a83d 100644 --- a/llvmpy/src/DataLayout.py +++ b/llvmpy/src/DataLayout.py @@ -30,7 +30,7 @@ class DataLayout: isLittleEndian = Method(cast(Bool, bool)) isBigEndian = Method(cast(Bool, bool)) - getStringRepresentation = Method(cast(StringRef, str)) + getStringRepresentation = Method(cast(StdString, str)) @CustomPythonMethod def __str__(self): diff --git a/llvmpy/src/Pass.py b/llvmpy/src/Pass.py index ad03d9a..52173cd 100644 --- a/llvmpy/src/Pass.py +++ b/llvmpy/src/Pass.py @@ -15,7 +15,7 @@ class Pass: _include_ = 'llvm/Pass.h' delete = Destructor() - getPassName = Method(cast(StringRef, str)) + getPassName = Method(cast(StdString, str)) dump = Method() @ModulePass diff --git a/llvmpy/src/Support/TargetRegistry.py b/llvmpy/src/Support/TargetRegistry.py index 640364b..2a445e7 100644 --- a/llvmpy/src/Support/TargetRegistry.py +++ b/llvmpy/src/Support/TargetRegistry.py @@ -16,8 +16,8 @@ from src.Support.CodeGen import Reloc, CodeModel, CodeGenOpt class Target: getNext = Method(const(ptr(Target))) - getName = Method(cast(StringRef, str)) - getShortDescription = Method(cast(StringRef, str)) + getName = Method(cast(StdString, str)) + getShortDescription = Method(cast(StdString, str)) def _has(): return Method(cast(Bool, bool)) From fde153aab6a4f123a759501c91fcbfbaa2e44a52 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 28 Feb 2013 18:05:30 -0600 Subject: [PATCH 330/516] Add relocation model enums and allow TargetMachine to handle these enums --- llvm/ee.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/llvm/ee.py b/llvm/ee.py index 18cef78..36c0bbf 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -52,6 +52,12 @@ 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 #===----------------------------------------------------------------------=== @@ -236,7 +242,8 @@ def get_default_triple(): class TargetMachine(llvm.Wrapper): @staticmethod - def new(triple='', cpu='', features='', opt=2, cm=CM_DEFAULT): + def new(triple='', cpu='', features='', opt=2, cm=CM_DEFAULT, + reloc=RELOC_DEFAULT): if not triple: triple = get_default_triple() if not cpu: @@ -250,14 +257,14 @@ class TargetMachine(llvm.Wrapper): target_options = api.llvm.TargetOptions.new() tm = target.createTargetMachine(triple, cpu, features, target_options, - api.llvm.Reloc.Model.Default, - cm, opt) + 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): + 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, @@ -279,8 +286,7 @@ class TargetMachine(llvm.Wrapper): target_options = api.llvm.TargetOptions.new() tm = target.createTargetMachine(str(triple), cpu, features, target_options, - api.llvm.Reloc.Model.Default, - cm, opt) + reloc, cm, opt) if not tm: raise llvm.LLVMException("Cannot create target machine") return TargetMachine(tm) From bb43f4097a30077c6d19b68fb8d9f18b68b0f70d Mon Sep 17 00:00:00 2001 From: Hernan Grecco Date: Fri, 1 Mar 2013 19:45:13 -0300 Subject: [PATCH 331/516] Implemented Python 3 compatible division in IntegerValue and RealValue --- llvm_cbuilder/builder.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 917b37e..9b970f4 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -988,6 +988,9 @@ class IntegerValue(OperatorMixin): else: return self._temp(self.parent.builder.sdiv(self.value, rhs.value)) + __truediv__ = __div__ + __floordiv__ = __div__ + def __mod__(self, rhs): if self.unsigned: return self._temp(self.parent.builder.urem(self.value, rhs.value)) @@ -1082,6 +1085,8 @@ class RealValue(OperatorMixin): def __div__(self, rhs): return self._temp(self.parent.builder.fdiv(self.value, rhs.value)) + __truediv__ = __div__ + def __mod__(self, rhs): return self._temp(self.parent.builder.frem(self.value, rhs.value)) From ba759b59d08418de7373fbbe93294303d309d27f Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Sat, 2 Mar 2013 12:53:31 -0600 Subject: [PATCH 332/516] update supported dependencies in readme --- README.rst | 10 +++++----- setup.py | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 973dfdb..b16249a 100644 --- a/README.rst +++ b/README.rst @@ -10,15 +10,15 @@ http://www.llvmpy.org Versions -------- -This package has been tested with LLVM 3.1 and 3.2, Python 2.7 and Python 3.2. -Other Python versions should work. +This package has been tested with LLVM 3.2, Python 2.6, 2.7 and 3.3. +Other Python versions may work. Quickstart ---------- -1. Get 3.1 or 3.2 version of LLVM, build it. Make sure ``--enable-pic`` is - passed to LLVM's ``configure``. - +1. Get 3.2 version of LLVM, build it. Make sure ``--enable-pic`` is + passed to LLVM's ``configure``. + For LLVM 3.2, make sure that environment variable ``REQUIRES_RTTI=1`` is defined when running ``make``. Otherwise, you may see "undefined symbol: _ZTIN4llvm24PassRegistrationListenerE". Please refer to diff --git a/setup.py b/setup.py index 4ed5c56..8202c5f 100644 --- a/setup.py +++ b/setup.py @@ -207,7 +207,6 @@ setup( "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", ], **kwds From f8deae06ddcaa8a2e062194d01c1736bf6809763 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Sat, 2 Mar 2013 12:56:00 -0600 Subject: [PATCH 333/516] remove excess whitespace --- llvm/core.py | 34 +++++++++---------- llvm/ee.py | 4 +-- llvm/passes.py | 4 +-- llvmpy/capsule.py | 2 +- llvmpy/gen/binding.py | 8 ++--- llvmpy/gen/gen.py | 2 +- llvmpy/src/Argument.py | 2 +- llvmpy/src/BasicBlock.py | 2 +- llvmpy/src/Constant.py | 14 ++++---- llvmpy/src/ExecutionEngine/ExecutionEngine.py | 2 +- llvmpy/src/GenericValue.py | 2 +- llvmpy/src/GlobalValue.py | 12 +++---- llvmpy/src/GlobalVariable.py | 3 +- llvmpy/src/IRBuilder.py | 2 +- llvmpy/src/Instruction.py | 6 ++-- llvmpy/src/Metadata.py | 2 +- llvmpy/src/PassRegistry.py | 2 +- llvmpy/src/Target/TargetLibraryInfo.py | 22 ++++++------ llvmpy/src/Transforms/PassManagerBuilder.py | 2 +- llvmpy/src/Type.py | 2 +- llvmpy/src/Value.py | 8 ++--- llvmpy/test_binding.py | 2 +- 22 files changed, 69 insertions(+), 70 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index bed5763..bbe5d01 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -388,7 +388,7 @@ class Module(llvm.Wrapper): return str(self) == str(rhs) else: return False - + def __ne__(self, rhs): return not (self == rhs) @@ -429,7 +429,7 @@ class Module(llvm.Wrapper): The `other' module is no longer valid after this method is invoked, all refs to it should be dropped. - + In the future, this API might be replaced with a full-fledged Linker class. """ @@ -560,7 +560,7 @@ class Module(llvm.Wrapper): pm = PassManager.new()._ptr formatted failed = tm.addPassesToEmitFile(pm, fileobj, cgft, False) - + if failed: raise llvm.LLVMException("Failed to write native object file") if ret: @@ -664,7 +664,7 @@ class Type(llvm.Wrapper): context = api.llvm.getGlobalContext() ptr = api.llvm.Type.getFP128Ty(context) return Type(ptr) - + @staticmethod def ppc_fp128(): """Create a 128-bit floating point type (two 64-bits).""" @@ -920,7 +920,7 @@ class PointerType(Type): class VectorType(Type): _type_ = api.llvm.VectorType - + @property def element(self): return Type(self._ptr.getVectorElementType()) @@ -989,7 +989,7 @@ class Value(llvm.Wrapper): @property def use_count(self): return self._ptr.getNumUses() - + @property def uses(self): return list(map(_make_value, self._ptr.list_use())) @@ -1263,7 +1263,7 @@ class GlobalValue(Constant): def _set_linkage(self, value): self._ptr.setLinkage(value) - + linkage = property(_get_linkage, _set_linkage) def _get_section(self): @@ -1287,7 +1287,7 @@ class GlobalValue(Constant): def _set_alignment(self, value): return self._ptr.setAlignment(value) - + alignment = property(_get_alignment, _set_alignment) @property @@ -1490,7 +1490,7 @@ class Function(GlobalValue): @property def basic_blocks(self): return list(map(_make_value, self._ptr.getBasicBlockList())) - + def viewCFG(self): return self._ptr.viewCFG() @@ -1510,7 +1510,7 @@ class Function(GlobalValue): def verify(self): # Although we're just asking LLVM to return the success or # failure, it appears to print result to stderr and abort. - + # Note: LLVM has a bug in preverifier that will always abort # the process upon failure. actions = api.llvm.VerifierFailureAction @@ -1528,7 +1528,7 @@ class Function(GlobalValue): class InlineAsm(Value): _type_ = api.llvm.InlineAsm - + @staticmethod def get(functype, asm, constrains, side_effect=False, align_stack=False, dialect=api.llvm.InlineAsm.AsmDialect.AD_ATT): @@ -1609,7 +1609,7 @@ class NamedMetaData(llvm.Wrapper): def delete(self): _ValueFactory.delete(self._ptr) self._ptr.eraseFromParent() - + @property def name(self): return self._ptr.getName() @@ -1639,7 +1639,7 @@ class Instruction(User): @property def is_binary_op(self): return self._ptr.isBinaryOp() - + @property def is_shift(self): return self._ptr.isShift() @@ -1663,7 +1663,7 @@ class Instruction(User): @property def is_commutative(self): return self._ptr.isCommutative() - + @property def is_volatile(self): """True if this is a volatile load or store.""" @@ -1925,7 +1925,7 @@ class Builder(llvm.Wrapper): def ret_void(self): self._guard_terminators() return _make_value(self._ptr.CreateRetVoid()) - + def ret(self, value): self._guard_terminators() return _make_value(self._ptr.CreateRet(value._ptr)) @@ -2039,7 +2039,7 @@ class Builder(llvm.Wrapper): "") inst = self._ptr.Insert(malloc, name) return _make_value(inst) - + def malloc_array(self, ty, size, name=""): context = api.llvm.getGlobalContext() allocsz = api.llvm.ConstantExpr.getSizeOf(ty._ptr) @@ -2242,7 +2242,7 @@ class Builder(llvm.Wrapper): def atomic_umin(self, *args, **kwargs): return self.atomic_rmw('umin', *args, **kwargs) - + def atomic_load(self, ptr, ordering, align=1, crossthread=True, volatile=False, name=""): inst = self.load(ptr, align=align, volatile=volatile, name=name) diff --git a/llvm/ee.py b/llvm/ee.py index 36c0bbf..9531427 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -156,7 +156,7 @@ class EngineBuilder(llvm.Wrapper): def select_target(self, *args): '''get the corresponding target machine - + Accept no arguments or (triple, march, mcpu, mattrs) ''' if args: @@ -338,7 +338,7 @@ class TargetMachine(llvm.Wrapper): @property def cpu(self): return self._ptr.getTargetCPU() - + @property def feature_string(self): return self._ptr.getTargetFeatureString() diff --git a/llvm/passes.py b/llvm/passes.py index 9f706d8..6216724 100644 --- a/llvm/passes.py +++ b/llvm/passes.py @@ -77,7 +77,7 @@ class PassManagerBuilder(llvm.Wrapper): @vectorize.setter def vectorize(self, enable): self._ptr.Vectorize = enable - + @property def loop_vectorize(self): @@ -200,7 +200,7 @@ class Pass(llvm.Wrapper): try: return self.__name except AttributeError: - return + return @property def description(self): diff --git a/llvmpy/capsule.py b/llvmpy/capsule.py index ec6fdde..e3b9537 100644 --- a/llvmpy/capsule.py +++ b/llvmpy/capsule.py @@ -33,7 +33,7 @@ class Capsule(object): "Wraps PyCapsule so that we can build weakref of it." from ._capsule import check, getClassName, getName, getPointer - + def __init__(self, capsule): assert Capsule.valid(capsule) self.capsule = capsule diff --git a/llvmpy/gen/binding.py b/llvmpy/gen/binding.py index 1b9c799..eeccab1 100644 --- a/llvmpy/gen/binding.py +++ b/llvmpy/gen/binding.py @@ -344,7 +344,7 @@ class Class(SubModule, _Type): class Enum(object): format = 'O' - + def __init__(self, *value_names): self.parent = None if len(value_names) == 1: @@ -507,7 +507,7 @@ class Method(object): def is_return_ownedptr(self): retty = self.signatures[0][0] return isinstance(retty, ownedptr) - + def process_ownedptr_args(self, writer, unwrapped): argtys = self.signatures[0][1:] for i, ty in enumerate(argtys): @@ -525,7 +525,7 @@ class CustomMethod(Method): ret = writer.call(self.methodname, retty.fullname, *args) writer.return_value(retty.wrap(writer, ret)) - + class StaticMethod(Method): def compile_cpp_body(self, writer, retty, argtys): @@ -544,7 +544,7 @@ class StaticMethod(Method): with decl as varargs: unwrapped = writer.unwrap_many(varargs) self.process_ownedptr_args(writer, unwrapped) - + func = '.'.join([self.parent.py_name, self.name]) ret = writer.call('_api.%s' % func, varargs=unwrapped) wrapped = writer.wrap(ret, self.is_return_ownedptr()) diff --git a/llvmpy/gen/gen.py b/llvmpy/gen/gen.py index 263c289..cd63b68 100644 --- a/llvmpy/gen/gen.py +++ b/llvmpy/gen/gen.py @@ -80,7 +80,7 @@ static } ''' println(fmt % locals()) - + fn.generate_cpp(println) println('static') diff --git a/llvmpy/src/Argument.py b/llvmpy/src/Argument.py index 4f0b7a4..babbd1c 100644 --- a/llvmpy/src/Argument.py +++ b/llvmpy/src/Argument.py @@ -12,4 +12,4 @@ class Argument: addAttr = Method(Void, ref(Attributes)) removeAttr = Method(Void, ref(Attributes)) getParamAlignment = Method(cast(Unsigned, int)) - + diff --git a/llvmpy/src/BasicBlock.py b/llvmpy/src/BasicBlock.py index 77eaf01..868b3c9 100644 --- a/llvmpy/src/BasicBlock.py +++ b/llvmpy/src/BasicBlock.py @@ -14,7 +14,7 @@ class BasicBlock: getParent = Method(ptr(Function)) getTerminator = Method(ptr(TerminatorInst)) - + empty = Method(cast(Bool, bool)) dropAllReferences = Method() isLandingPad = Method(cast(Bool, bool)) diff --git a/llvmpy/src/Constant.py b/llvmpy/src/Constant.py index 70dc3bf..8a091b5 100644 --- a/llvmpy/src/Constant.py +++ b/llvmpy/src/Constant.py @@ -73,7 +73,7 @@ class UndefValue: @ConstantInt class ConstantInt: _downcast_ = Constant, Value - + get = StaticMethod(ptr(ConstantInt), ptr(IntegerType), cast(int, Uint64), @@ -89,7 +89,7 @@ class ConstantInt: @ConstantFP class ConstantFP: _downcast_ = Constant, Value - + get = StaticMethod(ptr(Constant), ptr(Type), cast(float, Double)) getNegativeZero = StaticMethod(ptr(ConstantFP), ptr(Type)) getInfinity = StaticMethod(ptr(ConstantFP), ptr(Type), cast(bool, Bool)) @@ -103,7 +103,7 @@ class ConstantFP: @ConstantArray class ConstantArray: _downcast_ = Constant, Value - + get = CustomStaticMethod('ConstantArray_get', PyObjectPtr, # ptr(Constant), ptr(ArrayType), @@ -114,7 +114,7 @@ class ConstantArray: @ConstantStruct class ConstantStruct: _downcast_ = Constant, Value - + get = CustomStaticMethod('ConstantStruct_get', PyObjectPtr, # ptr(Constant) ptr(StructType), @@ -130,7 +130,7 @@ class ConstantStruct: @ConstantVector class ConstantVector: _downcast_ = Constant, Value - + get = CustomStaticMethod('ConstantVector_get', PyObjectPtr, # ptr(Constant) PyObjectPtr, # constants @@ -145,7 +145,7 @@ class ConstantDataSequential: @ConstantDataArray class ConstantDataArray: _downcast_ = Constant, Value - + getString = StaticMethod(ptr(Constant), ref(LLVMContext), cast(str, StringRef), @@ -178,7 +178,7 @@ def _factory_const_type(): @ConstantExpr class ConstantExpr: _downcast_ = Constant, Value - + getAlignOf = _factory(ptr(Type)) getSizeOf = _factory(ptr(Type)) getOffsetOf = _factory(ptr(Type), ptr(Constant)) diff --git a/llvmpy/src/ExecutionEngine/ExecutionEngine.py b/llvmpy/src/ExecutionEngine/ExecutionEngine.py index 038d344..3208269 100644 --- a/llvmpy/src/ExecutionEngine/ExecutionEngine.py +++ b/llvmpy/src/ExecutionEngine/ExecutionEngine.py @@ -18,7 +18,7 @@ class ExecutionEngine: 'llvm/ExecutionEngine/JIT.h') # force linking of jit delete = Destructor() - + create = CustomStaticMethod('ExecutionEngine_create', ptr(ExecutionEngine), ownedptr(Module), cast(bool, Bool), diff --git a/llvmpy/src/GenericValue.py b/llvmpy/src/GenericValue.py index e587b5f..4dc50d8 100644 --- a/llvmpy/src/GenericValue.py +++ b/llvmpy/src/GenericValue.py @@ -31,4 +31,4 @@ class GenericValue: toFloat = _accessor('ToFloat', cast(Double, float), ptr(Type)) - toPointer = _accessor('ToPointer', cast(VoidPtr, int)) \ No newline at end of file + toPointer = _accessor('ToPointer', cast(VoidPtr, int)) diff --git a/llvmpy/src/GlobalValue.py b/llvmpy/src/GlobalValue.py index 2583c6a..ff499f7 100644 --- a/llvmpy/src/GlobalValue.py +++ b/llvmpy/src/GlobalValue.py @@ -9,15 +9,15 @@ class GlobalValue: _include_ = 'llvm/GlobalValue.h' LinkageTypes = Enum(''' - ExternalLinkage, AvailableExternallyLinkage, LinkOnceAnyLinkage, - LinkOnceODRLinkage, LinkOnceODRAutoHideLinkage, WeakAnyLinkage, - WeakODRLinkage, AppendingLinkage, InternalLinkage, PrivateLinkage, - LinkerPrivateLinkage, LinkerPrivateWeakLinkage, DLLImportLinkage, + ExternalLinkage, AvailableExternallyLinkage, LinkOnceAnyLinkage, + LinkOnceODRLinkage, LinkOnceODRAutoHideLinkage, WeakAnyLinkage, + WeakODRLinkage, AppendingLinkage, InternalLinkage, PrivateLinkage, + LinkerPrivateLinkage, LinkerPrivateWeakLinkage, DLLImportLinkage, DLLExportLinkage, ExternalWeakLinkage, CommonLinkage ''') - VisibilityTypes = Enum('''DefaultVisibility, - HiddenVisibility, + VisibilityTypes = Enum('''DefaultVisibility, + HiddenVisibility, ProtectedVisibility''') setLinkage = Method(Void, LinkageTypes) diff --git a/llvmpy/src/GlobalVariable.py b/llvmpy/src/GlobalVariable.py index c38df27..8b196c0 100644 --- a/llvmpy/src/GlobalVariable.py +++ b/llvmpy/src/GlobalVariable.py @@ -11,7 +11,7 @@ from .Value import Constant @GlobalVariable class GlobalVariable: - ThreadLocalMode = Enum('''NotThreadLocal, GeneralDynamicTLSModel, + ThreadLocalMode = Enum('''NotThreadLocal, GeneralDynamicTLSModel, LocalDynamicTLSModel, InitialExecTLSModel, LocalExecTLSModel ''') @@ -46,4 +46,3 @@ class GlobalVariable: # setExternallyinitialized = Method(Void, cast(bool, Bool)) - \ No newline at end of file diff --git a/llvmpy/src/IRBuilder.py b/llvmpy/src/IRBuilder.py index afd78a0..c0766e9 100644 --- a/llvmpy/src/IRBuilder.py +++ b/llvmpy/src/IRBuilder.py @@ -94,7 +94,7 @@ class IRBuilder: cast(bool, Bool)] op = Method(*sig).require_only(2) return op - + CreateUDiv = _binop_is_exact() CreateSDiv = _binop_is_exact() CreateLShr = _binop_is_exact() diff --git a/llvmpy/src/Instruction.py b/llvmpy/src/Instruction.py index beb94f1..16f57c2 100644 --- a/llvmpy/src/Instruction.py +++ b/llvmpy/src/Instruction.py @@ -85,7 +85,7 @@ class Instruction: insertBefore = Method(Void, ptr(Instruction)) insertAfter = Method(Void, ptr(Instruction)) moveBefore = Method(Void, ptr(Instruction)) - + isTerminator = Method(cast(Bool, bool)) isBinaryOp = Method(cast(Bool, bool)) isShift = Method(cast(Bool, bool)) @@ -135,7 +135,7 @@ class BinaryOperator: @CallInst class CallInst: _downcast_ = Value, User, Instruction - + getCallingConv = Method(CallingConv.ID) setCallingConv = Method(Void, CallingConv.ID) getParamAlignment = Method(cast(Unsigned, int), cast(int, Unsigned)) @@ -298,7 +298,7 @@ class ReturnInst: @SwitchInst class SwitchInst: _downcast_ = Value, Instruction - + getCondition = Method(ptr(Value)) setCondition = Method(Void, ptr(Value)) getDefaultDest = Method(ptr(BasicBlock)) diff --git a/llvmpy/src/Metadata.py b/llvmpy/src/Metadata.py index cfeb6ce..65aac03 100644 --- a/llvmpy/src/Metadata.py +++ b/llvmpy/src/Metadata.py @@ -51,4 +51,4 @@ class NamedMDNode: from llvmpy import extra os = extra.make_raw_ostream_for_printing() self.print_(os, None) - return os.str() \ No newline at end of file + return os.str() diff --git a/llvmpy/src/PassRegistry.py b/llvmpy/src/PassRegistry.py index ede026c..f48e7f0 100644 --- a/llvmpy/src/PassRegistry.py +++ b/llvmpy/src/PassRegistry.py @@ -18,4 +18,4 @@ class PassRegistry: # This is a custom method that wraps enumerateWith # Returns list of tuples of (pass-arg, pass-name) - enumerate = CustomMethod('PassRegistry_enumerate', PyObjectPtr) \ No newline at end of file + enumerate = CustomMethod('PassRegistry_enumerate', PyObjectPtr) diff --git a/llvmpy/src/Target/TargetLibraryInfo.py b/llvmpy/src/Target/TargetLibraryInfo.py index 9c47814..3562fa7 100644 --- a/llvmpy/src/Target/TargetLibraryInfo.py +++ b/llvmpy/src/Target/TargetLibraryInfo.py @@ -10,7 +10,7 @@ LibFunc.Enum('Func', ''' ZdaPv, ZdlPv, Znaj, ZnajRKSt9nothrow_t, Znam, ZnamRKSt9nothrow_t, Znwj, ZnwjRKSt9nothrow_t, Znwm, ZnwmRKSt9nothrow_t, cxa_atexit, cxa_guard_abort, - cxa_guard_acquire, cxa_guard_release, memcpy_chk, + cxa_guard_acquire, cxa_guard_release, memcpy_chk, acos, acosf, acosh, acoshf, acoshl, acosl, asin, asinf, asinh, asinhf, asinhl, asinl, @@ -38,17 +38,17 @@ LibFunc.Enum('Func', ''' powl, putchar, puts, realloc, reallocf, rint, rintf, rintl, round, roundf, roundl, - sin, sinf, sinh, sinhf, - sinhl, sinl, siprintf, - sqrt, sqrtf, sqrtl, stpcpy, - strcat, strchr, strcmp, strcpy, - strcspn, strdup, strlen, strncat, - strncmp, strncpy, strndup, strnlen, - strpbrk, strrchr, strspn, strstr, - strtod, strtof, strtol, strtold, + sin, sinf, sinh, sinhf, + sinhl, sinl, siprintf, + sqrt, sqrtf, sqrtl, stpcpy, + strcat, strchr, strcmp, strcpy, + strcspn, strdup, strlen, strncat, + strncmp, strncpy, strndup, strnlen, + strpbrk, strrchr, strspn, strstr, + strtod, strtof, strtol, strtold, strtoll, strtoul, strtoull, tan, - tanf, tanh, tanhf, tanhl, - tanl, trunc, truncf, + tanf, tanh, tanhf, tanhl, + tanl, trunc, truncf, truncl, valloc, NumLibFuncs''') # not in llvm-3.2 abs, ffs, ffsl, ffsll, fprintf, isascii, # isdigit, labs, llabs, printf, sprintf, toascii diff --git a/llvmpy/src/Transforms/PassManagerBuilder.py b/llvmpy/src/Transforms/PassManagerBuilder.py index c940062..86be4fb 100644 --- a/llvmpy/src/Transforms/PassManagerBuilder.py +++ b/llvmpy/src/Transforms/PassManagerBuilder.py @@ -10,7 +10,7 @@ from src.Pass import Pass @PassManagerBuilder class PassManagerBuilder: _include_ = 'llvm/Transforms/IPO/PassManagerBuilder.h' - + new = Constructor() delete = Destructor() diff --git a/llvmpy/src/Type.py b/llvmpy/src/Type.py index ea1f0e5..874201e 100644 --- a/llvmpy/src/Type.py +++ b/llvmpy/src/Type.py @@ -201,7 +201,7 @@ class StructType: ).require_only(1) getNumElements = Method(cast(Unsigned, int)) getElementType = Method(ptr(Type), cast(int, Unsigned)) - + create = StaticMethod(ptr(StructType), ref(LLVMContext), cast(str, StringRef), diff --git a/llvmpy/src/Value.py b/llvmpy/src/Value.py index 669ed80..f9fddae 100644 --- a/llvmpy/src/Value.py +++ b/llvmpy/src/Value.py @@ -34,10 +34,10 @@ class Value: ValueTy = Enum(''' ArgumentVal, BasicBlockVal, FunctionVal, GlobalAliasVal, GlobalVariableVal, UndefValueVal, BlockAddressVal, ConstantExprVal, - ConstantAggregateZeroVal, ConstantDataArrayVal, ConstantDataVectorVal, - ConstantIntVal, ConstantFPVal, ConstantArrayVal, ConstantStructVal, - ConstantVectorVal, ConstantPointerNullVal, MDNodeVal, MDStringVal, - InlineAsmVal, PseudoSourceValueVal, FixedStackPseudoSourceValueVal, + ConstantAggregateZeroVal, ConstantDataArrayVal, ConstantDataVectorVal, + ConstantIntVal, ConstantFPVal, ConstantArrayVal, ConstantStructVal, + ConstantVectorVal, ConstantPointerNullVal, MDNodeVal, MDStringVal, + InlineAsmVal, PseudoSourceValueVal, FixedStackPseudoSourceValueVal, InstructionVal, ConstantFirstVal, ConstantLastVal ''') diff --git a/llvmpy/test_binding.py b/llvmpy/test_binding.py index aee0167..0e833e3 100644 --- a/llvmpy/test_binding.py +++ b/llvmpy/test_binding.py @@ -112,7 +112,7 @@ def test_basic_jit_use(): fpm.doInitialization() fpm.run(fn) fpm.doFinalization() - + pm.run(m) print(m) From a5078d6cd71090aa9139aa729e377b9714b7afed Mon Sep 17 00:00:00 2001 From: Hernan Grecco Date: Sun, 3 Mar 2013 17:27:01 -0300 Subject: [PATCH 334/516] Added testing infrastructure with travis --- .travis.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..95f434a --- /dev/null +++ b/.travis.yml @@ -0,0 +1,24 @@ +language: python + +python: + - "2.6" + - "2.7" + - "3.2" + - "3.3" + +branches: + only: + - master + +install: + - wget "http://repo.continuum.io/pkgs/free/linux-64/llvm-3.2-0.tar.bz2" + - tar -xjf llvm-3.2-0.tar.bz2 + - PATH+=":`pwd`/bin" + - export LD_LIBRARY_PATH="`pwd`/lib" + - export LLVM_CONFIG_PATH="`pwd`/bin/llvm-config" + - $LLVM_CONFIG_PATH --cflags # test llvm-config + - export LLVMPY_DYNLINK=1 + - python setup.py install -q + +script: python -c "import llvm; llvm.test()" + From 372d6018759744dee6dac70fc6814c452864b7c0 Mon Sep 17 00:00:00 2001 From: Hernan Grecco Date: Mon, 4 Mar 2013 23:28:10 -0300 Subject: [PATCH 335/516] Changed test command for travis --- .travis.yml | 2 +- llvm/__init__.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 95f434a..f4474f7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,5 +20,5 @@ install: - export LLVMPY_DYNLINK=1 - python setup.py install -q -script: python -c "import llvm; llvm.test()" +script: cd ~; python -c "import sys;import llvm;sys.exit(0 if llvm.test() == 0 else 1)" diff --git a/llvm/__init__.py b/llvm/__init__.py index e3e785f..8f71446 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -34,9 +34,11 @@ class LLVMException(Exception): def test(verbosity=1): """test(verbosity=1) -> TextTestResult - Run self-test, and return unittest.runner.TextTestResult object. + Run self-test, and return the number of failures + errors """ from llvm.test_llvmpy import run - return run(verbosity=verbosity) + result = run(verbosity=verbosity) + + return len(result.failures) + len(result.errors) From e4996f02d7573cec9033acb65176196a370710c8 Mon Sep 17 00:00:00 2001 From: Hernan Grecco Date: Mon, 4 Mar 2013 23:47:54 -0300 Subject: [PATCH 336/516] Fix for Python 3.2 --- llvmpy/include/python3adapt.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/llvmpy/include/python3adapt.h b/llvmpy/include/python3adapt.h index 5b19ebe..a60153f 100644 --- a/llvmpy/include/python3adapt.h +++ b/llvmpy/include/python3adapt.h @@ -9,13 +9,10 @@ #define PyBytes_FromStringAndSize PyString_FromStringAndSize #define PyBytes_FromString PyString_FromString -#endif - -#if (PY_VERSION_HEX >= 0x03000000) +#else #define PyString_Check PyUnicode_Check #define PyString_Size PyUnicode_GET_SIZE -#define PyString_AsString PyUnicode_AsUTF8 #define PyString_FromStringAndSize PyUnicode_FromStringAndSize #define PyString_FromString PyUnicode_FromString @@ -27,6 +24,12 @@ #define PyFile_Check(x) (1) +#if (PY_VERSION_HEX < 0x03030000) +#define PyString_AsString(x) PyBytes_AsString(PyUnicode_AsUTF8String(x)) +#else +#define PyString_AsString PyUnicode_AsUTF8 #endif -#endif //PYTHON3ADAPT_H \ No newline at end of file +#endif // (PY_VERSION_HEX < 0x03000000) + +#endif //PYTHON3ADAPT_H From 931352d4bfab72897dc8012c78d9f64739656226 Mon Sep 17 00:00:00 2001 From: Hernan Grecco Date: Tue, 5 Mar 2013 14:31:21 -0300 Subject: [PATCH 337/516] Fix memory leak in Python 3.2 --- llvmpy/include/python3adapt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvmpy/include/python3adapt.h b/llvmpy/include/python3adapt.h index a60153f..db7f28d 100644 --- a/llvmpy/include/python3adapt.h +++ b/llvmpy/include/python3adapt.h @@ -25,7 +25,7 @@ #define PyFile_Check(x) (1) #if (PY_VERSION_HEX < 0x03030000) -#define PyString_AsString(x) PyBytes_AsString(PyUnicode_AsUTF8String(x)) +#define PyString_AsString _PyUnicode_AsString #else #define PyString_AsString PyUnicode_AsUTF8 #endif From b8da3c7a7335e5b2f4a9cee14fe4ae5783fa000f Mon Sep 17 00:00:00 2001 From: Hernan Grecco Date: Tue, 5 Mar 2013 18:01:57 -0300 Subject: [PATCH 338/516] Changed imports in llpython --- llpython/byte_control.py | 8 ++++---- llpython/byte_flow.py | 6 +++--- llpython/byte_translator.py | 14 +++++++------- llpython/bytecode_visitor.py | 4 ++-- llpython/gen_bytecode_visitor.py | 4 ++-- llpython/nobitey.py | 7 +++---- llpython/phi_injector.py | 2 +- 7 files changed, 22 insertions(+), 23 deletions(-) diff --git a/llpython/byte_control.py b/llpython/byte_control.py index 9df6d5c..acd5a41 100644 --- a/llpython/byte_control.py +++ b/llpython/byte_control.py @@ -1,12 +1,12 @@ #! /usr/bin/env python # ______________________________________________________________________ - +from __future__ import absolute_import import opcode -import opcode_util +from . import opcode_util import pprint -from bytecode_visitor import BasicBlockVisitor, BenignBytecodeVisitorMixin -from control_flow import ControlFlowGraph +from .bytecode_visitor import BasicBlockVisitor, BenignBytecodeVisitorMixin +from .control_flow import ControlFlowGraph # ______________________________________________________________________ diff --git a/llpython/byte_flow.py b/llpython/byte_flow.py index 4a878b2..2201791 100644 --- a/llpython/byte_flow.py +++ b/llpython/byte_flow.py @@ -1,11 +1,11 @@ #! /usr/bin/env python # ______________________________________________________________________ - +from __future__ import absolute_import import dis import opcode -from bytecode_visitor import BasicBlockVisitor -import opcode_util +from .bytecode_visitor import BasicBlockVisitor +from . import opcode_util # ______________________________________________________________________ diff --git a/llpython/byte_translator.py b/llpython/byte_translator.py index 3922099..9b6d2de 100644 --- a/llpython/byte_translator.py +++ b/llpython/byte_translator.py @@ -4,19 +4,19 @@ ''' # ______________________________________________________________________ # Module imports - +from __future__ import absolute_import import opcode import types import logging import llvm.core as lc -import opcode_util -import bytetype -from bytecode_visitor import BytecodeFlowVisitor -from byte_flow import BytecodeFlowBuilder -from byte_control import ControlFlowBuilder -from phi_injector import PhiInjector, synthetic_opname +from . import opcode_util +from . import bytetype +from .bytecode_visitor import BytecodeFlowVisitor +from .byte_flow import BytecodeFlowBuilder +from .byte_control import ControlFlowBuilder +from .phi_injector import PhiInjector, synthetic_opname # ______________________________________________________________________ # Module data diff --git a/llpython/bytecode_visitor.py b/llpython/bytecode_visitor.py index dcc3a0c..009d1a0 100644 --- a/llpython/bytecode_visitor.py +++ b/llpython/bytecode_visitor.py @@ -1,10 +1,10 @@ #! /usr/bin/env python # ______________________________________________________________________ - +from __future__ import absolute_import import itertools import opcode -from opcode_util import itercode +from .opcode_util import itercode # ______________________________________________________________________ diff --git a/llpython/gen_bytecode_visitor.py b/llpython/gen_bytecode_visitor.py index 7f922e2..b29bc56 100644 --- a/llpython/gen_bytecode_visitor.py +++ b/llpython/gen_bytecode_visitor.py @@ -1,7 +1,7 @@ #! /usr/bin/env python # ______________________________________________________________________ - -import opcode_util +from __future__ import absolute_import +from . import opcode_util # ______________________________________________________________________ diff --git a/llpython/nobitey.py b/llpython/nobitey.py index 014216b..68bde5f 100644 --- a/llpython/nobitey.py +++ b/llpython/nobitey.py @@ -1,6 +1,6 @@ #! /usr/bin/env python # ______________________________________________________________________ - +from __future__ import absolute_import import sys import os.path import imp @@ -10,9 +10,8 @@ import types import llvm.core as lc import llvm.ee as le -import bytetype -import byte_translator -from pyaddfunc import pyaddfunc +from . import bytetype, byte_translator +from .pyaddfunc import pyaddfunc LLVM_TO_INT_PARSE_STR_MAP = { 8 : 'b', diff --git a/llpython/phi_injector.py b/llpython/phi_injector.py index 6cccb66..ee28ab5 100644 --- a/llpython/phi_injector.py +++ b/llpython/phi_injector.py @@ -1,7 +1,7 @@ #! /usr/bin/env python # ______________________________________________________________________ -from bytecode_visitor import BytecodeFlowVisitor, BenignBytecodeVisitorMixin +from .bytecode_visitor import BytecodeFlowVisitor, BenignBytecodeVisitorMixin # ______________________________________________________________________ From 3c4769c58d9e470ce720211063779086c836752b Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Tue, 5 Mar 2013 16:47:31 -0600 Subject: [PATCH 339/516] test bug: only attempt to compile when cc is available --- llvm/test_llvmpy.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index c96f471..8df32b8 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -9,6 +9,7 @@ import unittest import subprocess import tempfile import contextlib +from distutils.spawn import find_executable is_py3k = sys.version_info[0] >= 3 BITS = tuple.__itemsize__ * 8 @@ -31,7 +32,6 @@ import llvmpy tests = [] - # --------------------------------------------------------------------------- if sys.version_info[:2] <= (2, 6): @@ -674,6 +674,7 @@ tests.append(TestTargetMachines) # --------------------------------------------------------------------------- class TestNative(TestCase): + def setUp(self): self.tmpdir = tempfile.mkdtemp() @@ -694,8 +695,12 @@ class TestNative(TestCase): 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]) + s = subprocess.call([cc, '-o', dst, src]) if s != 0: raise Exception("Cannot compile") From 67f4acf91f09cd12c64d6238e5d17f9ffa1a5979 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Tue, 5 Mar 2013 16:49:40 -0600 Subject: [PATCH 340/516] update changelog --- CHANGELOG | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index d2e2263..46b7a92 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,9 @@ -2013-02-XX 0.11.0: +2013-03-05 0.11.1: +-------------------- + * fix test when cc is not available + + +2013-03-01 0.11.0: -------------------- * fix Python 3 support on Windows * New llvm binding From e63bdd6da24b7198311a08433bc38e287e6c3439 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 5 Mar 2013 17:17:21 -0600 Subject: [PATCH 341/516] Update changelog --- CHANGELOG | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 46b7a92..c36288a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,8 @@ 2013-03-05 0.11.1: -------------------- * fix test when cc is not available - + * fix Python 3 division (Hernan Grecco) (Issue #59) + * add relocation enums and add reloc argument for TargetMachine 2013-03-01 0.11.0: -------------------- From 6f524130d0e43109543182b753701435a7c36c2b Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Tue, 5 Mar 2013 17:21:28 -0600 Subject: [PATCH 342/516] formatting --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index c36288a..5af6169 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,7 @@ * fix Python 3 division (Hernan Grecco) (Issue #59) * add relocation enums and add reloc argument for TargetMachine + 2013-03-01 0.11.0: -------------------- * fix Python 3 support on Windows From bd129baa0a4413f5872baf8981a92c78ecd27a01 Mon Sep 17 00:00:00 2001 From: Hernan Grecco Date: Mon, 11 Mar 2013 15:51:03 -0300 Subject: [PATCH 343/516] Reimplemented FunctionAlreadyExists and usage (Exceptions are not iterable in Python 3) --- llvm_cbuilder/builder.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 9b970f4..648f384 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -14,7 +14,9 @@ from . import shortnames as types ### class FunctionAlreadyExists(NameError): - pass + + def __init__(self, func): + self.func = func def _is_int(ty): return isinstance(ty, lc.IntegerType) @@ -830,7 +832,7 @@ class CDefinition(object): try: func = self.define(module) except FunctionAlreadyExists as e: - (func,) = e + func = e.func return func def __getattr__(self, attr): From ec0dda4621855e845b276b3b48f743a1eb377ad7 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 12 Mar 2013 21:35:51 -0500 Subject: [PATCH 344/516] Fix ownership bug --- llvm/passes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/passes.py b/llvm/passes.py index 6216724..068a7a3 100644 --- a/llvm/passes.py +++ b/llvm/passes.py @@ -336,7 +336,7 @@ def build_pass_managers(tm, opt=2, loop_vectorize=False, vectorize=False, pmb.populate(pm) if fpm: - fpm.add(tm.target_data) + fpm.add(tm.target_data.clone()) fpm.add(TargetLibraryInfo.new(tm.triple)) if llvm.version >= (3, 2): fpm.add(TargetTransformInfo.new(tm)) From b913b2840e9ec758b0b387f7afef0ff36af33b03 Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Thu, 14 Mar 2013 15:21:14 +0000 Subject: [PATCH 345/516] Support non-inplace versions of bitwise left and right shift, and, or and xor --- llvm_cbuilder/builder.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 648f384..eaabd67 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -999,22 +999,22 @@ class IntegerValue(OperatorMixin): else: return self._temp(self.parent.builder.srem(self.value, rhs.value)) - def __ilshift__(self, rhs): + def __lshift__(self, rhs): return self._temp(self.parent.builder.shl(self.value, rhs.value)) - def __irshift__(self, rhs): + def __rshift__(self, rhs): if self.unsigned: return self._temp(self.self.parent.builder.lshr(self.value, rhs.value)) else: return self._temp(self.parent.builder.ashr(self.value, rhs.value)) - def __iand__(self, rhs): + def __and__(self, rhs): return self._temp(self.parent.builder.and_(self.value, rhs.value)) - def __ior__(self, rhs): + def __or__(self, rhs): return self._temp(self.parent.builder.or_(self.value, rhs.value)) - def __ixor__(self, rhs): + def __xor__(self, rhs): return self._temp(self.parent.builder.xor(self.value, rhs.value)) def __lt__(self, rhs): From d06a5f3eb401768e89b06d856ff918ceda668af8 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sun, 24 Mar 2013 14:56:26 -0500 Subject: [PATCH 346/516] Fix setOptLevel in EngineBuilder --- llvm/ee.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/ee.py b/llvm/ee.py index 9531427..1ef16ae 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -132,7 +132,7 @@ class EngineBuilder(llvm.Wrapper): level valid [0, 1, 2, 3] -- [None, Less, Default, Aggressive] ''' assert 0 <= level <= 3 - self._ptr.setOptLevel = level + self._ptr.setOptLevel(level) return self def mattrs(self, string): From a8c78a6e2efa707d823769c6c62740afb47b1576 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sun, 24 Mar 2013 14:57:04 -0500 Subject: [PATCH 347/516] Temporily remove setErrorStr. Current implementation does not work. --- llvmpy/include/llvm_binding/extra.h | 32 +++++++++++++---------------- llvmpy/src/EngineBuilder.py | 6 +++--- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/llvmpy/include/llvm_binding/extra.h b/llvmpy/include/llvm_binding/extra.h index 0e2d0a0..6626ede 100644 --- a/llvmpy/include/llvm_binding/extra.h +++ b/llvmpy/include/llvm_binding/extra.h @@ -401,24 +401,20 @@ PyObject* ExecutionEngine_RunFunction(llvm::ExecutionEngine* EE, return pycapsule_new(new GenericValue(ret), GVN); } -static -PyObject* EngineBuilder_setErrorStr(llvm::EngineBuilder* eb, PyObject* fileobj) -{ - - if (!PyFile_Check(fileobj)) { - PyErr_SetString(PyExc_TypeError, "Expecting a file object."); - return NULL; - } - - std::string buffer; - eb->setErrorStr(&buffer); - - if (-1 == PyFile_WriteString(buffer.c_str(), fileobj)) { - return NULL; - } - - return pycapsule_new(eb, "llvm::EngineBuilder"); -} +// FIXME +//static +//PyObject* EngineBuilder_setErrorStr(llvm::EngineBuilder* eb, PyObject* fileobj) +//{ +// +// std::string buffer; +// eb->setErrorStr(&buffer); +// +// if (-1 == PyFile_WriteString(buffer.c_str(), fileobj)) { +// return NULL; +// } +// +// return pycapsule_new(eb, "llvm::EngineBuilder"); +//} static PyObject* EngineBuilder_setMAttrs(llvm::EngineBuilder* eb, diff --git a/llvmpy/src/EngineBuilder.py b/llvmpy/src/EngineBuilder.py index 4e8ed12..ef3277f 100644 --- a/llvmpy/src/EngineBuilder.py +++ b/llvmpy/src/EngineBuilder.py @@ -23,9 +23,9 @@ class EngineBuilder: setEngineKind = _setter(Kind) setJITMemoryManager = _setter(ptr(JITMemoryManager)) - - setErrorStr = CustomMethod('EngineBuilder_setErrorStr', - PyObjectPtr, PyObjectPtr) +# FIXME +# setErrorStr = CustomMethod('EngineBuilder_setErrorStr', +# PyObjectPtr, PyObjectPtr) setOptLevel = _setter(CodeGenOpt.Level) #setTargetOptions = From 1b2a9dec9a999076ec2637bf64444c4ab991599b Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sun, 24 Mar 2013 14:57:23 -0500 Subject: [PATCH 348/516] Add splitBasicBlock --- llvmpy/src/BasicBlock.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/llvmpy/src/BasicBlock.py b/llvmpy/src/BasicBlock.py index 868b3c9..6efe704 100644 --- a/llvmpy/src/BasicBlock.py +++ b/llvmpy/src/BasicBlock.py @@ -24,3 +24,7 @@ class BasicBlock: getInstList = CustomMethod('BasicBlock_getInstList', PyObjectPtr) eraseFromParent = Method() + + splitBasicBlock = Method(ptr(BasicBlock), ptr(Instruction), + cast(str, StringRef)).require_only(1) + From 8800ebac6660e5536355bc05546db7867072f1f7 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sun, 24 Mar 2013 14:57:36 -0500 Subject: [PATCH 349/516] Add downcast mapping --- llvmpy/src/Constant.py | 20 ++++---- llvmpy/src/GlobalVariable.py | 3 +- llvmpy/src/Instruction.py | 92 ++++++++++++++++++++---------------- 3 files changed, 64 insertions(+), 51 deletions(-) diff --git a/llvmpy/src/Constant.py b/llvmpy/src/Constant.py index 8a091b5..77bd835 100644 --- a/llvmpy/src/Constant.py +++ b/llvmpy/src/Constant.py @@ -1,6 +1,6 @@ from binding import * from .namespace import llvm -from .Value import Value +from .Value import Value, User from .Value import Constant, UndefValue, ConstantInt, ConstantFP, ConstantArray from .Value import ConstantStruct, ConstantVector, ConstantVector from .Value import ConstantDataSequential, ConstantDataArray, ConstantExpr @@ -12,7 +12,7 @@ from .Instruction import CmpInst @Constant class Constant: - _downcast_ = Value + _downcast_ = Value, User isNullValue = Method(cast(bool, Bool)) isAllOnesValue = Method(cast(bool, Bool)) @@ -72,7 +72,7 @@ class UndefValue: @ConstantInt class ConstantInt: - _downcast_ = Constant, Value + _downcast_ = Constant, User, Value get = StaticMethod(ptr(ConstantInt), ptr(IntegerType), @@ -88,7 +88,7 @@ class ConstantInt: @ConstantFP class ConstantFP: - _downcast_ = Constant, Value + _downcast_ = Constant, User, Value get = StaticMethod(ptr(Constant), ptr(Type), cast(float, Double)) getNegativeZero = StaticMethod(ptr(ConstantFP), ptr(Type)) @@ -102,7 +102,7 @@ class ConstantFP: @ConstantArray class ConstantArray: - _downcast_ = Constant, Value + _downcast_ = Constant, User, Value get = CustomStaticMethod('ConstantArray_get', PyObjectPtr, # ptr(Constant), @@ -113,7 +113,7 @@ class ConstantArray: @ConstantStruct class ConstantStruct: - _downcast_ = Constant, Value + _downcast_ = Constant, User, Value get = CustomStaticMethod('ConstantStruct_get', PyObjectPtr, # ptr(Constant) @@ -129,7 +129,7 @@ class ConstantStruct: @ConstantVector class ConstantVector: - _downcast_ = Constant, Value + _downcast_ = Constant, User, Value get = CustomStaticMethod('ConstantVector_get', PyObjectPtr, # ptr(Constant) @@ -139,12 +139,12 @@ class ConstantVector: @ConstantDataSequential class ConstantDataSequential: - _downcast_ = Constant, Value + _downcast_ = Constant, User, Value @ConstantDataArray class ConstantDataArray: - _downcast_ = Constant, Value + _downcast_ = Constant, User, Value getString = StaticMethod(ptr(Constant), ref(LLVMContext), @@ -177,7 +177,7 @@ def _factory_const_type(): @ConstantExpr class ConstantExpr: - _downcast_ = Constant, Value + _downcast_ = Constant, User, Value getAlignOf = _factory(ptr(Type)) getSizeOf = _factory(ptr(Type)) diff --git a/llvmpy/src/GlobalVariable.py b/llvmpy/src/GlobalVariable.py index 8b196c0..e319e52 100644 --- a/llvmpy/src/GlobalVariable.py +++ b/llvmpy/src/GlobalVariable.py @@ -7,10 +7,11 @@ GlobalVariable = llvm.Class(GlobalValue) from .Module import Module from .Type import Type from .ADT.StringRef import StringRef -from .Value import Constant +from .Value import Value, User, Constant @GlobalVariable class GlobalVariable: + _downcast_ = Value, User ThreadLocalMode = Enum('''NotThreadLocal, GeneralDynamicTLSModel, LocalDynamicTLSModel, InitialExecTLSModel, LocalExecTLSModel diff --git a/llvmpy/src/Instruction.py b/llvmpy/src/Instruction.py index 16f57c2..edde8bc 100644 --- a/llvmpy/src/Instruction.py +++ b/llvmpy/src/Instruction.py @@ -110,6 +110,9 @@ class Instruction: clone = Method(ptr(Instruction)) + getNextNode = Method(ptr(Instruction)) + getPrevNode = Method(ptr(Instruction)) + # LLVM 3.3 # hasUnsafeAlgebra = Method(cast(Bool, bool)) # hasNoNans = Method(cast(Bool, bool)) @@ -120,17 +123,17 @@ class Instruction: @AtomicCmpXchgInst class AtomicCmpXchgInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @AtomicRMWInst class AtomicRMWInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction BinOp = Enum('Xchg', 'Add', 'Sub', 'And', 'Nand', 'Or', 'Xor', 'Max', 'Min', 'UMax', 'UMin', 'FIRST_BINOP', 'LAST_BINOP', 'BAD_BINOP') @BinaryOperator class BinaryOperator: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @CallInst class CallInst: @@ -160,7 +163,7 @@ class CallInst: @CmpInst class CmpInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction Predicate = Enum('FCMP_FALSE', 'FCMP_OEQ', 'FCMP_OGT', 'FCMP_OGE', 'FCMP_OLT', 'FCMP_OLE', 'FCMP_ONE', 'FCMP_ORD', 'FCMP_UNO', 'FCMP_UEQ', 'FCMP_UGT', 'FCMP_UGE', 'FCMP_ULT', 'FCMP_ULE', @@ -177,31 +180,31 @@ class CmpInst: @ExtractElementInst class ExtractElementInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @FenceInst class FenceInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @GetElementPtrInst class GetElementPtrInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @InsertElementInst class InsertElementInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @InsertValueInst class InsertValueInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @LandingPadInst class LandingPadInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @PHINode class PHINode: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction getNumIncomingValues = Method(cast(Unsigned, int)) getIncomingValue = Method(ptr(Value), cast(int, Unsigned)) setIncomingValue = Method(Void, cast(int, Unsigned), ptr(Value)) @@ -213,15 +216,15 @@ class PHINode: @SelectInst class SelectInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @ShuffleVectorInst class ShuffleVectorInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @StoreInst class StoreInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction isVolatile = Method(cast(Bool, bool)) isSimple = Method(cast(Bool, bool)) isUnordered = Method(cast(Bool, bool)) @@ -240,40 +243,40 @@ class StoreInst: @TerminatorInst class TerminatorInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction getNumSuccessors = Method(cast(Unsigned, int)) getSuccessor = Method(ptr(BasicBlock), cast(int, Unsigned)) setSuccessor = Method(Void, cast(int, Unsigned), ptr(BasicBlock)) @UnaryInstruction class UnaryInstruction: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction #call @IntrinsicInst class IntrinsicInst: _include_ = 'llvm/IntrinsicInst.h' - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction #compare @FCmpInst class FCmpInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @ICmpInst class ICmpInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction # terminator @BranchInst class BranchInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @IndirectBrInst class IndirectBrInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @InvokeInst class InvokeInst: @@ -289,15 +292,17 @@ class InvokeInst: @ResumeInst class ResumeInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @ReturnInst class ReturnInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction, TerminatorInst + getReturnValue = Method(ptr(Value)) + getNumSuccessors = Method(cast(Unsigned, int)) @SwitchInst class SwitchInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction getCondition = Method(ptr(Value)) setCondition = Method(Void, ptr(Value)) @@ -309,24 +314,29 @@ class SwitchInst: @UnreachableInst class UnreachableInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction # unary @AllocaInst class AllocaInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction + isArrayAllocation = Method(cast(Bool, bool)) + isStaticAlloca = Method(cast(Bool, bool)) + getArraySize = Method(ptr(Value)) + getAllocatedType = Method(ptr(Type)) + @CastInst class CastInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @ExtractValueInst class ExtractValueInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @LoadInst class LoadInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction isVolatile = Method(cast(Bool, bool)) isSimple = Method(cast(Bool, bool)) isUnordered = Method(cast(Bool, bool)) @@ -341,50 +351,52 @@ class LoadInst: AtomicOrdering, SynchronizationScope).require_only(1) + getPointerOperand = Method(ptr(Value)) + classof = StaticMethod(cast(Bool, bool), ptr(Value)) @VAArgInst class VAArgInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction # intrinsic @DbgInfoIntrinsic class DbgInfoIntrinsic: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @MemIntrinsic class MemIntrinsic: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @VACopyInst class VACopyInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @VAEndInst class VAEndInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @VAStartInst class VAStartInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @BitCastInst class BitCastInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @FPExtInst class FPExtInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @FPToSIInst class FPToSIInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @FPToUIInst class FPToUIInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction @FPTruncInst class FPTruncInst: - _downcast_ = Value, Instruction + _downcast_ = Value, User, Instruction From b6c1e7a961ca32178023593ad03bd1ab735553b2 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sun, 24 Mar 2013 14:57:58 -0500 Subject: [PATCH 350/516] Add some utils in BasicBlockUtils.h --- llvmpy/src/Transforms/Utils/BasicBlockUtils.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 llvmpy/src/Transforms/Utils/BasicBlockUtils.py diff --git a/llvmpy/src/Transforms/Utils/BasicBlockUtils.py b/llvmpy/src/Transforms/Utils/BasicBlockUtils.py new file mode 100644 index 0000000..8a571c2 --- /dev/null +++ b/llvmpy/src/Transforms/Utils/BasicBlockUtils.py @@ -0,0 +1,16 @@ +from binding import * +from src.namespace import llvm +from src.Value import MDNode +from src.Instruction import Instruction, TerminatorInst +llvm.includes.add('llvm/Transforms/Utils/BasicBlockUtils.h') + +SplitBlockAndInsertIfThen = llvm.Function('SplitBlockAndInsertIfThen', + ptr(TerminatorInst), + ptr(Instruction), # cmp + cast(bool, Bool), # unreachable + ptr(MDNode)) # branchweights + +ReplaceInstWithInst = llvm.Function('ReplaceInstWithInst', + Void, + ptr(Instruction), # from + ptr(Instruction)) # to \ No newline at end of file From 6c2ed9a3ed6fa204dba3290fc0a1f992437eafa3 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 25 Mar 2013 11:23:16 -0500 Subject: [PATCH 351/516] Add some more to CallInst and StoreInst --- llvmpy/src/Instruction.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/llvmpy/src/Instruction.py b/llvmpy/src/Instruction.py index edde8bc..e17e8a1 100644 --- a/llvmpy/src/Instruction.py +++ b/llvmpy/src/Instruction.py @@ -161,6 +161,10 @@ class CallInst: CreateFree = StaticMethod(ptr(Instruction), ptr(Value), ptr(BasicBlock)) + getNumArgOperands = Method(cast(Unsigned, int)) + getArgOperand = Method(ptr(Value), cast(int, Unsigned)) + setArgOperand = Method(Void, cast(int, Unsigned), ptr(Value)) + @CmpInst class CmpInst: _downcast_ = Value, User, Instruction @@ -239,6 +243,10 @@ class StoreInst: AtomicOrdering, SynchronizationScope).require_only(1) + getValueOperand = Method(ptr(Value)) + getPointerOperand = Method(ptr(Value)) + getPointerAddressSpace = Method(cast(Unsigned, int)) + classof = StaticMethod(cast(Bool, bool), ptr(Value)) @TerminatorInst From b14161c1847569c5667a54a9dd3260b06cf1d817 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 25 Mar 2013 17:23:41 -0500 Subject: [PATCH 352/516] Add Constant to GlobalVariable cast --- llvmpy/src/GlobalVariable.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvmpy/src/GlobalVariable.py b/llvmpy/src/GlobalVariable.py index e319e52..bffa9ee 100644 --- a/llvmpy/src/GlobalVariable.py +++ b/llvmpy/src/GlobalVariable.py @@ -11,7 +11,7 @@ from .Value import Value, User, Constant @GlobalVariable class GlobalVariable: - _downcast_ = Value, User + _downcast_ = Value, User, Constant ThreadLocalMode = Enum('''NotThreadLocal, GeneralDynamicTLSModel, LocalDynamicTLSModel, InitialExecTLSModel, LocalExecTLSModel From b13aee066849f21e0d0acd3106283ce1d4014fdd Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 28 Mar 2013 22:05:12 -0500 Subject: [PATCH 353/516] Two llvm wrapped instances are the same if they point to the same thing --- llvmpy/capsule.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/llvmpy/capsule.py b/llvmpy/capsule.py index e3b9537..9c1e86a 100644 --- a/llvmpy/capsule.py +++ b/llvmpy/capsule.py @@ -76,7 +76,7 @@ class Capsule(object): return False def __hash__(self): - return super(Capsule, self).__hash__() + return hash((self.pointer, self.name)) def __ne__(self, other): return not (self == other) @@ -174,13 +174,13 @@ class Wrapper(object): return self._capsule.capsule def __hash__(self): - return super(Wrapper, self).__hash__() + return hash(self._capsule) def __eq__(self, other): return self._capsule == other._capsule def __ne__(self, other): - return self._capsule != other._capsule + return not(self == other) def _downcast(self, newcls): return downcast(self, newcls) From 22b5d4695cbec0382831b2091666580cc372765c Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 1 Apr 2013 11:24:09 -0500 Subject: [PATCH 354/516] Add mutateType --- llvmpy/src/Value.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/llvmpy/src/Value.py b/llvmpy/src/Value.py index f9fddae..fb9c3cc 100644 --- a/llvmpy/src/Value.py +++ b/llvmpy/src/Value.py @@ -71,3 +71,5 @@ class Value: return os.str() getValueID = Method(cast(Unsigned, int)) + + mutateType = Method(Void, ptr(Type)) From 0b1abe7b26d35f11e826111c9fa026d087dd49d5 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 1 Apr 2013 11:24:19 -0500 Subject: [PATCH 355/516] Add isLayoutIdentical --- llvm/core.py | 4 ++++ llvm/test_llvmpy.py | 12 ++++++++++++ llvmpy/src/Type.py | 2 ++ 3 files changed, 18 insertions(+) diff --git a/llvm/core.py b/llvm/core.py index bbe5d01..719c8a4 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -895,6 +895,10 @@ class StructType(Type): def is_opaque(self): return self._ptr.isOpaque() + def is_layout_identical(self, other): + return self._ptr.isLayoutIdentical(other._ptr) + + class ArrayType(Type): """Represents an array type.""" _type_ = api.llvm.ArrayType diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 8df32b8..945ac41 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -1245,6 +1245,18 @@ class TestNamedMetaData(TestCase): tests.append(TestNamedMetaData) + +# --------------------------------------------------------------------------- + +class TestStruct(TestCase): + def test_struct_identical(self): + m = Module.new('test_struct_identical') + 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)) + +tests.append(TestStruct) + # --------------------------------------------------------------------------- def run(verbosity=1): diff --git a/llvmpy/src/Type.py b/llvmpy/src/Type.py index 874201e..afc148c 100644 --- a/llvmpy/src/Type.py +++ b/llvmpy/src/Type.py @@ -214,6 +214,8 @@ class StructType: cast(bool, Bool), # is packed ).require_only(2) + isLayoutIdentical = Method(cast(Bool, bool), # identical? + ptr(StructType)) # other isValidElementType = StaticMethod(cast(Bool, bool), ptr(Type)) From fab52057ba6b44a334e8eb004a1549f2ffe96b6a Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 8 Apr 2013 11:14:11 -0500 Subject: [PATCH 356/516] Improve docs on LLVM build instruction --- README.rst | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index b16249a..a9817ac 100644 --- a/README.rst +++ b/README.rst @@ -16,13 +16,18 @@ Other Python versions may work. Quickstart ---------- -1. Get 3.2 version of LLVM, build it. Make sure ``--enable-pic`` is - passed to LLVM's ``configure``. +1. Get and extract LLVM 3.2 source tarball. - For LLVM 3.2, make sure that environment variable ``REQUIRES_RTTI=1`` is - defined when running ``make``. Otherwise, you may see "undefined symbol: - _ZTIN4llvm24PassRegistrationListenerE". Please refer to - http://llvm.org/docs/Packaging.html#c-features for details. +2. Run ``./configure --enable-optimized`` in the extracted directory. + + **Note**: Without the ``--enable-optimized`` flag, debug build will be + selected. Unless you are developing LLVM or llvmpy, it is recommended + that the flag is used to reduce build time and binary size. + +3. Run ``REQUIRES_RTTI=1 make`` to build. + + **Note**: With LLVM 3.2, the default build configuration has C++ RTTI + disabled. However, llvmpy requires RTTI. 2. Get llvm-py and install it:: @@ -36,6 +41,14 @@ Quickstart 3. See documentation at 'http://www.llvmpy.org' and examples under 'test'. + +Common Build Problems +--------------------- + +1. If llvmpy cannot be imported due to "undefined symbol: + _ZTIN4llvm24PassRegistrationListenerE", it is because RTTI is not enabled + when building LLVM. "_ZTIN4llvm24PassRegistrationListenerE" is the typeinfo + of PassRegistrationListener class. LICENSE ------- From ca8fa2593a651b74327817700193c5a3ad766fac Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 8 Apr 2013 11:17:51 -0500 Subject: [PATCH 357/516] Add LLVM source link --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index a9817ac..aea8f64 100644 --- a/README.rst +++ b/README.rst @@ -16,7 +16,7 @@ Other Python versions may work. Quickstart ---------- -1. Get and extract LLVM 3.2 source tarball. +1. Get and extract LLVM 3.2 source tarball from `llvm.org `_. 2. Run ``./configure --enable-optimized`` in the extracted directory. From 003768cdea0632e0fb64b81fe6aa9b980ae0e94e Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 8 Apr 2013 11:20:21 -0500 Subject: [PATCH 358/516] Prettify docs. (Does this trigger a NOTE section?) --- README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index aea8f64..10f945b 100644 --- a/README.rst +++ b/README.rst @@ -20,9 +20,9 @@ Quickstart 2. Run ``./configure --enable-optimized`` in the extracted directory. - **Note**: Without the ``--enable-optimized`` flag, debug build will be - selected. Unless you are developing LLVM or llvmpy, it is recommended - that the flag is used to reduce build time and binary size. + **Note**: Without the ``--enable-optimized`` flag, debug build will be + selected. Unless you are developing LLVM or llvmpy, it is recommended + that the flag is used to reduce build time and binary size. 3. Run ``REQUIRES_RTTI=1 make`` to build. From 2479c2dc22f1df98fcc45bf4d72368f481e98893 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 8 Apr 2013 11:28:42 -0500 Subject: [PATCH 359/516] More detail --- README.rst | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index 10f945b..0fbcd24 100644 --- a/README.rst +++ b/README.rst @@ -16,30 +16,36 @@ Other Python versions may work. Quickstart ---------- -1. Get and extract LLVM 3.2 source tarball from `llvm.org `_. +1. Get and extract LLVM 3.2 source tarball from + `llvm.org `_. Then, ``cd`` into + the extracted directory. -2. Run ``./configure --enable-optimized`` in the extracted directory. +2. Run ``./configure --enable-optimized --prefix=LLVM_INSTALL_PATH``. **Note**: Without the ``--enable-optimized`` flag, debug build will be selected. Unless you are developing LLVM or llvmpy, it is recommended that the flag is used to reduce build time and binary size. + + **Note**: Use prefix to select the installation path. It is recommended + to separate your custom build from the default system package. Please + replace ``LLVM_INSTALL_PATH`` with your own path. 3. Run ``REQUIRES_RTTI=1 make`` to build. **Note**: With LLVM 3.2, the default build configuration has C++ RTTI disabled. However, llvmpy requires RTTI. -2. Get llvm-py and install it:: +4. Get llvm-py and install it:: $ git clone git@github.com:llvmpy/llvmpy.git $ cd llvmpy - $ python setup.py install + $ LLVM_CONFIG_PATH=LLVM_INSTALL_PATH/bin/llvm-config python setup.py install Run the tests:: $ python -c "import llvm; llvm.test()" -3. See documentation at 'http://www.llvmpy.org' and examples +5. See documentation at 'http://www.llvmpy.org' and examples under 'test'. Common Build Problems From 125e65e2613a1bbaf3a319a96d9939c09238be4f Mon Sep 17 00:00:00 2001 From: David H Post Date: Wed, 10 Apr 2013 15:15:19 -0500 Subject: [PATCH 360/516] Fix corrupted text and example in 7.3 Memory in LLVM --- docs/source/doc/kaleidoscope/PythonLangImpl7.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl7.rst b/docs/source/doc/kaleidoscope/PythonLangImpl7.rst index 7e86ee4..dee1c31 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl7.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl7.rst @@ -121,8 +121,8 @@ to talk about how LLVM represents stack variables. In LLVM, all memory accesses are explicit with load/store instructions, and it is carefully designed not to have (or need) an "address-of" operator. Notice how the type of the @G/@H global variables is actually -"i32\ *" even though the variable is defined as "i32". What this means -is that @G defines* space* for an i32 in the global data area, but its +"i32\*" even though the variable is defined as "i32". What this means +is that @G defines *space* for an i32 in the global data area, but its *name* actually refers to the address for that space. Stack variables work the same way, except that instead of being declared with global variable definitions, they are declared with the `LLVM alloca @@ -133,11 +133,11 @@ instruction `_: define i32 @example() { entry: - %X = alloca i32 ; type of %X is i32 *. + %X = alloca i32 ; type of %X is i32* ... - %tmp = load i32* %X ; load the stack value %X from the stack. - %tmp2 = add i32 %tmp, 1 ; increment it store i32 %tmp2, - i32* %X ; store it back + %tmp = load i32* %X ; load the stack value %X from the stack + %tmp2 = add i32 %tmp, 1 ; increment it + store i32 %tmp2, i32* %X ; store it back ... From 66346ee507d600da121713c039ecbfa501d27b90 Mon Sep 17 00:00:00 2001 From: David H Post Date: Thu, 11 Apr 2013 02:36:00 -0500 Subject: [PATCH 361/516] Corruption fixed in doc/llvm.core.Constant.rst (bottom of page needs work) --- docs/source/doc/llvm.core.Constant.rst | 657 +++++++++++++------------ 1 file changed, 329 insertions(+), 328 deletions(-) diff --git a/docs/source/doc/llvm.core.Constant.rst b/docs/source/doc/llvm.core.Constant.rst index ae67fa4..3822046 100644 --- a/docs/source/doc/llvm.core.Constant.rst +++ b/docs/source/doc/llvm.core.Constant.rst @@ -26,334 +26,335 @@ some examples: tr = Type.float() - r1 = Constant.real(tr, "3.141592") # create from a string r2 = - Constant.real(tr, 1.61803399) # create from a Python float {% - endhighlight %} - - # llvm.core.Constant - - This will become a table of contents (this text will be scraped). - {:toc} - - Static factory methods - ---------------------- - - ``null(ty)`` - ~~~~~~~~~~~~ - - A null value (all zeros) of type ``ty`` - - ``all_ones(ty)`` - ~~~~~~~~~~~~~~~~ - - All 1's value of type ``ty`` - - ``undef(ty)`` - ~~~~~~~~~~~~~ - - An undefined value of type ``ty`` - - ``int(ty, value)`` - ~~~~~~~~~~~~~~~~~~ - - Integer of type ``ty``, with value ``value`` (a Python int or long) - - ``int_signextend(ty, value)`` - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Integer of signed type ``ty`` (use for signed types) - - ``real(ty, value)`` - ~~~~~~~~~~~~~~~~~~~ - - Floating point value of type ``ty``, with value ``value`` (a Python - float) - - ``stringz(value)`` - ~~~~~~~~~~~~~~~~~~ - - A null-terminated string. ``value`` is a Python string - - ``string(value)`` - ~~~~~~~~~~~~~~~~~ - - As ``string(ty)``, but not null terminated - - ``array(ty, consts)`` - ~~~~~~~~~~~~~~~~~~~~~ - - Array of type ``ty``, initialized with ``consts`` (an iterable yielding - ``Constant`` objects of the appropriate type) - - ``struct(ty, consts)`` - ~~~~~~~~~~~~~~~~~~~~~~ - - Struct (unpacked) of type ``ty``, initialized with ``consts`` (an - iterable yielding ``Constant`` objects of the appropriate type) - - ``packed_struct(ty, consts)`` - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - As ``struct(ty, consts)`` but packed - - ``vector(consts)`` - ~~~~~~~~~~~~~~~~~~ - - Vector, initialized with ``consts`` (an iterable yielding ``Constant`` - objects of the appropriate type) - - ``sizeof(ty)`` - ~~~~~~~~~~~~~~ - - Constant value representing the sizeof the type ``ty`` - - Methods - ------- - - The following operations on constants are supported. For more details on - any operation, consult the `Constant - Expressions `_ - section of the LLVM Language Reference. - - ``k.neg()`` - ~~~~~~~~~~~ - - negation, same as ``0 - k`` - - ``k.not_()`` - ~~~~~~~~~~~~ - - 1's complement of ``k``. Note trailing underscore. - - ``k.add(k2)`` - ~~~~~~~~~~~~~ - - ``k + k2``, where ``k`` and ``k2`` are integers. - - ``k.fadd(k2)`` - ~~~~~~~~~~~~~~ - - ``k + k2``, where ``k`` and ``k2`` are floating-point. - - ``k.sub(k2)`` - ~~~~~~~~~~~~~ - - ``k - k2``, where ``k`` and ``k2`` are integers. - - ``k.fsub(k2)`` - ~~~~~~~~~~~~~~ - - ``k - k2``, where ``k`` and ``k2`` are floating-point. - - ``k.mul(k2)`` - ~~~~~~~~~~~~~ - - ``k * k2``, where ``k`` and ``k2`` are integers. - - ``k.fmul(k2)`` - ~~~~~~~~~~~~~~ - - ``k * k2``, where ``k`` and ``k2`` are floating-point. - - ``k.udiv(k2)`` - ~~~~~~~~~~~~~~ - - Quotient of unsigned division of ``k`` with ``k2`` - - ``k.sdiv(k2)`` - ~~~~~~~~~~~~~~ - - Quotient of signed division of ``k`` with ``k2`` - - ``k.fdiv(k2)`` - ~~~~~~~~~~~~~~ - - Quotient of floating point division of ``k`` with ``k2`` - - ``k.urem(k2)`` - ~~~~~~~~~~~~~~ - - Reminder of unsigned division of ``k`` with ``k2`` - - ``k.srem(k2)`` - ~~~~~~~~~~~~~~ - - Reminder of signed division of ``k`` with ``k2`` - - ``k.frem(k2)`` - ~~~~~~~~~~~~~~ - - Reminder of floating point division of ``k`` with ``k2`` - - ``k.and_(k2)`` - ~~~~~~~~~~~~~~ - - Bitwise and of ``k`` and ``k2``. Note trailing underscore. - - ``k.or_(k2)`` - ~~~~~~~~~~~~~ - - Bitwise or of ``k`` and ``k2``. Note trailing underscore. - - ``k.xor(k2)`` - ~~~~~~~~~~~~~ - - Bitwise exclusive-or of ``k`` and ``k2``. - - ``k.icmp(icmp, k2)`` - ~~~~~~~~~~~~~~~~~~~~ - - Compare ``k`` with ``k2`` using the predicate ``icmp``. See - `here `_ for list of predicates for integer - operands. - - ``k.fcmp(fcmp, k2)`` - ~~~~~~~~~~~~~~~~~~~~ - - Compare ``k`` with ``k2`` using the predicate ``fcmp``. See - `here `_ for list of predicates for real - operands. - - ``k.shl(k2)`` - ~~~~~~~~~~~~~ - - Shift ``k`` left by ``k2`` bits. - - ``k.lshr(k2)`` - ~~~~~~~~~~~~~~ - - Shift ``k`` logically right by ``k2`` bits (new bits are 0s). - - ``k.ashr(k2)`` - ~~~~~~~~~~~~~~ - - Shift ``k`` arithmetically right by ``k2`` bits (new bits are same as - previous sign bit). - - ``k.gep(indices)`` - ~~~~~~~~~~~~~~~~~~ - - GEP, see `LLVM docs `_. - - ``k.trunc(ty)`` - ~~~~~~~~~~~~~~~ - - Truncate ``k`` to a type ``ty`` of lower bitwidth. - - ``k.sext(ty)`` - ~~~~~~~~~~~~~~ - - Sign extend ``k`` to a type ``ty`` of higher bitwidth, while extending - the sign bit. - - ``k.zext(ty)`` - ~~~~~~~~~~~~~~ - - Sign extend ``k`` to a type ``ty`` of higher bitwidth, all new bits are - 0s. - - ``k.fptrunc(ty)`` - ~~~~~~~~~~~~~~~~~ - - Truncate floating point constant ``k`` to floating point type ``ty`` of - lower size than k's. - - ``k.fpext(ty)`` - ~~~~~~~~~~~~~~~ - - Extend floating point constant ``k`` to floating point type ``ty`` of - higher size than k's. - - ``k.uitofp(ty)`` - ~~~~~~~~~~~~~~~~ - - Convert an unsigned integer constant ``k`` to floating point constant of - type ``ty``. - - ``k.sitofp(ty)`` - ~~~~~~~~~~~~~~~~ - - Convert a signed integer constant ``k`` to floating point constant of - type ``ty``. - - ``k.fptoui(ty)`` - ~~~~~~~~~~~~~~~~ - - Convert a floating point constant ``k`` to an unsigned integer constant - of type ``ty``. - - ``k.fptosi(ty)`` - ~~~~~~~~~~~~~~~~ - - Convert a floating point constant ``k`` to a signed integer constant of - type ``ty``. - - ``k.ptrtoint(ty)`` - ~~~~~~~~~~~~~~~~~~ - - Convert a pointer constant ``k`` to an integer constant of type ``ty``. - - ``k.inttoptr(ty)`` - ~~~~~~~~~~~~~~~~~~ - - Convert an integer constant ``k`` to a pointer constant of type ``ty``. - - ``k.bitcast(ty)`` - ~~~~~~~~~~~~~~~~~ - - Convert ``k`` to a (equal-width) constant of type ``ty``. - - ``k.select(cond,k2,k3)`` - ~~~~~~~~~~~~~~~~~~~~~~~~ - - Replace value with ``k2`` if the 1-bit integer constant ``cond`` is 1, - else with ``k3``. - - ``k.extract_element(idx)`` - ~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Extract value at ``idx`` (integer constant) from a vector constant - ``k``. - - ``k.insert_element(k2,idx)`` - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Insert value ``k2`` (scalar constant) at index ``idx`` (integer - constant) of vector constant ``k``. - - ``k.shuffle_vector(k2,mask)`` - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Shuffle vector constant ``k`` based on vector constants ``k2`` and - ``mask``. - - -------------- - - # Other Constant Classes - The following subclasses of ``Constant`` do not provide additional - methods, **they serve only to provide richer type information.** - - Subclass \| LLVM C++ Class \| Remarks \| - ---------\|----------------\|---------\| ``ConstantExpr`` \| - ``llvmConstantExpr`` \| A constant expression \| - ``ConstantAggregateZero``\ \| ``llvmConstantAggregateZero``\ \| All-zero - constant \| ``ConstantInt``\ \| ``llvmConstantInt``\ \| An integer - constant \| ``ConstantFP``\ \| ``llvmConstantFP``\ \| A floating-point - constant \| ``ConstantArray``\ \| ``llvmConstantArray``\ \| An array - constant \| ``ConstantStruct``\ \| ``llvmConstantStruct``\ \| A - structure constant \| ``ConstantVector``\ \| ``llvmConstantVector``\ \| - A vector constant \| ``ConstantPointerNull``\ \| - ``llvmConstantPointerNull``\ \| All-zero pointer constant \| - ``UndefValue``\ \| ``llvmUndefValue``\ \| corresponds to ``undef`` of - LLVM IR \| - - These types are helpful in ``isinstance`` checks, like so: - - {% highlight python %} ti = Type.int(32) k1 = Constant.int(ti, 42) # - int32_t k1 = 42; k2 = Constant.array(ti, [k1, k1]) # int32_t k2[] = { - k1, k1 }; - - assert isinstance(k1, ConstantInt) assert isinstance(k2, ConstantArray) - + r1 = Constant.real(tr, "3.141592") # create from a string + r2 = Constant.real(tr, 1.61803399) # create from a Python float + + +# llvm.core.Constant +- This will become a table of contents (this text will be scraped). +{:toc} + + +Static factory methods +---------------------- + +``null(ty)`` +~~~~~~~~~~~~ + +A null value (all zeros) of type ``ty`` + +``all_ones(ty)`` +~~~~~~~~~~~~~~~~ + +All 1's value of type ``ty`` + +``undef(ty)`` +~~~~~~~~~~~~~ + +An undefined value of type ``ty`` + +``int(ty, value)`` +~~~~~~~~~~~~~~~~~~ + +Integer of type ``ty``, with value ``value`` (a Python int or long) + +``int_signextend(ty, value)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Integer of signed type ``ty`` (use for signed types) + +``real(ty, value)`` +~~~~~~~~~~~~~~~~~~~ + +Floating point value of type ``ty``, with value ``value`` (a Python +float) + +``stringz(value)`` +~~~~~~~~~~~~~~~~~~ + +A null-terminated string. ``value`` is a Python string + +``string(value)`` +~~~~~~~~~~~~~~~~~ + +As ``string(ty)``, but not null terminated + +``array(ty, consts)`` +~~~~~~~~~~~~~~~~~~~~~ + +Array of type ``ty``, initialized with ``consts`` (an iterable yielding +``Constant`` objects of the appropriate type) + +``struct(ty, consts)`` +~~~~~~~~~~~~~~~~~~~~~~ + +Struct (unpacked) of type ``ty``, initialized with ``consts`` (an +iterable yielding ``Constant`` objects of the appropriate type) + +``packed_struct(ty, consts)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As ``struct(ty, consts)`` but packed + +``vector(consts)`` +~~~~~~~~~~~~~~~~~~ + +Vector, initialized with ``consts`` (an iterable yielding ``Constant`` +objects of the appropriate type) + +``sizeof(ty)`` +~~~~~~~~~~~~~~ + +Constant value representing the sizeof the type ``ty`` + +Methods +------- + +The following operations on constants are supported. For more details on +any operation, consult the `Constant +Expressions `_ +section of the LLVM Language Reference. + +``k.neg()`` +~~~~~~~~~~~ + +negation, same as ``0 - k`` + +``k.not_()`` +~~~~~~~~~~~~ + +1's complement of ``k``. Note trailing underscore. + +``k.add(k2)`` +~~~~~~~~~~~~~ + +``k + k2``, where ``k`` and ``k2`` are integers. + +``k.fadd(k2)`` +~~~~~~~~~~~~~~ + +``k + k2``, where ``k`` and ``k2`` are floating-point. + +``k.sub(k2)`` +~~~~~~~~~~~~~ + +``k - k2``, where ``k`` and ``k2`` are integers. + +``k.fsub(k2)`` +~~~~~~~~~~~~~~ + +``k - k2``, where ``k`` and ``k2`` are floating-point. + +``k.mul(k2)`` +~~~~~~~~~~~~~ + +``k * k2``, where ``k`` and ``k2`` are integers. + +``k.fmul(k2)`` +~~~~~~~~~~~~~~ + +``k * k2``, where ``k`` and ``k2`` are floating-point. + +``k.udiv(k2)`` +~~~~~~~~~~~~~~ + +Quotient of unsigned division of ``k`` with ``k2`` + +``k.sdiv(k2)`` +~~~~~~~~~~~~~~ + +Quotient of signed division of ``k`` with ``k2`` + +``k.fdiv(k2)`` +~~~~~~~~~~~~~~ + +Quotient of floating point division of ``k`` with ``k2`` + +``k.urem(k2)`` +~~~~~~~~~~~~~~ + +Reminder of unsigned division of ``k`` with ``k2`` + +``k.srem(k2)`` +~~~~~~~~~~~~~~ + +Reminder of signed division of ``k`` with ``k2`` + +``k.frem(k2)`` +~~~~~~~~~~~~~~ + +Reminder of floating point division of ``k`` with ``k2`` + +``k.and_(k2)`` +~~~~~~~~~~~~~~ + +Bitwise and of ``k`` and ``k2``. Note trailing underscore. + +``k.or_(k2)`` +~~~~~~~~~~~~~ + +Bitwise or of ``k`` and ``k2``. Note trailing underscore. + +``k.xor(k2)`` +~~~~~~~~~~~~~ + +Bitwise exclusive-or of ``k`` and ``k2``. + +``k.icmp(icmp, k2)`` +~~~~~~~~~~~~~~~~~~~~ + +Compare ``k`` with ``k2`` using the predicate ``icmp``. See +`here `_ for list of predicates for integer +operands. + +``k.fcmp(fcmp, k2)`` +~~~~~~~~~~~~~~~~~~~~ + +Compare ``k`` with ``k2`` using the predicate ``fcmp``. See +`here `_ for list of predicates for real +operands. + +``k.shl(k2)`` +~~~~~~~~~~~~~ + +Shift ``k`` left by ``k2`` bits. + +``k.lshr(k2)`` +~~~~~~~~~~~~~~ + +Shift ``k`` logically right by ``k2`` bits (new bits are 0s). + +``k.ashr(k2)`` +~~~~~~~~~~~~~~ + +Shift ``k`` arithmetically right by ``k2`` bits (new bits are same as +previous sign bit). + +``k.gep(indices)`` +~~~~~~~~~~~~~~~~~~ + +GEP, see `LLVM docs `_. + +``k.trunc(ty)`` +~~~~~~~~~~~~~~~ + +Truncate ``k`` to a type ``ty`` of lower bitwidth. + +``k.sext(ty)`` +~~~~~~~~~~~~~~ + +Sign extend ``k`` to a type ``ty`` of higher bitwidth, while extending +the sign bit. + +``k.zext(ty)`` +~~~~~~~~~~~~~~ + +Sign extend ``k`` to a type ``ty`` of higher bitwidth, all new bits are +0s. + +``k.fptrunc(ty)`` +~~~~~~~~~~~~~~~~~ + +Truncate floating point constant ``k`` to floating point type ``ty`` of +lower size than k's. + +``k.fpext(ty)`` +~~~~~~~~~~~~~~~ + +Extend floating point constant ``k`` to floating point type ``ty`` of +higher size than k's. + +``k.uitofp(ty)`` +~~~~~~~~~~~~~~~~ + +Convert an unsigned integer constant ``k`` to floating point constant of +type ``ty``. + +``k.sitofp(ty)`` +~~~~~~~~~~~~~~~~ + +Convert a signed integer constant ``k`` to floating point constant of +type ``ty``. + +``k.fptoui(ty)`` +~~~~~~~~~~~~~~~~ + +Convert a floating point constant ``k`` to an unsigned integer constant +of type ``ty``. + +``k.fptosi(ty)`` +~~~~~~~~~~~~~~~~ + +Convert a floating point constant ``k`` to a signed integer constant of +type ``ty``. + +``k.ptrtoint(ty)`` +~~~~~~~~~~~~~~~~~~ + +Convert a pointer constant ``k`` to an integer constant of type ``ty``. + +``k.inttoptr(ty)`` +~~~~~~~~~~~~~~~~~~ + +Convert an integer constant ``k`` to a pointer constant of type ``ty``. + +``k.bitcast(ty)`` +~~~~~~~~~~~~~~~~~ + +Convert ``k`` to a (equal-width) constant of type ``ty``. + +``k.select(cond,k2,k3)`` +~~~~~~~~~~~~~~~~~~~~~~~~ + +Replace value with ``k2`` if the 1-bit integer constant ``cond`` is 1, +else with ``k3``. + +``k.extract_element(idx)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Extract value at ``idx`` (integer constant) from a vector constant +``k``. + +``k.insert_element(k2,idx)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert value ``k2`` (scalar constant) at index ``idx`` (integer +constant) of vector constant ``k``. + +``k.shuffle_vector(k2,mask)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Shuffle vector constant ``k`` based on vector constants ``k2`` and +``mask``. + +-------------- + +# Other Constant Classes +The following subclasses of ``Constant`` do not provide additional +methods, **they serve only to provide richer type information.** + +Subclass \| LLVM C++ Class \| Remarks \| +---------\|----------------\|---------\| ``ConstantExpr`` \| +``llvmConstantExpr`` \| A constant expression \| +``ConstantAggregateZero``\ \| ``llvmConstantAggregateZero``\ \| All-zero +constant \| ``ConstantInt``\ \| ``llvmConstantInt``\ \| An integer +constant \| ``ConstantFP``\ \| ``llvmConstantFP``\ \| A floating-point +constant \| ``ConstantArray``\ \| ``llvmConstantArray``\ \| An array +constant \| ``ConstantStruct``\ \| ``llvmConstantStruct``\ \| A +structure constant \| ``ConstantVector``\ \| ``llvmConstantVector``\ \| +A vector constant \| ``ConstantPointerNull``\ \| +``llvmConstantPointerNull``\ \| All-zero pointer constant \| +``UndefValue``\ \| ``llvmUndefValue``\ \| corresponds to ``undef`` of +LLVM IR \| + +These types are helpful in ``isinstance`` checks, like so: + +{% highlight python %} ti = Type.int(32) k1 = Constant.int(ti, 42) # +int32_t k1 = 42; k2 = Constant.array(ti, [k1, k1]) # int32_t k2[] = { +k1, k1 }; + +assert isinstance(k1, ConstantInt) assert isinstance(k2, ConstantArray) + Automatically Generated Documentation ------------------------------------- From 020032b57881968ba477be80dc365e8eba2b2a48 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 25 Apr 2013 14:10:57 -0500 Subject: [PATCH 362/516] Update docs --- docs/gh-pages.py | 2 +- docs/source/doc/getting_started.rst | 51 ++++++++++++++++------------- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/docs/gh-pages.py b/docs/gh-pages.py index dd30e28..3ee5d20 100755 --- a/docs/gh-pages.py +++ b/docs/gh-pages.py @@ -30,7 +30,7 @@ from subprocess import Popen, PIPE, CalledProcessError, check_call pages_dir = 'gh-pages' html_dir = '_build/html' pdf_dir = '_build/latex' -pages_repo = 'git@github.com:llvmpy/llvmpy-doc.git' +pages_repo = 'https://github.com/llvmpy/llvmpy-doc.git' #----------------------------------------------------------------------------- # Functions diff --git a/docs/source/doc/getting_started.rst b/docs/source/doc/getting_started.rst index f9b9c56..53c2982 100644 --- a/docs/source/doc/getting_started.rst +++ b/docs/source/doc/getting_started.rst @@ -38,7 +38,7 @@ supported, for a variety of reasons. Versions -------- -llvmpy 0.9 requires version 3.1 of LLVM. It may not work with +llvmpy 0.11.2 uses LLVM 3.2 (or at least 3.1). It may not work with previous versions. llvmpy has been built and tested with Python 2.7 and 3.2. It should work with @@ -65,22 +65,6 @@ It does not matter which compiler LLVM itself was built with (``g++``, ``llvm-g++`` or any other); llvmpy can be built with any compiler. It has been tried only with gcc/g++ though. - -LLVM and ``--enable-pic`` -------------------------- - -The result of an LLVM build is a set of static libraries and object -files. The llvmpy contains an extension package that is built into a -shared object (\_core.so) which links to these static libraries and -object files. It is therefore required that the LLVM libraries and -object files be built with the ``-fPIC`` option (generate position -independent code). Be sure to use the ``--enable-pic`` option while -configuring LLVM (default is no PIC), like this: - -.. code-block:: bash - - $ ~/llvm ./configure --enable-pic --enable-optimized - llvm-config ----------- @@ -98,13 +82,34 @@ is different from that of 'root', so even if ``llvm-config`` is in your Steps ----- -Get 3.1 version of LLVM, build it. Make sure '--enable-pic' is passed to -LLVM's 'configure'. +1. Get and extract LLVM 3.2 source tarball from + `llvm.org `_. Then, ``cd`` into + the extracted directory. -Get llvmpy and install it: +2. Run ``./configure --enable-optimized --prefix=LLVM_INSTALL_PATH``. + **Note**: Without the ``--enable-optimized`` flag, debug build will be + selected. Unless you are developing LLVM or llvmpy, it is recommended + that the flag is used to reduce build time and binary size. + + **Note**: Use prefix to select the installation path. It is recommended + to separate your custom build from the default system package. Please + replace ``LLVM_INSTALL_PATH`` with your own path. -.. code-block:: bash +3. Run ``REQUIRES_RTTI=1 make`` to build. - $ git clone git@github.com:numba/llvmpy.git - $ cd llvmpy $ python setup.py install + **Note**: With LLVM 3.2, the default build configuration has C++ RTTI + disabled. However, llvmpy requires RTTI. + +4. Get llvm-py and install it:: + + $ git clone git@github.com:llvmpy/llvmpy.git + $ cd llvmpy + $ LLVM_CONFIG_PATH=LLVM_INSTALL_PATH/bin/llvm-config python setup.py install + + Run the tests:: + + $ python -c "import llvm; llvm.test()" + +5. See documentation at 'http://www.llvmpy.org' and examples + under 'test'. From e74b26f84c8f7431df5e5e3e3e5992ec0494b5bb Mon Sep 17 00:00:00 2001 From: Conner Bryan Date: Sat, 27 Apr 2013 09:01:32 -0300 Subject: [PATCH 363/516] Add methods to instructions to retrieve metadata and determine if metadata exists for the instruction. --- llvm/core.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/llvm/core.py b/llvm/core.py index 719c8a4..d621579 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -1688,6 +1688,12 @@ class Instruction(User): def set_metadata(self, kind, metadata): self._ptr.setMetadata(kind, metadata._ptr) + + def has_metadata(self): + return self._ptr.hasMetadata() + + def get_metadata(self, kind): + return self._ptr.getMetadata(kind) @property def opcode(self): From a5f6f2596f56986e9c3f2959415500a642a3b5f9 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 25 Apr 2013 17:52:40 -0500 Subject: [PATCH 364/516] Fix ignored name arg --- llvm/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/core.py b/llvm/core.py index d621579..a51a3b3 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -730,7 +730,7 @@ class Type(llvm.Wrapper): otherwise, creates a literal type.""" context = api.llvm.getGlobalContext() is_packed = True - ptr = api.llvm.StructType.create(context) + ptr = api.llvm.StructType.create(context, name) ptr.setBody(llvm._extract_ptrs(element_tys), is_packed) return StructType(ptr) From b754e803ec3fa02b196982496073167bb014e290 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 2 May 2013 12:17:38 -0500 Subject: [PATCH 365/516] Cleanup --- llvm/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/core.py b/llvm/core.py index a51a3b3..0d0d1ae 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -1688,7 +1688,7 @@ class Instruction(User): def set_metadata(self, kind, metadata): self._ptr.setMetadata(kind, metadata._ptr) - + def has_metadata(self): return self._ptr.hasMetadata() From a357987597832a9c24d195302404328fd1f8e436 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 3 May 2013 10:45:02 -0500 Subject: [PATCH 366/516] Allow initialization of other targets. - Remove PTX/NVPTX targets from default built and init --- llvm/core.py | 25 ------------------ llvm/ee.py | 18 +++++++++++++ llvm/test_llvmpy.py | 7 ++--- llvmpy/gen/binding.py | 3 ++- llvmpy/src/Support/TargetSelect.py | 20 +++++++------- setup.py | 42 +++++++++++------------------- 6 files changed, 48 insertions(+), 67 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index 0d0d1ae..478728b 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -2305,28 +2305,3 @@ if api.llvm.InitializeNativeTargetAsmPrinter(): # should user trigger the initialization? raise llvm.LLVMException("No native asm printer!?") -#===----------------------------------------------------------------------=== -# Initialization -#===----------------------------------------------------------------------=== - -HAS_PTX = HAS_NVPTX = False - -if True: # use PTX? - try: - api.LLVMInitializePTXTarget() - api.LLVMInitializePTXTargetInfo() - api.LLVMInitializePTXTargetMC() - api.LLVMInitializePTXAsmPrinter() - HAS_PTX = True - except AttributeError: - try: - api.LLVMInitializeNVPTXTarget() - api.LLVMInitializeNVPTXTargetInfo() - api.LLVMInitializeNVPTXTargetMC() - api.LLVMInitializeNVPTXAsmPrinter() - HAS_NVPTX = True - except AttributeError: - pass - - - diff --git a/llvm/ee.py b/llvm/ee.py index 1ef16ae..017d0e0 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -222,6 +222,24 @@ class ExecutionEngine(llvm.Wrapper): # Target machine #===----------------------------------------------------------------------=== +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'] + 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 diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 945ac41..b228138 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -636,12 +636,13 @@ class TestTargetMachines(TestCase): self.assertTrue(le.get_host_cpu_name()) def test_ptx(self): - if lc.HAS_PTX: + if le.initialize_target('PTX', noraise=True): arch = 'ptx64' - elif lc.HAS_NVPTX: + elif le.initialize_target('NVPTX', noraise=True): arch = 'nvptx64' else: return # skip this test + print(arch) m, func = self._build_module() func.calling_convention = lc.CC_PTX_KERNEL # set calling conv @@ -650,7 +651,7 @@ class TestTargetMachines(TestCase): self.assertTrue(ptxtm.cpu) ptxasm = ptxtm.emit_assembly(m) self.assertIn('foo', ptxasm) - if lc.HAS_NVPTX: + if arch == 'nvptx64': self.assertIn('.address_size 64', ptxasm) self.assertIn('sm_20', ptxasm) diff --git a/llvmpy/gen/binding.py b/llvmpy/gen/binding.py index eeccab1..8006fd9 100644 --- a/llvmpy/gen/binding.py +++ b/llvmpy/gen/binding.py @@ -841,7 +841,8 @@ class Attr(object): # # Pick-up environ var # -PTX_SUPPORT = os.environ.get('LLVMPY_PTX_SUPPORT', '') + +TARGETS_BUILT = os.environ.get('LLVM_TARGETS_BUILT', '').split() def _parse_llvm_version(ver): import re diff --git a/llvmpy/src/Support/TargetSelect.py b/llvmpy/src/Support/TargetSelect.py index 85e1d74..3e638bc 100644 --- a/llvmpy/src/Support/TargetSelect.py +++ b/llvmpy/src/Support/TargetSelect.py @@ -1,8 +1,11 @@ +import os from binding import * from ..namespace import llvm, default llvm.includes.add('llvm/Support/TargetSelect.h') + + InitializeNativeTarget = llvm.Function('InitializeNativeTarget') InitializeNativeTargetAsmPrinter = llvm.Function( 'InitializeNativeTargetAsmPrinter', cast(Bool, bool)) @@ -11,20 +14,15 @@ InitializeNativeTargetAsmParser = llvm.Function( InitializeNativeTargetDisassembler = llvm.Function( 'InitializeNativeTargetDisassembler', cast(Bool, bool)) - #InitializeAllTargets = llvm.Function('InitializeAllTargets') #InitializeAllTargetInfos = llvm.Function('InitializeAllTargetInfos') #InitializeAllTargetMCs = llvm.Function('InitializeAllTargetMCs') #InitializeAllAsmPrinters = llvm.Function('InitializeAllAsmPrinters') -if PTX_SUPPORT == 'PTX': - LLVMInitializePTXTarget = default.Function('LLVMInitializePTXTarget') - LLVMInitializePTXTargetInfo = default.Function('LLVMInitializePTXTargetInfo') - LLVMInitializePTXTargetMC = default.Function('LLVMInitializePTXTargetMC') - LLVMInitializePTXAsmPrinter = default.Function('LLVMInitializePTXAsmPrinter') +for target in TARGETS_BUILT: + decls = 'Target', 'TargetInfo', 'TargetMC', 'AsmPrinter' + for k in map(lambda x: 'LLVMInitialize%s%s' % (target, x), decls): + if k == 'LLVMInitializeCppBackendAsmPrinter': + continue + globals()[k] = default.Function(k) -if PTX_SUPPORT == 'NVPTX': - LLVMInitializeNVPTXTarget = default.Function('LLVMInitializeNVPTXTarget') - LLVMInitializeNVPTXTargetInfo = default.Function('LLVMInitializeNVPTXTargetInfo') - LLVMInitializeNVPTXTargetMC = default.Function('LLVMInitializeNVPTXTargetMC') - LLVMInitializeNVPTXAsmPrinter = default.Function('LLVMInitializeNVPTXAsmPrinter') diff --git a/setup.py b/setup.py index 8202c5f..b74ec71 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,4 @@ +from __future__ import print_function import os import sys from subprocess import Popen, PIPE, check_call @@ -37,6 +38,11 @@ def run_llvm_config(extra_args): llvm_version = run_llvm_config(['--version']) print('LLVM version = %r' % llvm_version) +targets_built = run_llvm_config(['--targets-built']) +include_targets = set(os.environ.get('LLVMPY_TARGETS', '').split()) +targets_built = ' '.join(set(targets_built.split()) & include_targets) +print('LLVM targets = %s' % targets_built) + def get_libs_and_objs(components): parts = run_llvm_config(['--libs'] + components).split() libs = [] @@ -97,36 +103,20 @@ def determine_to_use_dynlink(libdir, llvm_version): dynlink = determine_to_use_dynlink(libdir, llvm_version) -ptx_support = '' + if dynlink: print('Using dynamic linking') libs_core = ['LLVM-%s' % llvm_version] objs_core = [] else: + extra_components = set() + for tm in map(lambda s: s.lower(), targets_built.split()): + postfixes = ['', 'asmprinter', 'codegen', 'desc', 'info'] + for postfix in postfixes: + extra_components.add(tm + postfix) enabled_components = set(get_enabled_components()) - ptx_components = set(['ptx', - 'ptxasmprinter', - 'ptxcodegen', - 'ptxdesc', - 'ptxinfo']) - nvptx_components = set(['nvptx', - 'nvptxasmprinter', - 'nvptxcodegen', - 'nvptxdesc', - 'nvptxinfo']) - - extra_components = [] - if (nvptx_components & enabled_components) == nvptx_components: - print("Using NVPTX") - extra_components.extend(nvptx_components) - ptx_support = 'NVPTX' - elif (ptx_components & enabled_components) == ptx_components: - print("Using PTX") - extra_components.extend(ptx_components) - ptx_support = 'PTX' - else: - print("No CUDA support") + extra_components = list(extra_components & enabled_components) libs_core, objs_core = get_libs_and_objs( ['core', 'analysis', 'scalaropts', 'executionengine', @@ -136,15 +126,13 @@ else: + extra_components) if sys.platform == 'win32': - # If no PTX lib got added, disable PTX in the build - if 'LLVMPTXCodeGen' in libs_core: - ptx_support = 'ptx' + pass else: macros.append(('_GNU_SOURCE', None)) # auto generate bindings -os.environ['LLVMPY_PTX_SUPPORT'] = ptx_support os.environ['LLVMPY_LLVM_VERSION'] = llvm_version +os.environ['LLVM_TARGETS_BUILT'] = targets_built check_call([sys.executable, 'llvmpy/build.py']) # generate shared objects From 489d8056b944cd583a6f436d79535a7b75a1d548 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 3 May 2013 10:57:38 -0500 Subject: [PATCH 367/516] Fix error msg --- llvm/ee.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/ee.py b/llvm/ee.py index 017d0e0..e4ee4bc 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -298,7 +298,7 @@ class TargetMachine(llvm.Wrapper): with contextlib.closing(BytesIO()) as error: target = api.llvm.TargetRegistry.lookupTarget(arch, triple, error) if not target: - raise llvm.LLVMException(error) + raise llvm.LLVMException(error.getvalue()) if not target.hasTargetMachine(): raise llvm.LLVMException(target, "No target machine.") target_options = api.llvm.TargetOptions.new() From 3e0dc2507010b8f655ff07c698de387ac1ffb187 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 10 May 2013 10:58:51 -0500 Subject: [PATCH 368/516] Silent capsule memory logger. --- llvmpy/capsule.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/llvmpy/capsule.py b/llvmpy/capsule.py index 9c1e86a..f66836f 100644 --- a/llvmpy/capsule.py +++ b/llvmpy/capsule.py @@ -3,6 +3,15 @@ from collections import defaultdict import logging logger = logging.getLogger(__name__) +def silent_logger(): + ''' + Silent logger for unless we have a error message. + ''' + logger.setLevel(logging.ERROR) + +# comment out the line below to re-enable logging at DEBUG level. +silent_logger() + def set_debug(enabled): ''' Side-effect: configure logger with it is not configured. From c1184271188a0c7d4cea1a74d241fc2e53b89936 Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Tue, 14 May 2013 04:26:10 -0500 Subject: [PATCH 369/516] Don't get name field from literal structure and avoid a segfault. --- llvm/core.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/llvm/core.py b/llvm/core.py index 478728b..453f1a8 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -879,7 +879,10 @@ class StructType(Type): self._ptr.setName(name) def _get_name(self): - return self._ptr.getName() + if self._ptr.isLiteral(): + return "" + else: + return self._ptr.getName() name = property(_get_name, _set_name) From 08bed7dd7432692e681f2a2e9d3fe773d7943162 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 14 May 2013 10:32:37 -0500 Subject: [PATCH 370/516] Fix bug with Module.to_bitcode() (Reported by Jun Koi) --- llvm/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/core.py b/llvm/core.py index 453f1a8..b085339 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -535,7 +535,7 @@ class Module(llvm.Wrapper): ret = False if fileobj is None: ret = True - fileobj = BytesIO + fileobj = BytesIO() api.llvm.WriteBitcodeToFile(self._ptr, fileobj) if ret: return fileobj.getvalue() From f4b320ff09e7b9756e1b799b4df20fd4e7482520 Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Tue, 14 May 2013 00:51:45 -0500 Subject: [PATCH 371/516] Fix a few erros. Add an array type --- llvm_array/__init__.py | 2 + llvm_array/array.py | 144 +++++++++++++++++++++++++++++++++ llvmpy/src/Function.py | 7 +- llvmpy/src/Value.py | 1 + llvmpy/src/ValueSymbolTable.py | 13 +++ setup.py | 1 + 6 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 llvm_array/__init__.py create mode 100644 llvm_array/array.py create mode 100644 llvmpy/src/ValueSymbolTable.py diff --git a/llvm_array/__init__.py b/llvm_array/__init__.py new file mode 100644 index 0000000..f6a0f3f --- /dev/null +++ b/llvm_array/__init__.py @@ -0,0 +1,2 @@ +from __future__ import absolute_imports +from .array.py import * diff --git a/llvm_array/array.py b/llvm_array/array.py new file mode 100644 index 0000000..12df60e --- /dev/null +++ b/llvm_array/array.py @@ -0,0 +1,144 @@ +# This should be moved to llvmpy +# +# There are different array kinds parameterized by eltype and nd +# +# Contiguous or Fortran +# struct { +# eltype *data; +# intp shape[nd]; +# } contiguous_array(eltype, nd) +# +# struct { +# eltype *data; +# diminfo shape[nd]; +# } strided_array(eltype, nd) +# +# struct { +# eltype *data; +# intp shape[nd]; +# intp stride[nd]; +# } strided_soa_array(eltype, nd) +# +# struct { +# intp dim; +# intp stride; +#} diminfo +# + +import llvm.core as lc +from llvm.core import Type +import llvm_cbuilder.shortnames as C + +CONTIGUOUS = 1 << 8 +STRIDED = CONTIGUOUS + 1 +STRIDED_SOA = CONTIGUOUS + 2 + +array_kinds = (CONTIGUOUS, STRIDED, STRIDED_SOA) + +void_type = C.void +int_type = C.int +char_type = C.char +int16_type = C.int16 +intp_type = C.intp + +diminfo_type = Type.struct([intp_type, # shape + intp_type # stride + ], name='diminfo') + +# This is the way we define LLVM arrays. +def cont_array_type(nd, el_type=char_type, name=''): + terms = [Type.pointer(el_type), # data + Type.array(intp_type, nd) # shape + ] + return Type.struct(terms, name=name) + +def strided_array_type(nd, el_type=char_type, name=''): + terms = [Type.pointer(el_type), # data + Type.array(diminfo_type, nd) # diminfo + ] + return Type.struct(terms, name=name) + +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): + if not isinstance(arrtyp, lc.StructType): + return None + 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 + + data_type = arrtyp.elements[0].pointee + s1 = arrtyp.elements[1] + nd = s1.count + + if arrtyp.element_count == 3: + if not isinstance(arrtyp.elements[2], lc.ArrayType): + return None + s2 = arrtyp.elements[2] + if s1.element != intp_type or s2.element != intp_type: + return None + if s1.count != s2.count: + return None + return STRIDED_SOA, nd, data_type + + if s1.element == diminfo_type: + return STRIDED, nd, data_type + elif s1.element == intp_type: + return CONTIGUOUS, nd, data_type + else: + 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(): + arr = cont_array_type(5) + assert check_array(arr) == (CONTIGUOUS, 5, char_type) + arr = strided_array_type(4) + assert check_array(arr) == (STRIDED, 4, char_type) + arr = strided_soa_type(3) + assert check_array(arr) == (STRIDED_SOA, 3, char_type) + +if __name__ == '__main__': + test() \ No newline at end of file diff --git a/llvmpy/src/Function.py b/llvmpy/src/Function.py index 55a50d9..c453fd1 100644 --- a/llvmpy/src/Function.py +++ b/llvmpy/src/Function.py @@ -2,6 +2,7 @@ from binding import * from .namespace import llvm from .Value import GlobalValue, Constant, Function, Argument, Value from .BasicBlock import BasicBlock +from .ValueSymbolTable import ValueSymbolTable from .Attributes import Attributes from .Type import Type from .DerivedTypes import FunctionType @@ -23,7 +24,7 @@ class Function: getCallingConv = Method(CallingConv.ID) setCallingConv = Method(Void, CallingConv.ID) - hasGC = Method(cast(bool, Bool)) + hasGC = Method(cast(Bool, bool)) getGC = Method(cast(ConstCharPtr, str)) setGC = Method(Void, cast(str, ConstCharPtr)) @@ -31,6 +32,7 @@ class Function: getArgumentList = CustomMethod('Function_getArgumentList', PyObjectPtr) getBasicBlockList = CustomMethod('Function_getBasicBlockList', PyObjectPtr) getEntryBlock = Method(ref(BasicBlock)) + getValueSymbolTable = Method(ref(ValueSymbolTable)) copyAttributesFrom = Method(Void, ptr(GlobalValue)) @@ -49,6 +51,9 @@ class Function: addFnAttr = Method(Void, Attributes.AttrVal) removeFnAttr = Method(Void, ref(Attributes)) + #hasFnAttribute = Method(cast(Bool, bool), Attributes.AttrVal) + + Create = Method(ptr(Function)) eraseFromParent = Method() eraseFromParent.disowning = True diff --git a/llvmpy/src/Value.py b/llvmpy/src/Value.py index fb9c3cc..922850f 100644 --- a/llvmpy/src/Value.py +++ b/llvmpy/src/Value.py @@ -8,6 +8,7 @@ MDNode = llvm.Class(Value) MDString = llvm.Class(Value) User = llvm.Class(Value) BasicBlock = llvm.Class(Value) +ValueSymbolTable = llvm.Class() Constant = llvm.Class(User) GlobalValue = llvm.Class(Constant) Function = llvm.Class(GlobalValue) diff --git a/llvmpy/src/ValueSymbolTable.py b/llvmpy/src/ValueSymbolTable.py new file mode 100644 index 0000000..862febc --- /dev/null +++ b/llvmpy/src/ValueSymbolTable.py @@ -0,0 +1,13 @@ +from binding import * +from .Value import ValueSymbolTable, Value +from .ADT.StringRef import StringRef + +@ValueSymbolTable +class ValueSymbolTable: + new = Constructor() + delete = Destructor() + lookup = Method(ptr(Value), cast(str, StringRef)) + empty = Method(cast(Bool, bool)) + size = Method(cast(Unsigned, int)) + dump = Method(Void) + diff --git a/setup.py b/setup.py index b74ec71..1dc8af8 100644 --- a/setup.py +++ b/setup.py @@ -180,6 +180,7 @@ setup( packages = ['llvm', 'llvm.workaround', 'llvm_cbuilder', 'llpython', + 'llvm_array', 'llvmpy.api', 'llvmpy.api.llvm'], py_modules = ['llvmpy', 'llvmpy._capsule', From db7323771fbc72b9dd08781445797f906be43915 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 14 May 2013 11:23:50 -0500 Subject: [PATCH 372/516] Fix PR --- llvmpy/src/Function.py | 7 ++++++- llvmpy/src/ValueSymbolTable.py | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/llvmpy/src/Function.py b/llvmpy/src/Function.py index c453fd1..04c3e65 100644 --- a/llvmpy/src/Function.py +++ b/llvmpy/src/Function.py @@ -1,6 +1,7 @@ from binding import * from .namespace import llvm from .Value import GlobalValue, Constant, Function, Argument, Value +from .Module import Module from .BasicBlock import BasicBlock from .ValueSymbolTable import ValueSymbolTable from .Attributes import Attributes @@ -53,7 +54,11 @@ class Function: removeFnAttr = Method(Void, ref(Attributes)) #hasFnAttribute = Method(cast(Bool, bool), Attributes.AttrVal) - Create = Method(ptr(Function)) + Create = StaticMethod(ptr(Function), + ptr(FunctionType), + GlobalValue.LinkageTypes, + cast(str, ConstCharPtr), + ptr(Module)).require_only(2) eraseFromParent = Method() eraseFromParent.disowning = True diff --git a/llvmpy/src/ValueSymbolTable.py b/llvmpy/src/ValueSymbolTable.py index 862febc..7e8890c 100644 --- a/llvmpy/src/ValueSymbolTable.py +++ b/llvmpy/src/ValueSymbolTable.py @@ -4,6 +4,7 @@ from .ADT.StringRef import StringRef @ValueSymbolTable class ValueSymbolTable: + _include_ = 'llvm/ValueSymbolTable.h' new = Constructor() delete = Destructor() lookup = Method(ptr(Value), cast(str, StringRef)) From 331f71f26f13431b07c9c5d37dda935fdbcd8059 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 16 May 2013 11:34:27 -0500 Subject: [PATCH 373/516] Fix hashing of llvm type --- llvm/core.py | 4 +++- llvm/test_llvmpy.py | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/llvm/core.py b/llvm/core.py index b085339..d25dec1 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -800,6 +800,9 @@ class Type(llvm.Wrapper): def __str__(self): return str(self._ptr) + def __hash__(self): + return hash(self._ptr) + def __eq__(self, rhs): return self._ptr is rhs._ptr @@ -901,7 +904,6 @@ class StructType(Type): def is_layout_identical(self, other): return self._ptr.isLayoutIdentical(other._ptr) - class ArrayType(Type): """Represents an array type.""" _type_ = api.llvm.ArrayType diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index b228138..36ea022 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -1258,6 +1258,32 @@ class TestStruct(TestCase): tests.append(TestStruct) +# --------------------------------------------------------------------------- + +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) + + # --------------------------------------------------------------------------- def run(verbosity=1): From 592f9c698819e9efacd7d340eb27a03fd887770f Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 16 May 2013 13:45:59 -0500 Subject: [PATCH 374/516] Allow retrieving argument attributes --- llvm/core.py | 38 ++++++++++++++++++++++++++++++++++++++ llvm/test_llvmpy.py | 18 ++++++++++++++++++ llvmpy/src/Argument.py | 10 ++++++++++ 3 files changed, 66 insertions(+) diff --git a/llvm/core.py b/llvm/core.py index d25dec1..74d7101 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -1372,6 +1372,8 @@ class GlobalVariable(GlobalValue): class Argument(Value): _type_ = api.llvm.Argument + _valid_attrs = frozenset([ATTR_BY_VAL, ATTR_NEST, ATTR_NO_ALIAS, + ATTR_NO_CAPTURE, ATTR_STRUCT_RET]) def add_attribute(self, attr): context = api.llvm.getGlobalContext() @@ -1379,6 +1381,9 @@ class Argument(Value): attrbldr.addAttribute(attr) attrs = api.llvm.Attributes.get(context, attrbldr) self._ptr.addAttr(attrs) + if attr not in self: + raise ValueError("Attribute %s is not valid for arg %s" % + (attr, self)) def remove_attribute(self, attr): context = api.llvm.getGlobalContext() @@ -1400,6 +1405,39 @@ class Argument(Value): alignment = property(_get_alignment, _set_alignment) + def __contains__(self, attr): + if attr == ATTR_BY_VAL: + return self.has_by_val() + elif attr == ATTR_NEST: + return self.has_nest() + elif attr == ATTR_NO_ALIAS: + return self.has_no_alias() + elif attr == ATTR_NO_CAPTURE: + return self.has_no_capture() + elif attr == ATTR_STRUCT_RET: + return self.has_struct_ret() + else: + raise ValueError('invalid attribute for argument') + + @property + def arg_no(self): + return self._ptr.getArgNo() + + def has_by_val(self): + return self._ptr.hasByValAttr() + + def has_nest(self): + return self._ptr.hasNestAttr() + + def has_no_alias(self): + return self._ptr.hasNoAliasAttr() + + def has_no_capture(self): + return self._ptr.hasNoCaptureAttr() + + def has_struct_ret(self): + return self._ptr.hasStructRetAttr() + class Function(GlobalValue): _type_ = api.llvm.Function diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 36ea022..3ecffff 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -1283,6 +1283,24 @@ class TestTypeHash(TestCase): tests.append(TestTypeHash) +# --------------------------------------------------------------------------- + +class TestArgAttr(TestCase): + def test_arg_attr(self): + m = Module.new('oifjda') + vptr = Type.pointer(Type.float()) + sptr = Type.pointer(Type.struct([])) + 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) # --------------------------------------------------------------------------- diff --git a/llvmpy/src/Argument.py b/llvmpy/src/Argument.py index babbd1c..6262147 100644 --- a/llvmpy/src/Argument.py +++ b/llvmpy/src/Argument.py @@ -13,3 +13,13 @@ class Argument: removeAttr = Method(Void, ref(Attributes)) getParamAlignment = Method(cast(Unsigned, int)) + getArgNo = Method(cast(Unsigned, int)) + + hasByValAttr = Method(cast(Bool, bool)) + hasNestAttr = Method(cast(Bool, bool)) + hasNoAliasAttr = Method(cast(Bool, bool)) + hasNoCaptureAttr = Method(cast(Bool, bool)) + hasStructRetAttr = Method(cast(Bool, bool)) + + if LLVM_VERSION > (3, 2): + hasReturnedAttr = Method(cast(Bool, bool)) From 96dc9076134a7507e88cdf7d715f937d09a8a083 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 16 May 2013 13:46:57 -0500 Subject: [PATCH 375/516] Make enum integer constants prints name --- llvm/core.py | 451 +++++++++++++++++++++++++++++---------------------- 1 file changed, 256 insertions(+), 195 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index 74d7101..9cb1946 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -47,144 +47,189 @@ from llvmpy import api #===----------------------------------------------------------------------=== # Enumerations #===----------------------------------------------------------------------=== +class Enum(int): + '''Overload integer to print the name of the enum. + ''' + def __repr__(self): + return '%s(%d)' % (type(self).__name__, self) + + @classmethod + def declare(cls): + scope = globals() + for name in filter(lambda s: s.startswith(cls.prefix), dir(cls)): + n = getattr(cls, name) + typ = type(name, (cls,), {}) + scope[name] = typ(n) + # type id (llvm::Type::TypeID) -TYPE_VOID = api.llvm.Type.TypeID.VoidTyID -TYPE_HALF = api.llvm.Type.TypeID.HalfTyID -TYPE_FLOAT = api.llvm.Type.TypeID.FloatTyID -TYPE_DOUBLE = api.llvm.Type.TypeID.DoubleTyID -TYPE_X86_FP80 = api.llvm.Type.TypeID.X86_FP80TyID -TYPE_FP128 = api.llvm.Type.TypeID.FP128TyID -TYPE_PPC_FP128 = api.llvm.Type.TypeID.PPC_FP128TyID -TYPE_LABEL = api.llvm.Type.TypeID.LabelTyID -TYPE_INTEGER = api.llvm.Type.TypeID.IntegerTyID -TYPE_FUNCTION = api.llvm.Type.TypeID.FunctionTyID -TYPE_STRUCT = api.llvm.Type.TypeID.StructTyID -TYPE_ARRAY = api.llvm.Type.TypeID.ArrayTyID -TYPE_POINTER = api.llvm.Type.TypeID.PointerTyID -TYPE_VECTOR = api.llvm.Type.TypeID.VectorTyID -TYPE_METADATA = api.llvm.Type.TypeID.MetadataTyID -TYPE_X86_MMX = api.llvm.Type.TypeID.X86_MMXTyID +class TypeEnum(Enum): + prefix = 'TYPE_' + TypeID = api.llvm.Type.TypeID + + TYPE_VOID = TypeID.VoidTyID + TYPE_HALF = TypeID.HalfTyID + TYPE_FLOAT = TypeID.FloatTyID + TYPE_DOUBLE = TypeID.DoubleTyID + TYPE_X86_FP80 = TypeID.X86_FP80TyID + TYPE_FP128 = TypeID.FP128TyID + TYPE_PPC_FP128 = TypeID.PPC_FP128TyID + TYPE_LABEL = TypeID.LabelTyID + TYPE_INTEGER = TypeID.IntegerTyID + TYPE_FUNCTION = TypeID.FunctionTyID + TYPE_STRUCT = TypeID.StructTyID + TYPE_ARRAY = TypeID.ArrayTyID + TYPE_POINTER = TypeID.PointerTyID + TYPE_VECTOR = TypeID.VectorTyID + TYPE_METADATA = TypeID.MetadataTyID + TYPE_X86_MMX = TypeID.X86_MMXTyID + +TypeEnum.declare() # value IDs (llvm::Value::ValueTy enum) # According to the doxygen docs, it is not a good idea to use these enums. # There are more values than those declared. -VALUE_ARGUMENT = api.llvm.Value.ValueTy.ArgumentVal -VALUE_BASIC_BLOCK = api.llvm.Value.ValueTy.BasicBlockVal -VALUE_FUNCTION = api.llvm.Value.ValueTy.FunctionVal -VALUE_GLOBAL_ALIAS = api.llvm.Value.ValueTy.GlobalAliasVal -VALUE_GLOBAL_VARIABLE = api.llvm.Value.ValueTy.GlobalVariableVal -VALUE_UNDEF_VALUE = api.llvm.Value.ValueTy.UndefValueVal -VALUE_BLOCK_ADDRESS = api.llvm.Value.ValueTy.BlockAddressVal -VALUE_CONSTANT_EXPR = api.llvm.Value.ValueTy.ConstantExprVal -VALUE_CONSTANT_AGGREGATE_ZERO = api.llvm.Value.ValueTy.ConstantAggregateZeroVal -VALUE_CONSTANT_DATA_ARRAY = api.llvm.Value.ValueTy.ConstantDataArrayVal -VALUE_CONSTANT_DATA_VECTOR = api.llvm.Value.ValueTy.ConstantDataVectorVal -VALUE_CONSTANT_INT = api.llvm.Value.ValueTy.ConstantIntVal -VALUE_CONSTANT_FP = api.llvm.Value.ValueTy.ConstantFPVal -VALUE_CONSTANT_ARRAY = api.llvm.Value.ValueTy.ConstantArrayVal -VALUE_CONSTANT_STRUCT = api.llvm.Value.ValueTy.ConstantStructVal -VALUE_CONSTANT_VECTOR = api.llvm.Value.ValueTy.ConstantVectorVal -VALUE_CONSTANT_POINTER_NULL = api.llvm.Value.ValueTy.ConstantPointerNullVal -VALUE_MD_NODE = api.llvm.Value.ValueTy.MDNodeVal -VALUE_MD_STRING = api.llvm.Value.ValueTy.MDStringVal -VALUE_INLINE_ASM = api.llvm.Value.ValueTy.InlineAsmVal -VALUE_PSEUDO_SOURCE_VALUE = api.llvm.Value.ValueTy.PseudoSourceValueVal -VALUE_FIXED_STACK_PSEUDO_SOURCE_VALUE = api.llvm.Value.ValueTy.FixedStackPseudoSourceValueVal -VALUE_INSTRUCTION = api.llvm.Value.ValueTy.InstructionVal +class ValueEnum(Enum): + prefix = 'VALUE_' + ValueTy = api.llvm.Value.ValueTy + + VALUE_ARGUMENT = ValueTy.ArgumentVal + VALUE_BASIC_BLOCK = ValueTy.BasicBlockVal + VALUE_FUNCTION = ValueTy.FunctionVal + VALUE_GLOBAL_ALIAS = ValueTy.GlobalAliasVal + VALUE_GLOBAL_VARIABLE = ValueTy.GlobalVariableVal + VALUE_UNDEF_VALUE = ValueTy.UndefValueVal + VALUE_BLOCK_ADDRESS = ValueTy.BlockAddressVal + VALUE_CONSTANT_EXPR = ValueTy.ConstantExprVal + VALUE_CONSTANT_AGGREGATE_ZERO = ValueTy.ConstantAggregateZeroVal + VALUE_CONSTANT_DATA_ARRAY = ValueTy.ConstantDataArrayVal + VALUE_CONSTANT_DATA_VECTOR = ValueTy.ConstantDataVectorVal + VALUE_CONSTANT_INT = ValueTy.ConstantIntVal + VALUE_CONSTANT_FP = ValueTy.ConstantFPVal + VALUE_CONSTANT_ARRAY = ValueTy.ConstantArrayVal + VALUE_CONSTANT_STRUCT = ValueTy.ConstantStructVal + VALUE_CONSTANT_VECTOR = ValueTy.ConstantVectorVal + VALUE_CONSTANT_POINTER_NULL = ValueTy.ConstantPointerNullVal + VALUE_MD_NODE = ValueTy.MDNodeVal + VALUE_MD_STRING = ValueTy.MDStringVal + VALUE_INLINE_ASM = ValueTy.InlineAsmVal + VALUE_PSEUDO_SOURCE_VALUE = ValueTy.PseudoSourceValueVal + VALUE_FIXED_STACK_PSEUDO_SOURCE_VALUE = ValueTy.FixedStackPseudoSourceValueVal + VALUE_INSTRUCTION = ValueTy.InstructionVal + +ValueEnum.declare() # instruction opcodes (from include/llvm/Instruction.def) -OPCODE_RET = 1 -OPCODE_BR = 2 -OPCODE_SWITCH = 3 -OPCODE_INDIRECT_BR = 4 -OPCODE_INVOKE = 5 -OPCODE_RESUME = 6 -OPCODE_UNREACHABLE = 7 -OPCODE_ADD = 8 -OPCODE_FADD = 9 -OPCODE_SUB = 10 -OPCODE_FSUB = 11 -OPCODE_MUL = 12 -OPCODE_FMUL = 13 -OPCODE_UDIV = 14 -OPCODE_SDIV = 15 -OPCODE_FDIV = 16 -OPCODE_UREM = 17 -OPCODE_SREM = 18 -OPCODE_FREM = 19 -OPCODE_SHL = 20 -OPCODE_LSHR = 21 -OPCODE_ASHR = 22 -OPCODE_AND = 23 -OPCODE_OR = 24 -OPCODE_XOR = 25 -OPCODE_ALLOCA = 26 -OPCODE_LOAD = 27 -OPCODE_STORE = 28 -OPCODE_GETELEMENTPTR = 29 -OPCODE_FENCE = 30 -OPCODE_ATOMICCMPXCHG = 31 -OPCODE_ATOMICRMW = 32 -OPCODE_TRUNC = 33 -OPCODE_ZEXT = 34 -OPCODE_SEXT = 35 -OPCODE_FPTOUI = 36 -OPCODE_FPTOSI = 37 -OPCODE_UITOFP = 38 -OPCODE_SITOFP = 39 -OPCODE_FPTRUNC = 40 -OPCODE_FPEXT = 41 -OPCODE_PTRTOINT = 42 -OPCODE_INTTOPTR = 43 -OPCODE_BITCAST = 44 -OPCODE_ICMP = 45 -OPCODE_FCMP = 46 -OPCODE_PHI = 47 -OPCODE_CALL = 48 -OPCODE_SELECT = 49 -OPCODE_USEROP1 = 50 -OPCODE_USEROP2 = 51 -OPCODE_VAARG = 52 -OPCODE_EXTRACTELEMENT = 53 -OPCODE_INSERTELEMENT = 54 -OPCODE_SHUFFLEVECTOR = 55 -OPCODE_EXTRACTVALUE = 56 -OPCODE_INSERTVALUE = 57 -OPCODE_LANDINGPAD = 58 +class OpcodeEnum(Enum): + prefix = 'OPCODE_' + + OPCODE_RET = 1 + OPCODE_BR = 2 + OPCODE_SWITCH = 3 + OPCODE_INDIRECT_BR = 4 + OPCODE_INVOKE = 5 + OPCODE_RESUME = 6 + OPCODE_UNREACHABLE = 7 + OPCODE_ADD = 8 + OPCODE_FADD = 9 + OPCODE_SUB = 10 + OPCODE_FSUB = 11 + OPCODE_MUL = 12 + OPCODE_FMUL = 13 + OPCODE_UDIV = 14 + OPCODE_SDIV = 15 + OPCODE_FDIV = 16 + OPCODE_UREM = 17 + OPCODE_SREM = 18 + OPCODE_FREM = 19 + OPCODE_SHL = 20 + OPCODE_LSHR = 21 + OPCODE_ASHR = 22 + OPCODE_AND = 23 + OPCODE_OR = 24 + OPCODE_XOR = 25 + OPCODE_ALLOCA = 26 + OPCODE_LOAD = 27 + OPCODE_STORE = 28 + OPCODE_GETELEMENTPTR = 29 + OPCODE_FENCE = 30 + OPCODE_ATOMICCMPXCHG = 31 + OPCODE_ATOMICRMW = 32 + OPCODE_TRUNC = 33 + OPCODE_ZEXT = 34 + OPCODE_SEXT = 35 + OPCODE_FPTOUI = 36 + OPCODE_FPTOSI = 37 + OPCODE_UITOFP = 38 + OPCODE_SITOFP = 39 + OPCODE_FPTRUNC = 40 + OPCODE_FPEXT = 41 + OPCODE_PTRTOINT = 42 + OPCODE_INTTOPTR = 43 + OPCODE_BITCAST = 44 + OPCODE_ICMP = 45 + OPCODE_FCMP = 46 + OPCODE_PHI = 47 + OPCODE_CALL = 48 + OPCODE_SELECT = 49 + OPCODE_USEROP1 = 50 + OPCODE_USEROP2 = 51 + OPCODE_VAARG = 52 + OPCODE_EXTRACTELEMENT = 53 + OPCODE_INSERTELEMENT = 54 + OPCODE_SHUFFLEVECTOR = 55 + OPCODE_EXTRACTVALUE = 56 + OPCODE_INSERTVALUE = 57 + OPCODE_LANDINGPAD = 58 + +OpcodeEnum.declare() # calling conventions -CC_C = api.llvm.CallingConv.ID.C -CC_FASTCALL = api.llvm.CallingConv.ID.Fast -CC_COLDCALL = api.llvm.CallingConv.ID.Cold -CC_GHC = api.llvm.CallingConv.ID.GHC -CC_X86_STDCALL = api.llvm.CallingConv.ID.X86_StdCall -CC_X86_FASTCALL = api.llvm.CallingConv.ID.X86_FastCall -CC_ARM_APCS = api.llvm.CallingConv.ID.ARM_APCS -CC_ARM_AAPCS = api.llvm.CallingConv.ID.ARM_AAPCS -CC_ARM_AAPCS_VFP = api.llvm.CallingConv.ID.ARM_AAPCS_VFP -CC_MSP430_INTR = api.llvm.CallingConv.ID.MSP430_INTR -CC_X86_THISCALL = api.llvm.CallingConv.ID.X86_ThisCall -CC_PTX_KERNEL = api.llvm.CallingConv.ID.PTX_Kernel -CC_PTX_DEVICE = api.llvm.CallingConv.ID.PTX_Device -CC_MBLAZE_INTR = api.llvm.CallingConv.ID.MBLAZE_INTR -CC_MBLAZE_SVOL = api.llvm.CallingConv.ID.MBLAZE_SVOL +class CCEnum(Enum): + prefix = 'CC_' + + ID = api.llvm.CallingConv.ID + + CC_C = ID.C + CC_FASTCALL = ID.Fast + CC_COLDCALL = ID.Cold + CC_GHC = ID.GHC + CC_X86_STDCALL = ID.X86_StdCall + CC_X86_FASTCALL = ID.X86_FastCall + CC_ARM_APCS = ID.ARM_APCS + CC_ARM_AAPCS = ID.ARM_AAPCS + CC_ARM_AAPCS_VFP = ID.ARM_AAPCS_VFP + CC_MSP430_INTR = ID.MSP430_INTR + CC_X86_THISCALL = ID.X86_ThisCall + CC_PTX_KERNEL = ID.PTX_Kernel + CC_PTX_DEVICE = ID.PTX_Device + CC_MBLAZE_INTR = ID.MBLAZE_INTR + CC_MBLAZE_SVOL = ID.MBLAZE_SVOL + +CCEnum.declare() # int predicates -ICMP_EQ = api.llvm.CmpInst.Predicate.ICMP_EQ -ICMP_NE = api.llvm.CmpInst.Predicate.ICMP_NE -ICMP_UGT = api.llvm.CmpInst.Predicate.ICMP_UGT -ICMP_UGE = api.llvm.CmpInst.Predicate.ICMP_UGE -ICMP_ULT = api.llvm.CmpInst.Predicate.ICMP_ULT -ICMP_ULE = api.llvm.CmpInst.Predicate.ICMP_ULE -ICMP_SGT = api.llvm.CmpInst.Predicate.ICMP_SGT -ICMP_SGE = api.llvm.CmpInst.Predicate.ICMP_SGE -ICMP_SLT = api.llvm.CmpInst.Predicate.ICMP_SLT -ICMP_SLE = api.llvm.CmpInst.Predicate.ICMP_SLE +class ICMPEnum(Enum): + prefix = 'ICMP_' + + Predicate = api.llvm.CmpInst.Predicate + ICMP_EQ = Predicate.ICMP_EQ + ICMP_NE = Predicate.ICMP_NE + ICMP_UGT = Predicate.ICMP_UGT + ICMP_UGE = Predicate.ICMP_UGE + ICMP_ULT = Predicate.ICMP_ULT + ICMP_ULE = Predicate.ICMP_ULE + ICMP_SGT = Predicate.ICMP_SGT + ICMP_SGE = Predicate.ICMP_SGE + ICMP_SLT = Predicate.ICMP_SLT + ICMP_SLE = Predicate.ICMP_SLE + +ICMPEnum.declare() # same as ICMP_xx, for backward compatibility + IPRED_EQ = ICMP_EQ IPRED_NE = ICMP_NE IPRED_UGT = ICMP_UGT @@ -197,24 +242,33 @@ IPRED_SLT = ICMP_SLT IPRED_SLE = ICMP_SLE # real predicates -FCMP_FALSE = api.llvm.CmpInst.Predicate.FCMP_FALSE -FCMP_OEQ = api.llvm.CmpInst.Predicate.FCMP_OEQ -FCMP_OGT = api.llvm.CmpInst.Predicate.FCMP_OGT -FCMP_OGE = api.llvm.CmpInst.Predicate.FCMP_OGE -FCMP_OLT = api.llvm.CmpInst.Predicate.FCMP_OLT -FCMP_OLE = api.llvm.CmpInst.Predicate.FCMP_OLE -FCMP_ONE = api.llvm.CmpInst.Predicate.FCMP_ONE -FCMP_ORD = api.llvm.CmpInst.Predicate.FCMP_ORD -FCMP_UNO = api.llvm.CmpInst.Predicate.FCMP_UNO -FCMP_UEQ = api.llvm.CmpInst.Predicate.FCMP_UEQ -FCMP_UGT = api.llvm.CmpInst.Predicate.FCMP_UGT -FCMP_UGE = api.llvm.CmpInst.Predicate.FCMP_UGE -FCMP_ULT = api.llvm.CmpInst.Predicate.FCMP_ULT -FCMP_ULE = api.llvm.CmpInst.Predicate.FCMP_ULE -FCMP_UNE = api.llvm.CmpInst.Predicate.FCMP_UNE -FCMP_TRUE = api.llvm.CmpInst.Predicate.FCMP_TRUE + +class FCMPEnum(Enum): + prefix = 'FCMP_' + + Predicate = api.llvm.CmpInst.Predicate + + FCMP_FALSE = Predicate.FCMP_FALSE + FCMP_OEQ = Predicate.FCMP_OEQ + FCMP_OGT = Predicate.FCMP_OGT + FCMP_OGE = Predicate.FCMP_OGE + FCMP_OLT = Predicate.FCMP_OLT + FCMP_OLE = Predicate.FCMP_OLE + FCMP_ONE = Predicate.FCMP_ONE + FCMP_ORD = Predicate.FCMP_ORD + FCMP_UNO = Predicate.FCMP_UNO + FCMP_UEQ = Predicate.FCMP_UEQ + FCMP_UGT = Predicate.FCMP_UGT + FCMP_UGE = Predicate.FCMP_UGE + FCMP_ULT = Predicate.FCMP_ULT + FCMP_ULE = Predicate.FCMP_ULE + FCMP_UNE = Predicate.FCMP_UNE + FCMP_TRUE = Predicate.FCMP_TRUE + +FCMPEnum.declare() # real predicates + RPRED_FALSE = FCMP_FALSE RPRED_OEQ = FCMP_OEQ RPRED_OGT = FCMP_OGT @@ -233,68 +287,69 @@ RPRED_UNE = FCMP_UNE RPRED_TRUE = FCMP_TRUE # linkages (see llvm::GlobalValue::LinkageTypes) -LINKAGE_EXTERNAL = \ - api.llvm.GlobalValue.LinkageTypes.ExternalLinkage -LINKAGE_AVAILABLE_EXTERNALLY = \ - api.llvm.GlobalValue.LinkageTypes.AvailableExternallyLinkage -LINKAGE_LINKONCE_ANY = \ - api.llvm.GlobalValue.LinkageTypes.LinkOnceAnyLinkage -LINKAGE_LINKONCE_ODR = \ - api.llvm.GlobalValue.LinkageTypes.LinkOnceODRLinkage -LINKAGE_WEAK_ANY = \ - api.llvm.GlobalValue.LinkageTypes.WeakAnyLinkage -LINKAGE_WEAK_ODR = \ - api.llvm.GlobalValue.LinkageTypes.WeakODRLinkage -LINKAGE_APPENDING = \ - api.llvm.GlobalValue.LinkageTypes.AppendingLinkage -LINKAGE_INTERNAL = \ - api.llvm.GlobalValue.LinkageTypes.InternalLinkage -LINKAGE_PRIVATE = \ - api.llvm.GlobalValue.LinkageTypes.PrivateLinkage -LINKAGE_DLLIMPORT = \ - api.llvm.GlobalValue.LinkageTypes.DLLImportLinkage -LINKAGE_DLLEXPORT = \ - api.llvm.GlobalValue.LinkageTypes.DLLExportLinkage -LINKAGE_EXTERNAL_WEAK = \ - api.llvm.GlobalValue.LinkageTypes.ExternalWeakLinkage -LINKAGE_COMMON = \ - api.llvm.GlobalValue.LinkageTypes.CommonLinkage -LINKAGE_LINKER_PRIVATE = \ - api.llvm.GlobalValue.LinkageTypes.LinkerPrivateLinkage -LINKAGE_LINKER_PRIVATE_WEAK = \ - api.llvm.GlobalValue.LinkageTypes.LinkerPrivateWeakLinkage +class LinkageEnum(Enum): + prefix = 'LINKAGE_' + LinkageTypes = api.llvm.GlobalValue.LinkageTypes + + LINKAGE_EXTERNAL = LinkageTypes.ExternalLinkage + LINKAGE_AVAILABLE_EXTERNALLY = LinkageTypes.AvailableExternallyLinkage + LINKAGE_LINKONCE_ANY = LinkageTypes.LinkOnceAnyLinkage + LINKAGE_LINKONCE_ODR = LinkageTypes.LinkOnceODRLinkage + LINKAGE_WEAK_ANY = LinkageTypes.WeakAnyLinkage + LINKAGE_WEAK_ODR = LinkageTypes.WeakODRLinkage + LINKAGE_APPENDING = LinkageTypes.AppendingLinkage + LINKAGE_INTERNAL = LinkageTypes.InternalLinkage + LINKAGE_PRIVATE = LinkageTypes.PrivateLinkage + LINKAGE_DLLIMPORT = LinkageTypes.DLLImportLinkage + LINKAGE_DLLEXPORT = LinkageTypes.DLLExportLinkage + LINKAGE_EXTERNAL_WEAK = LinkageTypes.ExternalWeakLinkage + LINKAGE_COMMON = LinkageTypes.CommonLinkage + LINKAGE_LINKER_PRIVATE = LinkageTypes.LinkerPrivateLinkage + LINKAGE_LINKER_PRIVATE_WEAK = LinkageTypes.LinkerPrivateWeakLinkage + +LinkageEnum.declare() # visibility (see llvm/GlobalValue.h) -VISIBILITY_DEFAULT = api.llvm.GlobalValue.VisibilityTypes.DefaultVisibility -VISIBILITY_HIDDEN = api.llvm.GlobalValue.VisibilityTypes.HiddenVisibility -VISIBILITY_PROTECTED = api.llvm.GlobalValue.VisibilityTypes.ProtectedVisibility +class VisibilityEnum(Enum): + prefix = 'VISIBILITY_' + + VISIBILITY_DEFAULT = api.llvm.GlobalValue.VisibilityTypes.DefaultVisibility + VISIBILITY_HIDDEN = api.llvm.GlobalValue.VisibilityTypes.HiddenVisibility + VISIBILITY_PROTECTED = api.llvm.GlobalValue.VisibilityTypes.ProtectedVisibility + +VisibilityEnum.declare() # parameter attributes llvm::Attributes::AttrVal (see llvm/Attributes.h) -ATTR_NONE = api.llvm.Attributes.AttrVal.None_ -ATTR_ZEXT = api.llvm.Attributes.AttrVal.ZExt -ATTR_SEXT = api.llvm.Attributes.AttrVal.SExt -ATTR_NO_RETURN = api.llvm.Attributes.AttrVal.NoReturn -ATTR_IN_REG = api.llvm.Attributes.AttrVal.InReg -ATTR_STRUCT_RET = api.llvm.Attributes.AttrVal.StructRet -ATTR_NO_UNWIND = api.llvm.Attributes.AttrVal.NoUnwind -ATTR_NO_ALIAS = api.llvm.Attributes.AttrVal.NoAlias -ATTR_BY_VAL = api.llvm.Attributes.AttrVal.ByVal -ATTR_NEST = api.llvm.Attributes.AttrVal.Nest -ATTR_READ_NONE = api.llvm.Attributes.AttrVal.ReadNone -ATTR_READONLY = api.llvm.Attributes.AttrVal.ReadOnly -ATTR_NO_INLINE = api.llvm.Attributes.AttrVal.NoInline -ATTR_ALWAYS_INLINE = api.llvm.Attributes.AttrVal.AlwaysInline -ATTR_OPTIMIZE_FOR_SIZE = api.llvm.Attributes.AttrVal.OptimizeForSize -ATTR_STACK_PROTECT = api.llvm.Attributes.AttrVal.StackProtect -ATTR_STACK_PROTECT_REQ = api.llvm.Attributes.AttrVal.StackProtectReq -ATTR_ALIGNMENT = api.llvm.Attributes.AttrVal.Alignment -ATTR_NO_CAPTURE = api.llvm.Attributes.AttrVal.NoCapture -ATTR_NO_REDZONE = api.llvm.Attributes.AttrVal.NoRedZone -ATTR_NO_IMPLICIT_FLOAT = api.llvm.Attributes.AttrVal.NoImplicitFloat -ATTR_NAKED = api.llvm.Attributes.AttrVal.Naked -ATTR_INLINE_HINT = api.llvm.Attributes.AttrVal.InlineHint -ATTR_STACK_ALIGNMENT = api.llvm.Attributes.AttrVal.StackAlignment +class AttrEnum(Enum): + prefix = 'ATTR_' + AttrVal = api.llvm.Attributes.AttrVal + ATTR_NONE = AttrVal.None_ + ATTR_ZEXT = AttrVal.ZExt + ATTR_SEXT = AttrVal.SExt + ATTR_NO_RETURN = AttrVal.NoReturn + ATTR_IN_REG = AttrVal.InReg + ATTR_STRUCT_RET = AttrVal.StructRet + ATTR_NO_UNWIND = AttrVal.NoUnwind + ATTR_NO_ALIAS = AttrVal.NoAlias + ATTR_BY_VAL = AttrVal.ByVal + ATTR_NEST = AttrVal.Nest + ATTR_READ_NONE = AttrVal.ReadNone + ATTR_READONLY = AttrVal.ReadOnly + ATTR_NO_INLINE = AttrVal.NoInline + ATTR_ALWAYS_INLINE = AttrVal.AlwaysInline + ATTR_OPTIMIZE_FOR_SIZE = AttrVal.OptimizeForSize + ATTR_STACK_PROTECT = AttrVal.StackProtect + ATTR_STACK_PROTECT_REQ = AttrVal.StackProtectReq + ATTR_ALIGNMENT = AttrVal.Alignment + ATTR_NO_CAPTURE = AttrVal.NoCapture + ATTR_NO_REDZONE = AttrVal.NoRedZone + ATTR_NO_IMPLICIT_FLOAT = AttrVal.NoImplicitFloat + ATTR_NAKED = AttrVal.Naked + ATTR_INLINE_HINT = AttrVal.InlineHint + ATTR_STACK_ALIGNMENT = AttrVal.StackAlignment + +AttrEnum.declare() class Module(llvm.Wrapper): """A Module instance stores all the information related to an LLVM module. @@ -1405,6 +1460,12 @@ class Argument(Value): alignment = property(_get_alignment, _set_alignment) + @property + def attributes(self): + '''Returns a set of defined attributes. + ''' + return set(attr for attr in self._valid_attrs if attr in self) + def __contains__(self, attr): if attr == ATTR_BY_VAL: return self.has_by_val() From edab81ed7e75006fbc490e691b212295aef3723f Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 17 May 2013 14:05:40 -0500 Subject: [PATCH 376/516] Fix GC problem with Module when it is GCed but re-instantiate from GlobalValue.module. --- llvmpy/src/GlobalValue.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvmpy/src/GlobalValue.py b/llvmpy/src/GlobalValue.py index ff499f7..d954ed0 100644 --- a/llvmpy/src/GlobalValue.py +++ b/llvmpy/src/GlobalValue.py @@ -46,4 +46,4 @@ class GlobalValue: eraseFromParent = Method() eraseFromParent.disowning = True - getParent = Method(ptr(Module)) + getParent = Method(ownedptr(Module)) From 5b2b878f24cc5e56d8aaf5bf01757ff0594139db Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 22 May 2013 15:17:59 -0500 Subject: [PATCH 377/516] Enable MCJIT --- llvm/ee.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/llvm/ee.py b/llvm/ee.py index e4ee4bc..7ea90d0 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -167,6 +167,11 @@ class EngineBuilder(llvm.Wrapper): ptr = self._ptr.selectTarget() return TargetMachine(ptr) + def mcjit(self, enable): + '''Enable/disable MCJIT + ''' + self._ptr.setUseMCJIT(enable) + return self #===----------------------------------------------------------------------=== # Execution engine From a0eb03b23950b9095f30e0bf15cd48d03166ab6e Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 23 May 2013 11:45:15 -0500 Subject: [PATCH 378/516] Fix CompareInstruction.predicate --- llvm/core.py | 18 ++++++++++++++-- llvm/test_llvmpy.py | 51 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index 9cb1946..fd72902 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -55,12 +55,18 @@ class Enum(int): @classmethod def declare(cls): + declared = cls._declared_ = {} scope = globals() for name in filter(lambda s: s.startswith(cls.prefix), dir(cls)): n = getattr(cls, name) typ = type(name, (cls,), {}) - scope[name] = typ(n) + obj = typ(n) + declared[n] = obj + scope[name] = obj + @classmethod + def get(cls, num): + return cls._declared_[num] # type id (llvm::Type::TypeID) class TypeEnum(Enum): @@ -1872,16 +1878,24 @@ class PHINode(Instruction): class SwitchInstruction(Instruction): + _type_ = api.llvm.SwitchInst def add_case(self, const, bblk): self._ptr.addCase(const._ptr, bblk._ptr) class CompareInstruction(Instruction): + _type_ = api.llvm.CmpInst @property def predicate(self): - return self._ptr.getPredicate() + n = self._ptr.getPredicate() + try: + return ICMPEnum.get(n) + except KeyError: + return FCMPEnum.get(n) + + #===----------------------------------------------------------------------=== # Basic block #===----------------------------------------------------------------------=== diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 3ecffff..e21a825 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -1302,6 +1302,57 @@ class TestArgAttr(TestCase): tests.append(TestArgAttr) +# --------------------------------------------------------------------------- + +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) + +# --------------------------------------------------------------------------- + +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) + + # --------------------------------------------------------------------------- def run(verbosity=1): From 1812cff2d0e23eaaccbe609d1bd9ae69b0af568f Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Sat, 25 May 2013 13:34:14 -0500 Subject: [PATCH 379/516] Fix import problem. --- llvm_array/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm_array/__init__.py b/llvm_array/__init__.py index f6a0f3f..5e807c2 100644 --- a/llvm_array/__init__.py +++ b/llvm_array/__init__.py @@ -1,2 +1,2 @@ from __future__ import absolute_imports -from .array.py import * +from .array import * From 009239713eb97ead506584652325f9ddf260557a Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Sat, 25 May 2013 13:35:37 -0500 Subject: [PATCH 380/516] Update llvm_array concepts. --- llvm_array/array.py | 261 +++++++++++++++++++++++++++++++------------- 1 file changed, 187 insertions(+), 74 deletions(-) diff --git a/llvm_array/array.py b/llvm_array/array.py index 12df60e..3cac244 100644 --- a/llvm_array/array.py +++ b/llvm_array/array.py @@ -24,19 +24,98 @@ # intp stride; #} diminfo # +# These are for low-level array-routines that need to know the number +# of dimensions at run-time (not just code-generation time): +# +# The first two are recommended +# +# struct { +# eltype *data; +# int32 nd; +# intp shape[nd]; +# } contiguous_array_nd(eltype) +# +# struct { +# eltype *data; +# int32 nd; +# diminfo shape[nd]; +# } strided_array_nd(eltype) +# +# +# Backward compatible but deprecated: +# struct { +# eltype *data; +# int32 nd; +# intp shape[nd]; +# intp stride[nd]; +# } strided_soa_array_nd(eltype) +# +# +# The most general (where the kind of array is stored as well as number +# of dimensions) +# Rarely needed. +# +# struct { +# eltype *data; +# int16 nd; +# int16 dimkind; +# ??? +# } array_nd(eltype) +# +# where ??? is run-time interpreted based on the dimkind to either: +# intp shape[nd]; for dimkind = C_CONTIGUOUS or F_CONTIGUOUS +# +# diminfo shape[nd]; for dimkind = STRIDED +# +# intp shape[ind]; +# intp strides[ind]; dimkind = STRIDED_SOA +# import llvm.core as lc from llvm.core import Type import llvm_cbuilder.shortnames as C -CONTIGUOUS = 1 << 8 -STRIDED = CONTIGUOUS + 1 -STRIDED_SOA = CONTIGUOUS + 2 +# Different Array Types +ARRAYBIT = 1<<4 +C_CONTIGUOUS = ARRAYBIT + 0 +F_CONTIGUOUS = ARRAYBIT + 1 +STRIDED = ARRAYBIT + 2 +STRIDED_SOA = ARRAYBIT + 3 -array_kinds = (CONTIGUOUS, STRIDED, STRIDED_SOA) +HAS_ND = 1<<5 +C_CONTIGUOUS_ND = C_CONTIGUOUS + HAS_ND +F_CONTIGUOUS_ND = F_CONTIGUOUS + HAS_ND +STRIDED_ND = STRIDED + HAS_ND +STRIDED_SOA_ND = STRIDED_SOA + HAS_ND + +HAS_DIMKIND = 1<<6 +C_CONTIGUOUS_DK = C_CONTIGUOUS + HAS_DIMKIND +F_CONTIGUOUS_DK = F_CONTIGUOUS + HAS_DIMKIND +STRIDED_DK = STRIDED + HAS_DIMKIND +STRIDED_SOA_DK = STRIDED_SOA + HAS_DIMKIND + +array_kinds = (C_CONTIGUOUS, F_CONTIGUOUS, STRIDED, STRIDED_SOA, + C_CONTIGUOUS_ND, F_CONTIGUOUS_ND, STRIDED_ND, STRIDED_SOA_DK, + C_CONTIGUOUS_DK, F_CONTIGUOUS_DK, STRIDED_DK, STRIDED_SOA_DK) + +_invmap = {} + +def kind_to_str(kind): + global _invmap + if not _invmap: + for key, value in globals().items(): + if isinstance(value, int) and value in array_kinds: + _invmap[value] = key + return _invmap[kind] + +def str_to_kind(str): + trial = eval(str) + if trial not in array_kinds: + raise ValueError("Invalid Array Kind") + return trial void_type = C.void -int_type = C.int +int32_type = C.int32 char_type = C.char int16_type = C.int16 intp_type = C.intp @@ -45,99 +124,133 @@ diminfo_type = Type.struct([intp_type, # shape intp_type # stride ], name='diminfo') -# This is the way we define LLVM arrays. -def cont_array_type(nd, el_type=char_type, name=''): - terms = [Type.pointer(el_type), # data - Type.array(intp_type, nd) # shape - ] - return Type.struct(terms, name=name) +_cache = {} +# This is the way we define LLVM arrays. +# CONTIGUOUS and STRIDED are strongly encouraged... +def array_type(nd, kind, el_type=char_type): + key = (kind, nd, el_type) + if _cache.has_key(key): + return _cache[key] -def strided_array_type(nd, el_type=char_type, name=''): - terms = [Type.pointer(el_type), # data - Type.array(diminfo_type, nd) # diminfo - ] - return Type.struct(terms, name=name) + base = kind & (~(HAS_ND | HAS_DIMKIND)) + if base == C_CONTIGUOUS: + dimstr = 'Array_C' + elif base == F_CONTIGUOUS: + dimstr = 'Array_F' + elif base == STRIDED: + dimstr = 'Array_S' + elif base == STRIDED_SOA: + dimstr = 'Array_A' + else: + raise TypeError("Do not understand Array kind of %d" % kind) + + terms = [Type.pointer(el_type)] # data + + if (kind & HAS_ND): + terms.append(int32_type) # nd + dimstr += '_ND' + elif (kind & HAS_DIMKIND): + terms.extend([int16_type, int16_type]) # nd, dimkind + dimstr += '_DK' + + if base in [C_CONTIGUOUS, F_CONTIGUOUS]: + terms.append(Type.array(intp_type, nd)) # shape + elif base == STRIDED: + terms.append(Type.array(diminfo_type, nd)) # diminfo + elif base == STRIDED_SOA: + terms.extend([Type.array(intp_type, nd), # shape + Type.array(intp_type, nd)]) # strides + + ret = Type.struct(terms, name=dimstr) + _cache[key] = ret + return ret -def 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): if not isinstance(arrtyp, lc.StructType): return None - 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): + if arrtyp.element_count not in [2, 3, 4, 5]: return None - data_type = arrtyp.elements[0].pointee - s1 = arrtyp.elements[1] + # Look through _cache and see if it's there + for key, value in _cache.items(): + if arrtyp is value: + return key + + return _raw_check_array(arrtyp) + +# Manual check +def _raw_check_array(arrtyp): + a0 = arrtyp.elements[0] + a1 = arrtyp.elements[1] + if not isinstance(a0, lc.PointerType) or \ + not (isinstance(a1, lc.ArrayType) or + (a1 == int32_type) or (a1 == int16_type)): + return None + + data_type = a0.pointee + + if arrtyp.is_literal: + c_contig = True + else: + if arrtyp.name.startswith('Array_F'): + c_contig = False + else: + c_contig = True + + + if a1 == int32_type: + num = 2 + strided = STRIDED_ND + strided_soa = STRIDED_SOA_ND + c_contiguous = C_CONTIGUOUS_ND + f_contiguous = F_CONTIGUOUS_ND + elif a1 == int16_type: + if arrtyp.element_count < 3 or arrtyp.elements[2] != int16_type: + return None + num = 3 + strided = STRIDED_DK + strided_soa = STRIDED_SOA_DK + c_contiguous = C_CONTIGUOUS_DK + f_contiguous = F_CONTIGUOUS_DK + else: + num = 1 + strided = STRIDED + strided_soa = STRIDED_SOA + c_contiguous = C_CONTIGUOUS + f_contiguous = F_CONTIGUOUS + + elcount = num + 2 + # otherwise we have lc.ArrType as element [1] + if arrtyp.element_count not in [num+1,num+2]: + return None + s1 = arrtyp.elements[num] nd = s1.count - if arrtyp.element_count == 3: - if not isinstance(arrtyp.elements[2], lc.ArrayType): + if arrtyp.element_count == elcount: + if not isinstance(arrtyp.elements[num+1], lc.ArrayType): return None - s2 = arrtyp.elements[2] + s2 = arrtyp.elements[num+1] if s1.element != intp_type or s2.element != intp_type: return None if s1.count != s2.count: return None - return STRIDED_SOA, nd, data_type + return strided_soa, nd, data_type if s1.element == diminfo_type: - return STRIDED, nd, data_type + return strided, nd, data_type elif s1.element == intp_type: - return CONTIGUOUS, nd, data_type + return c_contiguous if c_contig else f_contiguous, nd, data_type else: 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(): - arr = cont_array_type(5) - assert check_array(arr) == (CONTIGUOUS, 5, char_type) - arr = strided_array_type(4) + arr = array_type(5, C_CONTIGUOUS) + assert check_array(arr) == (C_CONTIGUOUS, 5, char_type) + arr = array_type(4, STRIDED) assert check_array(arr) == (STRIDED, 4, char_type) - arr = strided_soa_type(3) + arr = array_type(3, STRIDED_SOA) assert check_array(arr) == (STRIDED_SOA, 3, char_type) if __name__ == '__main__': From 6b333e84aa249869401ab5c02dd0cf95b43d6984 Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Mon, 27 May 2013 12:22:13 +0100 Subject: [PATCH 381/516] Use error message string from BytesIO --- llvm/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/core.py b/llvm/core.py index fd72902..9c8501e 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -504,7 +504,7 @@ class Module(llvm.Wrapper): mode, errmsg) if failed: - raise llvm.LLVMException(errmsg) + raise llvm.LLVMException(errmsg.getvalue()) def get_type_named(self, name): typ = self._ptr.getTypeByName(name) From 17ec89e457c05b3fdb004fb3636d47ea853484d0 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 28 May 2013 19:23:40 -0500 Subject: [PATCH 382/516] Fix win32 build --- llvm-config-win32.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/llvm-config-win32.py b/llvm-config-win32.py index 05fc94f..5f6c401 100644 --- a/llvm-config-win32.py +++ b/llvm-config-win32.py @@ -98,6 +98,9 @@ def main(): if option == '--version': print(get_llvm_version()) + elif option == '--targets-built': + print('X86') # just do X86 + elif option == '--libs': libs_options() From 2e8944916c8a95855ec26fcdc07d4094c1681aba Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 29 May 2013 16:16:19 -0500 Subject: [PATCH 383/516] Add DIBuilder binding --- llvmpy/src/DIBuilder.py | 357 +++++++++++++++++++++++ llvmpy/src/DebugInfo.py | 98 +++++++ llvmpy/src/Support/Dwarf.py | 563 ++++++++++++++++++++++++++++++++++++ 3 files changed, 1018 insertions(+) create mode 100644 llvmpy/src/DIBuilder.py create mode 100644 llvmpy/src/DebugInfo.py create mode 100644 llvmpy/src/Support/Dwarf.py diff --git a/llvmpy/src/DIBuilder.py b/llvmpy/src/DIBuilder.py new file mode 100644 index 0000000..9671963 --- /dev/null +++ b/llvmpy/src/DIBuilder.py @@ -0,0 +1,357 @@ +from binding import * +from .namespace import llvm + +DIBuilder = llvm.Class() + +from .Module import Module +from .Value import Value, MDNode, Function, BasicBlock +from .Instruction import Instruction +from .DebugInfo import DIFile, DIEnumerator, DIType, DIBasicType, DIDerivedType +from .DebugInfo import DIDescriptor, DIArray, DISubrange, DIGlobalVariable +from .DebugInfo import DIVariable, DISubprogram, DINameSpace, DILexicalBlockFile +from .DebugInfo import DILexicalBlock +from .ADT.SmallVector import SmallVector_Value +from .ADT.StringRef import StringRef + +unsigned_arg = cast(int, Unsigned) +stringref_arg = cast(str, StringRef) +bool_arg = cast(bool, Bool) +uint64_arg = cast(int, Uint64) +int64_arg = cast(int, Int64) + +@DIBuilder +class DIBuilder: + _include_ = 'llvm/DIBuilder.h' + new = Constructor(ref(Module)) + delete = Destructor() + + getCU = Method(const(ptr(MDNode))) + finalize = Method() + + createCompileUnit = Method(Void, + unsigned_arg, # Lang + stringref_arg, # File + stringref_arg, # Dir + stringref_arg, # Producer + bool_arg, # isOptimized + stringref_arg, # Flags, + unsigned_arg, # RV + # stringref_arg, # SplitName LLVM3.3 + ) #.require_only(7) + + createFile = Method(DIFile, + stringref_arg, # Filename + stringref_arg, # Directory + ) + + createEnumerator = Method(DIEnumerator, + stringref_arg, # Name + uint64_arg, # Val + ) + + createNullPtrType = Method(DIType, + stringref_arg, # Name + ) + + createBasicType = Method(DIType, + stringref_arg, # Name + uint64_arg, # SizeIntBits, + uint64_arg, # AlignInBits, + unsigned_arg, # Encoding + ) + + createQualifiedType = Method(DIType, + unsigned_arg, # Tag + ref(DIType), # FromTy + ) + + createPointerType = Method(DIType, + ref(DIType), # PointeeTy + uint64_arg, # SizeInBits + uint64_arg, # AlignInBits + stringref_arg, # Name + ).require_only(2) + + createReferenceType = Method(DIType, + unsigned_arg, # Tag + ref(DIType), # RTy + ) + + createTypedef = Method(DIType, + ref(DIType), # Ty + stringref_arg, # Name + ref(DIFile), # File + unsigned_arg, # LineNo + ref(DIDescriptor), # Context + ) + + createFriend = Method(DIType, + ref(DIType), # Ty + ref(DIType), # FriendTy + ) + + createInheritance = Method(DIType, + ref(DIType), # Ty + ref(DIType), # BaseTy + uint64_arg, # BaseOffset + unsigned_arg, # Flags + ) + + createMemberType = Method(DIType, + ref(DIDescriptor), # Scope + stringref_arg, # Name + ref(DIFile), # File + unsigned_arg, # LineNo + uint64_arg, # SizeInBits + uint64_arg, # AlignInBits + uint64_arg, # OffsetInBits + unsigned_arg, # Flags + ref(DIType), # Ty + ) + + createClassType = Method(DIType, + ref(DIDescriptor), # Scope + stringref_arg, # Name + ref(DIFile), # File + unsigned_arg, # LineNum + uint64_arg, # SizeInBits + uint64_arg, # AlignInBits + uint64_arg, # OffsetInBits, + unsigned_arg, # Flags + ref(DIType), # DerivedFrom + ref(DIArray), # Elements + ptr(MDNode), # VTableHolder = 0 + ptr(MDNode), # TemplateParms = 0 + ).require_only(10) + + createStructType = Method(DIType, + ref(DIDescriptor), # Scope + stringref_arg, # Name + ref(DIFile), # File + unsigned_arg, # LineNumber + uint64_arg, # SizeInBits + uint64_arg, # AlignInBits + unsigned_arg, # Flags + ref(DIArray), # Elements + unsigned_arg, # RunTimeLang = 0 + ).require_only(8) + + createUnionType = Method(DIType, + ref(DIDescriptor), # Scope + stringref_arg, # Name + ref(DIFile), # File + unsigned_arg, # LineNum + uint64_arg, # SizeInBits + uint64_arg, # AlignInBits + unsigned_arg, # Flags + ref(DIArray), # Elements + unsigned_arg, # RunTimeLang = 0 + ).require_only(8) + + createArrayType = Method(DIType, + uint64_arg, # Size + uint64_arg, # AlignInBits + ref(DIType), # Ty + ref(DIArray), # Subscripts + ) + + createVectorType = Method(DIType, + uint64_arg, # Size + uint64_arg, # AlignInBits + ref(DIType), # Ty + ref(DIArray), # Subscripts + ) + + createEnumerationType = Method(DIType, + ref(DIDescriptor), # Scope + stringref_arg, # Name + ref(DIFile), # File + unsigned_arg, # LineNumber + uint64_arg, # SizeInBits + uint64_arg, # AlignInBits + ref(DIArray), # Elements + ref(DIType), # ClassType + ) + + createSubroutineType = Method(DIType, + ref(DIFile), # File + ref(DIArray), # ParameterTypes + ) + + createArtificialType = Method(DIType, + ref(DIType), # Ty + ) + + createObjectPointerType = Method(DIType, + ref(DIType), # Ty + ) + + createTemporaryType = Method(DIType, ref(DIFile)).require_only(0) + + createForwardDecl = Method(DIType, + unsigned_arg, # Tag + stringref_arg, # Name + ref(DIDescriptor), # scope + ref(DIFile), # F + unsigned_arg, # Line + unsigned_arg, # RuntimeLang=0 + uint64_arg, # SizeInBits=0 + uint64_arg, # AlignInBits=0 + ).require_only(5) + + retainType = Method(Void, ref(DIType)) + + createUnspecifiedParameter = Method(DIDescriptor) + + getOrCreateArray = Method(DIArray, + ref(SmallVector_Value), # Elements + ) + + getOrCreateSubrange = Method(DISubrange, + int64_arg, # Lo + int64_arg, # Hi + ) + + createGlobalVariable = Method(DIGlobalVariable, + stringref_arg, # Name + ref(DIFile), # File + unsigned_arg, # LineNo + ref(DIType), # Ty + bool_arg, # isLocalToUnit + ptr(Value), # Val + ) + + createStaticVariable = Method(DIGlobalVariable, + ref(DIDescriptor), # Context + stringref_arg, # Name + stringref_arg, # LinkageName + ref(DIFile), # File + unsigned_arg, # LineNo + ref(DIType), # Ty + bool_arg, # isLocalToUnit + ptr(Value), # Val + ) + + createLocalVariable = Method(DIVariable, + unsigned_arg, # Tag, + ref(DIDescriptor), # Scope, + stringref_arg, # Name, + ref(DIFile), # File, + unsigned_arg, # LineNo, + ref(DIType), # Ty, + bool_arg, # AlwaysPreserve=false, + unsigned_arg, # Flags=0, + unsigned_arg, # ArgNo=0 + ).require_only(6) + + createComplexVariable = Method(DIVariable, + unsigned_arg, # Tag, + ref(DIDescriptor), # Scope, + stringref_arg, # Name, + ref(DIFile), # F, + unsigned_arg, # LineNo, + ref(DIType), # Ty, + ref(SmallVector_Value), # Addr, + unsigned_arg, # ArgNo=0, + ).require_only(7) + + createFunction = Method(DISubprogram, + ref(DIDescriptor), # Scope + stringref_arg, # Name + stringref_arg, # LinkageName + ref(DIFile), # File + unsigned_arg, # LineNo + ref(DIType), # Ty + bool_arg, # isLocalToUnit + bool_arg, # isDefinition + unsigned_arg, # ScopeLine + unsigned_arg, # Flags=0 + bool_arg, # isOptimized=false + ptr(Function), # *Fn=0 + ptr(MDNode), # *TParam=0, + ptr(MDNode), # *Decl=0 + ).require_only(9) + + + createMethod = Method(DISubprogram, + ref(DIDescriptor), # Scope + stringref_arg, # Name + stringref_arg, # LinkageName + ref(DIFile), # File + unsigned_arg, # LineNo + ref(DIType), # Ty + bool_arg, # isLocalToUnit + bool_arg, # isDefinition + unsigned_arg, # Virtuality=0 + unsigned_arg, # VTableIndex=0 + ptr(MDNode), # *VTableHolder=0 + unsigned_arg, # Flags=0 + bool_arg, # isOptimized=false + ptr(Function), # *Fn=0 + ptr(MDNode), # *TParam=0 + ).require_only(8) + + + createNameSpace = Method(DINameSpace, + ref(DIDescriptor), # Scope, + stringref_arg, # Name, + ref(DIFile), # File, + unsigned_arg, # LineNo + ) + + createLexicalBlockFile = Method(DILexicalBlockFile, + ref(DIDescriptor), # Scope, + ref(DIFile), # File + ) + + createLexicalBlock = Method(DILexicalBlock, + ref(DIDescriptor), # Scope, + ref(DIFile), # File, + unsigned_arg, # Line, + unsigned_arg, # Col + ) + + _insertDeclare_1 = Method(ptr(Instruction), + ptr(Value), # Storage, + ref(DIVariable), # VarInfo + ptr(BasicBlock), # *InsertAtEnd + ) + _insertDeclare_1.realname = 'insertDeclare' + + _insertDeclare_2 = Method(ptr(Instruction), + ptr(Value), # Storage, + ref(DIVariable), # VarInfo + ptr(Instruction), # *InsertBefore + ) + _insertDeclare_2.realname = 'insertDeclare' + + @CustomPythonMethod + def insertDeclare(self, storage, varinfo, insertpt): + if isinstance(insertbefore, _api.llvm.Instruction): + return self._insertDeclare_2(storage, varinfo, insertpt) + else: + return self._insertDeclare_1(storage, varinfo, insertpt) + + _insertDbgValueIntrinsic_1 = Method(ptr(Instruction), + ptr(Value), # *Val + uint64_arg, # Offset + ref(DIVariable), # VarInfo + ptr(BasicBlock), # *InsertAtEnd + ) + _insertDbgValueIntrinsic_1.realname = 'insertDbgValueIntrinsic' + + _insertDbgValueIntrinsic_2 = Method(ptr(Instruction), + ptr(Value), # *Val + uint64_arg, # Offset + ref(DIVariable), # VarInfo + ptr(Instruction), # *InsertAtEnd + ) + _insertDbgValueIntrinsic_2.realname = 'insertDbgValueIntrinsic' + + + @CustomPythonMethod + def insertDbgValueIntrinsic(self, storage, varinfo, insertpt): + if isinstance(insertbefore, _api.llvm.Instruction): + return self._insertDbgValueIntrinsic_2(storage, varinfo, insertpt) + else: + return self._insertDbgValueIntrinsic_1(storage, varinfo, insertpt) diff --git a/llvmpy/src/DebugInfo.py b/llvmpy/src/DebugInfo.py new file mode 100644 index 0000000..81fe168 --- /dev/null +++ b/llvmpy/src/DebugInfo.py @@ -0,0 +1,98 @@ +from binding import * +from .namespace import llvm + +from .ADT.StringRef import StringRef +from .Value import MDNode + +DIDescriptor = llvm.Class(MDNode) +DIEnumerator = llvm.Class(DIDescriptor) +DIScope = llvm.Class(DIDescriptor) +DIType = llvm.Class(DIScope) +DIBasicType = llvm.Class(DIType) +DIDerivedType = llvm.Class(DIType) +DICompositeType = llvm.Class(DIDerivedType) +DIFile = llvm.Class(DIScope) +DIArray = llvm.Class(DIDescriptor) +DISubrange = llvm.Class(DIDescriptor) +DIGlobalVariable = llvm.Class(DIDescriptor) +DIVariable = llvm.Class(DIDescriptor) +DISubprogram = llvm.Class(DIScope) +DINameSpace = llvm.Class(DIScope) +DILexicalBlockFile = llvm.Class(DIScope) +DILexicalBlock = llvm.Class(DIScope) + +llvm.includes.add('llvm/DebugInfo.h') + +return_bool = cast(Bool, bool) +return_stringref = cast(StringRef, str) +return_unsigned = cast(Unsigned, int) + +@DIDescriptor +class DIDescriptor: + pass + +@DIScope +class DIScope: + pass + +@DIFile +class DIFile: + # getFileNode = Method(ptr(MDNode)) # not in LLVM 3.2? + Verify = Method(return_bool) + +@DIEnumerator +class DIEnumerator: + getName = Method(return_stringref) + getEnumValue = Method(cast(Uint64, int)) + Verify = Method(return_bool) + +@DIType +class DIType: + getName = Method(return_stringref) + getLineNumber = Method(return_unsigned) + Verify = Method(return_bool) + +@DIBasicType +class DIBasicType: + pass + +@DIDerivedType +class DIDerivedType: + pass + +@DICompositeType +class DICompositeType: + pass + +@DIArray +class DIArray: + Verify = Method(return_bool) + +@DISubrange +class DISubrange: + Verify = Method(return_bool) + +@DIGlobalVariable +class DIGlobalVariable: + Verify = Method(return_bool) + +@DIVariable +class DIVariable: + Verify = Method(return_bool) + +@DISubprogram +class DISubprogram: + Verify = Method(return_bool) + +@DINameSpace +class DINameSpace: + Verify = Method(return_bool) + +@DILexicalBlockFile +class DILexicalBlockFile: + Verify = Method(return_bool) + +@DILexicalBlock +class DILexicalBlock: + Verify = Method(return_bool) + diff --git a/llvmpy/src/Support/Dwarf.py b/llvmpy/src/Support/Dwarf.py new file mode 100644 index 0000000..caecc24 --- /dev/null +++ b/llvmpy/src/Support/Dwarf.py @@ -0,0 +1,563 @@ +from binding import * +from ..namespace import llvm + +dwarf = llvm.Namespace('dwarf') + +dwarf.includes.add('llvm/Support/Dwarf.h') + +dwarf_constants = dwarf.Enum('dwarf_constants', +''' +DWARF_VERSION +DW_TAG_array_type +DW_TAG_class_type +DW_TAG_entry_point +DW_TAG_enumeration_type +DW_TAG_formal_parameter +DW_TAG_imported_declaration +DW_TAG_label +DW_TAG_lexical_block +DW_TAG_member +DW_TAG_pointer_type +DW_TAG_reference_type +DW_TAG_compile_unit +DW_TAG_string_type +DW_TAG_structure_type +DW_TAG_subroutine_type +DW_TAG_typedef +DW_TAG_union_type +DW_TAG_unspecified_parameters +DW_TAG_variant +DW_TAG_common_block +DW_TAG_common_inclusion +DW_TAG_inheritance +DW_TAG_inlined_subroutine +DW_TAG_module +DW_TAG_ptr_to_member_type +DW_TAG_set_type +DW_TAG_subrange_type +DW_TAG_with_stmt +DW_TAG_access_declaration +DW_TAG_base_type +DW_TAG_catch_block +DW_TAG_const_type +DW_TAG_constant +DW_TAG_enumerator +DW_TAG_file_type +DW_TAG_friend +DW_TAG_namelist +DW_TAG_namelist_item +DW_TAG_packed_type +DW_TAG_subprogram +DW_TAG_template_type_parameter +DW_TAG_template_value_parameter +DW_TAG_thrown_type +DW_TAG_try_block +DW_TAG_variant_part +DW_TAG_variable +DW_TAG_volatile_type +DW_TAG_dwarf_procedure +DW_TAG_restrict_type +DW_TAG_interface_type +DW_TAG_namespace +DW_TAG_imported_module +DW_TAG_unspecified_type +DW_TAG_partial_unit +DW_TAG_imported_unit +DW_TAG_condition +DW_TAG_shared_type +DW_TAG_type_unit +DW_TAG_rvalue_reference_type +DW_TAG_template_alias +DW_TAG_MIPS_loop +DW_TAG_format_label +DW_TAG_function_template +DW_TAG_class_template +DW_TAG_GNU_template_template_param +DW_TAG_GNU_template_parameter_pack +DW_TAG_GNU_formal_parameter_pack +DW_TAG_lo_user +DW_TAG_APPLE_property +DW_TAG_hi_user +DW_CHILDREN_no +DW_CHILDREN_yes +DW_AT_sibling +DW_AT_location +DW_AT_name +DW_AT_ordering +DW_AT_byte_size +DW_AT_bit_offset +DW_AT_bit_size +DW_AT_stmt_list +DW_AT_low_pc +DW_AT_high_pc +DW_AT_language +DW_AT_discr +DW_AT_discr_value +DW_AT_visibility +DW_AT_import +DW_AT_string_length +DW_AT_common_reference +DW_AT_comp_dir +DW_AT_const_value +DW_AT_containing_type +DW_AT_default_value +DW_AT_inline +DW_AT_is_optional +DW_AT_lower_bound +DW_AT_producer +DW_AT_prototyped +DW_AT_return_addr +DW_AT_start_scope +DW_AT_bit_stride +DW_AT_upper_bound +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_address_class +DW_AT_artificial +DW_AT_base_types +DW_AT_calling_convention +DW_AT_count +DW_AT_data_member_location +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_declaration +DW_AT_discr_list +DW_AT_encoding +DW_AT_external +DW_AT_frame_base +DW_AT_friend +DW_AT_identifier_case +DW_AT_macro_info +DW_AT_namelist_item +DW_AT_priority +DW_AT_segment +DW_AT_specification +DW_AT_static_link +DW_AT_type +DW_AT_use_location +DW_AT_variable_parameter +DW_AT_virtuality +DW_AT_vtable_elem_location +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_byte_stride +DW_AT_entry_pc +DW_AT_use_UTF8 +DW_AT_extension +DW_AT_ranges +DW_AT_trampoline +DW_AT_call_column +DW_AT_call_file +DW_AT_call_line +DW_AT_description +DW_AT_binary_scale +DW_AT_decimal_scale +DW_AT_small +DW_AT_decimal_sign +DW_AT_digit_count +DW_AT_picture_string +DW_AT_mutable +DW_AT_threads_scaled +DW_AT_explicit +DW_AT_object_pointer +DW_AT_endianity +DW_AT_elemental +DW_AT_pure +DW_AT_recursive +DW_AT_signature +DW_AT_main_subprogram +DW_AT_data_bit_offset +DW_AT_const_expr +DW_AT_enum_class +DW_AT_linkage_name +DW_AT_lo_user +DW_AT_hi_user +DW_AT_MIPS_loop_begin +DW_AT_MIPS_tail_loop_begin +DW_AT_MIPS_epilog_begin +DW_AT_MIPS_loop_unroll_factor +DW_AT_MIPS_software_pipeline_depth +DW_AT_MIPS_linkage_name +DW_AT_MIPS_stride +DW_AT_MIPS_abstract_name +DW_AT_MIPS_clone_origin +DW_AT_MIPS_has_inlines +DW_AT_MIPS_stride_byte +DW_AT_MIPS_stride_elem +DW_AT_MIPS_ptr_dopetype +DW_AT_MIPS_allocatable_dopetype +DW_AT_MIPS_assumed_shape_dopetype +DW_AT_MIPS_assumed_size +DW_AT_sf_names +DW_AT_src_info +DW_AT_mac_info +DW_AT_src_coords +DW_AT_body_begin +DW_AT_body_end +DW_AT_APPLE_optimized +DW_AT_APPLE_flags +DW_AT_APPLE_isa +DW_AT_APPLE_block +DW_AT_APPLE_major_runtime_vers +DW_AT_APPLE_runtime_class +DW_AT_APPLE_omit_frame_ptr +DW_AT_APPLE_property_name +DW_AT_APPLE_property_getter +DW_AT_APPLE_property_setter +DW_AT_APPLE_property_attribute +DW_AT_APPLE_objc_complete_type +DW_AT_APPLE_property +DW_FORM_addr +DW_FORM_block2 +DW_FORM_block4 +DW_FORM_data2 +DW_FORM_data4 +DW_FORM_data8 +DW_FORM_string +DW_FORM_block +DW_FORM_block1 +DW_FORM_data1 +DW_FORM_flag +DW_FORM_sdata +DW_FORM_strp +DW_FORM_udata +DW_FORM_ref_addr +DW_FORM_ref1 +DW_FORM_ref2 +DW_FORM_ref4 +DW_FORM_ref8 +DW_FORM_ref_udata +DW_FORM_indirect +DW_FORM_sec_offset +DW_FORM_exprloc +DW_FORM_flag_present +DW_FORM_ref_sig8 +DW_OP_addr +DW_OP_deref +DW_OP_const1u +DW_OP_const1s +DW_OP_const2u +DW_OP_const2s +DW_OP_const4u +DW_OP_const4s +DW_OP_const8u +DW_OP_const8s +DW_OP_constu +DW_OP_consts +DW_OP_dup +DW_OP_drop +DW_OP_over +DW_OP_pick +DW_OP_swap +DW_OP_rot +DW_OP_xderef +DW_OP_abs +DW_OP_and +DW_OP_div +DW_OP_minus +DW_OP_mod +DW_OP_mul +DW_OP_neg +DW_OP_not +DW_OP_or +DW_OP_plus +DW_OP_plus_uconst +DW_OP_shl +DW_OP_shr +DW_OP_shra +DW_OP_xor +DW_OP_skip +DW_OP_bra +DW_OP_eq +DW_OP_ge +DW_OP_gt +DW_OP_le +DW_OP_lt +DW_OP_ne +DW_OP_lit0 +DW_OP_lit1 +DW_OP_lit2 +DW_OP_lit3 +DW_OP_lit4 +DW_OP_lit5 +DW_OP_lit6 +DW_OP_lit7 +DW_OP_lit8 +DW_OP_lit9 +DW_OP_lit10 +DW_OP_lit11 +DW_OP_lit12 +DW_OP_lit13 +DW_OP_lit14 +DW_OP_lit15 +DW_OP_lit16 +DW_OP_lit17 +DW_OP_lit18 +DW_OP_lit19 +DW_OP_lit20 +DW_OP_lit21 +DW_OP_lit22 +DW_OP_lit23 +DW_OP_lit24 +DW_OP_lit25 +DW_OP_lit26 +DW_OP_lit27 +DW_OP_lit28 +DW_OP_lit29 +DW_OP_lit30 +DW_OP_lit31 +DW_OP_reg0 +DW_OP_reg1 +DW_OP_reg2 +DW_OP_reg3 +DW_OP_reg4 +DW_OP_reg5 +DW_OP_reg6 +DW_OP_reg7 +DW_OP_reg8 +DW_OP_reg9 +DW_OP_reg10 +DW_OP_reg11 +DW_OP_reg12 +DW_OP_reg13 +DW_OP_reg14 +DW_OP_reg15 +DW_OP_reg16 +DW_OP_reg17 +DW_OP_reg18 +DW_OP_reg19 +DW_OP_reg20 +DW_OP_reg21 +DW_OP_reg22 +DW_OP_reg23 +DW_OP_reg24 +DW_OP_reg25 +DW_OP_reg26 +DW_OP_reg27 +DW_OP_reg28 +DW_OP_reg29 +DW_OP_reg30 +DW_OP_reg31 +DW_OP_breg0 +DW_OP_breg1 +DW_OP_breg2 +DW_OP_breg3 +DW_OP_breg4 +DW_OP_breg5 +DW_OP_breg6 +DW_OP_breg7 +DW_OP_breg8 +DW_OP_breg9 +DW_OP_breg10 +DW_OP_breg11 +DW_OP_breg12 +DW_OP_breg13 +DW_OP_breg14 +DW_OP_breg15 +DW_OP_breg16 +DW_OP_breg17 +DW_OP_breg18 +DW_OP_breg19 +DW_OP_breg20 +DW_OP_breg21 +DW_OP_breg22 +DW_OP_breg23 +DW_OP_breg24 +DW_OP_breg25 +DW_OP_breg26 +DW_OP_breg27 +DW_OP_breg28 +DW_OP_breg29 +DW_OP_breg30 +DW_OP_breg31 +DW_OP_regx +DW_OP_fbreg +DW_OP_bregx +DW_OP_piece +DW_OP_deref_size +DW_OP_xderef_size +DW_OP_nop +DW_OP_push_object_address +DW_OP_call2 +DW_OP_call4 +DW_OP_call_ref +DW_OP_form_tls_address +DW_OP_call_frame_cfa +DW_OP_bit_piece +DW_OP_implicit_value +DW_OP_stack_value +DW_OP_lo_user +DW_OP_hi_user +DW_ATE_address +DW_ATE_boolean +DW_ATE_complex_float +DW_ATE_float +DW_ATE_signed +DW_ATE_signed_char +DW_ATE_unsigned +DW_ATE_unsigned_char +DW_ATE_imaginary_float +DW_ATE_packed_decimal +DW_ATE_numeric_string +DW_ATE_edited +DW_ATE_signed_fixed +DW_ATE_unsigned_fixed +DW_ATE_decimal_float +DW_ATE_UTF +DW_ATE_lo_user +DW_ATE_hi_user +DW_DS_unsigned +DW_DS_leading_overpunch +DW_DS_trailing_overpunch +DW_DS_leading_separate +DW_DS_trailing_separate +DW_END_default +DW_END_big +DW_END_little +DW_END_lo_user +DW_END_hi_user +DW_ACCESS_public +DW_ACCESS_protected +DW_ACCESS_private +DW_VIS_local +DW_VIS_exported +DW_VIS_qualified +DW_VIRTUALITY_none +DW_VIRTUALITY_virtual +DW_VIRTUALITY_pure_virtual +DW_LANG_C89 +DW_LANG_C +DW_LANG_Ada83 +DW_LANG_C_plus_plus +DW_LANG_Cobol74 +DW_LANG_Cobol85 +DW_LANG_Fortran77 +DW_LANG_Fortran90 +DW_LANG_Pascal83 +DW_LANG_Modula2 +DW_LANG_Java +DW_LANG_C99 +DW_LANG_Ada95 +DW_LANG_Fortran95 +DW_LANG_PLI +DW_LANG_ObjC +DW_LANG_ObjC_plus_plus +DW_LANG_UPC +DW_LANG_D +DW_LANG_Python +DW_LANG_lo_user +DW_LANG_Mips_Assembler +DW_LANG_hi_user +DW_ID_case_sensitive +DW_ID_up_case +DW_ID_down_case +DW_ID_case_insensitive +DW_CC_normal +DW_CC_program +DW_CC_nocall +DW_CC_lo_user +DW_CC_hi_user +DW_INL_not_inlined +DW_INL_inlined +DW_INL_declared_not_inlined +DW_INL_declared_inlined +DW_ORD_row_major +DW_ORD_col_major +DW_DSC_label +DW_DSC_range +DW_LNS_extended_op +DW_LNS_copy +DW_LNS_advance_pc +DW_LNS_advance_line +DW_LNS_set_file +DW_LNS_set_column +DW_LNS_negate_stmt +DW_LNS_set_basic_block +DW_LNS_const_add_pc +DW_LNS_fixed_advance_pc +DW_LNS_set_prologue_end +DW_LNS_set_epilogue_begin +DW_LNS_set_isa +DW_LNE_end_sequence +DW_LNE_set_address +DW_LNE_define_file +DW_LNE_set_discriminator +DW_LNE_lo_user +DW_LNE_hi_user +DW_MACINFO_define +DW_MACINFO_undef +DW_MACINFO_start_file +DW_MACINFO_end_file +DW_MACINFO_vendor_ext +DW_CFA_extended +DW_CFA_nop +DW_CFA_advance_loc +DW_CFA_offset +DW_CFA_restore +DW_CFA_set_loc +DW_CFA_advance_loc1 +DW_CFA_advance_loc2 +DW_CFA_advance_loc4 +DW_CFA_offset_extended +DW_CFA_restore_extended +DW_CFA_undefined +DW_CFA_same_value +DW_CFA_register +DW_CFA_remember_state +DW_CFA_restore_state +DW_CFA_def_cfa +DW_CFA_def_cfa_register +DW_CFA_def_cfa_offset +DW_CFA_def_cfa_expression +DW_CFA_expression +DW_CFA_offset_extended_sf +DW_CFA_def_cfa_sf +DW_CFA_def_cfa_offset_sf +DW_CFA_val_offset +DW_CFA_val_offset_sf +DW_CFA_val_expression +DW_CFA_MIPS_advance_loc8 +DW_CFA_GNU_window_save +DW_CFA_GNU_args_size +DW_CFA_lo_user +DW_CFA_hi_user +DW_EH_PE_absptr +DW_EH_PE_omit +DW_EH_PE_uleb128 +DW_EH_PE_udata2 +DW_EH_PE_udata4 +DW_EH_PE_udata8 +DW_EH_PE_sleb128 +DW_EH_PE_sdata2 +DW_EH_PE_sdata4 +DW_EH_PE_sdata8 +DW_EH_PE_signed +DW_EH_PE_pcrel +DW_EH_PE_textrel +DW_EH_PE_datarel +DW_EH_PE_funcrel +DW_EH_PE_aligned +DW_EH_PE_indirect +DW_APPLE_PROPERTY_readonly +DW_APPLE_PROPERTY_readwrite +DW_APPLE_PROPERTY_assign +DW_APPLE_PROPERTY_retain +DW_APPLE_PROPERTY_copy +DW_APPLE_PROPERTY_nonatomic +''') + +### The following enums are not available in LLVM 3.2 +# DW_AT_GNU_dwo_name +# DW_AT_GNU_vector +# DW_AT_GNU_template_name +# DW_AT_GNU_dwo_id +# DW_AT_GNU_ranges_base +# DW_AT_GNU_addr_base +# DW_AT_GNU_pubnames +# DW_AT_GNU_pubtypes +# DW_FORM_GNU_addr_index +# DW_FORM_GNU_str_index +# DW_OP_GNU_addr_index +# DW_OP_GNU_const_index From 84f1b433def8c4ef9a829c21a14cc26e523117df Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 30 May 2013 14:04:08 -0500 Subject: [PATCH 384/516] Use if-else instead of try-except for perf reason --- llvmpy/capsule.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/llvmpy/capsule.py b/llvmpy/capsule.py index f66836f..1b3813b 100644 --- a/llvmpy/capsule.py +++ b/llvmpy/capsule.py @@ -141,9 +141,10 @@ def wrap(cap, owned=False): cls = cap.get_class() addr = cap.pointer name = cap.name - try: # lookup cached object - return _cache[cls][addr] - except KeyError: + # 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() @@ -207,11 +208,10 @@ def downcast(obj, cls): 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: + 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) From 69c75355f4a919fa04ab49a5f933aaa99ec95bfb Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Fri, 31 May 2013 11:47:51 -0500 Subject: [PATCH 385/516] fix future import --- llvm_array/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm_array/__init__.py b/llvm_array/__init__.py index 5e807c2..08dd11b 100644 --- a/llvm_array/__init__.py +++ b/llvm_array/__init__.py @@ -1,2 +1,2 @@ -from __future__ import absolute_imports +from __future__ import absolute_import from .array import * From ad287faeb1f4473e112ef428e05610020c5357a1 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 31 May 2013 14:01:57 -0500 Subject: [PATCH 386/516] Fixes a werid case of refct problem --- llvmpy/capsule.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/llvmpy/capsule.py b/llvmpy/capsule.py index 1b3813b..5efed13 100644 --- a/llvmpy/capsule.py +++ b/llvmpy/capsule.py @@ -56,15 +56,15 @@ class Capsule(object): @property def classname(self): - return Capsule.getClassName(self.capsule) + return self.getClassName(self.capsule) @property def name(self): - return Capsule.getName(self.capsule) + return self.getName(self.capsule) @property def pointer(self): - return Capsule.getPointer(self.capsule) + return self.getPointer(self.capsule) @staticmethod def valid(capsule): From 2415042a2a07e99b24ab6859edb4d5d341ad5ea6 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 31 May 2013 15:01:02 -0500 Subject: [PATCH 387/516] DIDescriptor does not inherit MDNode --- llvmpy/src/DebugInfo.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/llvmpy/src/DebugInfo.py b/llvmpy/src/DebugInfo.py index 81fe168..8ddb1ee 100644 --- a/llvmpy/src/DebugInfo.py +++ b/llvmpy/src/DebugInfo.py @@ -4,7 +4,7 @@ from .namespace import llvm from .ADT.StringRef import StringRef from .Value import MDNode -DIDescriptor = llvm.Class(MDNode) +DIDescriptor = llvm.Class() DIEnumerator = llvm.Class(DIDescriptor) DIScope = llvm.Class(DIDescriptor) DIType = llvm.Class(DIScope) @@ -29,7 +29,8 @@ return_unsigned = cast(Unsigned, int) @DIDescriptor class DIDescriptor: - pass + new = Constructor(ptr(MDNode)) + delete = Destructor() @DIScope class DIScope: From 2338eae5f6a91651125b8180abafa8c9afaa90d8 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 13 Jun 2013 17:17:43 -0500 Subject: [PATCH 388/516] Fix py3 str has no buffer interface --- llvmpy/include/llvm_binding/extra.h | 67 ++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 10 deletions(-) diff --git a/llvmpy/include/llvm_binding/extra.h b/llvmpy/include/llvm_binding/extra.h index 6626ede..456f75e 100644 --- a/llvmpy/include/llvm_binding/extra.h +++ b/llvmpy/include/llvm_binding/extra.h @@ -270,7 +270,12 @@ llvm::ExecutionEngine* ExecutionEngine_create( ExecutionEngine *ee = ExecutionEngine::create(M, ForceInterpreter, &ErrorStr, OptLevel, GVsWithCode); - PyFile_WriteString(ErrorStr.c_str(), errout); + auto_pyobject buf = PyBytes_FromString(ErrorStr.c_str()); + if (errout && NULL == PyObject_CallMethod(errout, "write", "O", *buf)){ + return NULL; + } + +// PyFile_WriteString(ErrorStr.c_str(), errout); return ee; } @@ -292,7 +297,11 @@ llvm::ExecutionEngine* ExecutionEngine_createJIT( std::string ErrorStr; ExecutionEngine *ee = ExecutionEngine::createJIT(M, &ErrorStr, JMM, OL, GCsWithCode, RM, CMM); - PyFile_WriteString(ErrorStr.c_str(), errout); + auto_pyobject buf = PyBytes_FromString(ErrorStr.c_str()); + if (errout && NULL == PyObject_CallMethod(errout, "write", "O", *buf)){ + return NULL; + } +// PyFile_WriteString(ErrorStr.c_str(), errout); return ee; } @@ -512,9 +521,13 @@ PyObject* llvm_getBitcodeTargetTriple(llvm::StringRef Buf, if (FObj) { std::string ErrStr; Triple = getBitcodeTargetTriple(MB, Ctx, &ErrStr); - if (-1 == PyFile_WriteString(ErrStr.c_str(), FObj)) { + auto_pyobject buf = PyBytes_FromString(ErrStr.c_str()); + if (NULL == PyObject_CallMethod(FObj, "write", "O", *buf)){ return NULL; } +// if (-1 == PyFile_WriteString(ErrStr.c_str(), FObj)) { +// return NULL; +// } } else { Triple = getBitcodeTargetTriple(MB, Ctx); } @@ -585,9 +598,15 @@ PyObject* Linker_LinkInModule(llvm::Linker* Linker, if (! failed) { Py_RETURN_FALSE; } else { - if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) { + + auto_pyobject buf = PyBytes_FromString(errmsg.c_str()); + if (NULL == PyObject_CallMethod(ErrMsg, "write", "O", *buf)){ return NULL; } + +// if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) { +// return NULL; +// } Py_RETURN_TRUE; } } @@ -603,9 +622,13 @@ PyObject* Linker_LinkModules(llvm::Module* Dest, if (! failed) { Py_RETURN_FALSE; } else { - if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) { + auto_pyobject buf = PyBytes_FromString(errmsg.c_str()); + if (NULL == PyObject_CallMethod(ErrMsg, "write", "O", *buf)){ return NULL; } +// if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) { +// return NULL; +// } Py_RETURN_TRUE; } } @@ -665,9 +688,14 @@ PyObject* llvm_verifyModule(const llvm::Module& Fn, bool failed = llvm::verifyModule(Fn, Action, &errmsg); if (failed) { - if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) { + auto_pyobject buf = PyBytes_FromString(errmsg.c_str()); + if (NULL == PyObject_CallMethod(ErrMsg, "write", "O", *buf)){ return NULL; } + +// if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) { +// return NULL; +// } Py_RETURN_TRUE; } else { Py_RETURN_FALSE; @@ -790,9 +818,13 @@ PyObject* DynamicLibrary_LoadLibraryPermanently(const char * Filename, std::string errmsg; failed = DynamicLibrary::LoadLibraryPermanently(Filename, &errmsg); if (failed) { - if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) { + auto_pyobject buf = PyBytes_FromString(errmsg.c_str()); + if (NULL == PyObject_CallMethod(ErrMsg, "write", "O", *buf)){ return NULL; } +// if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) { +// return NULL; +// } } } else { failed = DynamicLibrary::LoadLibraryPermanently(Filename); @@ -835,7 +867,12 @@ PyObject* TargetRegistry_lookupTarget(const std::string &Triple, std::string error; const Target* target = TargetRegistry::lookupTarget(Triple, error); if (!target) { - PyFile_WriteString(error.c_str(), Error); +// PyFile_WriteString(error.c_str(), Error); + auto_pyobject buf = PyBytes_FromString(error.c_str()); + if (NULL == PyObject_CallMethod(Error, "write", "O", *buf)){ + return NULL; + } + Py_RETURN_NONE; } else { return pycapsule_new(const_cast(target), "llvm::Target"); @@ -852,7 +889,12 @@ PyObject* TargetRegistry_lookupTarget(const std::string &Arch, std::string error; const Target* target = TargetRegistry::lookupTarget(Arch, Triple, error); if (!target) { - PyFile_WriteString(error.c_str(), Error); +// PyFile_WriteString(error.c_str(), Error); + auto_pyobject buf = PyBytes_FromString(error.c_str()); + if (NULL == PyObject_CallMethod(Error, "write", "O", *buf)){ + return NULL; + } + Py_RETURN_NONE; } else { return pycapsule_new(const_cast(target), "llvm::Target"); @@ -867,7 +909,12 @@ PyObject* TargetRegistry_getClosestTargetForJIT(PyObject* Error) std::string error; const Target* target = TargetRegistry::getClosestTargetForJIT(error); if (!target) { - PyFile_WriteString(error.c_str(), Error); + auto_pyobject buf = PyBytes_FromString(error.c_str()); + if (NULL == PyObject_CallMethod(Error, "write", "O", *buf)){ + return NULL; + } + +// PyFile_WriteString(error.c_str(), Error); Py_RETURN_NONE; } else { return pycapsule_new(const_cast(target), "llvm::Target"); From 4c1b9016fb513a96463b68472ec6a5e6c1416912 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 31 Jul 2013 15:12:23 -0500 Subject: [PATCH 389/516] binding compiles with llvm 3.3 --- llvmpy/gen/binding.py | 3 +- llvmpy/include/llvm_binding/extra.h | 83 +++++++++++----- llvmpy/src/Argument.py | 19 +++- llvmpy/src/Attributes.py | 101 +++++++++++++++----- llvmpy/src/DIBuilder.py | 38 +++++--- llvmpy/src/DataLayout.py | 5 +- llvmpy/src/DerivedTypes.py | 5 +- llvmpy/src/Function.py | 22 ++++- llvmpy/src/GlobalValue.py | 5 +- llvmpy/src/IRBuilder.py | 6 +- llvmpy/src/InlineAsm.py | 5 +- llvmpy/src/Instruction.py | 26 +++-- llvmpy/src/LLVMContext.py | 5 +- llvmpy/src/Linker.py | 35 +++---- llvmpy/src/Module.py | 5 +- llvmpy/src/Support/Host.py | 29 ++++-- llvmpy/src/Target/TargetMachine.py | 12 ++- llvmpy/src/TargetTransformInfo.py | 16 +++- llvmpy/src/Transforms/PassManagerBuilder.py | 6 +- llvmpy/src/Type.py | 5 +- llvmpy/src/ValueSymbolTable.py | 5 +- setup.py | 7 +- 22 files changed, 324 insertions(+), 119 deletions(-) diff --git a/llvmpy/gen/binding.py b/llvmpy/gen/binding.py index 8006fd9..db4fdbf 100644 --- a/llvmpy/gen/binding.py +++ b/llvmpy/gen/binding.py @@ -247,7 +247,8 @@ class Class(SubModule, _Type): def __call__(self, defn): assert not self._is_defined # process the definition in "defn" - self.name = defn.__name__ + self.name = getattr(defn, '_name_', defn.__name__) + for k, v in defn.__dict__.items(): if isinstance(v, Method): self.methods.append(v) diff --git a/llvmpy/include/llvm_binding/extra.h b/llvmpy/include/llvm_binding/extra.h index 456f75e..cd1f59c 100644 --- a/llvmpy/include/llvm_binding/extra.h +++ b/llvmpy/include/llvm_binding/extra.h @@ -1,8 +1,22 @@ #include #include -#include -#include -#include +#if LLVM_VERSION_MAJOR >= 3 and LLVM_VERSION_MINOR >= 3 + #include + #include + #include + #include + #include + #include + #include +#else + #include + #include + #include + #include + #include + #include + #include +#endif #include #include #include @@ -12,11 +26,7 @@ #include #include #include -#include #include -#include -#include -#include #include #include @@ -56,6 +66,15 @@ namespace extra{ } +static +PyObject* callwrite(PyObject* self, PyObject* arg) +{ + char meth[] = "method"; + char fmt[] = "O"; + return PyObject_CallMethod(self, meth, fmt, arg); +} + + static PyObject* make_raw_ostream_for_printing(PyObject* self, PyObject* args) { @@ -271,7 +290,7 @@ llvm::ExecutionEngine* ExecutionEngine_create( &ErrorStr, OptLevel, GVsWithCode); auto_pyobject buf = PyBytes_FromString(ErrorStr.c_str()); - if (errout && NULL == PyObject_CallMethod(errout, "write", "O", *buf)){ + if (errout && NULL == callwrite(errout, *buf)){ return NULL; } @@ -298,7 +317,7 @@ llvm::ExecutionEngine* ExecutionEngine_createJIT( ExecutionEngine *ee = ExecutionEngine::createJIT(M, &ErrorStr, JMM, OL, GCsWithCode, RM, CMM); auto_pyobject buf = PyBytes_FromString(ErrorStr.c_str()); - if (errout && NULL == PyObject_CallMethod(errout, "write", "O", *buf)){ + if (errout && NULL == callwrite(errout, *buf)){ return NULL; } // PyFile_WriteString(ErrorStr.c_str(), errout); @@ -483,7 +502,7 @@ PyObject* llvm_ParseBitCodeFile(llvm::StringRef Buf, llvm::LLVMContext& Ctx, std::string ErrStr; M = ParseBitcodeFile(MB, Ctx, &ErrStr); auto_pyobject buf = PyBytes_FromString(ErrStr.c_str()); - if (NULL == PyObject_CallMethod(FObj, "write", "O", *buf)){ + if (NULL == callwrite(FObj, *buf)){ return NULL; } // if (-1 == PyFile_WriteString(ErrStr.c_str(), FObj)) { @@ -507,7 +526,7 @@ PyObject* llvm_WriteBitcodeToFile(const llvm::Module *M, PyObject* FObj) rso.flush(); StringRef ref = rso.str(); auto_pyobject buf = PyBytes_FromStringAndSize(ref.data(), ref.size()); - return PyObject_CallMethod(FObj, "write", "O", *buf); + return callwrite(FObj, *buf); } static @@ -522,7 +541,7 @@ PyObject* llvm_getBitcodeTargetTriple(llvm::StringRef Buf, std::string ErrStr; Triple = getBitcodeTargetTriple(MB, Ctx, &ErrStr); auto_pyobject buf = PyBytes_FromString(ErrStr.c_str()); - if (NULL == PyObject_CallMethod(FObj, "write", "O", *buf)){ + if (NULL == callwrite(FObj, *buf)){ return NULL; } // if (-1 == PyFile_WriteString(ErrStr.c_str(), FObj)) { @@ -594,19 +613,19 @@ PyObject* Linker_LinkInModule(llvm::Linker* Linker, PyObject* 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); +#endif if (! failed) { Py_RETURN_FALSE; } else { auto_pyobject buf = PyBytes_FromString(errmsg.c_str()); - if (NULL == PyObject_CallMethod(ErrMsg, "write", "O", *buf)){ + if (NULL == callwrite(ErrMsg, *buf)){ return NULL; } - -// if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) { -// return NULL; -// } Py_RETURN_TRUE; } } @@ -623,7 +642,7 @@ PyObject* Linker_LinkModules(llvm::Module* Dest, Py_RETURN_FALSE; } else { auto_pyobject buf = PyBytes_FromString(errmsg.c_str()); - if (NULL == PyObject_CallMethod(ErrMsg, "write", "O", *buf)){ + if (NULL == callwrite(ErrMsg, *buf)){ return NULL; } // if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) { @@ -689,7 +708,7 @@ PyObject* llvm_verifyModule(const llvm::Module& Fn, if (failed) { auto_pyobject buf = PyBytes_FromString(errmsg.c_str()); - if (NULL == PyObject_CallMethod(ErrMsg, "write", "O", *buf)){ + if (NULL == callwrite(ErrMsg, *buf)){ return NULL; } @@ -819,7 +838,7 @@ PyObject* DynamicLibrary_LoadLibraryPermanently(const char * Filename, failed = DynamicLibrary::LoadLibraryPermanently(Filename, &errmsg); if (failed) { auto_pyobject buf = PyBytes_FromString(errmsg.c_str()); - if (NULL == PyObject_CallMethod(ErrMsg, "write", "O", *buf)){ + if (NULL == callwrite(ErrMsg, *buf)){ return NULL; } // if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) { @@ -869,7 +888,7 @@ PyObject* TargetRegistry_lookupTarget(const std::string &Triple, if (!target) { // PyFile_WriteString(error.c_str(), Error); auto_pyobject buf = PyBytes_FromString(error.c_str()); - if (NULL == PyObject_CallMethod(Error, "write", "O", *buf)){ + if (NULL == callwrite(Error, *buf)){ return NULL; } @@ -891,7 +910,7 @@ PyObject* TargetRegistry_lookupTarget(const std::string &Arch, if (!target) { // PyFile_WriteString(error.c_str(), Error); auto_pyobject buf = PyBytes_FromString(error.c_str()); - if (NULL == PyObject_CallMethod(Error, "write", "O", *buf)){ + if (NULL == callwrite(Error, *buf)){ return NULL; } @@ -910,7 +929,7 @@ PyObject* TargetRegistry_getClosestTargetForJIT(PyObject* Error) const Target* target = TargetRegistry::getClosestTargetForJIT(error); if (!target) { auto_pyobject buf = PyBytes_FromString(error.c_str()); - if (NULL == PyObject_CallMethod(Error, "write", "O", *buf)){ + if (NULL == callwrite(Error, *buf)){ return NULL; } @@ -945,3 +964,21 @@ PyObject* llvm_sys_getHostCPUFeatures(PyObject* Features) } } + +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; +} \ No newline at end of file diff --git a/llvmpy/src/Argument.py b/llvmpy/src/Argument.py index 6262147..a08cca1 100644 --- a/llvmpy/src/Argument.py +++ b/llvmpy/src/Argument.py @@ -1,16 +1,27 @@ from binding import * from .namespace import llvm from .Value import Argument, Value -from .Attributes import Attributes +if LLVM_VERSION >= (3, 3): + from .Attributes import AttributeSet, Attribute +else: + from .Attributes import Attributes @Argument class Argument: - _include_ = 'llvm/Argument.h' + if LLVM_VERSION >= (3, 3): + _include_ = 'llvm/IR/Argument.h' + else: + _include_ = 'llvm/Argument.h' _downcast_ = Value - addAttr = Method(Void, ref(Attributes)) - removeAttr = Method(Void, ref(Attributes)) + if LLVM_VERSION >= (3, 3): + addAttr = Method(Void, ref(AttributeSet)) + removeAttr = Method(Void, ref(AttributeSet)) + else: + addAttr = Method(Void, ref(Attributes)) + removeAttr = Method(Void, ref(Attributes)) + getParamAlignment = Method(cast(Unsigned, int)) getArgNo = Method(cast(Unsigned, int)) diff --git a/llvmpy/src/Attributes.py b/llvmpy/src/Attributes.py index 4fe7651..303d61d 100644 --- a/llvmpy/src/Attributes.py +++ b/llvmpy/src/Attributes.py @@ -2,38 +2,91 @@ from binding import * from .namespace import llvm from .LLVMContext import LLVMContext -llvm.includes.add('llvm/Attributes.h') +if LLVM_VERSION >= (3, 3): + llvm.includes.add('llvm/IR/Attributes.h') +else: + llvm.includes.add('llvm/Attributes.h') + -Attributes = llvm.Class() AttrBuilder = llvm.Class() - -@Attributes -class Attributes: - AttrVal = Enum('''None, AddressSafety, Alignment, AlwaysInline, - ByVal, InlineHint, InReg, MinSize, - Naked, Nest, NoAlias, NoCapture, - NoImplicitFloat, NoInline, NonLazyBind, NoRedZone, - NoReturn, NoUnwind, OptimizeForSize, ReadNone, - ReadOnly, ReturnsTwice, SExt, StackAlignment, - StackProtect, StackProtectReq, StructRet, UWTable, ZExt''') - - delete = Destructor() - - get = StaticMethod(Attributes, ref(LLVMContext), ref(AttrBuilder)) +if LLVM_VERSION >= (3, 3): + Attribute = llvm.Class() + AttributeSet = llvm.Class() +else: + Attributes = llvm.Class() -@AttrBuilder -class AttrBuilder: +if LLVM_VERSION >= (3, 3): + @Attribute + class Attribute: + AttrKind = Enum('''None, Alignment, AlwaysInline, + ByVal, InlineHint, InReg, + MinSize, Naked, Nest, NoAlias, + NoBuiltin, NoCapture, NoDuplicate, NoImplicitFloat, + NoInline, NonLazyBind, NoRedZone, NoReturn, + NoUnwind, OptimizeForSize, ReadNone, ReadOnly, + Returned, ReturnsTwice, SExt, StackAlignment, + StackProtect, StackProtectReq, StackProtectStrong, StructRet, + SanitizeAddress, SanitizeThread, SanitizeMemory, UWTable, + ZExt, EndAttrKinds''') - new = Constructor() - delete = Destructor() + delete = Destructor() - clear = Method() + get = StaticMethod(Attribute, + ref(LLVMContext), + AttrKind, + cast(int, Uint64)).require_only(2) - addAttribute = Method(ref(AttrBuilder), Attributes.AttrVal) - removeAttribute = Method(ref(AttrBuilder), Attributes.AttrVal) + @AttrBuilder + class AttrBuilder: - addAlignmentAttr = Method(ref(AttrBuilder), cast(int, Unsigned)) + new = Constructor() + delete = Destructor() + + clear = Method() + + addAttribute = Method(ref(AttrBuilder), Attribute.AttrKind) + removeAttribute = Method(ref(AttrBuilder), Attribute.AttrKind) + + addAlignmentAttr = Method(ref(AttrBuilder), cast(int, Unsigned)) + + @AttributeSet + class AttributeSet: + delete = Destructor() + + get = StaticMethod(AttributeSet, + ref(LLVMContext), + cast(int, Unsigned), + ref(AttrBuilder)) + +else: + @Attributes + class Attributes: + AttrVal = Enum('''None, AddressSafety, Alignment, AlwaysInline, + ByVal, InlineHint, InReg, MinSize, + Naked, Nest, NoAlias, NoCapture, + NoImplicitFloat, NoInline, NonLazyBind, NoRedZone, + NoReturn, NoUnwind, OptimizeForSize, ReadNone, + ReadOnly, ReturnsTwice, SExt, StackAlignment, + StackProtect, StackProtectReq, StructRet, UWTable, ZExt''') + + delete = Destructor() + + get = StaticMethod(Attributes, ref(LLVMContext), ref(AttrBuilder)) + + + @AttrBuilder + class AttrBuilder: + + new = Constructor() + delete = Destructor() + + clear = Method() + + addAttribute = Method(ref(AttrBuilder), Attributes.AttrVal) + removeAttribute = Method(ref(AttrBuilder), Attributes.AttrVal) + + addAlignmentAttr = Method(ref(AttrBuilder), cast(int, Unsigned)) diff --git a/llvmpy/src/DIBuilder.py b/llvmpy/src/DIBuilder.py index 9671963..cb934d4 100644 --- a/llvmpy/src/DIBuilder.py +++ b/llvmpy/src/DIBuilder.py @@ -124,17 +124,31 @@ class DIBuilder: ptr(MDNode), # TemplateParms = 0 ).require_only(10) - createStructType = Method(DIType, - ref(DIDescriptor), # Scope - stringref_arg, # Name - ref(DIFile), # File - unsigned_arg, # LineNumber - uint64_arg, # SizeInBits - uint64_arg, # AlignInBits - unsigned_arg, # Flags - ref(DIArray), # Elements - unsigned_arg, # RunTimeLang = 0 - ).require_only(8) + if LLVM_VERSION >= (3, 3): + createStructType = Method(DIType, + ref(DIDescriptor), # Scope + stringref_arg, # Name + ref(DIFile), # File + unsigned_arg, # LineNumber + uint64_arg, # SizeInBits + uint64_arg, # AlignInBits + unsigned_arg, # Flags + ref(DIType), # DerivedFrom + ref(DIArray), # Elements + unsigned_arg, # RunTimeLang = 0 + ).require_only(9) + else: + createStructType = Method(DIType, + ref(DIDescriptor), # Scope + stringref_arg, # Name + ref(DIFile), # File + unsigned_arg, # LineNumber + uint64_arg, # SizeInBits + uint64_arg, # AlignInBits + unsigned_arg, # Flags + ref(DIArray), # Elements + unsigned_arg, # RunTimeLang = 0 + ).require_only(8) createUnionType = Method(DIType, ref(DIDescriptor), # Scope @@ -186,7 +200,7 @@ class DIBuilder: ref(DIType), # Ty ) - createTemporaryType = Method(DIType, ref(DIFile)).require_only(0) + #createTemporaryType = Method(DIType, ref(DIFile)).require_only(0) createForwardDecl = Method(DIType, unsigned_arg, # Tag diff --git a/llvmpy/src/DataLayout.py b/llvmpy/src/DataLayout.py index 812a83d..6741cda 100644 --- a/llvmpy/src/DataLayout.py +++ b/llvmpy/src/DataLayout.py @@ -15,7 +15,10 @@ from .GlobalVariable import GlobalVariable @DataLayout class DataLayout: - _include_ = 'llvm/DataLayout.h' + if LLVM_VERSION >= (3, 3): + _include_ = 'llvm/IR/DataLayout.h' + else: + _include_ = 'llvm/DataLayout.h' _new_string = Constructor(cast(str, StringRef)) _new_module = Constructor(ptr(Module)) diff --git a/llvmpy/src/DerivedTypes.py b/llvmpy/src/DerivedTypes.py index 02eec8c..fde01f3 100644 --- a/llvmpy/src/DerivedTypes.py +++ b/llvmpy/src/DerivedTypes.py @@ -8,7 +8,10 @@ FunctionType = llvm.Class(Type) @FunctionType class FunctionType: - _include_ = 'llvm/DerivedTypes.h' + if LLVM_VERSION >= (3, 3): + _include_ = 'llvm/IR/DerivedTypes.h' + else: + _include_ = 'llvm/DerivedTypes.h' _downcast_ = Type _get = StaticMethod(ptr(FunctionType), ptr(Type), cast(bool, Bool)) diff --git a/llvmpy/src/Function.py b/llvmpy/src/Function.py index 04c3e65..9c2c8b7 100644 --- a/llvmpy/src/Function.py +++ b/llvmpy/src/Function.py @@ -4,7 +4,10 @@ from .Value import GlobalValue, Constant, Function, Argument, Value from .Module import Module from .BasicBlock import BasicBlock from .ValueSymbolTable import ValueSymbolTable -from .Attributes import Attributes +if LLVM_VERSION >= (3, 3): + from .Attributes import Attribute, AttributeSet +else: + from .Attributes import Attributes from .Type import Type from .DerivedTypes import FunctionType from .LLVMContext import LLVMContext @@ -12,7 +15,11 @@ from .CallingConv import CallingConv @Function class Function: - _include_ = 'llvm/Function.h' + if LLVM_VERSION >= (3, 3): + _include_ = 'llvm/IR/Function.h' + else: + _include_ = 'llvm/Function.h' + _downcast_ = GlobalValue, Constant, Value getReturnType = Method(ptr(Type)) @@ -48,10 +55,17 @@ class Function: deleteBody = Method() viewCFG = Method() + viewCFGOnly = Method() - addFnAttr = Method(Void, Attributes.AttrVal) - removeFnAttr = Method(Void, ref(Attributes)) + if LLVM_VERSION >= (3, 3): + addFnAttr = Method(Void, Attribute.AttrKind) + addAttributes = Method(Void, cast(int, Unsigned), ref(AttributeSet)) + removeAttributes = Method(Void, cast(int, Unsigned), ref(AttributeSet)) + #removeFnAttr = Method(Void, Attribute.AttrKind) # 3.4? + else: + addFnAttr = Method(Void, Attributes.AttrVal) + removeFnAttr = Method(Void, ref(Attributes)) #hasFnAttribute = Method(cast(Bool, bool), Attributes.AttrVal) Create = StaticMethod(ptr(Function), diff --git a/llvmpy/src/GlobalValue.py b/llvmpy/src/GlobalValue.py index d954ed0..49071e3 100644 --- a/llvmpy/src/GlobalValue.py +++ b/llvmpy/src/GlobalValue.py @@ -6,7 +6,10 @@ from .ADT.StringRef import StringRef @GlobalValue class GlobalValue: - _include_ = 'llvm/GlobalValue.h' + if LLVM_VERSION >= (3, 3): + _include_ = 'llvm/IR/GlobalValue.h' + else: + _include_ = 'llvm/GlobalValue.h' LinkageTypes = Enum(''' ExternalLinkage, AvailableExternallyLinkage, LinkOnceAnyLinkage, diff --git a/llvmpy/src/IRBuilder.py b/llvmpy/src/IRBuilder.py index c0766e9..c4d8a86 100644 --- a/llvmpy/src/IRBuilder.py +++ b/llvmpy/src/IRBuilder.py @@ -18,7 +18,11 @@ IRBuilder = llvm.Class() @IRBuilder class IRBuilder: - _include_ = 'llvm/IRBuilder.h' + if LLVM_VERSION >= (3, 3): + _include_ = 'llvm/IR/IRBuilder.h' + else: + _include_ = 'llvm/IRBuilder.h' + _realname_ = 'IRBuilder<>' new = Constructor(ref(LLVMContext)) diff --git a/llvmpy/src/InlineAsm.py b/llvmpy/src/InlineAsm.py index 8793343..c96cef0 100644 --- a/llvmpy/src/InlineAsm.py +++ b/llvmpy/src/InlineAsm.py @@ -4,7 +4,10 @@ from .Value import Value from .DerivedTypes import FunctionType from .ADT.StringRef import StringRef -llvm.includes.add('llvm/InlineAsm.h') +if LLVM_VERSION >= (3, 3): + llvm.includes.add('llvm/IR/InlineAsm.h') +else: + llvm.includes.add('llvm/InlineAsm.h') InlineAsm = llvm.Class(Value) diff --git a/llvmpy/src/Instruction.py b/llvmpy/src/Instruction.py index e17e8a1..2771015 100644 --- a/llvmpy/src/Instruction.py +++ b/llvmpy/src/Instruction.py @@ -65,7 +65,10 @@ SynchronizationScope = llvm.Enum('SynchronizationScope', from .ADT.StringRef import StringRef from .CallingConv import CallingConv -from .Attributes import Attributes +if LLVM_VERSION >= (3, 3): + from .Attributes import AttributeSet, Attribute +else: + from .Attributes import Attributes from .Type import Type @@ -142,8 +145,12 @@ class CallInst: getCallingConv = Method(CallingConv.ID) setCallingConv = Method(Void, CallingConv.ID) getParamAlignment = Method(cast(Unsigned, int), cast(int, Unsigned)) - addAttribute = Method(Void, cast(int, Unsigned), ref(Attributes)) - removeAttribute = Method(Void, cast(int, Unsigned), ref(Attributes)) + if LLVM_VERSION >= (3, 3): + addAttribute = Method(Void, cast(int, Unsigned), Attribute.AttrKind) + removeAttribute = Method(Void, cast(int, Unsigned), ref(Attribute)) + else: + addAttribute = Method(Void, cast(int, Unsigned), ref(Attributes)) + removeAttribute = Method(Void, cast(int, Unsigned), ref(Attributes)) getCalledFunction = Method(ptr(Function)) getCalledValue = Method(ptr(Value)) setCalledFunction = Method(Void, ptr(Function)) @@ -264,7 +271,10 @@ class UnaryInstruction: @IntrinsicInst class IntrinsicInst: - _include_ = 'llvm/IntrinsicInst.h' + if LLVM_VERSION >= (3, 3): + _include_ = 'llvm/IR/IntrinsicInst.h' + else: + _include_ = 'llvm/IntrinsicInst.h' _downcast_ = Value, User, Instruction #compare @@ -292,8 +302,12 @@ class InvokeInst: getCallingConv = Method(CallingConv.ID) setCallingConv = Method(Void, CallingConv.ID) getParamAlignment = Method(cast(Unsigned, int), cast(int, Unsigned)) - addAttribute = Method(Void, cast(int, Unsigned), ref(Attributes)) - removeAttribute = Method(Void, cast(int, Unsigned), ref(Attributes)) + if LLVM_VERSION >= (3, 3): + addAttribute = Method(Void, cast(int, Unsigned), Attribute.AttrKind) + removeAttribute = Method(Void, cast(int, Unsigned), ref(Attribute)) + else: + addAttribute = Method(Void, cast(int, Unsigned), ref(Attributes)) + removeAttribute = Method(Void, cast(int, Unsigned), ref(Attributes)) getCalledFunction = Method(ptr(Function)) getCalledValue = Method(ptr(Value)) setCalledFunction = Method(Void, ptr(Function)) diff --git a/llvmpy/src/LLVMContext.py b/llvmpy/src/LLVMContext.py index 4a6b49a..8ec1607 100644 --- a/llvmpy/src/LLVMContext.py +++ b/llvmpy/src/LLVMContext.py @@ -3,6 +3,9 @@ from .namespace import llvm @llvm.Class() class LLVMContext: - _include_ = "llvm/LLVMContext.h" + if LLVM_VERSION >= (3, 3): + _include_ = "llvm/IR/LLVMContext.h" + else: + _include_ = "llvm/LLVMContext.h" llvm.Function('getGlobalContext', ref(LLVMContext)) diff --git a/llvmpy/src/Linker.py b/llvmpy/src/Linker.py index 960bd90..5f1b7af 100644 --- a/llvmpy/src/Linker.py +++ b/llvmpy/src/Linker.py @@ -10,30 +10,33 @@ Linker = llvm.Class() @Linker class Linker: - ControlFlags = Enum('Verbose, QuietWarnings, QuietErrors') + #ControlFlags = Enum('Verbose, QuietWarnings, QuietErrors') LinkerMode = Enum('DestroySource, PreserveSource') - _new_w_empty = Constructor(cast(str, StringRef), - cast(str, StringRef), - ref(LLVMContext), - cast(int, Unsigned)).require_only(3) + if LLVM_VERSION >= (3, 3): + new = Constructor(ptr(Module)) + else: + _new_w_empty = Constructor(cast(str, StringRef), + cast(str, StringRef), + ref(LLVMContext), + cast(int, Unsigned)).require_only(3) - _new_w_existing = Constructor(cast(str, StringRef), - ptr(Module), - cast(int, Unsigned)).require_only(2) + _new_w_existing = Constructor(cast(str, StringRef), + ptr(Module), + cast(int, Unsigned)).require_only(2) - @CustomPythonStaticMethod - def new(progname, module_or_name, *args): - if isinstance(module_or_name, Module): - return _new_w_existing(progname, module_or_name, *args) - else: - return _new_w_empty(progname, module_or_name, *args) + @CustomPythonStaticMethod + def new(progname, module_or_name, *args): + if isinstance(module_or_name, Module): + return _new_w_existing(progname, module_or_name, *args) + else: + return _new_w_empty(progname, module_or_name, *args) delete = Destructor() getModule = Method(ptr(Module)) - releaseModule = Method(ptr(Module)) - getLastError = Method(cast(ConstStdString, str)) + #releaseModule = Method(ptr(Module)) + #getLastError = Method(cast(ConstStdString, str)) LinkInModule = CustomMethod('Linker_LinkInModule', PyObjectPtr, # boolean diff --git a/llvmpy/src/Module.py b/llvmpy/src/Module.py index 46fad5a..9dbe754 100644 --- a/llvmpy/src/Module.py +++ b/llvmpy/src/Module.py @@ -16,7 +16,10 @@ from .Metadata import NamedMDNode @Module class Module: - _include_ = "llvm/Module.h" + if LLVM_VERSION >= (3, 3): + _include_ = "llvm/IR/Module.h" + else: + _include_ = "llvm/Module.h" # Enumerators Endianness = Enum('AnyEndianness', 'LittleEndian', 'BigEndian') PointerSize = Enum('AnyPointerSize', 'Pointer32', 'Pointer64') diff --git a/llvmpy/src/Support/Host.py b/llvmpy/src/Support/Host.py index 8163ebe..cd063e8 100644 --- a/llvmpy/src/Support/Host.py +++ b/llvmpy/src/Support/Host.py @@ -1,18 +1,29 @@ from binding import * from src.namespace import sys -isLittleEndianHost = sys.Function('isLittleEndianHost', - cast(Bool, bool)) - -isBigEndianHost = sys.Function('isBigEndianHost', - cast(Bool, bool)) - getDefaultTargetTriple = sys.Function('getDefaultTargetTriple', cast(ConstStdString, str)) -# llvm 3.3 -#getProcessTriple = sys.Function('getProcessTriple', -# cast(ConstStdString, str)) +if LLVM_VERSION >= (3, 3): + getProcessTriple = sys.Function('getProcessTriple', + cast(ConstStdString, str)) + + isLittleEndianHost = sys.CustomFunction('isLittleEndianHost', + 'llvm_sys_isLittleEndianHost', + cast(Bool, bool)) + + isBigEndianHost = sys.CustomFunction('isBigEndianHost', + 'llvm_sys_isBigEndianHost', + cast(Bool, bool)) + +else: + + isLittleEndianHost = sys.Function('isLittleEndianHost', + cast(Bool, bool)) + + isBigEndianHost = sys.Function('isBigEndianHost', + cast(Bool, bool)) + getHostCPUName = sys.Function('getHostCPUName', cast(ConstStdString, str)) diff --git a/llvmpy/src/Target/TargetMachine.py b/llvmpy/src/Target/TargetMachine.py index 1bd6843..84c0d5d 100644 --- a/llvmpy/src/Target/TargetMachine.py +++ b/llvmpy/src/Target/TargetMachine.py @@ -8,8 +8,10 @@ from src.ADT.StringRef import StringRef from src.Support.CodeGen import CodeModel, TLSModel, CodeGenOpt, Reloc from src.GlobalValue import GlobalValue from src.DataLayout import DataLayout -from src.TargetTransformInfo import (ScalarTargetTransformInfo, - VectorTargetTransformInfo) + +if LLVM_VERSION < (3, 3): + from src.TargetTransformInfo import (ScalarTargetTransformInfo, + VectorTargetTransformInfo) from src.PassManager import PassManagerBase from src.Support.FormattedStream import formatted_raw_ostream @@ -39,9 +41,11 @@ class TargetMachine: setMCUseDwarfDirectory = Method(Void, cast(bool, Bool)) getDataLayout = Method(const(ownedptr(DataLayout))) - getScalarTargetTransformInfo = Method(const( + + if LLVM_VERSION < (3, 3): + getScalarTargetTransformInfo = Method(const( ownedptr(ScalarTargetTransformInfo))) - getVectorTargetTransformInfo = Method(const( + getVectorTargetTransformInfo = Method(const( ownedptr(VectorTargetTransformInfo))) addPassesToEmitFile = Method(cast(bool, Bool), diff --git a/llvmpy/src/TargetTransformInfo.py b/llvmpy/src/TargetTransformInfo.py index 1208050..d51bc52 100644 --- a/llvmpy/src/TargetTransformInfo.py +++ b/llvmpy/src/TargetTransformInfo.py @@ -2,7 +2,10 @@ from binding import * from src.namespace import llvm from src.Pass import ImmutablePass -llvm.includes.add('llvm/TargetTransformInfo.h') +if LLVM_VERSION >= (3, 3): + llvm.includes.add('llvm/Analysis/TargetTransformInfo.h') +else: + llvm.includes.add('llvm/TargetTransformInfo.h') TargetTransformInfo = llvm.Class(ImmutablePass) ScalarTargetTransformInfo = llvm.Class() @@ -11,14 +14,17 @@ VectorTargetTransformInfo = llvm.Class() @ScalarTargetTransformInfo class ScalarTargetTransformInfo: - delete = Destructor() + if LLVM_VERSION < (3, 3): + delete = Destructor() @VectorTargetTransformInfo class VectorTargetTransformInfo: - delete = Destructor() + if LLVM_VERSION < (3, 3): + delete = Destructor() @TargetTransformInfo class TargetTransformInfo: - new = Constructor(ptr(ScalarTargetTransformInfo), - ptr(VectorTargetTransformInfo)) + if LLVM_VERSION < (3, 3): + new = Constructor(ptr(ScalarTargetTransformInfo), + ptr(VectorTargetTransformInfo)) diff --git a/llvmpy/src/Transforms/PassManagerBuilder.py b/llvmpy/src/Transforms/PassManagerBuilder.py index 86be4fb..146d409 100644 --- a/llvmpy/src/Transforms/PassManagerBuilder.py +++ b/llvmpy/src/Transforms/PassManagerBuilder.py @@ -36,7 +36,11 @@ class PassManagerBuilder: DisableSimplifyLibCalls = _attr_bool() DisableUnitAtATime = _attr_bool() DisableUnrollLoops = _attr_bool() - Vectorize = _attr_bool() + if LLVM_VERSION >= (3, 3): + BBVectorize = _attr_bool() + SLPVectorize = _attr_bool() + else: + Vectorize = _attr_bool() LoopVectorize = _attr_bool() LibraryInfo = Attr(getter=ownedptr(TargetLibraryInfo), diff --git a/llvmpy/src/Type.py b/llvmpy/src/Type.py index afc148c..50c4862 100644 --- a/llvmpy/src/Type.py +++ b/llvmpy/src/Type.py @@ -15,7 +15,10 @@ VectorType = llvm.Class(SequentialType) @Type class Type: - _include_ = 'llvm/Type.h' + if LLVM_VERSION >= (3, 3): + _include_ = 'llvm/IR/Type.h' + else: + _include_ = 'llvm/Type.h' TypeID = Enum(''' VoidTyID, HalfTyID, FloatTyID, DoubleTyID, diff --git a/llvmpy/src/ValueSymbolTable.py b/llvmpy/src/ValueSymbolTable.py index 7e8890c..8762156 100644 --- a/llvmpy/src/ValueSymbolTable.py +++ b/llvmpy/src/ValueSymbolTable.py @@ -4,7 +4,10 @@ from .ADT.StringRef import StringRef @ValueSymbolTable class ValueSymbolTable: - _include_ = 'llvm/ValueSymbolTable.h' + if LLVM_VERSION >= (3, 3): + _include_ = 'llvm/IR/ValueSymbolTable.h' + else: + _include_ = 'llvm/ValueSymbolTable.h' new = Constructor() delete = Destructor() lookup = Method(ptr(Value), cast(str, StringRef)) diff --git a/setup.py b/setup.py index 1dc8af8..2c3a38f 100644 --- a/setup.py +++ b/setup.py @@ -61,7 +61,12 @@ def auto_intrinsic_gen(incdir): # let's do auto intrinsic generation print("Generate intrinsic IDs") from tools import intrgen - path = "%s/llvm/Intrinsics.gen" % incdir + + if llvm_version >= (3, 3): + path = "%s/llvm/IR/Intrinsics.gen" % incdir + else: + path = "%s/llvm/Intrinsics.gen" % incdir + with open('llvm/_intrinsic_ids.py', 'w') as fout: intrgen.gen(path, fout) From 6d3253e4ea39a857a0f6119f561b8fd3e3ee50c3 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 31 Jul 2013 15:44:01 -0500 Subject: [PATCH 390/516] Add things to make MCJIT working --- llvm-config-win32.py | 2 ++ llvm/ee.py | 2 +- llvmpy/include/llvm_binding/extra.h | 1 + llvmpy/src/ExecutionEngine/ExecutionEngine.py | 2 ++ setup.py | 2 +- 5 files changed, 7 insertions(+), 2 deletions(-) diff --git a/llvm-config-win32.py b/llvm-config-win32.py index 5f6c401..e191290 100644 --- a/llvm-config-win32.py +++ b/llvm-config-win32.py @@ -53,6 +53,7 @@ LLVMInterpreter LLVMipa LLVMipo LLVMJIT +LLVMMCJIT LLVMLinker LLVMMC LLVMMCParser @@ -71,6 +72,7 @@ LLVMX86Desc LLVMX86Disassembler LLVMX86Info LLVMX86Utils +LLVMDebugInfo Advapi32 Shell32 """.split(): diff --git a/llvm/ee.py b/llvm/ee.py index 7ea90d0..e87777a 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -232,7 +232,7 @@ def initialize_target(target, noraise=False): It is safe to initialize the same target multiple times. """ prefix = 'LLVMInitialize' - postfixes = ['Target', 'TargetInfo', 'TargetMC', 'AsmPrinter'] + postfixes = ['Target', 'TargetInfo', 'TargetMC', 'AsmPrinter', 'AsmParser'] try: for postfix in postfixes: getattr(api, '%s%s%s' % (prefix, target, postfix))() diff --git a/llvmpy/include/llvm_binding/extra.h b/llvmpy/include/llvm_binding/extra.h index cd1f59c..49ac261 100644 --- a/llvmpy/include/llvm_binding/extra.h +++ b/llvmpy/include/llvm_binding/extra.h @@ -30,6 +30,7 @@ #include #include +#include // to make MCJIT working #include "auto_pyobject.h" diff --git a/llvmpy/src/ExecutionEngine/ExecutionEngine.py b/llvmpy/src/ExecutionEngine/ExecutionEngine.py index 3208269..d6dfe43 100644 --- a/llvmpy/src/ExecutionEngine/ExecutionEngine.py +++ b/llvmpy/src/ExecutionEngine/ExecutionEngine.py @@ -101,3 +101,5 @@ class ExecutionEngine: unwrapped = list(map(capsule.unwrap, args)) return self._runFunction(fn, tuple(unwrapped)) + finalizeObject = Method(Void) + diff --git a/setup.py b/setup.py index 2c3a38f..546e77e 100644 --- a/setup.py +++ b/setup.py @@ -124,7 +124,7 @@ else: extra_components = list(extra_components & enabled_components) libs_core, objs_core = get_libs_and_objs( - ['core', 'analysis', 'scalaropts', 'executionengine', + ['core', 'analysis', 'scalaropts', 'executionengine', 'mcjit', 'jit', 'native', 'interpreter', 'bitreader', 'bitwriter', 'instrumentation', 'ipa', 'ipo', 'transformutils', 'asmparser', 'linker', 'support', 'vectorize'] From 625858aa6fc48975c5f0bf45ffd3aa44f3d3b067 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 31 Jul 2013 16:05:24 -0500 Subject: [PATCH 391/516] fixes --- llvmpy/include/llvm_binding/extra.h | 7 ++++--- setup.py | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/llvmpy/include/llvm_binding/extra.h b/llvmpy/include/llvm_binding/extra.h index 49ac261..161c52e 100644 --- a/llvmpy/include/llvm_binding/extra.h +++ b/llvmpy/include/llvm_binding/extra.h @@ -70,7 +70,7 @@ namespace extra{ static PyObject* callwrite(PyObject* self, PyObject* arg) { - char meth[] = "method"; + char meth[] = "write"; char fmt[] = "O"; return PyObject_CallMethod(self, meth, fmt, arg); } @@ -965,7 +965,7 @@ PyObject* llvm_sys_getHostCPUFeatures(PyObject* Features) } } - +#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 3 static PyObject* llvm_sys_isLittleEndianHost() { @@ -982,4 +982,5 @@ PyObject* llvm_sys_isBigEndianHost() Py_RETURN_TRUE; else Py_RETURN_FALSE; -} \ No newline at end of file +} +#endif diff --git a/setup.py b/setup.py index 546e77e..e94a258 100644 --- a/setup.py +++ b/setup.py @@ -36,6 +36,7 @@ def run_llvm_config(extra_args): return stdout.decode().strip() llvm_version = run_llvm_config(['--version']) + print('LLVM version = %r' % llvm_version) targets_built = run_llvm_config(['--targets-built']) @@ -62,7 +63,7 @@ def auto_intrinsic_gen(incdir): print("Generate intrinsic IDs") from tools import intrgen - if llvm_version >= (3, 3): + if llvm_version.startswith('3.3'): path = "%s/llvm/IR/Intrinsics.gen" % incdir else: path = "%s/llvm/Intrinsics.gen" % incdir From 56a511854a6fd7f6776c58630088498385e5af30 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 31 Jul 2013 16:43:50 -0500 Subject: [PATCH 392/516] update "attribute(s)" ignorance --- llvm/core.py | 78 +++++++++++++++++++++++++++++++++++--------------- llvm/passes.py | 23 +++++++++++---- 2 files changed, 72 insertions(+), 29 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index 9c8501e..d413bef 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -325,11 +325,17 @@ class VisibilityEnum(Enum): VisibilityEnum.declare() -# parameter attributes llvm::Attributes::AttrVal (see llvm/Attributes.h) +# parameter attributes +# LLVM 3.2 llvm::Attributes::AttrVal (see llvm/Attributes.h) +# LLVM 3.3 llvm::Attribute::AttrKind (see llvm/Attributes.h) class AttrEnum(Enum): prefix = 'ATTR_' - AttrVal = api.llvm.Attributes.AttrVal + if llvm.version >= (3, 3): + AttrVal = api.llvm.Attribute.AttrKind + else: + AttrVal = api.llvm.Attributes.AttrVal + ATTR_NONE = AttrVal.None_ ATTR_ZEXT = AttrVal.ZExt ATTR_SEXT = AttrVal.SExt @@ -1436,29 +1442,55 @@ class Argument(Value): _valid_attrs = frozenset([ATTR_BY_VAL, ATTR_NEST, ATTR_NO_ALIAS, ATTR_NO_CAPTURE, ATTR_STRUCT_RET]) - def add_attribute(self, attr): - context = api.llvm.getGlobalContext() - attrbldr = api.llvm.AttrBuilder.new() - attrbldr.addAttribute(attr) - attrs = api.llvm.Attributes.get(context, attrbldr) - self._ptr.addAttr(attrs) - if attr not in self: - raise ValueError("Attribute %s is not valid for arg %s" % - (attr, self)) + if llvm.version >= (3, 3): + def add_attribute(self, attr): + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() + attrbldr.addAttribute(attr) + attrs = api.llvm.AttributeSet.get(context, 0, attrbldr) + self._ptr.addAttr(attrs) + + if attr not in self: + raise ValueError("Attribute %r is not valid for arg %s" % + (attr, self)) - def remove_attribute(self, attr): - context = api.llvm.getGlobalContext() - attrbldr = api.llvm.AttrBuilder.new() - attrbldr.addAttribute(attr) - attrs = api.llvm.Attributes.get(context, attrbldr) - self._ptr.removeAttr(attrs) + def remove_attribute(self, attr): + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() + attrbldr.addAttribute(attr) + attrs = api.llvm.AttributeSet.get(context, 0, attrbldr) + self._ptr.removeAttr(attrs) - def _set_alignment(self, align): - context = api.llvm.getGlobalContext() - attrbldr = api.llvm.AttrBuilder.new() - attrbldr.addAlignmentAttr(align) - attrs = api.llvm.Attributes.get(context, attrbldr) - self._ptr.addAttr(attrs) + def _set_alignment(self, align): + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() + attrbldr.addAlignmentAttr(align) + attrs = api.llvm.AttributeSet.get(context, 0, attrbldr) + self._ptr.addAttr(attrs) + else: + def add_attribute(self, attr): + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() + attrbldr.addAttribute(attr) + attrs = api.llvm.Attributes.get(context, attrbldr) + self._ptr.addAttr(attrs) + if attr not in self: + raise ValueError("Attribute %r is not valid for arg %s" % + (attr, self)) + + def remove_attribute(self, attr): + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() + attrbldr.addAttribute(attr) + attrs = api.llvm.Attributes.get(context, attrbldr) + self._ptr.removeAttr(attrs) + + def _set_alignment(self, align): + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() + attrbldr.addAlignmentAttr(align) + attrs = api.llvm.Attributes.get(context, attrbldr) + self._ptr.addAttr(attrs) def _get_alignment(self): return self._ptr.getParamAlignment() diff --git a/llvm/passes.py b/llvm/passes.py index 068a7a3..b13fa84 100644 --- a/llvm/passes.py +++ b/llvm/passes.py @@ -70,13 +70,24 @@ class PassManagerBuilder(llvm.Wrapper): def size_level(self, sizelevel): self._ptr.SizeLevel = sizelevel - @property - def vectorize(self): - return self._ptr.Vectorize + if llvm.version >= (3, 3): + @property + def bbvectorize(self): + return self._ptr.BBVectorize - @vectorize.setter - def vectorize(self, enable): - self._ptr.Vectorize = enable + @bbvectorize.setter + def bbvectorize(self, enable): + self._ptr.BBVectorize = enable + + vectorize = bbvectorize + else: + @property + def vectorize(self): + return self._ptr.Vectorize + + @vectorize.setter + def vectorize(self, enable): + self._ptr.Vectorize = enable @property From 319984f0e0a69672dc6dd315062c88bdd67987cc Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 31 Jul 2013 16:57:29 -0500 Subject: [PATCH 393/516] add MCJIT test --- llvm/core.py | 6 +++++- llvm/ee.py | 7 ++++++- llvm/test_llvmpy.py | 25 +++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index d413bef..99657d7 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -2454,4 +2454,8 @@ if api.llvm.InitializeNativeTargetAsmPrinter(): # should this be an optional feature? # should user trigger the initialization? raise llvm.LLVMException("No native asm printer!?") - +if api.llvm.InitializeNativeTargetAsmParser(): + # required by MCJIT? + # should this be an optional feature? + # should user trigger the initialization? + raise llvm.LLVMException("No native asm parser!?") diff --git a/llvm/ee.py b/llvm/ee.py index e87777a..583201b 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -152,7 +152,9 @@ class EngineBuilder(llvm.Wrapper): engine = self._ptr.create(tm._ptr) else: engine = self._ptr.create() - return ExecutionEngine(engine) + ee = ExecutionEngine(engine) + ee.finalize_object() # no effect for legacy JIT + return ee def select_target(self, *args): '''get the corresponding target machine @@ -218,6 +220,9 @@ class ExecutionEngine(llvm.Wrapper): def remove_module(self, module): return self._ptr.removeModule(module._ptr) + def finalize_object(self): + return self._ptr.finalizeObject() + @property def target_data(self): ptr = self._ptr.getDataLayout() diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index e21a825..8d38ed0 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -1353,6 +1353,31 @@ class TestCmp(TestCase): tests.append(TestCmp) +# --------------------------------------------------------------------------- + +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)) + +if llvm.version >= (3, 3): + # MCJIT broken in 3.2 + # The test will segfault in OSX? + tests.append(TestMCJIT) + # --------------------------------------------------------------------------- def run(verbosity=1): From c0e9dedc9048e7849b767c193542ef507d21f8c0 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 31 Jul 2013 17:50:30 -0500 Subject: [PATCH 394/516] add binding to dynamiclibrary namespace for multimodule linking --- llvm/ee.py | 14 ++++++++++++++ llvm/test_llvmpy.py | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/llvm/ee.py b/llvm/ee.py index 583201b..fe21ea2 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -195,6 +195,9 @@ class ExecutionEngine(llvm.Wrapper): ptr = self._ptr.runFunction(fn._ptr, list(map(lambda x: x._ptr, args))) 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): return self._ptr.getPointerToFunction(fn._ptr) @@ -371,3 +374,14 @@ class TargetMachine(llvm.Wrapper): def feature_string(self): return self._ptr.getTargetFeatureString() + + +#===----------------------------------------------------------------------=== +# Dynamic Library +#===----------------------------------------------------------------------=== + +def dylib_add_symbol(name, ptr): + api.llvm.sys.DynamicLibrary.AddSymbol(name, ptr) + +def dylib_address_of_symbol(name): + return api.llvm.sys.DynamicLibrary.SearchForAddressOfSymbol(name) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 8d38ed0..19c402c 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -1373,6 +1373,43 @@ class TestMCJIT(TestCase): 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): # MCJIT broken in 3.2 # The test will segfault in OSX? From c4db61c7f53b513645761dadfdc19a105aa410e0 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 1 Aug 2013 13:02:45 -0500 Subject: [PATCH 395/516] add test for basic arith operators and problems for div and mod on 32bit platforms --- llvm/test_llvmpy.py | 62 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 19c402c..e51c406 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -1415,6 +1415,68 @@ if llvm.version >= (3, 3): # The test will segfault in OSX? tests.append(TestMCJIT) + +class TestArith(TestCase): + ''' + Test basic arithmetic support with LLVM old-JIT + ''' + 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()] + + for ty in inttys: + self.func_template(ty, iop) + 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') + + def test_div(self): + if BITS == 32: + print('skipped test for div') + print('known failure due to unresolved external symbol __udivdi3') + return + self.template('udiv', 'fdiv') + + def test_rem(self): + if BITS == 32: + print('skipped test for rem') + print('known failure due to unresolved external symbol __umoddi3') + return + self.template('urem', 'frem') + +tests.append(TestArith) + # --------------------------------------------------------------------------- def run(verbosity=1): From 2a25b1c2b3819bb11fe330dfd64674c06d5db00d Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 1 Aug 2013 11:50:36 -0500 Subject: [PATCH 396/516] fix avx detection for py3 --- llvm/workaround/avx_support.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/llvm/workaround/avx_support.py b/llvm/workaround/avx_support.py index 81cb936..0b1c2da 100644 --- a/llvm/workaround/avx_support.py +++ b/llvm/workaround/avx_support.py @@ -50,8 +50,7 @@ def detect_osx_like(): stdout=subprocess.PIPE) except OSError: return False - - features = info.stdout.read() + features = info.stdout.read().decode('UTF8') features = features.split() return 'AVX1.0' in features and 'OSXSAVE' in features and 'XSAVE' in features From 0421ad8456fe86facbd6d975cf47ea05845f2671 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 2 Aug 2013 12:12:35 -0500 Subject: [PATCH 397/516] add dev docs --- llvmpy/README | 5 -- llvmpy/README.md | 151 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+), 5 deletions(-) delete mode 100644 llvmpy/README create mode 100644 llvmpy/README.md diff --git a/llvmpy/README b/llvmpy/README deleted file mode 100644 index 2bfabcd..0000000 --- a/llvmpy/README +++ /dev/null @@ -1,5 +0,0 @@ -# README - -This is a reimplementation of the LLVM binding, aiming to provide a more familiar interface to the C++ API whenever possible. - -The implementation uses a custom DSL in python to describe the interface (under binding directory). The DSL serves as input to *gen.py* for generation of the .cpp and .py files for the actual binding. diff --git a/llvmpy/README.md b/llvmpy/README.md new file mode 100644 index 0000000..4e444f8 --- /dev/null +++ b/llvmpy/README.md @@ -0,0 +1,151 @@ +# README + +This is a reimplementation of the LLVM binding, aiming to provide a more +familiar interface to the C++ API whenever possible. + +The implementation uses a custom DSL in python to describe the interface. +The DSL serves as input to *gen/gen.py* for generation of the .cpp and .py files +for the actual binding. + +# How to Add New Class + +Let's use the `llvm::Module` as an example because it should be one of the most +familiar class in LLVM. + +Reference code in https://github.com/llvmpy/llvmpy/blob/master/llvmpy/src/Module.py +and see LLVM documentation at http://llvm.org/docs/doxygen/html/classllvm_1_1Module.html + +1) Import binding helpers + +```python +from binding import * +# Yes, it is bad practice to import star. +# I will fix it one day. +``` + +2) Import LLVM namespace + +```python +from .namespace import llvm +``` + +3) Declare the class + +```python +Module = llvm.Class() +``` + +4) Import all the dependencies for the definition + +5) Define the class + +```python +@Module +class Module: + ... +``` + +## Inside the definition... + +5.1) Use the ``_include_`` attribute to add include files. + +5.2) Use ``Enum`` to create an enumerator type. + +5.3) Make constructor + +Not every class needs to have a binding for the constructor. +Only add things that will be used. + +```python +new = Constructor(cast(str, StringRef), ref(LLVMContext)) +``` + +The constructor must be named as "new". + +The args to ``Constructor`` are parameters of the signature. +The first parameter means cast Python string to a StringRef. +The second parameter means pass LLVMContext object as a value reference. + +5.4) Make destructor + +Not every class needs to have a binding for the destructor. +Only add things that will be used. +If it is always owned by another object, it usually does not need to have one. + +```python +delete = Destructor() +``` + +The destructor must be named as "delete". + +5.5) Add Simple Methods + +```python +getFunction = Method(ptr(Function), cast(str, StringRef)) +``` + +The first arg is the return type: a ponter to Function. +The rest of the args are for the parameters. + +Note: ``cast(fromtype, totype)`` can be used as return-type as well. +In that case, the ``fromtype`` will usually refer to a LLVM object +and the ``totype`` will refer to the Python object. + +5.6) Add custom methods defined in C++ + +The ``list_functions`` is created as a ``CustomMethod``. + +```python +list_functions = CustomMethod('Module_list_functions', PyObjectPtr) +``` + +The first arg is the name that appears in C++. +The second argument is the return-type. +The rest of the arguments are parameters. + +The definition of ``Module_list_functions`` is located in +"include/llvm_binding/extra.h". + +5.7) Add custom python method + +One can also add custom methods in Python, e.g. ``__str__``. + +```python +@CustomPythonMethod +def __str__(self): + from llvmpy import extra + os = extra.make_raw_ostream_for_printing() + self.print_(os, None) + return os.str() +``` + +The body of ``__str__`` is directly copied to the Python output file. +Thus, it can't reference to anything in current file scope. + +# Static Methods + +``StaticMethod`` https://github.com/llvmpy/llvmpy/blob/master/llvmpy/src/PassRegistry.py + +``CustomStaticMethod`` https://github.com/llvmpy/llvmpy/blob/master/llvmpy/src/Support/TargetRegistry.py + + +# Namespace + +``Namespace`` https://github.com/llvmpy/llvmpy/blob/master/llvmpy/src/Support/CodeGen.py + +# Functions + +``Function`` https://github.com/llvmpy/llvmpy/blob/master/llvmpy/src/Assembly/Parser.py + +``CustomFunction`` https://github.com/llvmpy/llvmpy/blob/master/llvmpy/src/Bitcode/ReaderWriter.py + + + + + +# Other Things from the binding.py + +https://github.com/llvmpy/llvmpy/blob/master/llvmpy/gen/binding.py + +The list of C++ types: https://github.com/llvmpy/llvmpy/blob/master/llvmpy/gen/binding.py#L218 + From 84a95945ea7ec06ff361fc3aa62ca623bb00f516 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Tue, 6 Aug 2013 14:17:14 -0500 Subject: [PATCH 398/516] update marker header file --- llvm-config-win32.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm-config-win32.py b/llvm-config-win32.py index e191290..8c268cb 100644 --- a/llvm-config-win32.py +++ b/llvm-config-win32.py @@ -108,7 +108,7 @@ def main(): elif option == '--includedir': incdir = join(find_llvm_prefix(), 'include') - ensure_file(join(incdir, 'llvm' , 'BasicBlock.h')) + ensure_file(join(incdir, 'llvm' , 'Linker.h')) print(incdir) elif option == '--libdir': From c20c4d776f9b44475cae61b7da8922895dd09817 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 12 Aug 2013 14:42:49 -0500 Subject: [PATCH 399/516] fix exception handling for TargetMachine --- llvm/ee.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/ee.py b/llvm/ee.py index fe21ea2..832f422 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -282,7 +282,7 @@ class TargetMachine(llvm.Wrapper): with contextlib.closing(BytesIO()) as error: target = api.llvm.TargetRegistry.lookupTarget(triple, error) if not target: - raise llvm.LLVMException(error) + raise llvm.LLVMException(error.getvalue()) if not target.hasTargetMachine(): raise llvm.LLVMException(target, "No target machine.") target_options = api.llvm.TargetOptions.new() From b4d943a6717ff2431c4df6578d6afccbed3f9f62 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 12 Aug 2013 14:43:23 -0500 Subject: [PATCH 400/516] add autoselect ELF generation for MCJIT --- llvm/ee.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/llvm/ee.py b/llvm/ee.py index 832f422..4090a0f 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -30,6 +30,7 @@ "Execution Engine and related classes." +import sys from io import BytesIO import contextlib @@ -150,6 +151,12 @@ class EngineBuilder(llvm.Wrapper): ''' if tm is not None: engine = self._ptr.create(tm._ptr) + elif (sys.prefix.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) else: engine = self._ptr.create() ee = ExecutionEngine(engine) @@ -173,6 +180,7 @@ class EngineBuilder(llvm.Wrapper): '''Enable/disable MCJIT ''' self._ptr.setUseMCJIT(enable) + self._use_mcjit = True return self #===----------------------------------------------------------------------=== From eb4fc653f2ca3e8d9c4f31817b791070a75886d3 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 12 Aug 2013 14:52:16 -0500 Subject: [PATCH 401/516] ensure MCJIT ELF autoselect works --- llvm/ee.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/ee.py b/llvm/ee.py index 4090a0f..b91c4cb 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -151,12 +151,12 @@ class EngineBuilder(llvm.Wrapper): ''' if tm is not None: engine = self._ptr.create(tm._ptr) - elif (sys.prefix.startswith('win32') and + 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) + engine = self._ptr.create(tm._ptr) else: engine = self._ptr.create() ee = ExecutionEngine(engine) From 1e9d37a64e489efdd9c06a2b365e7b6063336652 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 12 Aug 2013 15:59:17 -0500 Subject: [PATCH 402/516] add no-signed-wrap and no-unsigned-wrap flags to IRBuilder --- llvm/core.py | 20 ++++++++++++-------- llvm/test_llvmpy.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index 99657d7..0fbd5ab 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -2124,20 +2124,23 @@ class Builder(llvm.Wrapper): # arithmethic, bitwise and logical - def add(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateAdd(lhs._ptr, rhs._ptr, name)) + def add(self, lhs, rhs, name="", nuw=False, nsw=False): + return _make_value(self._ptr.CreateAdd(lhs._ptr, rhs._ptr, name, + nuw, nsw)) def fadd(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateFAdd(lhs._ptr, rhs._ptr, name)) - def sub(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateSub(lhs._ptr, rhs._ptr, name)) + def sub(self, lhs, rhs, name="", nuw=False, nsw=False): + return _make_value(self._ptr.CreateSub(lhs._ptr, rhs._ptr, name, + nuw, nsw)) def fsub(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateFSub(lhs._ptr, rhs._ptr, name)) - def mul(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateMul(lhs._ptr, rhs._ptr, name)) + def mul(self, lhs, rhs, name="", nuw=False, nsw=False): + return _make_value(self._ptr.CreateMul(lhs._ptr, rhs._ptr, name, + nuw, nsw)) def fmul(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateFMul(lhs._ptr, rhs._ptr, name)) @@ -2160,8 +2163,9 @@ class Builder(llvm.Wrapper): def frem(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateFRem(lhs._ptr, rhs._ptr, name)) - def shl(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateShl(lhs._ptr, rhs._ptr, name)) + def shl(self, lhs, rhs, name="", nuw=False, nsw=False): + return _make_value(self._ptr.CreateShl(lhs._ptr, rhs._ptr, name, + nuw, nsw)) def lshr(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateLShr(lhs._ptr, rhs._ptr, name)) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index e51c406..9c3e695 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -1477,6 +1477,40 @@ class TestArith(TestCase): tests.append(TestArith) +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') + +tests.append(TestNUWNSW) + # --------------------------------------------------------------------------- def run(verbosity=1): From cfe5e9ea92f617b5a3e02b70aff5f26963f03393 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 12 Aug 2013 16:11:24 -0500 Subject: [PATCH 403/516] add exact flag to IRBuilder --- llvm/core.py | 20 ++++++++++++-------- llvm/test_llvmpy.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index 0fbd5ab..7535b0f 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -2145,11 +2145,13 @@ class Builder(llvm.Wrapper): def fmul(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateFMul(lhs._ptr, rhs._ptr, name)) - def udiv(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateUDiv(lhs._ptr, rhs._ptr, name)) + def udiv(self, lhs, rhs, name="", exact=False): + return _make_value(self._ptr.CreateUDiv(lhs._ptr, rhs._ptr, name, + exact)) - def sdiv(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateSDiv(lhs._ptr, rhs._ptr, name)) + def sdiv(self, lhs, rhs, name="", exact=False): + return _make_value(self._ptr.CreateSDiv(lhs._ptr, rhs._ptr, name, + exact)) def fdiv(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateFDiv(lhs._ptr, rhs._ptr, name)) @@ -2167,11 +2169,13 @@ class Builder(llvm.Wrapper): return _make_value(self._ptr.CreateShl(lhs._ptr, rhs._ptr, name, nuw, nsw)) - def lshr(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateLShr(lhs._ptr, rhs._ptr, name)) + def lshr(self, lhs, rhs, name="", exact=False): + return _make_value(self._ptr.CreateLShr(lhs._ptr, rhs._ptr, name, + exact)) - def ashr(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateAShr(lhs._ptr, rhs._ptr, name)) + def ashr(self, lhs, rhs, name="", exact=False): + return _make_value(self._ptr.CreateAShr(lhs._ptr, rhs._ptr, name, + exact)) def and_(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateAnd(lhs._ptr, rhs._ptr, name)) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 9c3e695..250e404 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -1511,6 +1511,37 @@ class TestNUWNSW(TestCase): tests.append(TestNUWNSW) + +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) + # --------------------------------------------------------------------------- def run(verbosity=1): From 1ed3c773103a09d126a645c6af9f4bb5809a4d99 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 12 Aug 2013 16:16:38 -0500 Subject: [PATCH 404/516] add neg nuw nsw --- llvm/core.py | 4 ++-- llvm/test_llvmpy.py | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index 7535b0f..945dd86 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -2186,8 +2186,8 @@ class Builder(llvm.Wrapper): def xor(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateXor(lhs._ptr, rhs._ptr, name)) - def neg(self, val, name=""): - return _make_value(self._ptr.CreateNeg(val._ptr, name)) + def neg(self, val, name="", nuw=False, nsw=False): + return _make_value(self._ptr.CreateNeg(val._ptr, name, nuw, nsw)) def not_(self, val, name=""): return _make_value(self._ptr.CreateNot(val._ptr, name)) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 250e404..2a5c1f5 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -1509,6 +1509,13 @@ class TestNUWNSW(TestCase): 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) From d060c10096ea97d091a8cced5610a5bc887971a9 Mon Sep 17 00:00:00 2001 From: majidaldo Date: Tue, 13 Aug 2013 14:42:54 -0500 Subject: [PATCH 405/516] add conda build script --- buildscripts/condarecipe/bld.bat | 6 ++++++ buildscripts/condarecipe/build.sh | 13 +++++++++++++ buildscripts/condarecipe/meta.yaml | 27 +++++++++++++++++++++++++++ buildscripts/condarecipe/run_test.py | 19 +++++++++++++++++++ 4 files changed, 65 insertions(+) create mode 100644 buildscripts/condarecipe/bld.bat create mode 100644 buildscripts/condarecipe/build.sh create mode 100644 buildscripts/condarecipe/meta.yaml create mode 100644 buildscripts/condarecipe/run_test.py diff --git a/buildscripts/condarecipe/bld.bat b/buildscripts/condarecipe/bld.bat new file mode 100644 index 0000000..45ef910 --- /dev/null +++ b/buildscripts/condarecipe/bld.bat @@ -0,0 +1,6 @@ +set LLVMPY_DYNLINK=0 +set INCLUDE=%LIBRARY_INC% +set LIBPATH=%LIBRARY_LIB% +set LIB=%LIBRARY_LIB% +python setup.py install +if errorlevel 1 exit 1 diff --git a/buildscripts/condarecipe/build.sh b/buildscripts/condarecipe/build.sh new file mode 100644 index 0000000..5c98fde --- /dev/null +++ b/buildscripts/condarecipe/build.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +if [[ (`uname` == Linux) && (`uname -m` != armv6l) ]] +then + export CC=gcc + #gcc44 + export CXX=g++ + #g++44 +fi + +export LLVMPY_DYNLINK=$DISTRO_BUILD + +$PYTHON setup.py install diff --git a/buildscripts/condarecipe/meta.yaml b/buildscripts/condarecipe/meta.yaml new file mode 100644 index 0000000..05007f3 --- /dev/null +++ b/buildscripts/condarecipe/meta.yaml @@ -0,0 +1,27 @@ +package: + name: llvmpy + version: master + +source: + git_url: git@github.com:llvmpy/llvmpy.git +# git_tag: 0.12.0 + +requirements: + build: + - llvm + - python + run: + - llvm [unix] + - python + +test: + imports: + - llvm + - llvmpy + - llvmpy._api + - llvmpy._capsule + - llpython + - llvm_array + - llvm_cbuilder + + diff --git a/buildscripts/condarecipe/run_test.py b/buildscripts/condarecipe/run_test.py new file mode 100644 index 0000000..281a599 --- /dev/null +++ b/buildscripts/condarecipe/run_test.py @@ -0,0 +1,19 @@ +import sys +import platform +import llvm + +from llvm.core import Module +from llvm.ee import EngineBuilder +m = Module.new('fjoidajfa') +eb = EngineBuilder.new(m) +target = eb.select_target() + +print('target.triple=%r' % target.triple) +if sys.platform == 'darwin': + s = {'64bit': 'x86_64', '32bit': 'x86'}[platform.architecture()[0]] + assert target.triple.startswith(s + '-apple-darwin') + +assert llvm.test(verbosity=2) == 0 + +print('llvm.__version__: %s' % llvm.__version__) +#assert llvm.__version__ == '0.12.0' From bf0253c9f9d96bb922f4c88ecffc85d01f0ecbb1 Mon Sep 17 00:00:00 2001 From: majidaldo Date: Tue, 13 Aug 2013 14:55:13 -0500 Subject: [PATCH 406/516] add chrpath --- buildscripts/condarecipe/meta.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/buildscripts/condarecipe/meta.yaml b/buildscripts/condarecipe/meta.yaml index 05007f3..15d9f8a 100644 --- a/buildscripts/condarecipe/meta.yaml +++ b/buildscripts/condarecipe/meta.yaml @@ -10,6 +10,7 @@ requirements: build: - llvm - python + - chrpath run: - llvm [unix] - python From 3a289ccace2efe5d3f898f59441768c5865445ff Mon Sep 17 00:00:00 2001 From: majidaldo Date: Tue, 13 Aug 2013 14:55:42 -0500 Subject: [PATCH 407/516] add percent python --- buildscripts/condarecipe/bld.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildscripts/condarecipe/bld.bat b/buildscripts/condarecipe/bld.bat index 45ef910..e9177c5 100644 --- a/buildscripts/condarecipe/bld.bat +++ b/buildscripts/condarecipe/bld.bat @@ -2,5 +2,5 @@ set LLVMPY_DYNLINK=0 set INCLUDE=%LIBRARY_INC% set LIBPATH=%LIBRARY_LIB% set LIB=%LIBRARY_LIB% -python setup.py install +%PYTHON% setup.py install if errorlevel 1 exit 1 From 1be8b07cedfff7a73aaad59e4b076a75dde8f03d Mon Sep 17 00:00:00 2001 From: majidaldo Date: Tue, 13 Aug 2013 14:59:33 -0500 Subject: [PATCH 408/516] charpath just for linux --- buildscripts/condarecipe/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildscripts/condarecipe/meta.yaml b/buildscripts/condarecipe/meta.yaml index 15d9f8a..b079986 100644 --- a/buildscripts/condarecipe/meta.yaml +++ b/buildscripts/condarecipe/meta.yaml @@ -10,7 +10,7 @@ requirements: build: - llvm - python - - chrpath + - chrpath [linux] run: - llvm [unix] - python From d10b182479b58a25bb45a6bd5c8d1a6aa8ee468c Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 13 Aug 2013 15:27:49 -0500 Subject: [PATCH 409/516] dislabe MCJIT tests for LLVM3.2 --- llvm/test_llvmpy.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 2a5c1f5..f8d6adb 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -1418,7 +1418,7 @@ if llvm.version >= (3, 3): class TestArith(TestCase): ''' - Test basic arithmetic support with LLVM old-JIT + Test basic arithmetic support with LLVM MCJIT ''' def func_template(self, ty, op): m = Module.new('dofjaa') @@ -1475,7 +1475,9 @@ class TestArith(TestCase): return self.template('urem', 'frem') -tests.append(TestArith) +if llvm.version >= (3, 3): + # MCJIT is broken in 3.2 + tests.append(TestArith) class TestNUWNSW(TestCase): def make_module(self): From 07c64779d8e3a86d0ac64139bf0bafd26b629e1e Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 13 Aug 2013 18:38:41 -0500 Subject: [PATCH 410/516] begin low-level runtime implementation --- llrtc/Makefile | 21 ++++++++++ llrtc/README.md | 25 +++++++++++ llrtc/common.mk | 26 ++++++++++++ llrtc/lib/Makefile | 44 +++++++++++++++++++ llrtc/lib/test_udivmod64.c | 22 ++++++++++ llrtc/lib/test_udivmod64.py | 53 +++++++++++++++++++++++ llrtc/lib/udivmod64.c | 84 +++++++++++++++++++++++++++++++++++++ llrtc/lib/udivmod64.h | 11 +++++ llrtc/tools/striptriple.py | 15 +++++++ 9 files changed, 301 insertions(+) create mode 100644 llrtc/Makefile create mode 100644 llrtc/README.md create mode 100644 llrtc/common.mk create mode 100644 llrtc/lib/Makefile create mode 100644 llrtc/lib/test_udivmod64.c create mode 100644 llrtc/lib/test_udivmod64.py create mode 100644 llrtc/lib/udivmod64.c create mode 100644 llrtc/lib/udivmod64.h create mode 100644 llrtc/tools/striptriple.py diff --git a/llrtc/Makefile b/llrtc/Makefile new file mode 100644 index 0000000..c271d0e --- /dev/null +++ b/llrtc/Makefile @@ -0,0 +1,21 @@ +DIRECTORIES = divmod + +all: + for mydir in $(DIRECTORIES); do \ + make -C $$mydir; \ + done + +test: + for mydir in $(DIRECTORIES); do \ + make -C $$mydir test; \ + done + +clean-test: + for mydir in $(DIRECTORIES); do \ + make -C $$mydir clean-test; \ + done + +clean: + for mydir in $(DIRECTORIES); do \ + make -C $$mydir clean; \ + done \ No newline at end of file diff --git a/llrtc/README.md b/llrtc/README.md new file mode 100644 index 0000000..539d9c3 --- /dev/null +++ b/llrtc/README.md @@ -0,0 +1,25 @@ +# LLRT: Low Level Runtime + +## Why? + +The same reason for LLVM compiler-rt. LLVM generates libgcc symbols, such as +__divdi3 for 64-bit division on 32-bit platform. They are not also available. +We need to ship compiler-rt but it is not Windows ready. +This subproject aims to provide a small portable subset of compiler-rt. +Start small and add only the things we really needed. +Performance is not crucial but should not be terrible. +Functionality and usefullness should be more important than performance. + +## Developer Instructions + +LLRT implements some functionalities in compiler-rt in ANSI C. +The C files are compiled using clang to produce LLVM IR which are shipped. +The IR files are committed in the repository. +So, remember to build the IR files commit them after modifying the C files. + +## Build Requirement + +- Make +- Clang +- Python + diff --git a/llrtc/common.mk b/llrtc/common.mk new file mode 100644 index 0000000..3de9c12 --- /dev/null +++ b/llrtc/common.mk @@ -0,0 +1,26 @@ +CLANG = clang +CF = -Wall -ansi +OUTDIR = .. + +all: ir + +$(OUTPUT).c: $(OUTPUT).h + +$(OUTPUT): test.c $(OUTPUT).c + $(CLANG) $(CF) -ftrapv -o $@ $+ + +test: $(OUTPUT) + python test.py + +ir: + CLANG -m32 $(CF) -O0 -emit-llvm -S $(OUTPUT).c -o $(OUTDIR)/x86/$(OUTPUT).ll + CLANG -m64 $(CF) -O0 -emit-llvm -S $(OUTPUT).c -o $(OUTDIR)/x86_64/$(OUTPUT).ll + python ../tools/striptriple.py $(OUTDIR)/x86/$(OUTPUT).ll + python ../tools/striptriple.py $(OUTDIR)/x86_64/$(OUTPUT).ll + +clean-test: + rm -f $(OUTPUT) + +clean: clean-test + rm -f $(OUTDIR)/x86/$(OUTPUT).ll + rm -f $(OUTDIR)/x86_64/$(OUTPUT).ll diff --git a/llrtc/lib/Makefile b/llrtc/lib/Makefile new file mode 100644 index 0000000..1bb325f --- /dev/null +++ b/llrtc/lib/Makefile @@ -0,0 +1,44 @@ +OUTPUT = llrt +SOURCES = udivmod64.c + +CLANG = clang +CF = -Wall -ansi +CF_TEST = $(CF) -ftrapv +CF_BUILD = $(CF) -O0 -emit-llvm +OUTDIR = .. + +all: ir + +ir: $(SOURCES) + $(CLANG) -m32 $(CF_BUILD) -S -o $(OUTDIR)/$(OUTPUT)_x86.ll -c $(SOURCES) + python ../tools/striptriple.py $(OUTDIR)/$(OUTPUT)_x86.ll + $(CLANG) -m64 $(CF_BUILD) -S -o $(OUTDIR)/$(OUTPUT)_x86_64.ll -c $(SOURCES) + python ../tools/striptriple.py $(OUTDIR)/$(OUTPUT)_x86_64.ll + +lib$(OUTPUT).a: $(SOURCES) + $(CLANG) $(CF) -o $@ -c $+ + +build-test: lib$(OUTPUT).a + for src in $(SOURCES); do \ + $(CLANG) $(CF_TEST) -o test_$${src%.*} test_$$src -L. -lllrt; \ + done; + +test: build-test + for src in $(SOURCES); do \ + echo "testing $${src%.*}"; \ + python test_$${src%.*}.py > test_$${src%.*}.out; \ + done; + +clean-test: + rm -f *.out + rm -f *.a + for src in $(SOURCES); do \ + rm -f test_$${src%.*} ;\ + done; + +clean-dist: + rm $(OUTDIR)/*.ll + +clean: clean-test clean-dist + +udivmod64.c: udivmod64.h diff --git a/llrtc/lib/test_udivmod64.c b/llrtc/lib/test_udivmod64.c new file mode 100644 index 0000000..e2935c5 --- /dev/null +++ b/llrtc/lib/test_udivmod64.c @@ -0,0 +1,22 @@ +#include +#include + +extern uint64_t +udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder); + +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; +} \ No newline at end of file diff --git a/llrtc/lib/test_udivmod64.py b/llrtc/lib/test_udivmod64.py new file mode 100644 index 0000000..487a458 --- /dev/null +++ b/llrtc/lib/test_udivmod64.py @@ -0,0 +1,53 @@ +import math +import os +import subprocess +udt = os.path.join('.', 'test_udivmod64') + +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() diff --git a/llrtc/lib/udivmod64.c b/llrtc/lib/udivmod64.c new file mode 100644 index 0000000..a028aea --- /dev/null +++ b/llrtc/lib/udivmod64.c @@ -0,0 +1,84 @@ +/* +Implements unsigned divmod using for platform missing 64-bit division and/or +modulo functions. +*/ +#include "udivmod64.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); + } + } + *remainder = state.tmp; + return quotient; +} diff --git a/llrtc/lib/udivmod64.h b/llrtc/lib/udivmod64.h new file mode 100644 index 0000000..9cbcd8c --- /dev/null +++ b/llrtc/lib/udivmod64.h @@ -0,0 +1,11 @@ +#ifndef LLRT_UDIVMOD_H_ +#define LLRT_UDIVMOD_H_ + +#include + +#define BITS_PER_BYTE 8 + +uint64_t udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder); + +#endif /* LLRT_UDIVMOD_H_ */ + diff --git a/llrtc/tools/striptriple.py b/llrtc/tools/striptriple.py new file mode 100644 index 0000000..a20ba34 --- /dev/null +++ b/llrtc/tools/striptriple.py @@ -0,0 +1,15 @@ +import sys +import re + +buf = [] +with open(sys.argv[1], 'r') as fin: + tripleline = re.compile('^target\s+triple\s+=\s+') + for line in fin.readlines(): + if not tripleline.match(line): + buf.append(line) + +with open(sys.argv[1], 'w') as fout: + for line in buf: + fout.write(line) + + From 7d1c4c18a0539f61d1aba1e55fdea537a8300ec5 Mon Sep 17 00:00:00 2001 From: majidaldo Date: Wed, 14 Aug 2013 14:39:10 -0500 Subject: [PATCH 411/516] high version number --- buildscripts/condarecipe/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildscripts/condarecipe/meta.yaml b/buildscripts/condarecipe/meta.yaml index b079986..2b05015 100644 --- a/buildscripts/condarecipe/meta.yaml +++ b/buildscripts/condarecipe/meta.yaml @@ -1,6 +1,6 @@ package: name: llvmpy - version: master + version: 99.9.9 source: git_url: git@github.com:llvmpy/llvmpy.git From 8480d55faf0e671326b37576a05d0e1fbd7cb79b Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 14 Aug 2013 15:29:13 -0500 Subject: [PATCH 412/516] add sdivmod; improve build system; --- llrtc/Makefile | 29 ++++++------- llrtc/common.mk | 26 ------------ llrtc/lib/.gitignore | 4 ++ llrtc/lib/Makefile | 68 ++++++++++++++++++++----------- llrtc/lib/{udivmod64.h => llrt.h} | 7 ++-- llrtc/lib/sdivmod64.c | 40 ++++++++++++++++++ llrtc/lib/test_sdivmod64.c | 21 ++++++++++ llrtc/lib/test_sdivmod64.py | 56 +++++++++++++++++++++++++ llrtc/lib/test_udivmod64.c | 6 +-- llrtc/lib/test_udivmod64.py | 2 +- llrtc/lib/udivmod64.c | 4 +- 11 files changed, 190 insertions(+), 73 deletions(-) delete mode 100644 llrtc/common.mk create mode 100644 llrtc/lib/.gitignore rename llrtc/lib/{udivmod64.h => llrt.h} (50%) create mode 100644 llrtc/lib/sdivmod64.c create mode 100644 llrtc/lib/test_sdivmod64.c create mode 100644 llrtc/lib/test_sdivmod64.py diff --git a/llrtc/Makefile b/llrtc/Makefile index c271d0e..bde100e 100644 --- a/llrtc/Makefile +++ b/llrtc/Makefile @@ -1,21 +1,22 @@ -DIRECTORIES = divmod - all: - for mydir in $(DIRECTORIES); do \ - make -C $$mydir; \ - done + make -C lib + +ir: + make -C lib ir test: - for mydir in $(DIRECTORIES); do \ - make -C $$mydir test; \ - done + make -C lib test clean-test: - for mydir in $(DIRECTORIES); do \ - make -C $$mydir clean-test; \ - done + make -C lib clean-test + +clean-temp: + make -C lib clean-temp clean: - for mydir in $(DIRECTORIES); do \ - make -C $$mydir clean; \ - done \ No newline at end of file + make -C lib clean + +install: ir + make -C lib clean-test + make -C lib clean-temp + \ No newline at end of file diff --git a/llrtc/common.mk b/llrtc/common.mk deleted file mode 100644 index 3de9c12..0000000 --- a/llrtc/common.mk +++ /dev/null @@ -1,26 +0,0 @@ -CLANG = clang -CF = -Wall -ansi -OUTDIR = .. - -all: ir - -$(OUTPUT).c: $(OUTPUT).h - -$(OUTPUT): test.c $(OUTPUT).c - $(CLANG) $(CF) -ftrapv -o $@ $+ - -test: $(OUTPUT) - python test.py - -ir: - CLANG -m32 $(CF) -O0 -emit-llvm -S $(OUTPUT).c -o $(OUTDIR)/x86/$(OUTPUT).ll - CLANG -m64 $(CF) -O0 -emit-llvm -S $(OUTPUT).c -o $(OUTDIR)/x86_64/$(OUTPUT).ll - python ../tools/striptriple.py $(OUTDIR)/x86/$(OUTPUT).ll - python ../tools/striptriple.py $(OUTDIR)/x86_64/$(OUTPUT).ll - -clean-test: - rm -f $(OUTPUT) - -clean: clean-test - rm -f $(OUTDIR)/x86/$(OUTPUT).ll - rm -f $(OUTDIR)/x86_64/$(OUTPUT).ll diff --git a/llrtc/lib/.gitignore b/llrtc/lib/.gitignore new file mode 100644 index 0000000..fbcf76a --- /dev/null +++ b/llrtc/lib/.gitignore @@ -0,0 +1,4 @@ +*.o +*.run +*.out +*.ll diff --git a/llrtc/lib/Makefile b/llrtc/lib/Makefile index 1bb325f..8c9361d 100644 --- a/llrtc/lib/Makefile +++ b/llrtc/lib/Makefile @@ -1,44 +1,66 @@ OUTPUT = llrt -SOURCES = udivmod64.c +SOURCES = udivmod64.c sdivmod64.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: $(SOURCES) - $(CLANG) -m32 $(CF_BUILD) -S -o $(OUTDIR)/$(OUTPUT)_x86.ll -c $(SOURCES) - python ../tools/striptriple.py $(OUTDIR)/$(OUTPUT)_x86.ll - $(CLANG) -m64 $(CF_BUILD) -S -o $(OUTDIR)/$(OUTPUT)_x86_64.ll -c $(SOURCES) - python ../tools/striptriple.py $(OUTDIR)/$(OUTPUT)_x86_64.ll +ir: $(OUTDIR)/$(OUTPUT)_x86.ll $(OUTDIR)/$(OUTPUT)_x86_64.ll -lib$(OUTPUT).a: $(SOURCES) - $(CLANG) $(CF) -o $@ -c $+ +$(OUTDIR)/$(OUTPUT)_x86.ll: $(SOURCES:.c=_x86.bc) + $(LLVM_LINK) -S $+ -o $@ + python $(STRIPPER) $@ -build-test: lib$(OUTPUT).a - for src in $(SOURCES); do \ - $(CLANG) $(CF_TEST) -o test_$${src%.*} test_$$src -L. -lllrt; \ - done; +$(OUTDIR)/$(OUTPUT)_x86_64.ll: $(SOURCES:.c=_x86_64.bc) + $(LLVM_LINK) -S $+ -o $@ + python $(STRIPPER) $@ -test: build-test - for src in $(SOURCES); do \ - echo "testing $${src%.*}"; \ - python test_$${src%.*}.py > test_$${src%.*}.out; \ +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 *.a - for src in $(SOURCES); do \ - rm -f test_$${src%.*} ;\ - done; + rm -f *.o + rm -f *.run -clean-dist: - rm $(OUTDIR)/*.ll +clean-dist: clean-temp + rm -f *.ll + +clean-temp: + rm -f *.bc + rm -f *.o + rm -f *.out clean: clean-test clean-dist -udivmod64.c: udivmod64.h +%.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 diff --git a/llrtc/lib/udivmod64.h b/llrtc/lib/llrt.h similarity index 50% rename from llrtc/lib/udivmod64.h rename to llrtc/lib/llrt.h index 9cbcd8c..0d26309 100644 --- a/llrtc/lib/udivmod64.h +++ b/llrtc/lib/llrt.h @@ -1,11 +1,12 @@ -#ifndef LLRT_UDIVMOD_H_ -#define LLRT_UDIVMOD_H_ +#ifndef LLRT_H_ +#define LLRT_H_ #include #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); -#endif /* LLRT_UDIVMOD_H_ */ +#endif /* LLRT_H_ */ diff --git a/llrtc/lib/sdivmod64.c b/llrtc/lib/sdivmod64.c new file mode 100644 index 0000000..df294b3 --- /dev/null +++ b/llrtc/lib/sdivmod64.c @@ -0,0 +1,40 @@ +#include "llrt.h" +#include + +/* +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; +} diff --git a/llrtc/lib/test_sdivmod64.c b/llrtc/lib/test_sdivmod64.c new file mode 100644 index 0000000..1e804d6 --- /dev/null +++ b/llrtc/lib/test_sdivmod64.c @@ -0,0 +1,21 @@ +#include +#include +#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; +} diff --git a/llrtc/lib/test_sdivmod64.py b/llrtc/lib/test_sdivmod64.py new file mode 100644 index 0000000..4aa49a9 --- /dev/null +++ b/llrtc/lib/test_sdivmod64.py @@ -0,0 +1,56 @@ +import math +import os +import subprocess +udt = os.path.join('.', 'test_sdivmod64.run') + +def testcase(dividend, divisor): + print 'divmod64(%d, %d)' % (dividend, divisor) + + procargs = ('%s %s %s' % (udt, dividend, divisor)).split() + result = subprocess.check_output(procargs) + gotQ, gotR = map(int, result.splitlines()) + + expectQ = dividend // divisor + expectR = dividend % divisor + + print 'Q = %d, R = %d' % (gotQ, gotR) + + if expectQ != gotQ: + raise ValueError("invalid quotient: got=%d but expect=%d" % + (gotQ, expectQ)) + if expectR != gotR: + raise ValueError("invalid remainder: got=%d but expect=%d" % + (gotR, expectR)) + print 'OK' + +def testsequence(): + subjects = [ + (0, 1), + (0, 0xffffffff), + (1, 2), + (1, 983219), + (2, 2), + (3, 2), + (1024, 2), + (2048, 512), + (21321, 512), + (9329189, 1031), + (0xffffffff, 2), + (0xffffffff, 0xffff), + (0x1ffffffff, 2), + (0x1ffffffff, 0xffff), + (0xffff, 0xffffffff), + (0x0fffffffffffffff, 0xffff), + (0x7fffffffffffffff, 0x7fffffffffffffff), + (0x7fffffffffffffff, 0x7ffffffffffffff0), + (0x7fffffffffffffff, 87655678587161901), + ] + + for dvd, dvr in subjects: + testcase(dvd, dvr) + testcase(dvd, -dvr) + testcase(-dvd, dvr) + testcase(-dvd, -dvr) + +if __name__ == '__main__': + testsequence() diff --git a/llrtc/lib/test_udivmod64.c b/llrtc/lib/test_udivmod64.c index e2935c5..70b44aa 100644 --- a/llrtc/lib/test_udivmod64.c +++ b/llrtc/lib/test_udivmod64.c @@ -1,8 +1,6 @@ #include #include - -extern uint64_t -udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder); +#include "llrt.h" int main(int argc, char * argv[]){ uint64_t n, d, q, r; @@ -19,4 +17,4 @@ int main(int argc, char * argv[]){ printf("%llu\n", r); return 0; -} \ No newline at end of file +} diff --git a/llrtc/lib/test_udivmod64.py b/llrtc/lib/test_udivmod64.py index 487a458..da07ccb 100644 --- a/llrtc/lib/test_udivmod64.py +++ b/llrtc/lib/test_udivmod64.py @@ -1,7 +1,7 @@ import math import os import subprocess -udt = os.path.join('.', 'test_udivmod64') +udt = os.path.join('.', 'test_udivmod64.run') def testcase(dividend, divisor): print 'divmod64(%d, %d)' % (dividend, divisor) diff --git a/llrtc/lib/udivmod64.c b/llrtc/lib/udivmod64.c index a028aea..5936f98 100644 --- a/llrtc/lib/udivmod64.c +++ b/llrtc/lib/udivmod64.c @@ -2,7 +2,7 @@ Implements unsigned divmod using for platform missing 64-bit division and/or modulo functions. */ -#include "udivmod64.h" +#include "llrt.h" /* count left zero for 64-bit words @@ -79,6 +79,6 @@ uint64_t udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder) quotient |= 1ull << (63 - i); } } - *remainder = state.tmp; + if (remainder) *remainder = state.tmp; return quotient; } From e69048ad3dd6bdf541796e4f64e699962fe5006b Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 14 Aug 2013 17:24:34 -0500 Subject: [PATCH 413/516] add div64 and mod64 --- llrtc/Makefile | 2 +- llrtc/lib/Makefile | 2 +- llrtc/lib/div64.c | 11 +++++++++++ llrtc/lib/llrt.h | 7 +++++++ llrtc/lib/mod64.c | 15 +++++++++++++++ 5 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 llrtc/lib/div64.c create mode 100644 llrtc/lib/mod64.c diff --git a/llrtc/Makefile b/llrtc/Makefile index bde100e..b15eac5 100644 --- a/llrtc/Makefile +++ b/llrtc/Makefile @@ -17,6 +17,6 @@ clean: make -C lib clean install: ir - make -C lib clean-test + cp llrt_*.ll ../llvm/llrt make -C lib clean-temp \ No newline at end of file diff --git a/llrtc/lib/Makefile b/llrtc/lib/Makefile index 8c9361d..9dbfb27 100644 --- a/llrtc/lib/Makefile +++ b/llrtc/lib/Makefile @@ -1,5 +1,5 @@ OUTPUT = llrt -SOURCES = udivmod64.c sdivmod64.c +SOURCES = udivmod64.c sdivmod64.c div64.c mod64.c TESTS = test_udivmod64.c test_sdivmod64.c CLANG = clang diff --git a/llrtc/lib/div64.c b/llrtc/lib/div64.c new file mode 100644 index 0000000..8466965 --- /dev/null +++ b/llrtc/lib/div64.c @@ -0,0 +1,11 @@ +#include "llrt.h" + +uint64_t udiv64(uint64_t dividend, uint64_t divisor) +{ + return udivmod64(dividend, divisor, NULL); +} + +int64_t sdiv64(int64_t dividend, int64_t divisor) +{ + return sdivmod64(dividend, divisor, NULL); +} diff --git a/llrtc/lib/llrt.h b/llrtc/lib/llrt.h index 0d26309..4e9e348 100644 --- a/llrtc/lib/llrt.h +++ b/llrtc/lib/llrt.h @@ -3,10 +3,17 @@ #include +#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_ */ diff --git a/llrtc/lib/mod64.c b/llrtc/lib/mod64.c new file mode 100644 index 0000000..875f6b9 --- /dev/null +++ b/llrtc/lib/mod64.c @@ -0,0 +1,15 @@ +#include "llrt.h" + +uint64_t umod64(uint64_t dividend, uint64_t divisor) +{ + uint64_t rem; + udivmod64(dividend, divisor, &rem); + return rem; +} + +int64_t smod64(int64_t dividend, int64_t divisor) +{ + int64_t rem; + sdivmod64(dividend, divisor, &rem); + return rem; +} From bf8693bb806be4192810b740c08300876d76cb34 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 14 Aug 2013 17:45:38 -0500 Subject: [PATCH 414/516] disable float div/mod test temporarily --- llvm/core.py | 3 + llvm/llrt.py | 77 ++++++++ llvm/llrt/llrt_x86.ll | 371 +++++++++++++++++++++++++++++++++++++++ llvm/llrt/llrt_x86_64.ll | 371 +++++++++++++++++++++++++++++++++++++++ llvm/test_llvmpy.py | 42 ++++- 5 files changed, 858 insertions(+), 6 deletions(-) create mode 100644 llvm/llrt.py create mode 100644 llvm/llrt/llrt_x86.ll create mode 100644 llvm/llrt/llrt_x86_64.ll diff --git a/llvm/core.py b/llvm/core.py index 945dd86..c4fe560 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -1848,6 +1848,9 @@ class Instruction(User): def erase_from_parent(self): return self._ptr.eraseFromParent() + def replace_all_uses_with(self, inst): + self._ptr.replaceAllUsesWith(inst) + class CallOrInvokeInstruction(Instruction): _type_ = api.llvm.CallInst, api.llvm.InvokeInst diff --git a/llvm/llrt.py b/llvm/llrt.py new file mode 100644 index 0000000..b80914e --- /dev/null +++ b/llvm/llrt.py @@ -0,0 +1,77 @@ +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. + ''' + 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) + + diff --git a/llvm/llrt/llrt_x86.ll b/llvm/llrt/llrt_x86.ll new file mode 100644 index 0000000..5096214 --- /dev/null +++ b/llvm/llrt/llrt_x86.ll @@ -0,0 +1,371 @@ +; ModuleID = 'udivmod64_x86.bc' +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32-S128" + +%struct.div_state_ = type { i64, i64 } + +define i64 @udivmod64(i64 %dividend, i64 %divisor, i64* %remainder) nounwind ssp { + %1 = alloca i64, align 4 + %2 = alloca i64, align 8 + %3 = alloca i64, align 8 + %4 = alloca i64*, align 4 + %state = alloca %struct.div_state_, align 4 + %quotient = alloca i64, align 8 + %i = alloca i32, align 4 + %skipahead = alloca i32, align 4 + store i64 %dividend, i64* %2, align 8 + store i64 %divisor, i64* %3, align 8 + store i64* %remainder, i64** %4, align 4 + %5 = getelementptr inbounds %struct.div_state_* %state, i32 0, i32 0 + store i64 0, i64* %5, align 4 + %6 = getelementptr inbounds %struct.div_state_* %state, i32 0, i32 1 + %7 = load i64* %2, align 8 + store i64 %7, i64* %6, align 4 + store i64 0, i64* %quotient, align 8 + %8 = load i64* %3, align 8 + %9 = icmp eq i64 %8, 0 + br i1 %9, label %10, label %11 + +;