#
# Copyright (c) 2017 Intel Corporation
# SPDX-License-Identifier: BSD-2-Clause
#

import copy

import numpy as np
from llvmlite import ir as lir

from numba.core import types, typing, utils, ir, config, ir_utils, registry
from numba.core.typing.templates import (CallableTemplate, signature,
                                         infer_global, AbstractTemplate)
from numba.core.imputils import lower_builtin
from numba.core.extending import register_jitable
from numba.core.errors import NumbaValueError
from numba.misc.special import literal_unroll
import numba

import operator
from numba.np import numpy_support

class StencilFuncLowerer(object):
    '''Callable class responsible for lowering calls to a specific StencilFunc.
    '''
    def __init__(self, sf):
        self.stencilFunc = sf

    def __call__(self, context, builder, sig, args):
        cres = self.stencilFunc.compile_for_argtys(sig.args, {},
                    sig.return_type, None)
        res = context.call_internal(builder, cres.fndesc, sig, args)
        context.add_linking_libs([cres.library])
        return res

@register_jitable
def raise_if_incompatible_array_sizes(a, *args):
    ashape = a.shape

    # We need literal_unroll here because the stencil might take
    # multiple input arrays with different types that are not compatible
    # (e.g. values as float[:] and flags as bool[:])
    # When more than three total arrays are given, the second and third
    # are iterated over in the loop below. Without literal_unroll, their
    # types have to match.
    # An example failing signature without literal_unroll might be
    # (float[:], float[:], bool[:]) (Just (float[:], bool[:]) wouldn't fail)
    for arg in literal_unroll(args):
        if a.ndim != arg.ndim:
            raise ValueError("Secondary stencil array does not have same number "
                             " of dimensions as the first stencil input.")
        argshape = arg.shape
        for i in range(len(ashape)):
            if ashape[i] > argshape[i]:
                raise ValueError("Secondary stencil array has some dimension "
                                 "smaller the same dimension in the first "
                                 "stencil input.")

def slice_addition(the_slice, addend):
    """ Called by stencil in Python mode to add the loop index to a
        user-specified slice.
    """
    return slice(the_slice.start + addend, the_slice.stop + addend)

class StencilFunc(object):
    """
    A special type to hold stencil information for the IR.
    """

    id_counter = 0

    def __init__(self, kernel_ir, mode, options):
        self.id = type(self).id_counter
        type(self).id_counter += 1
        self.kernel_ir = kernel_ir
        self.mode = mode
        self.options = options
        self.kws = []       # remember original kws arguments

        # stencils only supported for CPU context currently
        self._typingctx = registry.cpu_target.typing_context
        self._targetctx = registry.cpu_target.target_context
        self._typingctx.refresh()
        self._targetctx.refresh()
        self._install_type(self._typingctx)
        self.neighborhood = self.options.get("neighborhood")
        self._type_cache = {}
        self._lower_me = StencilFuncLowerer(self)

    def replace_return_with_setitem(self, blocks, index_vars, out_name):
        """
        Find return statements in the IR and replace them with a SetItem
        call of the value "returned" by the kernel into the result array.
        Returns the block labels that contained return statements.
        """
        ret_blocks = []

        for label, block in blocks.items():
            scope = block.scope
            loc = block.loc
            new_body = []
            for stmt in block.body:
                if isinstance(stmt, ir.Return):
                    ret_blocks.append(label)
                    # If 1D array then avoid the tuple construction.
                    if len(index_vars) == 1:
                        rvar = ir.Var(scope, out_name, loc)
                        ivar = ir.Var(scope, index_vars[0], loc)
                        new_body.append(ir.SetItem(rvar, ivar, stmt.value, loc))
                    else:
                        # Convert the string names of the index variables into
                        # ir.Var's.
                        var_index_vars = []
                        for one_var in index_vars:
                            index_var = ir.Var(scope, one_var, loc)
                            var_index_vars += [index_var]

                        s_index_name = ir_utils.mk_unique_var("stencil_index")
                        s_index_var  = ir.Var(scope, s_index_name, loc)
                        # Build a tuple from the index ir.Var's.
                        tuple_call = ir.Expr.build_tuple(var_index_vars, loc)
                        new_body.append(ir.Assign(tuple_call, s_index_var, loc))
                        rvar = ir.Var(scope, out_name, loc)
                        # Write the return statements original value into
                        # the array using the tuple index.
                        si = ir.SetItem(rvar, s_index_var, stmt.value, loc)
                        new_body.append(si)
                else:
                    new_body.append(stmt)
            block.body = new_body
        return ret_blocks

    def add_indices_to_kernel(self, kernel, index_names, ndim,
                              neighborhood, standard_indexed, typemap, calltypes):
        """
        Transforms the stencil kernel as specified by the user into one
        that includes each dimension's index variable as part of the getitem
        calls.  So, in effect array[-1] becomes array[index0-1].
        """
        const_dict = {}
        kernel_consts = []

        if config.DEBUG_ARRAY_OPT >= 1:
            print("add_indices_to_kernel", ndim, neighborhood)
            ir_utils.dump_blocks(kernel.blocks)

        if neighborhood is None:
            need_to_calc_kernel = True
        else:
            need_to_calc_kernel = False
            if len(neighborhood) != ndim:
                raise ValueError("%d dimensional neighborhood specified for %d " \
                    "dimensional input array" % (len(neighborhood), ndim))

        tuple_table = ir_utils.get_tuple_table(kernel.blocks)

        relatively_indexed = set()

        for block in kernel.blocks.values():
            scope = block.scope
            loc = block.loc
            new_body = []
            for stmt in block.body:
                if (isinstance(stmt, ir.Assign) and
                    isinstance(stmt.value, ir.Const)):
                    if config.DEBUG_ARRAY_OPT >= 1:
                        print("remembering in const_dict", stmt.target.name,
                              stmt.value.value)
                    # Remember consts for use later.
                    const_dict[stmt.target.name] = stmt.value.value
                if ((isinstance(stmt, ir.Assign)
                        and isinstance(stmt.value, ir.Expr)
                        and stmt.value.op in ['setitem', 'static_setitem']
                        and stmt.value.value.name in kernel.arg_names) or
                   (isinstance(stmt, ir.SetItem)
                        and stmt.target.name in kernel.arg_names)):
                    raise ValueError("Assignments to arrays passed to stencil " \
                        "kernels is not allowed.")
                if (isinstance(stmt, ir.Assign)
                        and isinstance(stmt.value, ir.Expr)
                        and stmt.value.op in ['getitem', 'static_getitem']
                        and stmt.value.value.name in kernel.arg_names
                        and stmt.value.value.name not in standard_indexed):
                    # We found a getitem from the input array.
                    if stmt.value.op == 'getitem':
                        stmt_index_var = stmt.value.index
                    else:
                        stmt_index_var = stmt.value.index_var
                        # allow static_getitem since rewrite passes are applied
                        #raise ValueError("Unexpected static_getitem in add_indices_to_kernel.")

                    relatively_indexed.add(stmt.value.value.name)

                    # Store the index used after looking up the variable in
                    # the const dictionary.
                    if need_to_calc_kernel:
                        assert hasattr(stmt_index_var, 'name')

                        if stmt_index_var.name in tuple_table:
                            kernel_consts += [tuple_table[stmt_index_var.name]]
                        elif stmt_index_var.name in const_dict:
                            kernel_consts += [const_dict[stmt_index_var.name]]
                        else:
                            raise NumbaValueError("stencil kernel index is not "
                                "constant, 'neighborhood' option required")

                    if ndim == 1:
                        # Single dimension always has index variable 'index0'.
                        # tmpvar will hold the real index and is computed by
                        # adding the relative offset in stmt.value.index to
                        # the current absolute location in index0.
                        index_var = ir.Var(scope, index_names[0], loc)
                        tmpname = ir_utils.mk_unique_var("stencil_index")
                        tmpvar  = ir.Var(scope, tmpname, loc)
                        stmt_index_var_typ = typemap[stmt_index_var.name]
                        # If the array is indexed with a slice then we
                        # have to add the index value with a call to
                        # slice_addition.
                        if isinstance(stmt_index_var_typ, types.misc.SliceType):
                            sa_var = ir.Var(scope, ir_utils.mk_unique_var("slice_addition"), loc)
                            sa_func = numba.njit(slice_addition)
                            sa_func_typ = types.functions.Dispatcher(sa_func)
                            typemap[sa_var.name] = sa_func_typ
                            g_sa = ir.Global("slice_addition", sa_func, loc)
                            new_body.append(ir.Assign(g_sa, sa_var, loc))
                            slice_addition_call = ir.Expr.call(sa_var, [stmt_index_var, index_var], (), loc)
                            calltypes[slice_addition_call] = sa_func_typ.get_call_type(self._typingctx, [stmt_index_var_typ, types.intp], {})
                            new_body.append(ir.Assign(slice_addition_call, tmpvar, loc))
                            new_body.append(ir.Assign(
                                           ir.Expr.getitem(stmt.value.value, tmpvar, loc),
                                           stmt.target, loc))
                        else:
                            acc_call = ir.Expr.binop(operator.add, stmt_index_var,
                                                     index_var, loc)
                            new_body.append(ir.Assign(acc_call, tmpvar, loc))
                            new_body.append(ir.Assign(
                                           ir.Expr.getitem(stmt.value.value, tmpvar, loc),
                                           stmt.target, loc))
                    else:
                        index_vars = []
                        sum_results = []
                        s_index_name = ir_utils.mk_unique_var("stencil_index")
                        s_index_var  = ir.Var(scope, s_index_name, loc)
                        const_index_vars = []
                        ind_stencils = []

                        stmt_index_var_typ = typemap[stmt_index_var.name]
                        # Same idea as above but you have to extract
                        # individual elements out of the tuple indexing
                        # expression and add the corresponding index variable
                        # to them and then reconstitute as a tuple that can
                        # index the array.
                        for dim in range(ndim):
                            tmpname = ir_utils.mk_unique_var("const_index")
                            tmpvar  = ir.Var(scope, tmpname, loc)
                            new_body.append(ir.Assign(ir.Const(dim, loc),
                                                      tmpvar, loc))
                            const_index_vars += [tmpvar]
                            index_var = ir.Var(scope, index_names[dim], loc)
                            index_vars += [index_var]

                            tmpname = ir_utils.mk_unique_var("ind_stencil_index")
                            tmpvar  = ir.Var(scope, tmpname, loc)
                            ind_stencils += [tmpvar]
                            getitemname = ir_utils.mk_unique_var("getitem")
                            getitemvar  = ir.Var(scope, getitemname, loc)
                            getitemcall = ir.Expr.getitem(stmt_index_var,
                                                       const_index_vars[dim], loc)
                            new_body.append(ir.Assign(getitemcall, getitemvar, loc))
                            # Get the type of this particular part of the index tuple.
                            if isinstance(stmt_index_var_typ, types.ConstSized):
                                one_index_typ = stmt_index_var_typ[dim]
                            else:
                                one_index_typ = stmt_index_var_typ[:]
                            # If the array is indexed with a slice then we
                            # have to add the index value with a call to
                            # slice_addition.
                            if isinstance(one_index_typ, types.misc.SliceType):
                                sa_var = ir.Var(scope, ir_utils.mk_unique_var("slice_addition"), loc)
                                sa_func = numba.njit(slice_addition)
                                sa_func_typ = types.functions.Dispatcher(sa_func)
                                typemap[sa_var.name] = sa_func_typ
                                g_sa = ir.Global("slice_addition", sa_func, loc)
                                new_body.append(ir.Assign(g_sa, sa_var, loc))
                                slice_addition_call = ir.Expr.call(sa_var, [getitemvar, index_vars[dim]], (), loc)
                                calltypes[slice_addition_call] = sa_func_typ.get_call_type(self._typingctx, [one_index_typ, types.intp], {})
                                new_body.append(ir.Assign(slice_addition_call, tmpvar, loc))
                            else:
                                acc_call = ir.Expr.binop(operator.add, getitemvar,
                                                         index_vars[dim], loc)
                                new_body.append(ir.Assign(acc_call, tmpvar, loc))

                        tuple_call = ir.Expr.build_tuple(ind_stencils, loc)
                        new_body.append(ir.Assign(tuple_call, s_index_var, loc))
                        new_body.append(ir.Assign(
                                  ir.Expr.getitem(stmt.value.value,s_index_var,loc),
                                  stmt.target,loc))
                else:
                    new_body.append(stmt)
            block.body = new_body

        if need_to_calc_kernel:
            # Find the size of the kernel by finding the maximum absolute value
            # index used in the kernel specification.
            neighborhood = [[0,0] for _ in range(ndim)]
            if len(kernel_consts) == 0:
                raise NumbaValueError("Stencil kernel with no accesses to "
                                      "relatively indexed arrays.")

            for index in kernel_consts:
                if isinstance(index, tuple) or isinstance(index, list):
                    for i in range(len(index)):
                        te = index[i]
                        if isinstance(te, ir.Var) and te.name in const_dict:
                            te = const_dict[te.name]
                        if isinstance(te, int):
                            neighborhood[i][0] = min(neighborhood[i][0], te)
                            neighborhood[i][1] = max(neighborhood[i][1], te)
                        else:
                            raise NumbaValueError(
                                "stencil kernel index is not constant,"
                                "'neighborhood' option required")
                    index_len = len(index)
                elif isinstance(index, int):
                    neighborhood[0][0] = min(neighborhood[0][0], index)
                    neighborhood[0][1] = max(neighborhood[0][1], index)
                    index_len = 1
                else:
                    raise NumbaValueError(
                        "Non-tuple or non-integer used as stencil index.")
                if index_len != ndim:
                    raise NumbaValueError(
                        "Stencil index does not match array dimensionality.")

        return (neighborhood, relatively_indexed)


    def get_return_type(self, argtys):
        if config.DEBUG_ARRAY_OPT >= 1:
            print("get_return_type", argtys)
            ir_utils.dump_blocks(self.kernel_ir.blocks)

        if not isinstance(argtys[0], types.npytypes.Array):
            raise NumbaValueError("The first argument to a stencil kernel must "
                                  "be the primary input array.")

        from numba.core import typed_passes
        typemap, return_type, calltypes, _ = typed_passes.type_inference_stage(
                self._typingctx,
                self._targetctx,
                self.kernel_ir,
                argtys,
                None,
                {})
        if isinstance(return_type, types.npytypes.Array):
            raise NumbaValueError(
                "Stencil kernel must return a scalar and not a numpy array.")

        real_ret = types.npytypes.Array(return_type, argtys[0].ndim,
                                                     argtys[0].layout)
        return (real_ret, typemap, calltypes)

    def _install_type(self, typingctx):
        """Constructs and installs a typing class for a StencilFunc object in
        the input typing context.
        """
        _ty_cls = type('StencilFuncTyping_' +
                       str(self.id),
                       (AbstractTemplate,),
                       dict(key=self, generic=self._type_me))
        typingctx.insert_user_function(self, _ty_cls)

    def compile_for_argtys(self, argtys, kwtys, return_type, sigret):
        # look in the type cache to find if result array is passed
        (_, result, typemap, calltypes) = self._type_cache[argtys]
        new_func = self._stencil_wrapper(result, sigret, return_type,
                                         typemap, calltypes, *argtys)
        return new_func

    def _type_me(self, argtys, kwtys):
        """
        Implement AbstractTemplate.generic() for the typing class
        built by StencilFunc._install_type().
        Return the call-site signature.
        """
        if (self.neighborhood is not None and
            len(self.neighborhood) != argtys[0].ndim):
            raise NumbaValueError("%d dimensional neighborhood specified "
                                  "for %d dimensional input array" %
                                  (len(self.neighborhood), argtys[0].ndim))

        argtys_extra = argtys
        sig_extra = ""
        result = None
        if 'out' in kwtys:
            argtys_extra += (kwtys['out'],)
            sig_extra += ", out=None"
            result = kwtys['out']

        if 'neighborhood' in kwtys:
            argtys_extra += (kwtys['neighborhood'],)
            sig_extra += ", neighborhood=None"

        # look in the type cache first
        if argtys_extra in self._type_cache:
            (_sig, _, _, _) = self._type_cache[argtys_extra]
            return _sig

        (real_ret, typemap, calltypes) = self.get_return_type(argtys)
        sig = signature(real_ret, *argtys_extra)
        dummy_text = ("def __numba_dummy_stencil({}{}):\n    pass\n".format(
                        ",".join(self.kernel_ir.arg_names), sig_extra))
        exec(dummy_text) in globals(), locals()
        dummy_func = eval("__numba_dummy_stencil")
        sig = sig.replace(pysig=utils.pysignature(dummy_func))
        self._targetctx.insert_func_defn([(self._lower_me, self, argtys_extra)])
        self._type_cache[argtys_extra] = (sig, result, typemap, calltypes)
        return sig

    def copy_ir_with_calltypes(self, ir, calltypes):
        """
        Create a copy of a given IR along with its calltype information.
        We need a copy of the calltypes because copy propagation applied
        to the copied IR will change the calltypes and make subsequent
        uses of the original IR invalid.
        """
        copy_calltypes = {}
        kernel_copy = ir.copy()
        kernel_copy.blocks = {}
        # For each block...
        for (block_label, block) in ir.blocks.items():
            new_block = copy.deepcopy(ir.blocks[block_label])
            new_block.body = []
            # For each statement in each block...
            for stmt in ir.blocks[block_label].body:
                # Copy the statement to the new copy of the kernel
                # and if the original statement is in the original
                # calltypes then add the type associated with this
                # statement to the calltypes copy.
                scopy = copy.deepcopy(stmt)
                new_block.body.append(scopy)
                if stmt in calltypes:
                    copy_calltypes[scopy] = calltypes[stmt]
            kernel_copy.blocks[block_label] = new_block
        return (kernel_copy, copy_calltypes)

    def _stencil_wrapper(self, result, sigret, return_type, typemap, calltypes, *args):
        # Overall approach:
        # 1) Construct a string containing a function definition for the stencil function
        #    that will execute the stencil kernel.  This function definition includes a
        #    unique stencil function name, the parameters to the stencil kernel, loop
        #    nests across the dimensions of the input array.  Those loop nests use the
        #    computed stencil kernel size so as not to try to compute elements where
        #    elements outside the bounds of the input array would be needed.
        # 2) The but of the loop nest in this new function is a special sentinel
        #    assignment.
        # 3) Get the IR of this new function.
        # 4) Split the block containing the sentinel assignment and remove the sentinel
        #    assignment.  Insert the stencil kernel IR into the stencil function IR
        #    after label and variable renaming of the stencil kernel IR to prevent
        #    conflicts with the stencil function IR.
        # 5) Compile the combined stencil function IR + stencil kernel IR into existence.

        # Copy the kernel so that our changes for this callsite
        # won't effect other callsites.
        (kernel_copy, copy_calltypes) = self.copy_ir_with_calltypes(
                                            self.kernel_ir, calltypes)
        # The stencil kernel body becomes the body of a loop, for which args aren't needed.
        ir_utils.remove_args(kernel_copy.blocks)
        first_arg = kernel_copy.arg_names[0]

        in_cps, out_cps = ir_utils.copy_propagate(kernel_copy.blocks, typemap)
        name_var_table = ir_utils.get_name_var_table(kernel_copy.blocks)
        ir_utils.apply_copy_propagate(
            kernel_copy.blocks,
            in_cps,
            name_var_table,
            typemap,
            copy_calltypes)

        if "out" in name_var_table:
            raise NumbaValueError("Cannot use the reserved word 'out' in stencil kernels.")

        sentinel_name = ir_utils.get_unused_var_name("__sentinel__", name_var_table)
        if config.DEBUG_ARRAY_OPT >= 1:
            print("name_var_table", name_var_table, sentinel_name)

        the_array = args[0]

        if config.DEBUG_ARRAY_OPT >= 1:
            print("_stencil_wrapper", return_type, return_type.dtype,
                                      type(return_type.dtype), args)
            ir_utils.dump_blocks(kernel_copy.blocks)

        # We generate a Numba function to execute this stencil and here
        # create the unique name of this function.
        stencil_func_name = "__numba_stencil_%s_%s" % (
                                        hex(id(the_array)).replace("-", "_"),
                                        self.id)

        # We will put a loop nest in the generated function for each
        # dimension in the input array.  Here we create the name for
        # the index variable for each dimension.  index0, index1, ...
        index_vars = []
        for i in range(the_array.ndim):
            index_var_name = ir_utils.get_unused_var_name("index" + str(i),
                                                          name_var_table)
            index_vars += [index_var_name]

        # Create extra signature for out and neighborhood.
        out_name = ir_utils.get_unused_var_name("out", name_var_table)
        neighborhood_name = ir_utils.get_unused_var_name("neighborhood",
                                                         name_var_table)
        sig_extra = ""
        if result is not None:
            sig_extra += ", {}=None".format(out_name)
        if "neighborhood" in dict(self.kws):
            sig_extra += ", {}=None".format(neighborhood_name)

        # Get a list of the standard indexed array names.
        standard_indexed = self.options.get("standard_indexing", [])

        if first_arg in standard_indexed:
            raise NumbaValueError("The first argument to a stencil kernel must "
                                  "use relative indexing, not standard indexing.")

        if len(set(standard_indexed) - set(kernel_copy.arg_names)) != 0:
            raise NumbaValueError("Standard indexing requested for an array name "
                                  "not present in the stencil kernel definition.")

        # Add index variables to getitems in the IR to transition the accesses
        # in the kernel from relative to regular Python indexing.  Returns the
        # computed size of the stencil kernel and a list of the relatively indexed
        # arrays.
        kernel_size, relatively_indexed = self.add_indices_to_kernel(
                kernel_copy, index_vars, the_array.ndim,
                self.neighborhood, standard_indexed, typemap, copy_calltypes)
        if self.neighborhood is None:
            self.neighborhood = kernel_size

        if config.DEBUG_ARRAY_OPT >= 1:
            print("After add_indices_to_kernel")
            ir_utils.dump_blocks(kernel_copy.blocks)

        # The return in the stencil kernel becomes a setitem for that
        # particular point in the iteration space.
        ret_blocks = self.replace_return_with_setitem(kernel_copy.blocks,
                                                      index_vars, out_name)

        if config.DEBUG_ARRAY_OPT >= 1:
            print("After replace_return_with_setitem", ret_blocks)
            ir_utils.dump_blocks(kernel_copy.blocks)

        # Start to form the new function to execute the stencil kernel.
        func_text = "def {}({}{}):\n".format(stencil_func_name,
                        ",".join(kernel_copy.arg_names), sig_extra)

        # Get loop ranges for each dimension, which could be either int
        # or variable. In the latter case we'll use the extra neighborhood
        # argument to the function.
        ranges = []
        for i in range(the_array.ndim):
            if isinstance(kernel_size[i][0], int):
                lo = kernel_size[i][0]
                hi = kernel_size[i][1]
            else:
                lo = "{}[{}][0]".format(neighborhood_name, i)
                hi = "{}[{}][1]".format(neighborhood_name, i)
            ranges.append((lo, hi))

        # If there are more than one relatively indexed arrays, add a call to
        # a function that will raise an error if any of the relatively indexed
        # arrays are of different size than the first input array.
        if len(relatively_indexed) > 1:
            func_text += "    raise_if_incompatible_array_sizes(" + first_arg
            for other_array in relatively_indexed:
                if other_array != first_arg:
                    func_text += "," + other_array
            func_text += ")\n"

        # Get the shape of the first input array.
        shape_name = ir_utils.get_unused_var_name("full_shape", name_var_table)
        func_text += "    {} = {}.shape\n".format(shape_name, first_arg)

        # Converts cval to a string constant
        def cval_as_str(cval):
            if not np.isfinite(cval):
                # See if this is a string-repr numerical const, issue #7286
                if np.isnan(cval):
                    return "np.nan"
                elif np.isinf(cval):
                    if cval < 0:
                        return "-np.inf"
                    else:
                        return "np.inf"
            else:
                return str(cval)

        # If we have to allocate the output array (the out argument was not used)
        # then us numpy.full if the user specified a cval stencil decorator option
        # or np.zeros if they didn't to allocate the array.
        if result is None:
            return_type_name = numpy_support.as_dtype(
                               return_type.dtype).type.__name__
            if "cval" in self.options:
                cval = self.options["cval"]
                if return_type.dtype != typing.typeof.typeof(cval):
                    msg = "cval type does not match stencil return type."
                    raise NumbaValueError(msg)
                out_init ="{} = np.full({}, {}, dtype=np.{})\n".format(
                            out_name, shape_name, cval_as_str(cval),
                            return_type_name)
            else:
                out_init ="{} = np.zeros({}, dtype=np.{})\n".format(
                            out_name, shape_name, return_type_name)
            func_text += "    " + out_init
        else: # result is present, if cval is set then use it
            if "cval" in self.options:
                cval = self.options["cval"]
                cval_ty = typing.typeof.typeof(cval)
                if not self._typingctx.can_convert(cval_ty, return_type.dtype):
                    msg = "cval type does not match stencil return type."
                    raise NumbaValueError(msg)
                out_init = "{}[:] = {}\n".format(out_name, cval_as_str(cval))
                func_text += "    " + out_init

        offset = 1
        # Add the loop nests to the new function.
        for i in range(the_array.ndim):
            for j in range(offset):
                func_text += "    "
            # ranges[i][0] is the minimum index used in the i'th dimension
            # but minimum's greater than 0 don't preclude any entry in the array.
            # So, take the minimum of 0 and the minimum index found in the kernel
            # and this will be a negative number (potentially -0).  Then, we do
            # unary - on that to get the positive offset in this dimension whose
            # use is precluded.
            # ranges[i][1] is the maximum of 0 and the observed maximum index
            # in this dimension because negative maximums would not cause us to
            # preclude any entry in the array from being used.
            func_text += ("for {} in range(-min(0,{}),"
                          "{}[{}]-max(0,{})):\n").format(
                            index_vars[i],
                            ranges[i][0],
                            shape_name,
                            i,
                            ranges[i][1])
            offset += 1

        for j in range(offset):
            func_text += "    "
        # Put a sentinel in the code so we can locate it in the IR.  We will
        # remove this sentinel assignment and replace it with the IR for the
        # stencil kernel body.
        func_text += "{} = 0\n".format(sentinel_name)
        func_text += "    return {}\n".format(out_name)

        if config.DEBUG_ARRAY_OPT >= 1:
            print("new stencil func text")
            print(func_text)

        # Force the new stencil function into existence.
        exec(func_text) in globals(), locals()
        stencil_func = eval(stencil_func_name)
        if sigret is not None:
            pysig = utils.pysignature(stencil_func)
            sigret.pysig = pysig
        # Get the IR for the newly created stencil function.
        from numba.core import compiler
        stencil_ir = compiler.run_frontend(stencil_func)
        ir_utils.remove_dels(stencil_ir.blocks)

        # rename all variables in stencil_ir afresh
        var_table = ir_utils.get_name_var_table(stencil_ir.blocks)
        new_var_dict = {}
        reserved_names = ([sentinel_name, out_name, neighborhood_name,
                           shape_name] + kernel_copy.arg_names + index_vars)
        for name, var in var_table.items():
            if not name in reserved_names:
                new_var_dict[name] = ir_utils.mk_unique_var(name)
        ir_utils.replace_var_names(stencil_ir.blocks, new_var_dict)

        stencil_stub_last_label = max(stencil_ir.blocks.keys()) + 1

        # Shift labels in the kernel copy so they are guaranteed unique
        # and don't conflict with any labels in the stencil_ir.
        kernel_copy.blocks = ir_utils.add_offset_to_labels(
                                kernel_copy.blocks, stencil_stub_last_label)
        new_label = max(kernel_copy.blocks.keys()) + 1
        # Adjust ret_blocks to account for addition of the offset.
        ret_blocks = [x + stencil_stub_last_label for x in ret_blocks]

        if config.DEBUG_ARRAY_OPT >= 1:
            print("ret_blocks w/ offsets", ret_blocks, stencil_stub_last_label)
            print("before replace sentinel stencil_ir")
            ir_utils.dump_blocks(stencil_ir.blocks)
            print("before replace sentinel kernel_copy")
            ir_utils.dump_blocks(kernel_copy.blocks)

        # Search all the block in the stencil outline for the sentinel.
        for label, block in stencil_ir.blocks.items():
            for i, inst in enumerate(block.body):
                if (isinstance( inst, ir.Assign) and
                    inst.target.name == sentinel_name):
                    # We found the sentinel assignment.
                    loc = inst.loc
                    scope = block.scope
                    # split block across __sentinel__
                    # A new block is allocated for the statements prior to the
                    # sentinel but the new block maintains the current block
                    # label.
                    prev_block = ir.Block(scope, loc)
                    prev_block.body = block.body[:i]
                    # The current block is used for statements after sentinel.
                    block.body = block.body[i + 1:]
                    # But the current block gets a new label.
                    body_first_label = min(kernel_copy.blocks.keys())

                    # The previous block jumps to the minimum labelled block of
                    # the parfor body.
                    prev_block.append(ir.Jump(body_first_label, loc))
                    # Add all the parfor loop body blocks to the gufunc
                    # function's IR.
                    for (l, b) in kernel_copy.blocks.items():
                        stencil_ir.blocks[l] = b

                    stencil_ir.blocks[new_label] = block
                    stencil_ir.blocks[label] = prev_block
                    # Add a jump from all the blocks that previously contained
                    # a return in the stencil kernel to the block
                    # containing statements after the sentinel.
                    for ret_block in ret_blocks:
                        stencil_ir.blocks[ret_block].append(
                            ir.Jump(new_label, loc))
                    break
            else:
                continue
            break

        stencil_ir.blocks = ir_utils.rename_labels(stencil_ir.blocks)
        ir_utils.remove_dels(stencil_ir.blocks)

        assert(isinstance(the_array, types.Type))
        array_types = args

        new_stencil_param_types = list(array_types)

        if config.DEBUG_ARRAY_OPT >= 1:
            print("new_stencil_param_types", new_stencil_param_types)
            ir_utils.dump_blocks(stencil_ir.blocks)

        # Compile the combined stencil function with the replaced loop
        # body in it.
        ir_utils.fixup_var_define_in_scope(stencil_ir.blocks)
        new_func = compiler.compile_ir(
            self._typingctx,
            self._targetctx,
            stencil_ir,
            new_stencil_param_types,
            None,
            compiler.DEFAULT_FLAGS,
            {})
        return new_func

    def __call__(self, *args, **kwargs):
        if (self.neighborhood is not None and
            len(self.neighborhood) != args[0].ndim):
            raise ValueError("{} dimensional neighborhood specified for {} "
                             "dimensional input array".format(
                                len(self.neighborhood), args[0].ndim))

        if 'out' in kwargs:
            result = kwargs['out']
            rdtype = result.dtype
            rttype = numpy_support.from_dtype(rdtype)
            result_type = types.npytypes.Array(rttype, result.ndim,
                                               numpy_support.map_layout(result))
            array_types = tuple([typing.typeof.typeof(x) for x in args])
            array_types_full = tuple([typing.typeof.typeof(x) for x in args] +
                                     [result_type])
        else:
            result = None
            array_types = tuple([typing.typeof.typeof(x) for x in args])
            array_types_full = array_types

        if config.DEBUG_ARRAY_OPT >= 1:
            print("__call__", array_types, args, kwargs)

        (real_ret, typemap, calltypes) = self.get_return_type(array_types)
        new_func = self._stencil_wrapper(result, None, real_ret, typemap,
                                         calltypes, *array_types_full)

        if result is None:
            return new_func.entry_point(*args)
        else:
            return new_func.entry_point(*(args+(result,)))

def stencil(func_or_mode='constant', **options):
    # called on function without specifying mode style
    if not isinstance(func_or_mode, str):
        mode = 'constant'  # default style
        func = func_or_mode
    else:
        mode = func_or_mode
        func = None

    for option in options:
        if option not in ["cval", "standard_indexing", "neighborhood"]:
            raise ValueError("Unknown stencil option " + option)

    wrapper = _stencil(mode, options)
    if func is not None:
        return wrapper(func)
    return wrapper

def _stencil(mode, options):
    if mode != 'constant':
        raise ValueError("Unsupported mode style " + mode)

    def decorated(func):
        from numba.core import compiler
        kernel_ir = compiler.run_frontend(func)
        return StencilFunc(kernel_ir, mode, options)

    return decorated

@lower_builtin(stencil)
def stencil_dummy_lower(context, builder, sig, args):
    "lowering for dummy stencil calls"
    return lir.Constant(lir.IntType(types.intp.bitwidth), 0)

[((827, 1, 827, 23), 'numba.core.imputils.lower_builtin', 'lower_builtin', ({(827, 15, 827, 22): 'stencil'}, {}), '(stencil)', False, 'from numba.core.imputils import lower_builtin\n'), ((48, 15, 48, 35), 'numba.misc.special.literal_unroll', 'literal_unroll', ({(48, 30, 48, 34): 'args'}, {}), '(args)', False, 'from numba.misc.special import literal_unroll\n'), ((155, 22, 155, 61), 'numba.core.ir_utils.get_tuple_table', 'ir_utils.get_tuple_table', ({(155, 47, 155, 60): 'kernel.blocks'}, {}), '(kernel.blocks)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((348, 45, 354, 19), 'numba.core.typed_passes.type_inference_stage', 'typed_passes.type_inference_stage', ({(349, 16, 349, 31): 'self._typingctx', (350, 16, 350, 31): 'self._targetctx', (351, 16, 351, 30): 'self.kernel_ir', (352, 16, 352, 22): 'argtys', (353, 16, 353, 20): 'None', (354, 16, 354, 18): '{}'}, {}), '(self._typingctx, self._targetctx, self.\n    kernel_ir, argtys, None, {})', False, 'from numba.core import typed_passes\n'), ((359, 19, 360, 70), 'numba.core.types.npytypes.Array', 'types.npytypes.Array', ({(359, 40, 359, 51): 'return_type', (359, 53, 359, 67): 'argtys[0].ndim', (360, 53, 360, 69): 'argtys[0].layout'}, {}), '(return_type, argtys[0].ndim, argtys[0].layout)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((410, 14, 410, 48), 'numba.core.typing.templates.signature', 'signature', ({(410, 24, 410, 32): 'real_ret', (410, 34, 410, 47): '*argtys_extra'}, {}), '(real_ret, *argtys_extra)', False, 'from numba.core.typing.templates import CallableTemplate, signature, infer_global, AbstractTemplate\n'), ((428, 22, 428, 31), 'numba.core.ir.copy', 'ir.copy', ({}, {}), '()', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((431, 36, 431, 53), 'numba.core.ir.blocks.items', 'ir.blocks.items', ({}, {}), '()', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((469, 8, 469, 48), 'numba.core.ir_utils.remove_args', 'ir_utils.remove_args', ({(469, 29, 469, 47): 'kernel_copy.blocks'}, {}), '(kernel_copy.blocks)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((472, 26, 472, 78), 'numba.core.ir_utils.copy_propagate', 'ir_utils.copy_propagate', ({(472, 50, 472, 68): 'kernel_copy.blocks', (472, 70, 472, 77): 'typemap'}, {}), '(kernel_copy.blocks, typemap)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((473, 25, 473, 72), 'numba.core.ir_utils.get_name_var_table', 'ir_utils.get_name_var_table', ({(473, 53, 473, 71): 'kernel_copy.blocks'}, {}), '(kernel_copy.blocks)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((474, 8, 479, 27), 'numba.core.ir_utils.apply_copy_propagate', 'ir_utils.apply_copy_propagate', ({(475, 12, 475, 30): 'kernel_copy.blocks', (476, 12, 476, 18): 'in_cps', (477, 12, 477, 26): 'name_var_table', (478, 12, 478, 19): 'typemap', (479, 12, 479, 26): 'copy_calltypes'}, {}), '(kernel_copy.blocks, in_cps, name_var_table,\n    typemap, copy_calltypes)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((484, 24, 484, 84), 'numba.core.ir_utils.get_unused_var_name', 'ir_utils.get_unused_var_name', ({(484, 53, 484, 67): '"""__sentinel__"""', (484, 69, 484, 83): 'name_var_table'}, {}), "('__sentinel__', name_var_table)", False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((511, 19, 511, 70), 'numba.core.ir_utils.get_unused_var_name', 'ir_utils.get_unused_var_name', ({(511, 48, 511, 53): '"""out"""', (511, 55, 511, 69): 'name_var_table'}, {}), "('out', name_var_table)", False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((512, 28, 513, 72), 'numba.core.ir_utils.get_unused_var_name', 'ir_utils.get_unused_var_name', ({(512, 57, 512, 71): '"""neighborhood"""', (513, 57, 513, 71): 'name_var_table'}, {}), "('neighborhood', name_var_table)", False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((582, 21, 582, 79), 'numba.core.ir_utils.get_unused_var_name', 'ir_utils.get_unused_var_name', ({(582, 50, 582, 62): '"""full_shape"""', (582, 64, 582, 78): 'name_var_table'}, {}), "('full_shape', name_var_table)", False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((670, 21, 670, 56), 'numba.core.compiler.run_frontend', 'compiler.run_frontend', ({(670, 43, 670, 55): 'stencil_func'}, {}), '(stencil_func)', False, 'from numba.core import compiler\n'), ((671, 8, 671, 47), 'numba.core.ir_utils.remove_dels', 'ir_utils.remove_dels', ({(671, 29, 671, 46): 'stencil_ir.blocks'}, {}), '(stencil_ir.blocks)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((674, 20, 674, 66), 'numba.core.ir_utils.get_name_var_table', 'ir_utils.get_name_var_table', ({(674, 48, 674, 65): 'stencil_ir.blocks'}, {}), '(stencil_ir.blocks)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((681, 8, 681, 67), 'numba.core.ir_utils.replace_var_names', 'ir_utils.replace_var_names', ({(681, 35, 681, 52): 'stencil_ir.blocks', (681, 54, 681, 66): 'new_var_dict'}, {}), '(stencil_ir.blocks, new_var_dict)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((687, 29, 688, 76), 'numba.core.ir_utils.add_offset_to_labels', 'ir_utils.add_offset_to_labels', ({(688, 32, 688, 50): 'kernel_copy.blocks', (688, 52, 688, 75): 'stencil_stub_last_label'}, {}), '(kernel_copy.blocks, stencil_stub_last_label)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((740, 28, 740, 69), 'numba.core.ir_utils.rename_labels', 'ir_utils.rename_labels', ({(740, 51, 740, 68): 'stencil_ir.blocks'}, {}), '(stencil_ir.blocks)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((741, 8, 741, 47), 'numba.core.ir_utils.remove_dels', 'ir_utils.remove_dels', ({(741, 29, 741, 46): 'stencil_ir.blocks'}, {}), '(stencil_ir.blocks)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((754, 8, 754, 61), 'numba.core.ir_utils.fixup_var_define_in_scope', 'ir_utils.fixup_var_define_in_scope', ({(754, 43, 754, 60): 'stencil_ir.blocks'}, {}), '(stencil_ir.blocks)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((755, 19, 762, 15), 'numba.core.compiler.compile_ir', 'compiler.compile_ir', ({(756, 12, 756, 27): 'self._typingctx', (757, 12, 757, 27): 'self._targetctx', (758, 12, 758, 22): 'stencil_ir', (759, 12, 759, 35): 'new_stencil_param_types', (760, 12, 760, 16): 'None', (761, 12, 761, 34): 'compiler.DEFAULT_FLAGS', (762, 12, 762, 14): '{}'}, {}), '(self._typingctx, self._targetctx, stencil_ir,\n    new_stencil_param_types, None, compiler.DEFAULT_FLAGS, {})', False, 'from numba.core import compiler\n'), ((822, 20, 822, 47), 'numba.core.compiler.run_frontend', 'compiler.run_frontend', ({(822, 42, 822, 46): 'func'}, {}), '(func)', False, 'from numba.core import compiler\n'), ((830, 24, 830, 56), 'llvmlite.ir.IntType', 'lir.IntType', ({(830, 36, 830, 55): 'types.intp.bitwidth'}, {}), '(types.intp.bitwidth)', True, 'from llvmlite import ir as lir\n'), ((145, 12, 145, 47), 'numba.core.ir_utils.dump_blocks', 'ir_utils.dump_blocks', ({(145, 33, 145, 46): 'kernel.blocks'}, {}), '(kernel.blocks)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((341, 12, 341, 55), 'numba.core.ir_utils.dump_blocks', 'ir_utils.dump_blocks', ({(341, 33, 341, 54): 'self.kernel_ir.blocks'}, {}), '(self.kernel_ir.blocks)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((344, 18, 345, 64), 'numba.core.errors.NumbaValueError', 'NumbaValueError', ({(344, 34, 345, 63): '"""The first argument to a stencil kernel must be the primary input array."""'}, {}), "(\n    'The first argument to a stencil kernel must be the primary input array.')", False, 'from numba.core.errors import NumbaValueError\n'), ((356, 18, 357, 77), 'numba.core.errors.NumbaValueError', 'NumbaValueError', ({(357, 16, 357, 76): '"""Stencil kernel must return a scalar and not a numpy array."""'}, {}), "('Stencil kernel must return a scalar and not a numpy array.')", False, 'from numba.core.errors import NumbaValueError\n'), ((432, 24, 432, 61), 'copy.deepcopy', 'copy.deepcopy', ({(432, 38, 432, 60): 'ir.blocks[block_label]'}, {}), '(ir.blocks[block_label])', False, 'import copy\n'), ((482, 18, 482, 91), 'numba.core.errors.NumbaValueError', 'NumbaValueError', ({(482, 34, 482, 90): '"""Cannot use the reserved word \'out\' in stencil kernels."""'}, {}), '("Cannot use the reserved word \'out\' in stencil kernels.")', False, 'from numba.core.errors import NumbaValueError\n'), ((493, 12, 493, 52), 'numba.core.ir_utils.dump_blocks', 'ir_utils.dump_blocks', ({(493, 33, 493, 51): 'kernel_copy.blocks'}, {}), '(kernel_copy.blocks)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((524, 18, 525, 82), 'numba.core.errors.NumbaValueError', 'NumbaValueError', ({(524, 34, 525, 81): '"""The first argument to a stencil kernel must use relative indexing, not standard indexing."""'}, {}), "(\n    'The first argument to a stencil kernel must use relative indexing, not standard indexing.'\n    )", False, 'from numba.core.errors import NumbaValueError\n'), ((528, 18, 529, 82), 'numba.core.errors.NumbaValueError', 'NumbaValueError', ({(528, 34, 529, 81): '"""Standard indexing requested for an array name not present in the stencil kernel definition."""'}, {}), "(\n    'Standard indexing requested for an array name not present in the stencil kernel definition.'\n    )", False, 'from numba.core.errors import NumbaValueError\n'), ((543, 12, 543, 52), 'numba.core.ir_utils.dump_blocks', 'ir_utils.dump_blocks', ({(543, 33, 543, 51): 'kernel_copy.blocks'}, {}), '(kernel_copy.blocks)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((552, 12, 552, 52), 'numba.core.ir_utils.dump_blocks', 'ir_utils.dump_blocks', ({(552, 33, 552, 51): 'kernel_copy.blocks'}, {}), '(kernel_copy.blocks)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((666, 20, 666, 51), 'numba.core.utils.pysignature', 'utils.pysignature', ({(666, 38, 666, 50): 'stencil_func'}, {}), '(stencil_func)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((696, 12, 696, 51), 'numba.core.ir_utils.dump_blocks', 'ir_utils.dump_blocks', ({(696, 33, 696, 50): 'stencil_ir.blocks'}, {}), '(stencil_ir.blocks)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((698, 12, 698, 52), 'numba.core.ir_utils.dump_blocks', 'ir_utils.dump_blocks', ({(698, 33, 698, 51): 'kernel_copy.blocks'}, {}), '(kernel_copy.blocks)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((750, 12, 750, 51), 'numba.core.ir_utils.dump_blocks', 'ir_utils.dump_blocks', ({(750, 33, 750, 50): 'stencil_ir.blocks'}, {}), '(stencil_ir.blocks)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((775, 21, 775, 53), 'numba.np.numpy_support.from_dtype', 'numpy_support.from_dtype', ({(775, 46, 775, 52): 'rdtype'}, {}), '(rdtype)', False, 'from numba.np import numpy_support\n'), ((307, 22, 308, 67), 'numba.core.errors.NumbaValueError', 'NumbaValueError', ({(307, 38, 308, 66): '"""Stencil kernel with no accesses to relatively indexed arrays."""'}, {}), "('Stencil kernel with no accesses to relatively indexed arrays.'\n    )", False, 'from numba.core.errors import NumbaValueError\n'), ((415, 32, 415, 61), 'numba.core.utils.pysignature', 'utils.pysignature', ({(415, 50, 415, 60): 'dummy_func'}, {}), '(dummy_func)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((440, 24, 440, 43), 'copy.deepcopy', 'copy.deepcopy', ({(440, 38, 440, 42): 'stmt'}, {}), '(stmt)', False, 'import copy\n'), ((587, 19, 587, 36), 'numpy.isfinite', 'np.isfinite', ({(587, 31, 587, 35): 'cval'}, {}), '(cval)', True, 'import numpy as np\n'), ((589, 19, 589, 33), 'numpy.isnan', 'np.isnan', ({(589, 28, 589, 32): 'cval'}, {}), '(cval)', True, 'import numpy as np\n'), ((620, 26, 620, 52), 'numba.core.typing.typeof.typeof', 'typing.typeof.typeof', ({(620, 47, 620, 51): 'cval'}, {}), '(cval)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((680, 37, 680, 65), 'numba.core.ir_utils.mk_unique_var', 'ir_utils.mk_unique_var', ({(680, 60, 680, 64): 'name'}, {}), '(name)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((777, 47, 777, 79), 'numba.np.numpy_support.map_layout', 'numpy_support.map_layout', ({(777, 72, 777, 78): 'result'}, {}), '(result)', False, 'from numba.np import numpy_support\n'), ((332, 26, 333, 77), 'numba.core.errors.NumbaValueError', 'NumbaValueError', ({(333, 24, 333, 76): '"""Stencil index does not match array dimensionality."""'}, {}), "('Stencil index does not match array dimensionality.')", False, 'from numba.core.errors import NumbaValueError\n'), ((591, 21, 591, 35), 'numpy.isinf', 'np.isinf', ({(591, 30, 591, 34): 'cval'}, {}), '(cval)', True, 'import numpy as np\n'), ((603, 31, 604, 49), 'numba.np.numpy_support.as_dtype', 'numpy_support.as_dtype', ({(604, 31, 604, 48): 'return_type.dtype'}, {}), '(return_type.dtype)', False, 'from numba.np import numpy_support\n'), ((607, 40, 607, 66), 'numba.core.typing.typeof.typeof', 'typing.typeof.typeof', ({(607, 61, 607, 65): 'cval'}, {}), '(cval)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((609, 26, 609, 46), 'numba.core.errors.NumbaValueError', 'NumbaValueError', ({(609, 42, 609, 45): 'msg'}, {}), '(msg)', False, 'from numba.core.errors import NumbaValueError\n'), ((623, 26, 623, 46), 'numba.core.errors.NumbaValueError', 'NumbaValueError', ({(623, 42, 623, 45): 'msg'}, {}), '(msg)', False, 'from numba.core.errors import NumbaValueError\n'), ((712, 33, 712, 53), 'numba.core.ir.Block', 'ir.Block', ({(712, 42, 712, 47): 'scope', (712, 49, 712, 52): 'loc'}, {}), '(scope, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((778, 33, 778, 56), 'numba.core.typing.typeof.typeof', 'typing.typeof.typeof', ({(778, 54, 778, 55): 'x'}, {}), '(x)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((783, 33, 783, 56), 'numba.core.typing.typeof.typeof', 'typing.typeof.typeof', ({(783, 54, 783, 55): 'x'}, {}), '(x)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((107, 31, 107, 59), 'numba.core.ir.Var', 'ir.Var', ({(107, 38, 107, 43): 'scope', (107, 45, 107, 53): 'out_name', (107, 55, 107, 58): 'loc'}, {}), '(scope, out_name, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((108, 31, 108, 64), 'numba.core.ir.Var', 'ir.Var', ({(108, 38, 108, 43): 'scope', (108, 45, 108, 58): 'index_vars[0]', (108, 60, 108, 63): 'loc'}, {}), '(scope, index_vars[0], loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((118, 39, 118, 78), 'numba.core.ir_utils.mk_unique_var', 'ir_utils.mk_unique_var', ({(118, 62, 118, 77): '"""stencil_index"""'}, {}), "('stencil_index')", False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((119, 39, 119, 71), 'numba.core.ir.Var', 'ir.Var', ({(119, 46, 119, 51): 'scope', (119, 53, 119, 65): 's_index_name', (119, 67, 119, 70): 'loc'}, {}), '(scope, s_index_name, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((121, 37, 121, 77), 'numba.core.ir.Expr.build_tuple', 'ir.Expr.build_tuple', ({(121, 57, 121, 71): 'var_index_vars', (121, 73, 121, 76): 'loc'}, {}), '(var_index_vars, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((123, 31, 123, 59), 'numba.core.ir.Var', 'ir.Var', ({(123, 38, 123, 43): 'scope', (123, 45, 123, 53): 'out_name', (123, 55, 123, 58): 'loc'}, {}), '(scope, out_name, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((126, 29, 126, 75), 'numba.core.ir.SetItem', 'ir.SetItem', ({(126, 40, 126, 44): 'rvar', (126, 46, 126, 57): 's_index_var', (126, 59, 126, 69): 'stmt.value', (126, 71, 126, 74): 'loc'}, {}), '(rvar, s_index_var, stmt.value, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((212, 36, 212, 70), 'numba.core.ir.Var', 'ir.Var', ({(212, 43, 212, 48): 'scope', (212, 50, 212, 64): 'index_names[0]', (212, 66, 212, 69): 'loc'}, {}), '(scope, index_names[0], loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((213, 34, 213, 73), 'numba.core.ir_utils.mk_unique_var', 'ir_utils.mk_unique_var', ({(213, 57, 213, 72): '"""stencil_index"""'}, {}), "('stencil_index')", False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((214, 34, 214, 61), 'numba.core.ir.Var', 'ir.Var', ({(214, 41, 214, 46): 'scope', (214, 48, 214, 55): 'tmpname', (214, 57, 214, 60): 'loc'}, {}), '(scope, tmpname, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((242, 39, 242, 78), 'numba.core.ir_utils.mk_unique_var', 'ir_utils.mk_unique_var', ({(242, 62, 242, 77): '"""stencil_index"""'}, {}), "('stencil_index')", False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((243, 39, 243, 71), 'numba.core.ir.Var', 'ir.Var', ({(243, 46, 243, 51): 'scope', (243, 53, 243, 65): 's_index_name', (243, 67, 243, 70): 'loc'}, {}), '(scope, s_index_name, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((293, 37, 293, 75), 'numba.core.ir.Expr.build_tuple', 'ir.Expr.build_tuple', ({(293, 57, 293, 69): 'ind_stencils', (293, 71, 293, 74): 'loc'}, {}), '(ind_stencils, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((329, 26, 330, 74), 'numba.core.errors.NumbaValueError', 'NumbaValueError', ({(330, 24, 330, 73): '"""Non-tuple or non-integer used as stencil index."""'}, {}), "('Non-tuple or non-integer used as stencil index.')", False, 'from numba.core.errors import NumbaValueError\n'), ((721, 38, 721, 68), 'numba.core.ir.Jump', 'ir.Jump', ({(721, 46, 721, 62): 'body_first_label', (721, 64, 721, 67): 'loc'}, {}), '(body_first_label, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((779, 38, 779, 61), 'numba.core.typing.typeof.typeof', 'typing.typeof.typeof', ({(779, 59, 779, 60): 'x'}, {}), '(x)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((109, 40, 109, 79), 'numba.core.ir.SetItem', 'ir.SetItem', ({(109, 51, 109, 55): 'rvar', (109, 57, 109, 61): 'ivar', (109, 63, 109, 73): 'stmt.value', (109, 75, 109, 78): 'loc'}, {}), '(rvar, ivar, stmt.value, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((115, 40, 115, 67), 'numba.core.ir.Var', 'ir.Var', ({(115, 47, 115, 52): 'scope', (115, 54, 115, 61): 'one_var', (115, 63, 115, 66): 'loc'}, {}), '(scope, one_var, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((122, 40, 122, 79), 'numba.core.ir.Assign', 'ir.Assign', ({(122, 50, 122, 60): 'tuple_call', (122, 62, 122, 73): 's_index_var', (122, 75, 122, 78): 'loc'}, {}), '(tuple_call, s_index_var, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((221, 38, 221, 64), 'numba.njit', 'numba.njit', ({(221, 49, 221, 63): 'slice_addition'}, {}), '(slice_addition)', False, 'import numba\n'), ((222, 42, 222, 77), 'numba.core.types.functions.Dispatcher', 'types.functions.Dispatcher', ({(222, 69, 222, 76): 'sa_func'}, {}), '(sa_func)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((224, 35, 224, 76), 'numba.core.ir.Global', 'ir.Global', ({(224, 45, 224, 61): '"""slice_addition"""', (224, 63, 224, 70): 'sa_func', (224, 72, 224, 75): 'loc'}, {}), "('slice_addition', sa_func, loc)", False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((226, 50, 226, 108), 'numba.core.ir.Expr.call', 'ir.Expr.call', ({(226, 63, 226, 69): 'sa_var', (226, 71, 226, 98): '[stmt_index_var, index_var]', (226, 100, 226, 102): '()', (226, 104, 226, 107): 'loc'}, {}), '(sa_var, [stmt_index_var, index_var], (), loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((233, 39, 234, 68), 'numba.core.ir.Expr.binop', 'ir.Expr.binop', ({(233, 53, 233, 65): 'operator.add', (233, 67, 233, 81): 'stmt_index_var', (234, 53, 234, 62): 'index_var', (234, 64, 234, 67): 'loc'}, {}), '(operator.add, stmt_index_var, index_var, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((254, 38, 254, 75), 'numba.core.ir_utils.mk_unique_var', 'ir_utils.mk_unique_var', ({(254, 61, 254, 74): '"""const_index"""'}, {}), "('const_index')", False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((255, 38, 255, 65), 'numba.core.ir.Var', 'ir.Var', ({(255, 45, 255, 50): 'scope', (255, 52, 255, 59): 'tmpname', (255, 61, 255, 64): 'loc'}, {}), '(scope, tmpname, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((259, 40, 259, 76), 'numba.core.ir.Var', 'ir.Var', ({(259, 47, 259, 52): 'scope', (259, 54, 259, 70): 'index_names[dim]', (259, 72, 259, 75): 'loc'}, {}), '(scope, index_names[dim], loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((262, 38, 262, 81), 'numba.core.ir_utils.mk_unique_var', 'ir_utils.mk_unique_var', ({(262, 61, 262, 80): '"""ind_stencil_index"""'}, {}), "('ind_stencil_index')", False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((263, 38, 263, 65), 'numba.core.ir.Var', 'ir.Var', ({(263, 45, 263, 50): 'scope', (263, 52, 263, 59): 'tmpname', (263, 61, 263, 64): 'loc'}, {}), '(scope, tmpname, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((265, 42, 265, 75), 'numba.core.ir_utils.mk_unique_var', 'ir_utils.mk_unique_var', ({(265, 65, 265, 74): '"""getitem"""'}, {}), "('getitem')", False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((266, 42, 266, 73), 'numba.core.ir.Var', 'ir.Var', ({(266, 49, 266, 54): 'scope', (266, 56, 266, 67): 'getitemname', (266, 69, 266, 72): 'loc'}, {}), '(scope, getitemname, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((267, 42, 268, 82), 'numba.core.ir.Expr.getitem', 'ir.Expr.getitem', ({(267, 58, 267, 72): 'stmt_index_var', (268, 55, 268, 76): 'const_index_vars[dim]', (268, 78, 268, 81): 'loc'}, {}), '(stmt_index_var, const_index_vars[dim], loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((294, 40, 294, 79), 'numba.core.ir.Assign', 'ir.Assign', ({(294, 50, 294, 60): 'tuple_call', (294, 62, 294, 73): 's_index_var', (294, 75, 294, 78): 'loc'}, {}), '(tuple_call, s_index_var, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((320, 34, 322, 65), 'numba.core.errors.NumbaValueError', 'NumbaValueError', ({(321, 32, 322, 64): '"""stencil kernel index is not constant,\'neighborhood\' option required"""'}, {}), '(\n    "stencil kernel index is not constant,\'neighborhood\' option required")', False, 'from numba.core.errors import NumbaValueError\n'), ((734, 28, 734, 51), 'numba.core.ir.Jump', 'ir.Jump', ({(734, 36, 734, 45): 'new_label', (734, 47, 734, 50): 'loc'}, {}), '(new_label, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((204, 34, 205, 75), 'numba.core.errors.NumbaValueError', 'NumbaValueError', ({(204, 50, 205, 74): '"""stencil kernel index is not constant, \'neighborhood\' option required"""'}, {}), '(\n    "stencil kernel index is not constant, \'neighborhood\' option required")', False, 'from numba.core.errors import NumbaValueError\n'), ((220, 51, 220, 91), 'numba.core.ir_utils.mk_unique_var', 'ir_utils.mk_unique_var', ({(220, 74, 220, 90): '"""slice_addition"""'}, {}), "('slice_addition')", False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((225, 44, 225, 72), 'numba.core.ir.Assign', 'ir.Assign', ({(225, 54, 225, 58): 'g_sa', (225, 60, 225, 66): 'sa_var', (225, 68, 225, 71): 'loc'}, {}), '(g_sa, sa_var, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((228, 44, 228, 87), 'numba.core.ir.Assign', 'ir.Assign', ({(228, 54, 228, 73): 'slice_addition_call', (228, 75, 228, 81): 'tmpvar', (228, 83, 228, 86): 'loc'}, {}), '(slice_addition_call, tmpvar, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((235, 44, 235, 76), 'numba.core.ir.Assign', 'ir.Assign', ({(235, 54, 235, 62): 'acc_call', (235, 64, 235, 70): 'tmpvar', (235, 72, 235, 75): 'loc'}, {}), '(acc_call, tmpvar, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((269, 44, 269, 83), 'numba.core.ir.Assign', 'ir.Assign', ({(269, 54, 269, 65): 'getitemcall', (269, 67, 269, 77): 'getitemvar', (269, 79, 269, 82): 'loc'}, {}), '(getitemcall, getitemvar, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((280, 42, 280, 68), 'numba.njit', 'numba.njit', ({(280, 53, 280, 67): 'slice_addition'}, {}), '(slice_addition)', False, 'import numba\n'), ((281, 46, 281, 81), 'numba.core.types.functions.Dispatcher', 'types.functions.Dispatcher', ({(281, 73, 281, 80): 'sa_func'}, {}), '(sa_func)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((283, 39, 283, 80), 'numba.core.ir.Global', 'ir.Global', ({(283, 49, 283, 65): '"""slice_addition"""', (283, 67, 283, 74): 'sa_func', (283, 76, 283, 79): 'loc'}, {}), "('slice_addition', sa_func, loc)", False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((285, 54, 285, 114), 'numba.core.ir.Expr.call', 'ir.Expr.call', ({(285, 67, 285, 73): 'sa_var', (285, 75, 285, 104): '[getitemvar, index_vars[dim]]', (285, 106, 285, 108): '()', (285, 110, 285, 113): 'loc'}, {}), '(sa_var, [getitemvar, index_vars[dim]], (), loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((289, 43, 290, 78), 'numba.core.ir.Expr.binop', 'ir.Expr.binop', ({(289, 57, 289, 69): 'operator.add', (289, 71, 289, 81): 'getitemvar', (290, 57, 290, 72): 'index_vars[dim]', (290, 74, 290, 77): 'loc'}, {}), '(operator.add, getitemvar, index_vars[dim], loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((296, 34, 296, 83), 'numba.core.ir.Expr.getitem', 'ir.Expr.getitem', ({(296, 50, 296, 66): 'stmt.value.value', (296, 67, 296, 78): 's_index_var', (296, 79, 296, 82): 'loc'}, {}), '(stmt.value.value, s_index_var, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((230, 43, 230, 89), 'numba.core.ir.Expr.getitem', 'ir.Expr.getitem', ({(230, 59, 230, 75): 'stmt.value.value', (230, 77, 230, 83): 'tmpvar', (230, 85, 230, 88): 'loc'}, {}), '(stmt.value.value, tmpvar, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((237, 43, 237, 89), 'numba.core.ir.Expr.getitem', 'ir.Expr.getitem', ({(237, 59, 237, 75): 'stmt.value.value', (237, 77, 237, 83): 'tmpvar', (237, 85, 237, 88): 'loc'}, {}), '(stmt.value.value, tmpvar, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((256, 54, 256, 72), 'numba.core.ir.Const', 'ir.Const', ({(256, 63, 256, 66): 'dim', (256, 68, 256, 71): 'loc'}, {}), '(dim, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((279, 55, 279, 95), 'numba.core.ir_utils.mk_unique_var', 'ir_utils.mk_unique_var', ({(279, 78, 279, 94): '"""slice_addition"""'}, {}), "('slice_addition')", False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((284, 48, 284, 76), 'numba.core.ir.Assign', 'ir.Assign', ({(284, 58, 284, 62): 'g_sa', (284, 64, 284, 70): 'sa_var', (284, 72, 284, 75): 'loc'}, {}), '(g_sa, sa_var, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((287, 48, 287, 91), 'numba.core.ir.Assign', 'ir.Assign', ({(287, 58, 287, 77): 'slice_addition_call', (287, 79, 287, 85): 'tmpvar', (287, 87, 287, 90): 'loc'}, {}), '(slice_addition_call, tmpvar, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n'), ((291, 48, 291, 80), 'numba.core.ir.Assign', 'ir.Assign', ({(291, 58, 291, 66): 'acc_call', (291, 68, 291, 74): 'tmpvar', (291, 76, 291, 79): 'loc'}, {}), '(acc_call, tmpvar, loc)', False, 'from numba.core import types, typing, utils, ir, config, ir_utils, registry\n')]