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 _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_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 _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_Tuple(self, node): self.check_context(node) sig, lfunc = self.context.external_library.declare( self.llvm_module, 'PyTuple_Pack') objs = self.visitlist(nodes.CoercionNode.coerce(node.elts, object_)) n = nodes.ConstNode(len(node.elts), minitypes.Py_ssize_t) args = [n] + objs new_node = nodes.NativeCallNode(sig, args, lfunc, name='tuple') # TODO: determine element type of node.elts new_node.type = typesystem.TupleType(object_, size=len(node.elts)) return nodes.ObjectTempNode(new_node)
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. """ # 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 #typesystem.extmethod_to_function(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] # lookup_impl = NumbaVirtualLookup() lookup_impl = DebugVirtualLookup() ptr = lookup_impl.lookup(env, always_present, node, args) vmethod = ptr.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 _create_llvm_string(self, str): return self.translator.visit(nodes.ConstNode(str, char.pointer()))
def rewrite_array_iteration(self, node): """ Convert 1D array iteration to for-range and indexing: for value in my_array: ... becomes for i in my_array.shape[0]: value = my_array[i] ... """ logger.debug(ast.dump(node)) orig_target = node.target orig_iter = node.iter #-------------------------------------------------------------------- # Replace node.target with a temporary #-------------------------------------------------------------------- target_name = orig_target.id + '.idx' target_temp = nodes.TempNode(Py_ssize_t) node.target = target_temp.store() #-------------------------------------------------------------------- # Create range(A.shape[0]) #-------------------------------------------------------------------- call_func = ast.Name(id='range', ctx=ast.Load()) nodes.typednode(call_func, typesystem.range_) shape_index = ast.Index(nodes.ConstNode(0, typesystem.Py_ssize_t)) shape_index.type = typesystem.npy_intp stop = ast.Subscript(value=nodes.ShapeAttributeNode(orig_iter), slice=shape_index, ctx=ast.Load()) nodes.typednode(stop, npy_intp) #-------------------------------------------------------------------- # Create range iterator and replace node.iter #-------------------------------------------------------------------- call_args = [ nodes.ConstNode(0, typesystem.Py_ssize_t), nodes.CoercionNode(stop, typesystem.Py_ssize_t), nodes.ConstNode(1, typesystem.Py_ssize_t), ] node.iter = ast.Call(func=call_func, args=call_args) nodes.typednode(node.iter, call_func.type) node.index = target_temp.load(invariant=True) #-------------------------------------------------------------------- # Add assignment to new target variable at the start of the body #-------------------------------------------------------------------- index = ast.Index(value=node.index) index.type = target_temp.type subscript = ast.Subscript(value=orig_iter, slice=index, ctx=ast.Load()) nodes.typednode(subscript, get_type(orig_iter).dtype) #-------------------------------------------------------------------- # Add assignment to new target variable at the start of the body #-------------------------------------------------------------------- assign = ast.Assign(targets=[orig_target], value=subscript) node.body = [assign] + node.body #-------------------------------------------------------------------- # Specialize new for loop through range iteration #-------------------------------------------------------------------- return self.visit(node)
def cast(node, dst_type): if len(node.args) == 0: return nodes.ConstNode(0, dst_type) else: return nodes.CoercionNode(node.args[0], dst_type=dst_type)
def _create_llvm_string(self, str): return self.translator.visit(nodes.ConstNode(str, c_string_type))