From 40b84ffd7445d2ab8f2e5ca875a22bc88950d46e Mon Sep 17 00:00:00 2001 From: Jon Riehl Date: Tue, 16 Oct 2012 10:18:13 -0500 Subject: [PATCH 1/2] 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 2/2] 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:])