Exemple #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
Exemple #2
0
    def single_compare(self, node):
        rhs = node.comparators[0]

        if is_obj(node.left.type):
            node = self.single_compare_objects(node)

        elif node.left.type.is_pointer and rhs.type.is_pointer:
            # Coerce pointers to integer values before comparing
            node.left = nodes.CoercionNode(node.left, Py_uintptr_t)
            node.comparators = [nodes.CoercionNode(rhs, Py_uintptr_t)]

        elif node.left.type.is_complex and rhs.type.is_complex:
            real1, imag1 = extract(node.left)
            real2, imag2 = extract(rhs)
            op = type(node.ops[0])
            if op == ast.Eq:
                lhs = compare(real1, ast.Eq(), real2)
                rhs = compare(imag1, ast.Eq(), imag2)
                result = ast.BoolOp(ast.And(), [lhs, rhs])
            elif op == ast.NotEq:
                lhs = compare(real1, ast.NotEq(), real2)
                rhs = compare(imag1, ast.NotEq(), imag2)
                result = ast.BoolOp(ast.Or(), [lhs, rhs])
            else:
                raise NotImplementedError("ordered comparisons are not "
                                          "implemented for complex numbers")
            node = nodes.typednode(result, bool_)

        return node
Exemple #3
0
def round_(typesystem, node, number, ndigits):
    argtype = get_type(number)

    if len(node.args) == 1 and argtype.is_int:
        # round(myint) -> float(myint)
        return nodes.CoercionNode(node.args[0], double)

    if argtype.is_float or argtype.is_int:
        dst_type = double
    else:
        dst_type = object_
        node.args[0] = nodes.CoercionNode(node.args[0], object_)

    node.variable = Variable(dst_type)
    return node # nodes.CoercionNode(node, double)
Exemple #4
0
 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
Exemple #5
0
def resolve_call(context, call_node, obj_call_node, func_type):
    """
    Find the right type inferrer function for a call to an attribute
    of a certain module.


        call_node:     the original ast.Call node that we need to resolve
                       the type for

        obj_call_node: the nodes.ObjectCallNode that would replace the
                       ast.Call unless we override that with another node.

        func_type: module_attribute
            |__________> module: Python module
            |__________> attr: Attribute name
            |__________> value: Attribute value


    Returns a new AST node that should replace the ast.Call node.
    """
    result = dispatch_on_value(context, call_node, func_type)

    if result is not None and not isinstance(result, ast.AST):
        assert isinstance(result, Type), (Type, result)
        type = result
        result = obj_call_node
        # result.variable = symtab.Variable(type)
        result = nodes.CoercionNode(result, type)

    return result
Exemple #6
0
def round_(context, node, number, ndigits):
    # is_math = is_math_function(node.args, round)
    argtype = get_type(number)

    if len(node.args) == 1 and argtype.is_int:
        # round(myint) -> float(myint)
        return nodes.CoercionNode(node.args[0], double)

    if argtype.is_float or argtype.is_int:
        dst_type = double
    else:
        dst_type = object_
        node.args[0] = nodes.CoercionNode(node.args[0], object_)

    node.variable = Variable(dst_type)
    return node  # nodes.CoercionNode(node, double)
Exemple #7
0
def ord_(typesystem, node, expr):
    type = get_type(expr)
    if type.is_int and type.typename in ("char", "uchar"):
        return nodes.CoercionNode(expr, int_)
    elif type.is_string:
        # TODO:
        pass
Exemple #8
0
    def _resolve_int_number(self, func, node, argtype, dst_type, ext_name):
        assert len(node.args) == 2

        arg1, arg2 = node.args
        if arg1.variable.type.is_string:
            return nodes.CoercionNode(nodes.ObjectTempNode(
                self.external_call(ext_name, args=[arg1, nodes.NULL, arg2])),
                                      dst_type=dst_type)
Exemple #9
0
 def build_array(self):
     self.dst_data = nodes.LLVMValueRefNode(void.pointer(), None)
     self.dst_shape = nodes.LLVMValueRefNode(self.shape_type, None)
     self.dst_strides = nodes.LLVMValueRefNode(self.shape_type, None)
     array_node = nodes.ArrayNewNode(
             self.type, self.dst_data, self.dst_shape, self.dst_strides,
             base=self.value.clone)
     return nodes.CoercionNode(array_node, self.type)
Exemple #10
0
def resolve_pow(type, args):
    have_mod = len(args) == 3

    if (type.is_int or type.is_float) and not have_mod and not is_win32:
        result = resolve_intrinsic(args, pow, type)
    else:
        result = nodes.call_pyfunc(pow, args)

    return nodes.CoercionNode(result, type)
Exemple #11
0
def resolve_pow(env, restype, args):
    promote = env.crnt.typesystem.promote
    if restype.is_numeric:
        type = reduce(promote, [double, restype] + [a.type for a in args])
        signature = type(*[type] * len(args))
        result = nodes.MathCallNode(signature, args, None, name='pow')
    else:
        result = nodes.call_pyfunc(pow, args)
    return nodes.CoercionNode(result, restype)
Exemple #12
0
    def _resolve_builtin_call_or_object(self, node, func):
        """
        Resolve an ast.Call() of a built-in function, or call the built-in
        through the object layer otherwise.
        """
        result = self._resolve_builtin_call(node, func)
        if result is None:
            result = nodes.call_pyfunc(func, node.args)

        return nodes.CoercionNode(result, node.type)
Exemple #13
0
    def visit_Subscript(self, node):
        if isinstance(node.value, nodes.ArrayAttributeNode):
            if node.value.is_read_only and isinstance(node.ctx, ast.Store):
                raise error.NumbaError("Attempt to load read-only attribute")

        # Short-circuit visiting a Slice child if this is a nopython
        # string slice.
        if (self.nopython and node.value.type.is_c_string
                and node.type.is_c_string):
            return self.visit(self._c_string_slice(node))

        # logging.debug(ast.dump(node))
        # TODO: do this in the respective cases below when needed
        self.generic_visit(node)

        node_type = node.value.type
        if node_type.is_object or (node_type.is_array
                                   and node.slice.type.is_object):
            # Array or object slicing
            if isinstance(node.ctx, ast.Load):
                result = function_util.external_call(
                    self.context,
                    self.llvm_module,
                    'PyObject_GetItem',
                    args=[node.value, node.slice])
                node = nodes.CoercionNode(result, dst_type=node.type)
                node = self.visit(node)
            else:
                # This is handled in visit_Assign
                pass
        elif (node.value.type.is_array and not node.type.is_array
              and node.slice.type.is_int):
            # Array index with integer indices
            node = nodes.DataPointerNode(node.value, node.slice, node.ctx)
        elif node.value.type.is_c_string and node.type.is_c_string:
            node.value = nodes.CoercionNode(node.value, dst_type=object_)
            node.type = object_
            node = nodes.CoercionNode(nodes.ObjectTempNode(node),
                                      dst_type=c_string_type)
            node = self.visit(node)

        return node
Exemple #14
0
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
Exemple #15
0
def len_(typesystem, node, obj):
    # Simplify len(array) to ndarray.shape[0]
    argtype = get_type(obj)
    if argtype.is_array:
        shape_attr = nodes.ArrayAttributeNode('shape', node.args[0])
        new_node = nodes.index(shape_attr, 0)
        return new_node
    elif argtype.is_string:
        return nodes.CoercionNode(nodes.typednode(node, size_t), Py_ssize_t)

    return Py_ssize_t # Object call
Exemple #16
0
    def single_compare(self, node):
        rhs = node.comparators[0]

        if is_obj(node.left.type):
            node = self.single_compare_objects(node)

        elif node.left.type.is_pointer and rhs.type.is_pointer:
            # Coerce pointers to integer values before comparing
            node.left = nodes.CoercionNode(node.left, Py_uintptr_t)
            node.comparators = [nodes.CoercionNode(rhs, Py_uintptr_t)]

        elif node.left.type.is_complex and rhs.type.is_complex:
            real1, imag1 = extract(node.left)
            real2, imag2 = extract(rhs)
            lhs = compare(real1, real2)
            rhs = compare(imag1, imag2)
            result = ast.BoolOp(ast.And(), [lhs, rhs])
            node = nodes.typednode(result, bool_)

        return node
Exemple #17
0
def pow_(typesystem, node, base, exponent, mod=None):
    if mod:
        warnings.warn(
            "pow() with modulo (third) argument not natively supported")
        return nodes.call_pyfunc(pow, [base, exponent, mod])

    from . import mathmodule
    dst_type = mathmodule.binop_type(typesystem, base, exponent)
    result = mathmodule.infer_math_call(typesystem, node, base, exponent, mod)
    if dst_type.is_int:
        # TODO: Implement pow(int) in llvmmath
        return nodes.CoercionNode(result, dst_type)
    return result
Exemple #18
0
def resolve_libc_math(args, py_func, type):
    signature = intrinsic_signature(len(args), type)
    math_name = get_funcname(py_func)
    name = math_suffix(math_name, type)

    use_double_impl = not have_impl(name)
    if use_double_impl:
        assert have_double_impl(math_name)
        signature = double(*[double] * len(args))
        name = math_suffix(math_name, double)

    result = nodes.MathCallNode(signature, args, llvm_func=None,
                                py_func=py_func, name=name)
    return nodes.CoercionNode(result, type)
Exemple #19
0
 def retrieve_closure_from_numbafunc(self, node):
     """
     Retrieve the closure scope from ((NumbaFunctionObject *)
                                          numba_func).func_closure
     """
     # TODO: use llvmwrapper.get_closure_scope()
     pointer = nodes.ptrfromobj(node.func)
     type = typedefs.NumbaFunctionObject.ref()
     closure_obj_struct = nodes.CoercionNode(pointer, type)
     cur_scope = nodes.StructAttribute(closure_obj_struct,
                                       'func_closure',
                                       ctx=ast.Load(),
                                       type=type)
     return cur_scope
Exemple #20
0
    def setup_error_return(self, node, ret_type):
        """
        Set FunctionDef.error_return to the AST statement that returns a
        "bad value" that can be used as error indicator.
        """
        value = nodes.badval(ret_type)

        if value is not None:
            value = nodes.CoercionNode(value, dst_type=ret_type).cloneable

        error_return = ast.Return(value=value)

        if self.nopython and is_obj(self.func_signature.return_type):
            error_return = nodes.WithPythonNode(body=[error_return])

        error_return = self.visit(error_return)
        node.error_return = error_return
Exemple #21
0
    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
Exemple #22
0
    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)
Exemple #23
0
    def visit_Raise(self, node):
        # Create void * temporaries
        args = []  # Type, Value, Traceback, Cause
        for arg in [node.type, node.inst, node.tback, None]:
            if arg:
                arg = nodes.CoercionNode(arg, object_)
                arg = nodes.PointerFromObject(arg)
            else:
                arg = nodes.NULL

            args.append(arg)

        # Call numba/external/utitilies/cpyutils.c:do_raise()
        set_exc = function_util.utility_call(self.context, self.llvm_module,
                                             'Raise', args)

        result = self.visit(set_exc)
        return result
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_
Exemple #25
0
    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])
Exemple #26
0
def unellipsify(node, slices, subscript_node):
    """
    Given an array node `node`, process all AST slices and create the
    final type:

        - process newaxes (None or numpy.newaxis)
        - replace Ellipsis with a bunch of ast.Slice objects
        - process integer indices
        - append any missing slices in trailing dimensions
    """
    type = node.variable.type

    if not type.is_array:
        assert type.is_object
        return object_, node

    if (len(slices) == 1 and nodes.is_constant_index(slices[0]) and
            slices[0].value.pyval is Ellipsis):
        # A[...]
        return type, node

    result = []
    seen_ellipsis = False

    # Filter out newaxes
    newaxes = [newaxis for newaxis in slices if nodes.is_newaxis(newaxis)]
    n_indices = len(slices) - len(newaxes)

    full_slice = ast.Slice(lower=None, upper=None, step=None)
    full_slice.variable = Variable(typesystem.slice_)
    ast.copy_location(full_slice, slices[0])

    # process ellipses and count integer indices
    indices_seen = 0
    for slice_node in slices[::-1]:
        slice_type = slice_node.variable.type
        if slice_type.is_ellipsis:
            if seen_ellipsis:
                result.append(full_slice)
            else:
                nslices = type.ndim - n_indices + 1
                result.extend([full_slice] * nslices)
                seen_ellipsis = True
        elif (slice_type.is_slice or slice_type.is_int or
              nodes.is_newaxis(slice_node)):
            indices_seen += slice_type.is_int
            result.append(slice_node)
        else:
            # TODO: Coerce all object operands to integer indices?
            # TODO: (This will break indexing with the Ellipsis object or
            # TODO:  with slice objects that we couldn't infer)
            return object_, nodes.CoercionNode(node, object_)

    # Reverse our reversed processed list of slices
    result.reverse()

    # append any missing slices (e.g. a2d[:]
    result_length = len(result) - len(newaxes)
    if result_length < type.ndim:
        nslices = type.ndim - result_length
        result.extend([full_slice] * nslices)

    subscript_node.slice = ast.ExtSlice(result)
    ast.copy_location(subscript_node.slice, slices[0])

    # create the final array type and set it in value.variable
    result_dtype = node.variable.type.dtype
    result_ndim = node.variable.type.ndim + len(newaxes) - indices_seen
    if result_ndim > 0:
        result_type = result_dtype[(slice(None),) * result_ndim]
    elif result_ndim == 0:
        result_type = result_dtype
    else:
        result_type = object_

    return result_type, node
Exemple #27
0
    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)
Exemple #28
0
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
Exemple #29
0
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)
Exemple #30
0
def chr_(typesystem, node, expr):
    type = get_type(expr)
    if type.is_int:
        return nodes.CoercionNode(expr, char)