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 visit_Attribute(self, node): if (self.nopython and not node.value.type.is_module and not node.value.type.is_complex): raise error.NumbaError( node, "Cannot access Python attribute in nopython context (%s)" % node.attr) if node.value.type.is_complex: value = self.visit(node.value) return nodes.ComplexAttributeNode(value, node.attr) elif node.type.is_numpy_attribute: return nodes.ObjectInjectNode(node.type.value) elif node.type.is_numpy_dtype: dtype_type = node.type.dtype return nodes.ObjectInjectNode(dtype_type.get_dtype()) elif is_obj(node.value.type): if node.value.type.is_module: # Resolve module attributes as constants if node.type.is_module_attribute: new_node = nodes.ObjectInjectNode(node.type.value) else: new_node = nodes.ConstNode( getattr(node.value.type.module, node.attr)) else: new_node = function_util.external_call( self.context, self.llvm_module, 'PyObject_GetAttrString', args=[node.value, nodes.ConstNode(node.attr)]) return self.visit(new_node) self.generic_visit(node) return node
def _object_Not(self, node): callnode = function_util.external_call(self.function_cache, self.llvm_module, 'PyObject_IsTrue', args=[node.operand]) cmpnode = ast.Compare(callnode, [nodes.Eq()], [nodes.ConstNode(0)]) return self.visit( nodes.IfExp(cmpnode, nodes.ObjectInjectNode(True), nodes.ObjectInjectNode(False)))
def visit_ClosureNode(self, node): """ Compile the inner function. """ # Compile closure, skip CFA and type inference node.func_env.qualified_name = self.get_qname(node) numba.pipeline.run_env(self.env, node.func_env, pipeline_name='compile') translator = node.func_env.translator # translator.link() node.lfunc = translator.lfunc node.lfunc_pointer = translator.lfunc_pointer if node.need_numba_func: return self.create_numba_function(node, node.func_env) else: func_name = node.func_def.name self.symtab[func_name] = Variable(name=func_name, type=node.type, is_local=True) # return nodes.LLVMValueRefNode(node.type, node.lfunc) # TODO: Remove assignment altogether! # return nodes.NoneNode() return nodes.ObjectInjectNode(None, type=object_)
def _object_Pow(self, node): args = [node.left, node.right, nodes.ObjectInjectNode(None)] return self.visit(function_util.external_call(self.context, self.llvm_module, 'PyNumber_Power', args=args), llvm_module=self.llvm_module)
def visit_Slice(self, node): """ Rewrite slice objects. Do this late in the pipeline so that other code can still recognize the code structure. """ slice_values = [node.lower, node.upper, node.step] if self.nopython: raise error.NumbaError(node, "Cannot slice in nopython context") if node.variable.is_constant: return self.visit( nodes.ObjectInjectNode(node.variable.constant_value)) bounds = [] for node in slice_values: if node is None: bounds.append(nodes.NULL_obj) else: bounds.append(node) new_slice = function_util.external_call(self.context, self.llvm_module, 'PySlice_New', args=bounds, temp_name='slice') return self.visit(new_slice)
def _print(self, value, dest=None): signature, lfunc = self.context.external_library.declare( self.llvm_module, 'PyObject_CallMethod') if dest is None: dest = nodes.ObjectInjectNode(sys.stdout) value = function_util.external_call(self.context, self.llvm_module, "PyObject_Str", args=[value]) args = [dest, nodes.ConstNode("write"), nodes.ConstNode("O"), value] return nodes.NativeCallNode(signature, args, lfunc)
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 visit_ConstNode(self, node): constant = node.pyval if node.type.is_complex: real = nodes.ConstNode(constant.real, node.type.base_type) imag = nodes.ConstNode(constant.imag, node.type.base_type) node = nodes.ComplexNode(real, imag) elif node.type.is_pointer: addr_int = constnodes.get_pointer_address(constant, node.type) node = nodes.ptrfromint(addr_int, node.type) elif node.type.is_object and not nodes.is_null_constant(constant): node = nodes.ObjectInjectNode(constant, node.type) return node
def visit_CoerceToObject(self, node): new_node = node node_type = node.node.type if node_type.is_bool: new_node = function_util.external_call(self.context, self.llvm_module, "PyBool_FromLong", args=[node.node]) elif node_type.is_numeric: cls = None args = node.node, if node_type.is_int: cls = self._get_int_conversion_func(node_type, pyapi._from_long) elif node_type.is_float: cls = pyapi.PyFloat_FromDouble elif node_type.is_complex: cls = pyapi.PyComplex_FromDoubles complex_value = nodes.CloneableNode(node.node) args = [ nodes.ComplexAttributeNode(complex_value, "real"), nodes.ComplexAttributeNode(complex_value.clone, "imag") ] else: raise error.NumbaError( node, "Don't know how to coerce type %r to PyObject" % node_type) if cls: new_node = function_util.external_call(self.context, self.llvm_module, cls.__name__, args=args) elif node_type.is_pointer and not node_type.is_string(): # Create ctypes pointer object ctypes_pointer_type = node_type.to_ctypes() args = [ nodes.CoercionNode(node.node, int64), nodes.ObjectInjectNode(ctypes_pointer_type, object_) ] new_node = nodes.call_pyfunc(ctypes.cast, args) self.generic_visit(new_node) return new_node
def register_array_expression(self, node, lhs=None): super(ArrayExpressionRewriteUfunc, self).register_array_expression(node, lhs) py_ufunc, signature, ufunc_builder = self.get_py_ufunc(lhs, node) # Vectorize Python function vectorizer = self.vectorizer_cls(py_ufunc) vectorizer.add(restype=signature.return_type, argtypes=signature.args) ufunc = vectorizer.build_ufunc() # Call ufunc args = ufunc_builder.operands if lhs is None: keywords = None else: keywords = [ast.keyword('out', lhs)] func = nodes.ObjectInjectNode(ufunc) call_ufunc = nodes.ObjectCallNode(signature=None, func=func, args=args, keywords=keywords, py_func=ufunc) return nodes.ObjectTempNode(call_ufunc)
def build_wrapper_function_ast(env, wrapper_lfunc, llvm_module): """ Build AST for LLVM function wrapper. lfunc: LLVM function to wrap llvm_module: module the wrapper is being defined in The resulting AST has a NativeCallNode to the wrapped function. The arguments are LLVMValueRefNode nodes which still need their llvm_value set to the object from the tuple. This happens in visit_FunctionWrapperNode during codegen. """ func = env.crnt.func func_signature = env.crnt.func_signature func_name = env.crnt.func_name # Insert external declaration lfunc = llvm_module.get_or_insert_function( func_signature.to_llvm(env.context), env.crnt.lfunc.name) # Build AST wrapper = nodes.FunctionWrapperNode(lfunc, func_signature, func, fake_pyfunc, func_name) error_return = ast.Return(nodes.CoercionNode(nodes.NULL_obj, object_)) is_closure = bool(closures.is_closure_signature(func_signature)) nargs = len(func_signature.args) - is_closure # Call wrapped function with unpacked object arguments # (delay actual arguments) args = [nodes.LLVMValueRefNode(object_, None) for i in range(nargs)] if is_closure: # Insert m_self as scope argument type closure_scope = get_closure_scope(func_signature, wrapper_lfunc.args[0]) args.insert(0, closure_scope) func_call = nodes.NativeCallNode(func_signature, args, lfunc) if not is_obj(func_signature.return_type): # Check for error using PyErr_Occurred() func_call = nodes.PyErr_OccurredNode(func_call) # Coerce and return result if func_signature.return_type.is_void: wrapper.body = func_call result_node = nodes.ObjectInjectNode(None) else: wrapper.body = None result_node = func_call wrapper.return_result = ast.Return(value=nodes.CoercionNode(result_node, object_)) # Update wrapper wrapper.error_return = error_return wrapper.cellvars = [] wrapper.wrapped_nargs = nargs wrapper.wrapped_args = args[is_closure:] return wrapper