Example #1
0
def minmax(typesystem, args, op):
    if len(args) < 2:
        return

    res = args[0]
    for arg in args[1:]:
        lhs_type = get_type(res)
        rhs_type = get_type(arg)
        res_type = typesystem.promote(lhs_type, rhs_type)
        if lhs_type != res_type:
            res = nodes.CoercionNode(res, res_type)
        if rhs_type != res_type:
            arg = nodes.CoercionNode(arg, res_type)

        lhs_temp = nodes.TempNode(res_type)
        rhs_temp = nodes.TempNode(res_type)
        res_temp = nodes.TempNode(res_type)
        lhs = lhs_temp.load(invariant=True)
        rhs = rhs_temp.load(invariant=True)
        expr = ast.IfExp(ast.Compare(lhs, [op], [rhs]), lhs, rhs)
        body = [
            ast.Assign([lhs_temp.store()], res),
            ast.Assign([rhs_temp.store()], arg),
            ast.Assign([res_temp.store()], expr),
        ]
        res = nodes.ExpressionNode(body, res_temp.load(invariant=True))

    return res
Example #2
0
    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)
Example #3
0
    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)
Example #4
0
 def visit_PyErr_OccurredNode(self, node):
     check_err = nodes.CheckErrorNode(nodes.ptrtoint(
         function_util.external_call(self.context, self.llvm_module,
                                     'PyErr_Occurred')),
                                      goodval=nodes.ptrtoint(nodes.NULL))
     result = nodes.CloneableNode(node.node)
     result = nodes.ExpressionNode(stmts=[result, check_err],
                                   expr=result.clone)
     return self.visit(result)
Example #5
0
    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))
Example #6
0
    def visit_ListComp(self, node):
        """
        Rewrite list comprehensions to the equivalent for loops.

        AST syntax:

            ListComp(expr elt, comprehension* generators)
            comprehension = (expr target, expr iter, expr* ifs)

            'ifs' represent a chain of ANDs
        """
        assert len(node.generators) > 0

        # Create innermost body, i.e. list.append(expr)
        # TODO: size hint for PyList_New
        list_create = ast.List(elts=[], ctx=ast.Load())
        list_create.type = typesystem.object_  # typesystem.list_()
        list_create = nodes.CloneableNode(list_create)
        list_value = nodes.CloneNode(list_create)
        list_append = ast.Attribute(list_value, "append", ast.Load())
        append_call = ast.Call(func=list_append,
                               args=[node.elt],
                               keywords=[],
                               starargs=None,
                               kwargs=None)

        # Build up the loops from inwards to outwards
        body = append_call
        for comprehension in reversed(node.generators):
            # Hanlde the 'if' clause
            ifs = comprehension.ifs
            if len(ifs) > 1:
                make_boolop = lambda op1_op2: ast.BoolOp(op=ast.And(),
                                                         values=op1_op2)
                if_test = reduce(make_boolop, ifs)
            elif len(ifs) == 1:
                if_test, = ifs
            else:
                if_test = None

            if if_test is not None:
                body = ast.If(test=if_test, body=[body], orelse=[])

            # Wrap list.append() call or inner loops
            body = ast.For(target=comprehension.target,
                           iter=comprehension.iter,
                           body=[body],
                           orelse=[])

        expr = nodes.ExpressionNode(stmts=[list_create, body], expr=list_value)
        return self.visit(expr)
Example #7
0
    def visit_NativeCallNode(self, node):
        badval, goodval = node.badval, node.goodval
        if node not in self.visited_callnodes and (badval is not None
                                                   or goodval is not None):
            self.visited_callnodes.add(node)

            result = node.cloneable
            body = nodes.CheckErrorNode(result, badval, goodval, node.exc_type,
                                        node.exc_msg, node.exc_args)

            node = nodes.ExpressionNode(stmts=[body], expr=result.clone)
            return self.visit(node)
        else:
            self.generic_visit(node)
            return node
Example #8
0
    def visit_InstantiateClosureScope(self, node):
        """
        Instantiate a closure scope.

        After instantiation, assign the parent scope and all function
        arguments that belong in the scope to the scope.
        """
        ctor = nodes.objconst(node.ext_type.__new__)
        ext_type_arg = nodes.objconst(node.ext_type)
        create_scope = nodes.ObjectCallNode(signature=node.scope_type(object_),
                                            func=ctor,
                                            args=[ext_type_arg])

        create_scope = create_scope.cloneable
        scope = create_scope.clone
        stats = [create_scope]

        # Chain outer scope - if present - to current scope
        outer_scope = self.outer_scope
        if outer_scope:
            outer_scope_name, outer_scope_type = outer_scope_field(scope.type)
            dst = lookup_scope_attribute(scope,
                                         outer_scope_name,
                                         ctx=ast.Store())
            assmt = ast.Assign(targets=[dst], value=outer_scope)
            stats.append(assmt)

        # Assign function arguments that are cellvars
        for arg in self.ast.args.args:
            name = arg.id

            if name in node.scope_type.unmangled_symtab:
                dst = lookup_scope_attribute(scope, name, ast.Store())
                src = self._load_name(name)
                src.variable.assign_in_closure_scope = True
                assmt = ast.Assign(targets=[dst], value=src)
                stats.append(assmt)

        logger.debug("instantiating %s", scope.type)
        self.ast.cur_scope = scope
        return self.visit(nodes.ExpressionNode(stmts=stats, expr=scope))
Example #9
0
    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)
Example #10
0
    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)