def _create_methoddef(py_func, func_name, func_doc, func_pointer): # struct PyMethodDef { # const char *ml_name; /* The name of the built-in function/method */ # PyCFunction ml_meth; /* The C function that implements it */ # int ml_flags; /* Combination of METH_xxx flags, which mostly # describe the args expected by the C func */ # const char *ml_doc; /* The __doc__ attribute, or NULL */ # }; PyMethodDef = struct([('name', c_string_type), ('method', void.pointer()), ('flags', int_), ('doc', c_string_type)]) c_PyMethodDef = PyMethodDef.to_ctypes() PyCFunction_NewEx = ctypes.pythonapi.PyCFunction_NewEx PyCFunction_NewEx.argtypes = [ctypes.POINTER(c_PyMethodDef), ctypes.py_object, ctypes.c_void_p] PyCFunction_NewEx.restype = ctypes.py_object # It is paramount to put these into variables first, since every # access may return a new string object! keep_alive(py_func, func_name) keep_alive(py_func, func_doc) methoddef = c_PyMethodDef() methoddef.name = func_name methoddef.doc = func_doc methoddef.method = ctypes.c_void_p(func_pointer) methoddef.flags = 1 # METH_VARARGS return methoddef
def keep_alive(self, obj): """ Keep an object alive for the lifetime of the translated unit. This is a HACK. Make live objects part of the function-cache """ functions.keep_alive(self.func, obj)
def numbafunction_new(py_func, func_name, func_doc, module_name, func_pointer, wrapped_lfunc_pointer, wrapped_signature): methoddef = _create_methoddef(py_func, func_name, func_doc, func_pointer) keep_alive(py_func, methoddef) keep_alive(py_func, module_name) wrapper = extension_types.create_function(methoddef, py_func, wrapped_lfunc_pointer, wrapped_signature, module_name) return methoddef, wrapper
def codegen(self, codegen): func_env = self.env.translation.crnt dependencies = codegen.visitlist(self.dependencies) cdef = self.cbuilder_cdefinition(self.dependencies, dependencies) self.lfunc = cdef.define(func_env.llvm_module) #, optimize=False) functions.keep_alive(func_env.func, self.lfunc) return self.lfunc
def numbafunction_new( py_func, func_name, func_doc, module_name, func_pointer, wrapped_lfunc_pointer, wrapped_signature ): "Create a NumbaFunction (numbafunction.c)" methoddef = _create_methoddef(py_func, func_name, func_doc, func_pointer) keep_alive(py_func, methoddef) keep_alive(py_func, module_name) wrapper = numbawrapper.create_function(methoddef, py_func, wrapped_lfunc_pointer, wrapped_signature, module_name) return methoddef, wrapper
def numbafunction_new(py_func, func_name, func_doc, module_name, func_pointer, wrapped_lfunc_pointer, wrapped_signature): "Create a NumbaFunction (numbafunction.c)" methoddef = _create_methoddef(py_func, func_name, func_doc, func_pointer) keep_alive(py_func, methoddef) keep_alive(py_func, module_name) wrapper = numbawrapper.create_function(methoddef, py_func, wrapped_lfunc_pointer, wrapped_signature, module_name) return methoddef, wrapper
def _create_methoddef(py_func, func_name, func_doc, func_pointer): """ Create a PyMethodDef ctypes struct. struct PyMethodDef { const char *ml_name; /* The name of the built-in function/method */ PyCFunction ml_meth; /* The C function that implements it */ int ml_flags; /* Combination of METH_xxx flags, which mostly describe the args expected by the C func */ const char *ml_doc; /* The __doc__ attribute, or NULL */ }; """ PyMethodDef = struct([('name', char.pointer()), ('method', void.pointer()), ('flags', int_), ('doc', char.pointer())]) c_PyMethodDef = PyMethodDef.to_ctypes() PyCFunction_NewEx = ctypes.pythonapi.PyCFunction_NewEx PyCFunction_NewEx.argtypes = [ctypes.POINTER(c_PyMethodDef), ctypes.py_object, ctypes.c_void_p] PyCFunction_NewEx.restype = ctypes.py_object # It is paramount to put these into variables first, since every # access may return a new string object! keep_alive(py_func, func_name) keep_alive(py_func, func_doc) methoddef = c_PyMethodDef() if PY3: if func_name is not None: func_name = func_name.encode('utf-8') if func_doc is not None: func_doc = func_doc.encode('utf-8') methoddef.name = func_name methoddef.doc = func_doc methoddef.method = ctypes.c_void_p(func_pointer) methoddef.flags = 1 # METH_VARARGS return methoddef
def build_wrapper_translation(env, llvm_module=None): """ Generate a wrapper function in the given llvm module. """ from numba import pipeline if llvm_module: wrapper_module = llvm_module else: wrapper_module = env.llvm_context.module # Create wrapper code generator and wrapper AST func_name = '__numba_wrapper_%s' % env.crnt.func_name signature = object_(void.pointer(), object_) symtab = dict(self=Variable(object_, is_local=True), args=Variable(object_, is_local=True)) func_env = env.crnt.inherit( func=fake_pyfunc, name=func_name, mangled_name=None, # Force FunctionEnvironment.init() # to generate a new mangled name. func_signature=signature, locals={}, symtab=symtab, refcount_args=False, llvm_module=wrapper_module) # Create wrapper LLVM function func_env.lfunc = pipeline.get_lfunc(env, func_env) # Build wrapper ast wrapper_node = build_wrapper_function_ast(env, wrapper_lfunc=func_env.lfunc, llvm_module=wrapper_module) func_env.ast = wrapper_node # Specialize and compile wrapper pipeline.run_env(env, func_env, pipeline_name='late_translate') keep_alive(fake_pyfunc, func_env.lfunc) return func_env.translator # TODO: Amend callers to eat func_env
def _create_methoddef(py_func, func_name, func_doc, func_pointer): """ Create a PyMethodDef ctypes struct. struct PyMethodDef { const char *ml_name; /* The name of the built-in function/method */ PyCFunction ml_meth; /* The C function that implements it */ int ml_flags; /* Combination of METH_xxx flags, which mostly describe the args expected by the C func */ const char *ml_doc; /* The __doc__ attribute, or NULL */ }; """ PyMethodDef = struct([("name", c_string_type), ("method", void.pointer()), ("flags", int_), ("doc", c_string_type)]) c_PyMethodDef = PyMethodDef.to_ctypes() PyCFunction_NewEx = ctypes.pythonapi.PyCFunction_NewEx PyCFunction_NewEx.argtypes = [ctypes.POINTER(c_PyMethodDef), ctypes.py_object, ctypes.c_void_p] PyCFunction_NewEx.restype = ctypes.py_object # It is paramount to put these into variables first, since every # access may return a new string object! keep_alive(py_func, func_name) keep_alive(py_func, func_doc) methoddef = c_PyMethodDef() if PY3: if func_name is not None: func_name = func_name.encode("utf-8") if func_doc is not None: func_doc = func_doc.encode("utf-8") methoddef.name = func_name methoddef.doc = func_doc methoddef.method = ctypes.c_void_p(func_pointer) methoddef.flags = 1 # METH_VARARGS return methoddef
def register_array_expression(self, node, lhs=None): super(ArrayExpressionRewriteNative, self).register_array_expression( node, lhs) lhs_type = lhs.type if lhs else node.type is_expr = lhs is None if node.type.is_array and lhs_type.ndim < node.type.ndim: # TODO: this is valid in NumPy if the leading dimensions of the # TODO: RHS have extent 1 raise error.NumbaError( node, "Right hand side must have a " "dimensionality <= %d" % lhs_type.ndim) # Create ufunc scalar kernel ufunc_ast, signature, ufunc_builder = self.get_py_ufunc_ast(lhs, node) signature.struct_by_reference = True # Compile ufunc scalar kernel with numba ast.fix_missing_locations(ufunc_ast) func_env, (_, _, _) = pipeline.run_pipeline2( self.env, None, ufunc_ast, signature, function_globals={}, ) # Manual linking lfunc = func_env.lfunc # print lfunc operands = ufunc_builder.operands functions.keep_alive(self.func, lfunc) operands = [nodes.CloneableNode(operand) for operand in operands] if lhs is not None: lhs = nodes.CloneableNode(lhs) broadcast_operands = [lhs] + operands lhs = lhs.clone else: broadcast_operands = operands[:] shape = slicenodes.BroadcastNode(lhs_type, broadcast_operands) operands = [op.clone for op in operands] if lhs is None and self.nopython: raise error.NumbaError( node, "Cannot allocate new memory in nopython context") elif lhs is None: # TODO: determine best output order at runtime shape = shape.cloneable lhs = nodes.ArrayNewEmptyNode(lhs_type, shape.clone, lhs_type.is_f_contig).cloneable # Build minivect wrapper kernel context = NumbaproStaticArgsContext() context.llvm_module = self.env.llvm_context.module # context.debug = True context.optimize_broadcasting = False b = context.astbuilder variables = [b.variable(name_node.type, "op%d" % i) for i, name_node in enumerate([lhs] + operands)] miniargs = [b.funcarg(variable) for variable in variables] body = miniutils.build_kernel_call(lfunc.name, signature, miniargs, b) minikernel = b.function_from_numpy( templating.temp_name("array_expression"), body, miniargs) lminikernel, ctypes_kernel = context.run_simple( minikernel, specializers.StridedSpecializer) # Build call to minivect kernel operands.insert(0, lhs) args = [shape] scalar_args = [] for operand in operands: if operand.type.is_array: data_p = self.array_attr(operand, 'data') data_p = nodes.CoercionNode(data_p, operand.type.dtype.pointer()) if not isinstance(operand, nodes.CloneNode): operand = nodes.CloneNode(operand) strides_p = self.array_attr(operand, 'strides') args.extend((data_p, strides_p)) else: scalar_args.append(operand) args.extend(scalar_args) result = nodes.NativeCallNode(minikernel.type, args, lminikernel) # Use native slicing in array expressions slicenodes.mark_nopython(ast.Suite(body=result.args)) if not is_expr: # a[:] = b[:] * c[:] return result # b[:] * c[:], return new array as expression return nodes.ExpressionNode(stmts=[result], expr=lhs.clone)