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