def visit_ArrayNewNode(self, node): if self.nopython: raise error.NumbaError( node, "Cannot yet allocate new array in nopython context") PyArray_Type = nodes.ObjectInjectNode(np.ndarray) descr = nodes.ObjectInjectNode(node.type.dtype.get_dtype()).cloneable ndim = nodes.const(node.type.ndim, int_) flags = nodes.const(0, int_) args = [PyArray_Type, descr.clone, ndim, node.shape, node.strides, node.data, flags] incref_descr = nodes.IncrefNode(descr) incref_base = None setbase = None if node.base is None: args.append(nodes.NULL_obj) else: base = nodes.CloneableNode(node.base) incref_base = nodes.IncrefNode(base) args.append(base.clone) array = nodes.PyArray_NewFromDescr(args) array = nodes.ObjectTempNode(array).cloneable body = [incref_descr, incref_base, array, setbase] if node.base is not None: body.append(nodes.PyArray_SetBaseObject([array.clone, base.clone])) # TODO: PyArray_UpdateFlags() result = nodes.ExpressionNode(filter(None, body), array.clone) return self.visit(result)
def str_to_int(self, dst_type, node): # TODO: int <-> string conversions are explicit, this should not # TODO: be a coercion if self.nopython: node = nodes.CoercionNode( function_util.external_call( self.context, self.llvm_module, ('atol' if dst_type.is_int else 'atof'), args=[node.node]), dst_type, name=node.name, ) else: if dst_type.is_int: cvtobj = function_util.external_call( self.context, self.llvm_module, 'PyInt_FromString' if not PY3 else 'PyLong_FromString', args=[node.node, nodes.NULL, nodes.const(10, int_)]) else: cvtobj = function_util.external_call( self.context, self.llvm_module, 'PyFloat_FromString', args=[node.node, nodes.const(0, Py_ssize_t)]) node = nodes.CoerceToNative(nodes.ObjectTempNode(cvtobj), dst_type, name=node.name) result = self.visit(node) return result
def _c_string_slice(self, node): ret_val = node logger.debug(node.slice) node_slice = node.slice if isinstance(node_slice, nodes.ObjectInjectNode): node_slice = node.slice.object lower, upper, step = ( value if value is None else nodes.const(value, size_t) for value in (node_slice.start, node_slice.stop, node_slice.step)) else: lower, upper, step = (node_slice.lower, node_slice.upper, node_slice.step) if step is None: node_value = self.visit(node.value) if lower is None: lower = nodes.const(0, size_t) if upper is None: ret_val = nodes.LLMacroNode( macros.c_string_slice_1.__signature__, macros.c_string_slice_1, self.visit(node.value), self.visit(lower)) else: ret_val = nodes.LLMacroNode( macros.c_string_slice_2.__signature__, macros.c_string_slice_2, self.visit(node.value), self.visit(lower), self.visit(upper)) logger.debug(ret_val) else: raise NotImplementedError('String slices where step != None.') return ret_val
def visit_ArrayNewNode(self, node): if self.nopython: # Give the codegen (subclass) a chance to handle this self.generic_visit(node) return node PyArray_Type = nodes.ObjectInjectNode(np.ndarray) descr = nodes.ObjectInjectNode(node.type.dtype.get_dtype()).cloneable ndim = nodes.const(node.type.ndim, int_) flags = nodes.const(0, int_) args = [PyArray_Type, descr.clone, ndim, node.shape, node.strides, node.data, flags] incref_descr = nodes.IncrefNode(descr) incref_base = None setbase = None if node.base is None: args.append(nodes.NULL_obj) else: base = nodes.CloneableNode(node.base) incref_base = nodes.IncrefNode(base) args.append(base.clone) array = nodes.PyArray_NewFromDescr(args).cloneable body = [incref_descr, incref_base, array, setbase] if node.base is not None: body.append(nodes.PyArray_SetBaseObject([array.clone, base.clone])) # TODO: PyArray_UpdateFlags() result = nodes.ExpressionNode(filter(None, body), array.clone) return self.visit(result)
def _c_string_slice(self, node): ret_val = node logger.debug(node.slice) node_slice = node.slice if isinstance(node_slice, nodes.ObjectInjectNode): node_slice = node.slice.object lower, upper, step = (value if value is None else nodes.const( value, size_t) for value in (node_slice.start, node_slice.stop, node_slice.step)) else: lower, upper, step = (node_slice.lower, node_slice.upper, node_slice.step) if step is None: node_value = self.visit(node.value) if lower is None: lower = nodes.const(0, size_t) if upper is None: ret_val = nodes.LLMacroNode( macros.c_string_slice_1.__signature__, macros.c_string_slice_1, self.visit(node.value), self.visit(lower)) else: ret_val = nodes.LLMacroNode( macros.c_string_slice_2.__signature__, macros.c_string_slice_2, self.visit(node.value), self.visit(lower), self.visit(upper)) logger.debug(ret_val) else: raise NotImplementedError('String slices where step != None.') return ret_val
def create_numba_function(self, node, translator): closure_scope = self.ast.cur_scope if closure_scope is None: closure_scope = nodes.NULL scope_type = void.pointer() else: assert node.func_def.args.args[0].variable.type scope_type = closure_scope.type node.wrapper_func, node.wrapper_lfunc, methoddef = ( translator.build_wrapper_function(get_lfunc=True)) # Keep methoddef alive # assert methoddef in node.py_func.live_objects modname = self.module_name self.keep_alive(modname) # Create function signature with closure scope at runtime create_numbafunc_signature = node.type( void.pointer(), # PyMethodDef *ml object_, # PyObject *module void.pointer(), # PyObject *code scope_type, # PyObject *closure void.pointer(), # void *native_func object_, # PyObject *native_signature object_, # PyObject *keep_alive ) # Create function with closure scope at runtime create_numbafunc = nodes.ptrfromint( extension_types.NumbaFunction_NewEx_pointer, create_numbafunc_signature.pointer()) methoddef_p = ctypes.cast(ctypes.byref(methoddef), ctypes.c_void_p).value args = [ nodes.const(methoddef_p, void.pointer()), nodes.const(modname, object_), nodes.NULL, closure_scope, nodes.const(node.lfunc_pointer, void.pointer()), nodes.const(node.type.signature, object_), nodes.NULL, # nodes.const(node.py_func, object_), ] func_call = nodes.NativeFunctionCallNode( signature=create_numbafunc_signature, function_node=create_numbafunc, args=args) result = func_call #stats = [nodes.inject_print(nodes.const("calling...", c_string_type)), # result] #result = ast.Suite(body=stats) result = self.visit(result) return result
def visit_ArrayNewEmptyNode(self, node): if self.nopython: raise error.NumbaError( node, "Cannot yet allocate new empty array in nopython context") ndim = nodes.const(node.type.ndim, int_) dtype = nodes.const(node.type.dtype.get_dtype(), object_).cloneable is_fortran = nodes.const(node.is_fortran, int_) result = nodes.PyArray_Empty([ndim, node.shape, dtype, is_fortran]) result = nodes.ObjectTempNode(result) incref_descr = nodes.IncrefNode(dtype) return self.visit(nodes.ExpressionNode([incref_descr], result))
def unpack_range_args(node): start, stop, step = (nodes.const(0, Py_ssize_t), None, nodes.const(1, Py_ssize_t)) if len(node.args) == 0: raise error.NumbaError(node, "Expected at least one argument") elif len(node.args) == 1: stop, = node.args elif len(node.args) == 2: start, stop = node.args else: start, stop, step = node.args return [start, stop, step]
def next(self, context, for_node, llvm_module): "Index element and update index" index = self.index.load value = nodes.CloneableNode(index(for_node.iter, index)) add = ast.BinOp(index, ast.Add(), nodes.const(1, Py_ssize_t)) return nodes.ExpressionNode(stmts=[value, assign(self.index.store, add)], expr=value.clone)
def next(self, context, for_node, llvm_module): "Index element and update index" index = self.index.load value = nodes.CloneableNode(index(for_node.iter, index)) add = ast.BinOp(index, ast.Add(), nodes.const(1, Py_ssize_t)) return nodes.ExpressionNode( stmts=[value, assign(self.index.store, add)], expr=value.clone)
def coerce_to_function_pointer(self, node, jit_func_type, func_pointer_type): jit_func = jit_func_type.jit_func if jit_func.signature != func_pointer_type.base_type: raise error.NumbaError(node, "Cannot coerce jit funcion %s to function of type %s" % ( jit_func, func_pointer_type)) pointer = self.env.llvm_context.get_pointer_to_function(jit_func.lfunc) new_node = nodes.const(pointer, func_pointer_type) return new_node
def visit_CoercionNode(self, node): if not isinstance(node, nodes.CoercionNode): # CoercionNode.__new__ returns the node to be coerced if it doesn't # need coercion return node node_type = node.node.type dst_type = node.dst_type if __debug__ and self.env and self.env.debug_coercions: logger.debug('coercion: %s --> %s\n%s', node_type, dst_type, utils.pformat_ast(node)) # TODO: the below is a problem due to implicit string <-> int coercions! if (node_type.is_string and dst_type.is_numeric and not (node_type.is_pointer or node_type.is_null)): if dst_type.typename in ('char', 'uchar'): raise error.NumbaError( node, "Conversion from string to (u)char not yet supported") result = self.str_to_int(dst_type, node) elif self.nopython and (is_obj(node_type) ^ is_obj(dst_type)): raise error.NumbaError( node, "Cannot coerce to or from object in " "nopython context") elif is_obj(node.dst_type) and not is_obj(node_type): node = nodes.ObjectTempNode( nodes.CoerceToObject(node.node, node.dst_type, name=node.name)) result = self.visit(node) elif is_obj(node_type) and not is_obj(node.dst_type): node = nodes.CoerceToNative(node.node, node.dst_type, name=node.name) result = self.visit(node) elif node_type.is_null: if not dst_type.is_pointer: raise error.NumbaError( node.node, "NULL must be cast or implicitly " "coerced to a pointer type") result = self.visit(nodes.NULL.coerce(dst_type)) elif node_type.is_numeric and dst_type.is_bool: to_bool = ast.Compare(node.node, [ast.NotEq()], [nodes.const(0, node_type)]) to_bool = nodes.typednode(to_bool, bool_) result = self.visit(to_bool) else: self.generic_visit(node) if dst_type == node.node.type: result = node.node else: result = node if __debug__ and self.env and self.env.debug_coercions: logger.debug('result = %s', utils.pformat_ast(result)) return result
def parse_signature(node, func_type): types = [] for arg in node.args: if not arg.variable.type.is_cast: raise error.NumbaError(arg, "Expected a numba type") else: types.append(arg.variable.type) signature = func_type.dst_type(*types) new_node = nodes.const(signature, typesystem.CastType(signature)) return new_node
def visit_CoercionNode(self, node): if not isinstance(node, nodes.CoercionNode): # CoercionNode.__new__ returns the node to be coerced if it doesn't # need coercion return node node_type = node.node.type dst_type = node.dst_type if __debug__ and self.env and self.env.debug_coercions: logger.debug('coercion: %s --> %s\n%s', node_type, dst_type, utils.pformat_ast(node)) # TODO: the below is a problem due to implicit string <-> int coercions! if (node_type.is_string and dst_type.is_numeric and not (node_type.is_pointer or node_type.is_null)): if dst_type.typename in ('char', 'uchar'): raise error.NumbaError( node, "Conversion from string to (u)char not yet supported") result = self.str_to_int(dst_type, node) elif self.nopython and (is_obj(node_type) ^ is_obj(dst_type)): raise error.NumbaError(node, "Cannot coerce to or from object in " "nopython context") elif is_obj(node.dst_type) and not is_obj(node_type): node = nodes.ObjectTempNode(nodes.CoerceToObject( node.node, node.dst_type, name=node.name)) result = self.visit(node) elif is_obj(node_type) and not is_obj(node.dst_type): node = nodes.CoerceToNative(node.node, node.dst_type, name=node.name) result = self.visit(node) elif node_type.is_null: if not dst_type.is_pointer: raise error.NumbaError(node.node, "NULL must be cast or implicitly " "coerced to a pointer type") result = self.visit(nodes.NULL.coerce(dst_type)) elif node_type.is_numeric and dst_type.is_bool: to_bool = ast.Compare(node.node, [ast.NotEq()], [nodes.const(0, node_type)]) to_bool = nodes.typednode(to_bool, bool_) result = self.visit(to_bool) else: self.generic_visit(node) if dst_type == node.node.type: result = node.node else: result = node if __debug__ and self.env and self.env.debug_coercions: logger.debug('result = %s', utils.pformat_ast(result)) return result
def visit_Print(self, node): if self.nopython: printfunc = self._print_nopython dst_type = c_string_type else: printfunc = self._print dst_type = object_ result = [] if node.values: print_space = printfunc(nodes.const(" ", dst_type), node.dest) for value in node.values: result.append(printfunc(value, node.dest)) result.append(print_space) if node.nl: result.pop() # pop last space if node.nl: result.append(printfunc(nodes.const("\n", dst_type), node.dest)) return ast.Suite(body=self.visitlist(result))
def visit_Print(self, node): if self.nopython: printfunc = self._print_nopython dst_type = string_ else: printfunc = self._print dst_type = object_ result = [] if node.values: print_space = printfunc(nodes.const(" ", dst_type), node.dest) for value in node.values: result.append(printfunc(value, node.dest)) result.append(print_space) if node.nl: result.pop() # pop last space if node.nl: result.append(printfunc(nodes.const("\n", dst_type), node.dest)) return ast.Suite(body=self.visitlist(result))
def visit_ArrayNewNode(self, node): if self.nopython: # Give the codegen (subclass) a chance to handle this self.generic_visit(node) return node PyArray_Type = nodes.ObjectInjectNode(np.ndarray) descr = nodes.ObjectInjectNode(node.type.dtype.get_dtype()).cloneable ndim = nodes.const(node.type.ndim, int_) flags = nodes.const(0, int_) args = [ PyArray_Type, descr.clone, ndim, node.shape, node.strides, node.data, flags ] incref_descr = nodes.IncrefNode(descr) incref_base = None setbase = None if node.base is None: args.append(nodes.NULL_obj) else: base = nodes.CloneableNode(node.base) incref_base = nodes.IncrefNode(base) args.append(base.clone) array = nodes.PyArray_NewFromDescr(args) array = nodes.ObjectTempNode(array).cloneable body = [incref_descr, incref_base, array, setbase] if node.base is not None: body.append(nodes.PyArray_SetBaseObject([array.clone, base.clone])) # TODO: PyArray_UpdateFlags() result = nodes.ExpressionNode(filter(None, body), array.clone) return self.visit(result)
def lookup(self, env, always_present, node, args): """ :param node: ExtensionMethodNode :param args: [vtable_node, prehash_node] :return: The virtual method as a Node """ from numba.utility import virtuallookup if always_present and False: lookup = virtuallookup.lookup_method else: lookup = virtuallookup.lookup_and_assert_method args.append(nodes.const(node.attr, c_string_type)) vmethod = call_jit(lookup, args) return vmethod
def single_compare_objects(self, node): op = type(node.ops[0]) if op not in opmap: raise error.NumbaError( node, "%s comparisons not yet implemented" % (op,)) # Build arguments for PyObject_RichCompareBool operator = nodes.const(opmap[op], int_) args = [node.left, node.comparators[0], operator] # Call PyObject_RichCompareBool compare = function_util.external_call(self.context, self.llvm_module, 'PyObject_RichCompareBool', args=args) # Coerce int result to bool return nodes.CoercionNode(compare, bool_)
def visit_Name(self, node): if (is_obj(node.type) and isinstance(node.ctx, ast.Load) and getattr(node, 'cf_maybe_null', False)): # Check for unbound objects and raise UnboundLocalError if so value = nodes.LLVMValueRefNode(Py_uintptr_t, None) node.loaded_name = value exc_msg = node.variable.name if hasattr(node, 'lineno'): exc_msg = '%s%s' % (error.format_pos(node), exc_msg) check_unbound = nodes.CheckErrorNode( value, badval=nodes.const(0, Py_uintptr_t), exc_type=UnboundLocalError, exc_msg=exc_msg) node.check_unbound = self.visit(check_unbound) return node
def single_compare_objects(self, node): op = type(node.ops[0]) if op not in opmap: raise error.NumbaError( node, "%s comparisons not yet implemented" % (op, )) # Build arguments for PyObject_RichCompareBool operator = nodes.const(opmap[op], int_) args = [node.left, node.comparators[0], operator] # Call PyObject_RichCompareBool compare = function_util.external_call(self.context, self.llvm_module, 'PyObject_RichCompare', args=args) # Coerce int result to bool return nodes.CoercionNode(compare, node.type)
def get_closure_scope(func_signature, func_obj): """ Retrieve the closure from the NumbaFunction from the func_closure attribute. func_signature: signature of closure function func_obj: LLVM Value referencing the closure function as a Python object """ closure_scope_type = func_signature.args[0] offset = numbawrapper.numbafunc_closure_field_offset closure = nodes.LLVMValueRefNode(void.pointer(), func_obj) closure = nodes.CoercionNode(closure, char.pointer()) closure_field = nodes.pointer_add(closure, nodes.const(offset, size_t)) closure_field = nodes.CoercionNode(closure_field, closure_scope_type.pointer()) closure_scope = nodes.DereferenceNode(closure_field) return closure_scope
def visit_Name(self, node): if (is_obj(node.type) and isinstance(node.ctx, ast.Load) and getattr(node, 'cf_maybe_null', False)): # Check for unbound objects and raise UnboundLocalError if so value = nodes.LLVMValueRefNode(Py_uintptr_t, None) node.loaded_name = value exc_msg = node.variable.name if hasattr(node, 'lineno'): exc_msg = '%s%s' % (error.format_pos(node), exc_msg) check_unbound = nodes.CheckErrorNode(value, badval=nodes.const( 0, Py_uintptr_t), exc_type=UnboundLocalError, exc_msg=exc_msg) node.check_unbound = self.visit(check_unbound) return node
def _print_nopython(self, value, dest=None): if dest is not None: raise error.NumbaError(dest, "No file may be given in nopython mode") # stdin, stdout, stderr = stdio_util.get_stdio_streams() # stdout = stdio_util.get_stream_as_node(stdout) format = codegen.get_printf_specifier(value.type) if format is None: raise error.NumbaError( value, "Printing values of type '%s' is not supported " "in nopython mode" % (value.type, )) return function_util.external_call( self.context, self.llvm_module, 'printf', args=[nodes.const(format, c_string_type), value])
def _print_nopython(self, value, dest=None): if dest is not None: raise error.NumbaError(dest, "No file may be given in nopython mode") # stdin, stdout, stderr = stdio_util.get_stdio_streams() # stdout = stdio_util.get_stream_as_node(stdout) format = codegen.get_printf_specifier(value.type) if format is None: raise error.NumbaError( value, "Printing values of type '%s' is not supported " "in nopython mode" % (value.type,)) return function_util.external_call( self.context, self.llvm_module, 'printf', args=[nodes.const(format, c_string_type), value])
def _trap(self, body, node): if node.exc_msg and node.print_on_trap: pos = error.format_pos(node) if node.exception_type: exc_type = '%s: ' % node.exception_type.__name__ else: exc_type = '' msg = '%s%s%%s' % (exc_type, pos) format = nodes.const(msg, c_string_type) print_msg = function_util.external_call(self.context, self.llvm_module, 'printf', args=[format, node.exc_msg]) body.append(print_msg) trap = nodes.LLVMIntrinsicNode(signature=void(), args=[], func_name='TRAP') body.append(trap)
def _trap(self, body, node): if node.exc_msg and node.print_on_trap: pos = error.format_pos(node) if node.exception_type: exc_type = '%s: ' % node.exception_type.__name__ else: exc_type = '' msg = '%s%s%%s' % (exc_type, pos) format = nodes.const(msg, c_string_type) print_msg = function_util.external_call( self.context, self.llvm_module, 'printf', args=[format, node.exc_msg]) body.append(print_msg) trap = nodes.LLVMIntrinsicNode(signature=void(), args=[], func_name='TRAP') body.append(trap)
def typedcontainer_infer(compile_typedcontainer, type_node, iterable_node): """ Type inferer for typed containers, register with numba.register_inferer(). :param compile_typedcontainer: item_type -> typed container extension class :param type_node: type parameter to typed container constructor :param iterable_node: value parameter to typed container constructor (optional) """ assert type_node is not None type = get_type(type_node) if type.is_cast: elem_type = type.dst_type # Pre-compile typed list implementation typedcontainer_ctor = compile_typedcontainer(elem_type) # Inject the typedlist directly to avoid runtime implementation lookup iterable_node = iterable_node or nodes.const(None, object_) result = nodes.call_pyfunc(typedcontainer_ctor, (iterable_node,)) return nodes.CoercionNode(result, typedcontainer_ctor.exttype) return object_
def visit_For(self, node): while_node = make_while_from_for(node) test = nodes.const(True, bool_) while_node.test = test impl = loopimpl.find_iterator_impl(node) # Get the iterator, loop body, and the item iter = impl.getiter(self.context, node, self.llvm_module) body = impl.body(self.context, node, self.llvm_module) item = impl.next(self.context, node, self.llvm_module) # Coerce item to LHS and assign item = nodes.CoercionNode(item, node.target.type) target_assmnt = ast.Assign(targets=[node.target], value=item) # Update While node body body.insert(0, target_assmnt) while_node.body = body nodes.merge_cfg_in_while(while_node) return ast.Suite(body=[iter, while_node])
def rewrite_prange(env, prange_node, target, locals_dict, closures_dict): func_def = prange_node.func_def struct_type = prange_node.privates_struct_type templ = templating.TemplateContext(env.context, prange_template % func_def.name) # Allocate context for each thread num_threads = NUM_THREADS contexts_array_type = minitypes.CArrayType(struct_type, num_threads) # Create variables for template substitution nsteps = templ.temp_var('nsteps') temp_i = templ.temp_var('i', int32) contexts = templ.temp_var('contexts', contexts_array_type) temp_struct = templ.temp_var('temp_struct', struct_type) lastprivates = templ.temp_var("lastprivates") pack_struct = templ.code_var('pack_struct') if isinstance(target, ast.Name): target_name = target.id struct_type.add_field(target_name, Py_ssize_t) else: raise error.NumbaError( prange_node, "Only name target for prange is currently supported") # Create code for reductions and (last)privates for name, reduction_op in prange_node.reductions.iteritems(): default = get_reduction_default(reduction_op) pack_struct.codes.append("%s.%s = %s" % (temp_struct, name, default)) # Update struct type with closure scope, index variable, start, # stop and step struct_type.add_field('__numba_closure_scope', void.pointer()) struct_type.add_field('__numba_start', npy_intp) struct_type.add_field('__numba_stop', npy_intp) struct_type.add_field('__numba_step', npy_intp) # Interpolate code and variables and run type inference # TODO: UNDO monkeypatching func_def.type = prange_node.func_env.func_signature func_def.is_prange_body = True func_def.prange_node = prange_node num_threads_node = nodes.const(num_threads, Py_ssize_t) invoke = InvokeAndJoinThreads(env, contexts=contexts.node, func_def_name=func_def.name, struct_type=struct_type, target_name=target_name, num_threads=num_threads_node, closures=closures_dict) closure_scope = nodes.ClosureScopeLoadNode() subs = dict( func_def=func_def, func_def_name=func_def.name, closure_scope=closure_scope, invoke_and_join_threads=invoke, num_threads=num_threads_node, start=nodes.UntypedCoercion(prange_node.start, Py_ssize_t), stop=nodes.UntypedCoercion(prange_node.stop, Py_ssize_t), step=nodes.UntypedCoercion(prange_node.step, Py_ssize_t), ) tree = templ.template(subs) temporaries = {} templ.update_locals(temporaries) locals_dict.update(temporaries) kill_attribute_assignments(env, prange_node, temporaries) # TODO: Make this an SSA variable locals_dict[target_name] = Py_ssize_t prange_node.target = target prange_node.num_threads_node = num_threads_node #.clone prange_node.template_vars = { 'contexts': contexts, 'i': temp_i, 'lastprivates': lastprivates, 'nsteps': nsteps, } # print(templ.substituted_template) return tree
def visit_CoercionNode(self, node): if not isinstance(node, nodes.CoercionNode): # CoercionNode.__new__ returns the node to be coerced if it doesn't # need coercion return node node_type = node.node.type dst_type = node.dst_type if __debug__ and self.env and self.env.debug_coercions: logger.debug('coercion: %s --> %s\n%s', node_type, dst_type, utils.pformat_ast(node)) if self.nopython and (is_obj(node_type) ^ is_obj(dst_type)): raise error.NumbaError( node, "Cannot coerce to or from object in " "nopython context") if is_obj(node.dst_type) and not is_obj(node_type): node = nodes.ObjectTempNode( nodes.CoerceToObject(node.node, node.dst_type, name=node.name)) result = self.visit(node) elif is_obj(node_type) and not is_obj(node.dst_type): node = nodes.CoerceToNative(node.node, node.dst_type, name=node.name) result = self.visit(node) elif node_type.is_null: if not dst_type.is_pointer: raise error.NumbaError( node.node, "NULL must be cast or implicitly " "coerced to a pointer type") result = self.visit(nodes.NULL.coerce(dst_type)) elif node_type.is_numeric and dst_type.is_bool: to_bool = ast.Compare(node.node, [ast.NotEq()], [nodes.const(0, node_type)]) to_bool = nodes.typednode(to_bool, bool_) result = self.visit(to_bool) elif node_type.is_c_string and dst_type.is_numeric: # TODO: int <-> string conversions are explicit, this should not # TODO: be a coercion if self.nopython: node = nodes.CoercionNode( function_util.external_call( self.context, self.llvm_module, ('atol' if dst_type.is_int else 'atof'), args=[node.node]), dst_type, name=node.name, ) else: if dst_type.is_int: cvtobj = function_util.external_call( self.context, self.llvm_module, 'PyInt_FromString' if not PY3 else 'PyLong_FromString', args=[node.node, nodes.NULL, nodes.const(10, int_)]) else: cvtobj = function_util.external_call( self.context, self.llvm_module, 'PyFloat_FromString', args=[node.node, nodes.const(0, Py_ssize_t)]) node = nodes.CoerceToNative(nodes.ObjectTempNode(cvtobj), dst_type, name=node.name) result = self.visit(node) else: self.generic_visit(node) if dst_type == node.node.type: result = node.node else: result = node if __debug__ and self.env and self.env.debug_coercions: logger.debug('result = %s', utils.pformat_ast(result)) return result
def visit_ArrayNewEmptyNode(self, node): ndim = nodes.const(node.type.ndim, int_) dtype = nodes.const(node.type.dtype.get_dtype(), object_) is_fortran = nodes.const(node.is_fortran, int_) result = nodes.PyArray_Empty([ndim, node.shape, dtype, is_fortran]) return self.visit(result)
def create_numba_function(self, node, p): closure_scope = self.ast.cur_scope if closure_scope is None: closure_scope = nodes.NULL scope_type = void.pointer() else: assert node.func_def.args.args[0].variable.type scope_type = closure_scope.type node.wrapper_func, node.wrapper_lfunc, methoddef = ( p.translator.build_wrapper_function(get_lfunc=True)) # Keep methoddef alive assert methoddef in node.py_func.live_objects modname = self.func.__module__ node.py_func.live_objects.append(modname) # Create function with closure scope at runtime create_numbafunc_signature = node.type( void.pointer(), # PyMethodDef *ml object_, # PyObject *module void.pointer(), # PyObject *code scope_type, # PyObject *closure void.pointer(), # void *native_func object_, # PyObject *native_signature object_, # PyObject *keep_alive ) create_numbafunc = nodes.ptrfromint( extension_types.NumbaFunction_NewEx_pointer, create_numbafunc_signature.pointer()) methoddef_p = ctypes.cast(ctypes.byref(methoddef), ctypes.c_void_p).value args = [ nodes.const(methoddef_p, void.pointer()), nodes.const(modname, object_), nodes.NULL, closure_scope, nodes.const(node.lfunc_pointer, void.pointer()), nodes.const(node.type.signature, object_), nodes.const(node.py_func, object_), ] func_call = nodes.NativeFunctionCallNode( signature=create_numbafunc_signature, function_node=create_numbafunc, args=args) # Assign closure to its name func_name = node.func_def.name dst = self._load_name(func_name, self.symtab[func_name].is_cellvar) dst.ctx = ast.Store() result = ast.Assign(targets=[dst], value=func_call) #stats = [nodes.inject_print(nodes.const("calling...", c_string_type)), # result] #result = ast.Suite(body=stats) result = self.visit(result) return result
def lookup(self, env, always_present, node, args): args.append(nodes.const(node.attr, c_string_type)) vmethod = function_util.utility_call( env.context, env.crnt.llvm_module, "lookup_method", args) return vmethod
def handle_method_call(self, env, node, call_node): """ Resolve an extension method of a dynamic hash-based vtable: PyCustomSlots_Table ***vtab_slot = (((char *) obj) + vtab_offset) lookup_virtual_method(*vtab_slot) We may cache (*vtab_slot), but we may not cache (**vtab_slot), since compilations may regenerate the table. However, we could *preload* (**vtab_slot), where function calls invalidate the preload, if we were so inclined. """ from numba.utility import virtuallookup # Make the object we call the method on clone-able node.value = nodes.CloneableNode(node.value) ext_type = node.ext_type func_signature = node.type offset = ext_type.vtab_offset # __________________________________________________________________ # Retrieve vtab vtab_ppp = nodes.value_at_offset(node.value, offset, void.pointer().pointer()) vtab_struct_pp = nodes.DereferenceNode(vtab_ppp) # __________________________________________________________________ # Calculate pre-hash prehash = virtual.hash_signature(func_signature, func_signature.name) prehash_node = nodes.ConstNode(prehash, uint64) # __________________________________________________________________ # Retrieve method pointer # A method is always present when it was given a static signature, # e.g. @double(double) always_present = node.attr in ext_type.vtab_type.methodnames args = [vtab_struct_pp, prehash_node] if always_present: lookup = virtuallookup.lookup_method else: lookup = virtuallookup.lookup_and_assert_method args.append(nodes.const(node.attr, c_string_type)) vmethod = call_jit(lookup, args).coerce(func_signature.pointer()) vmethod = vmethod.cloneable # __________________________________________________________________ # Call method pointer # Insert first argument 'self' in args list args = call_node.args args.insert(0, nodes.CloneNode(node.value)) method_call = nodes.NativeFunctionCallNode(func_signature, vmethod, args) # __________________________________________________________________ # Generate fallback # TODO: Subclassing! # if not always_present: # # TODO: Enable this path and generate a phi for the result # # Generate object call # obj_args = [nodes.CoercionNode(arg, object_) for arg in args] # obj_args.append(nodes.NULL) # object_call = function_util.external_call( # env.context, env.crnt.llvm_module, # 'PyObject_CallMethodObjArgs', obj_args) # # # if vmethod != NULL: vmethod(obj, ...) # # else: obj.method(...) # method_call = nodes.if_else( # ast.NotEq(), # vmethod.clone, nodes.NULL, # lhs=method_call, rhs=object_call) return method_call
def getiter(self, context, for_node, llvm_module): self.index = nodes.TempNode(Py_ssize_t, "iterator_index") return assign(self.index, nodes.const(0, Py_ssize_t))
def typeof(expr_type): from numba import nodes type = typesystem.CastType(expr_type) return nodes.const(expr_type, type)
def visit_Name(self, node): if node.variable.is_constant: obj = node.variable.constant_value return self.visit(nodes.const(obj, node.type)) return node
def visit_CoercionNode(self, node): if not isinstance(node, nodes.CoercionNode): # CoercionNode.__new__ returns the node to be coerced if it doesn't # need coercion return node node_type = node.node.type dst_type = node.dst_type if __debug__ and self.env and self.env.debug_coercions: logger.debug('coercion: %s --> %s\n%s', node_type, dst_type, utils.pformat_ast(node)) if self.nopython and is_obj(node_type): raise error.NumbaError(node, "Cannot coerce to or from object in " "nopython context") if is_obj(node.dst_type) and not is_obj(node_type): node = nodes.ObjectTempNode(nodes.CoerceToObject( node.node, node.dst_type, name=node.name)) result = self.visit(node) elif is_obj(node_type) and not is_obj(node.dst_type): node = nodes.CoerceToNative(node.node, node.dst_type, name=node.name) result = self.visit(node) elif node_type.is_null: if not dst_type.is_pointer: raise error.NumbaError(node.node, "NULL must be cast or implicitly " "coerced to a pointer type") result = self.visit(nodes.NULL.coerce(dst_type)) elif node_type.is_numeric and dst_type.is_bool: to_bool = ast.Compare(node.node, [ast.NotEq()], [nodes.const(0, node_type)]) to_bool = nodes.typednode(to_bool, bool_) result = self.visit(to_bool) elif node_type.is_c_string and dst_type.is_numeric: # TODO: int <-> string conversions are explicit, this should not # TODO: be a coercion if self.nopython: node = nodes.CoercionNode( function_util.external_call( self.context, self.llvm_module, ('atol' if dst_type.is_int else 'atof'), args=[node.node]), dst_type, name=node.name,) else: if dst_type.is_int: cvtobj = function_util.external_call( self.context, self.llvm_module, 'PyInt_FromString' if not PY3 else 'PyLong_FromString', args=[node.node, nodes.NULL, nodes.const(10, int_)]) else: cvtobj = function_util.external_call( self.context, self.llvm_module, 'PyFloat_FromString', args=[node.node, nodes.const(0, Py_ssize_t)]) node = nodes.CoerceToNative(nodes.ObjectTempNode(cvtobj), dst_type, name=node.name) result = self.visit(node) else: self.generic_visit(node) if dst_type == node.node.type: result = node.node else: result = node if __debug__ and self.env and self.env.debug_coercions: logger.debug('result = %s', utils.pformat_ast(result)) return result
def lookup(self, env, always_present, node, args): args.append(nodes.const(node.attr, c_string_type)) vmethod = function_util.utility_call(env.context, env.crnt.llvm_module, "lookup_method", args) return vmethod
def create_numba_function(self, node, func_env): from numba.codegen import llvmwrapper closure_scope = self.ast.cur_scope if closure_scope is None: closure_scope = nodes.NULL scope_type = void.pointer() else: assert node.func_def.args.args[0].variable.type scope_type = closure_scope.type self.env.translation.push_env(func_env) try: node.wrapper_func, node.wrapper_lfunc, methoddef = ( llvmwrapper.build_wrapper_function(self.env)) finally: self.env.translation.pop() # Keep methoddef alive # assert methoddef in node.py_func.live_objects modname = self.module_name self.keep_alive(modname) # Create function signature with closure scope at runtime create_numbafunc_signature = node.type( void.pointer(), # PyMethodDef *ml object_, # PyObject *module void.pointer(), # PyObject *code scope_type, # PyObject *closure void.pointer(), # void *native_func object_, # PyObject *native_signature object_, # PyObject *keep_alive ) # Create function with closure scope at runtime create_numbafunc = nodes.ptrfromint( numbawrapper.NumbaFunction_NewEx_pointer, create_numbafunc_signature.pointer()) methoddef_p = ctypes.cast(ctypes.byref(methoddef), ctypes.c_void_p).value args = [ nodes.const(methoddef_p, void.pointer()), nodes.const(modname, object_), nodes.NULL, closure_scope, nodes.const(node.lfunc_pointer, void.pointer()), nodes.const(node.type.signature, object_), nodes.NULL, # nodes.const(node.py_func, object_), ] func_call = nodes.NativeFunctionCallNode( signature=create_numbafunc_signature, function_node=create_numbafunc, args=args) result = func_call #stats = [nodes.inject_print(nodes.const("calling...", c_string_type)), # result] #result = ast.Suite(body=stats) result = self.visit(result) return result
def typeof(self, expr): from numba import nodes obj = expr.variable.type type = typesystem.CastType(obj) return nodes.const(obj, type)