1from collections import namedtuple
2
3import numpy as np
4
5from llvmlite.llvmpy.core import Type, Builder, ICMP_EQ, Constant
6
7from numba.core import types, cgutils
8from numba.core.compiler_lock import global_compiler_lock
9from numba.core.caching import make_library_cache, NullCache
10
11
12_wrapper_info = namedtuple('_wrapper_info', ['library', 'env', 'name'])
13
14
15def _build_ufunc_loop_body(load, store, context, func, builder, arrays, out,
16                           offsets, store_offset, signature, pyapi, env):
17    elems = load()
18
19    # Compute
20    status, retval = context.call_conv.call_function(builder, func,
21                                                     signature.return_type,
22                                                     signature.args, elems)
23
24    # Store
25    with builder.if_else(status.is_ok, likely=True) as (if_ok, if_error):
26        with if_ok:
27            store(retval)
28        with if_error:
29            gil = pyapi.gil_ensure()
30            context.call_conv.raise_error(builder, pyapi, status)
31            pyapi.gil_release(gil)
32
33    # increment indices
34    for off, ary in zip(offsets, arrays):
35        builder.store(builder.add(builder.load(off), ary.step), off)
36
37    builder.store(builder.add(builder.load(store_offset), out.step),
38                  store_offset)
39
40    return status.code
41
42
43def _build_ufunc_loop_body_objmode(load, store, context, func, builder,
44                                   arrays, out, offsets, store_offset,
45                                   signature, env, pyapi):
46    elems = load()
47
48    # Compute
49    _objargs = [types.pyobject] * len(signature.args)
50    # We need to push the error indicator to avoid it messing with
51    # the ufunc's execution.  We restore it unless the ufunc raised
52    # a new error.
53    with pyapi.err_push(keep_new=True):
54        status, retval = context.call_conv.call_function(builder, func,
55                                                         types.pyobject,
56                                                         _objargs, elems)
57        # Release owned reference to arguments
58        for elem in elems:
59            pyapi.decref(elem)
60    # NOTE: if an error occurred, it will be caught by the Numpy machinery
61
62    # Store
63    store(retval)
64
65    # increment indices
66    for off, ary in zip(offsets, arrays):
67        builder.store(builder.add(builder.load(off), ary.step), off)
68
69    builder.store(builder.add(builder.load(store_offset), out.step),
70                  store_offset)
71
72    return status.code
73
74
75def build_slow_loop_body(context, func, builder, arrays, out, offsets,
76                         store_offset, signature, pyapi, env):
77    def load():
78        elems = [ary.load_direct(builder.load(off))
79                 for off, ary in zip(offsets, arrays)]
80        return elems
81
82    def store(retval):
83        out.store_direct(retval, builder.load(store_offset))
84
85    return _build_ufunc_loop_body(load, store, context, func, builder, arrays,
86                                  out, offsets, store_offset, signature, pyapi,
87                                  env=env)
88
89
90def build_obj_loop_body(context, func, builder, arrays, out, offsets,
91                        store_offset, signature, pyapi, envptr, env):
92    env_body = context.get_env_body(builder, envptr)
93    env_manager = pyapi.get_env_manager(env, env_body, envptr)
94
95    def load():
96        # Load
97        elems = [ary.load_direct(builder.load(off))
98                 for off, ary in zip(offsets, arrays)]
99        # Box
100        elems = [pyapi.from_native_value(t, v, env_manager)
101                 for v, t in zip(elems, signature.args)]
102        return elems
103
104    def store(retval):
105        is_ok = cgutils.is_not_null(builder, retval)
106        # If an error is raised by the object mode ufunc, it will
107        # simply get caught by the Numpy ufunc machinery.
108        with builder.if_then(is_ok, likely=True):
109            # Unbox
110            native = pyapi.to_native_value(signature.return_type, retval)
111            assert native.cleanup is None
112            # Store
113            out.store_direct(native.value, builder.load(store_offset))
114            # Release owned reference
115            pyapi.decref(retval)
116
117    return _build_ufunc_loop_body_objmode(load, store, context, func, builder,
118                                          arrays, out, offsets, store_offset,
119                                          signature, envptr, pyapi)
120
121
122def build_fast_loop_body(context, func, builder, arrays, out, offsets,
123                         store_offset, signature, ind, pyapi, env):
124    def load():
125        elems = [ary.load_aligned(ind)
126                 for ary in arrays]
127        return elems
128
129    def store(retval):
130        out.store_aligned(retval, ind)
131
132    return _build_ufunc_loop_body(load, store, context, func, builder, arrays,
133                                  out, offsets, store_offset, signature, pyapi,
134                                  env=env)
135
136
137def build_ufunc_wrapper(library, context, fname, signature, objmode, cres):
138    """
139    Wrap the scalar function with a loop that iterates over the arguments
140
141    Returns
142    -------
143    (library, env, name)
144    """
145    assert isinstance(fname, str)
146    byte_t = Type.int(8)
147    byte_ptr_t = Type.pointer(byte_t)
148    byte_ptr_ptr_t = Type.pointer(byte_ptr_t)
149    intp_t = context.get_value_type(types.intp)
150    intp_ptr_t = Type.pointer(intp_t)
151
152    fnty = Type.function(Type.void(), [byte_ptr_ptr_t, intp_ptr_t,
153                                       intp_ptr_t, byte_ptr_t])
154
155    wrapperlib = context.codegen().create_library('ufunc_wrapper')
156    wrapper_module = wrapperlib.create_ir_module('')
157    if objmode:
158        func_type = context.call_conv.get_function_type(
159            types.pyobject, [types.pyobject] * len(signature.args))
160    else:
161        func_type = context.call_conv.get_function_type(
162            signature.return_type, signature.args)
163
164    func = wrapper_module.add_function(func_type, name=fname)
165    func.attributes.add("alwaysinline")
166
167    wrapper = wrapper_module.add_function(fnty, "__ufunc__." + func.name)
168    arg_args, arg_dims, arg_steps, arg_data = wrapper.args
169    arg_args.name = "args"
170    arg_dims.name = "dims"
171    arg_steps.name = "steps"
172    arg_data.name = "data"
173
174    builder = Builder(wrapper.append_basic_block("entry"))
175
176    # Prepare Environment
177    envname = context.get_env_name(cres.fndesc)
178    env = cres.environment
179    envptr = builder.load(context.declare_env_global(builder.module, envname))
180
181    # Emit loop
182    loopcount = builder.load(arg_dims, name="loopcount")
183
184    # Prepare inputs
185    arrays = []
186    for i, typ in enumerate(signature.args):
187        arrays.append(UArrayArg(context, builder, arg_args, arg_steps, i, typ))
188
189    # Prepare output
190    out = UArrayArg(context, builder, arg_args, arg_steps, len(arrays),
191                    signature.return_type)
192
193    # Setup indices
194    offsets = []
195    zero = context.get_constant(types.intp, 0)
196    for _ in arrays:
197        p = cgutils.alloca_once(builder, intp_t)
198        offsets.append(p)
199        builder.store(zero, p)
200
201    store_offset = cgutils.alloca_once(builder, intp_t)
202    builder.store(zero, store_offset)
203
204    unit_strided = cgutils.true_bit
205    for ary in arrays:
206        unit_strided = builder.and_(unit_strided, ary.is_unit_strided)
207
208    pyapi = context.get_python_api(builder)
209    if objmode:
210        # General loop
211        gil = pyapi.gil_ensure()
212        with cgutils.for_range(builder, loopcount, intp=intp_t):
213            build_obj_loop_body(
214                context, func, builder, arrays, out, offsets,
215                store_offset, signature, pyapi, envptr, env,
216            )
217        pyapi.gil_release(gil)
218        builder.ret_void()
219
220    else:
221        with builder.if_else(unit_strided) as (is_unit_strided, is_strided):
222            with is_unit_strided:
223                with cgutils.for_range(builder, loopcount, intp=intp_t) as loop:
224                    build_fast_loop_body(
225                        context, func, builder, arrays, out, offsets,
226                        store_offset, signature, loop.index, pyapi,
227                        env=envptr,
228                    )
229
230            with is_strided:
231                # General loop
232                with cgutils.for_range(builder, loopcount, intp=intp_t):
233                    build_slow_loop_body(
234                        context, func, builder, arrays, out, offsets,
235                        store_offset, signature, pyapi,
236                        env=envptr,
237                    )
238
239        builder.ret_void()
240    del builder
241
242    # Link and finalize
243    wrapperlib.add_ir_module(wrapper_module)
244    wrapperlib.add_linking_library(library)
245    return _wrapper_info(library=wrapperlib, env=env, name=wrapper.name)
246
247
248class UArrayArg(object):
249    def __init__(self, context, builder, args, steps, i, fe_type):
250        self.context = context
251        self.builder = builder
252        self.fe_type = fe_type
253        offset = self.context.get_constant(types.intp, i)
254        offseted_args = self.builder.load(builder.gep(args, [offset]))
255        data_type = context.get_data_type(fe_type)
256        self.dataptr = self.builder.bitcast(offseted_args,
257                                            data_type.as_pointer())
258        sizeof = self.context.get_abi_sizeof(data_type)
259        self.abisize = self.context.get_constant(types.intp, sizeof)
260        offseted_step = self.builder.gep(steps, [offset])
261        self.step = self.builder.load(offseted_step)
262        self.is_unit_strided = builder.icmp(ICMP_EQ, self.abisize, self.step)
263        self.builder = builder
264
265    def load_direct(self, byteoffset):
266        """
267        Generic load from the given *byteoffset*.  load_aligned() is
268        preferred if possible.
269        """
270        ptr = cgutils.pointer_add(self.builder, self.dataptr, byteoffset)
271        return self.context.unpack_value(self.builder, self.fe_type, ptr)
272
273    def load_aligned(self, ind):
274        # Using gep() instead of explicit pointer addition helps LLVM
275        # vectorize the loop.
276        ptr = self.builder.gep(self.dataptr, [ind])
277        return self.context.unpack_value(self.builder, self.fe_type, ptr)
278
279    def store_direct(self, value, byteoffset):
280        ptr = cgutils.pointer_add(self.builder, self.dataptr, byteoffset)
281        self.context.pack_value(self.builder, self.fe_type, value, ptr)
282
283    def store_aligned(self, value, ind):
284        ptr = self.builder.gep(self.dataptr, [ind])
285        self.context.pack_value(self.builder, self.fe_type, value, ptr)
286
287
288GufWrapperCache = make_library_cache('guf')
289
290
291class _GufuncWrapper(object):
292    def __init__(self, py_func, cres, sin, sout, cache, is_parfors):
293        """
294        The *is_parfors* argument is a boolean that indicates if the GUfunc
295        being built is to be used as a ParFors kernel. If True, it disables
296        the caching on the wrapper as a separate unit because it will be linked
297        into the caller function and cached along with it.
298        """
299        self.py_func = py_func
300        self.cres = cres
301        self.sin = sin
302        self.sout = sout
303        self.is_objectmode = self.signature.return_type == types.pyobject
304        self.cache = (GufWrapperCache(py_func=self.py_func)
305                      if cache else NullCache())
306        self.is_parfors = bool(is_parfors)
307
308    @property
309    def library(self):
310        return self.cres.library
311
312    @property
313    def context(self):
314        return self.cres.target_context
315
316    @property
317    def call_conv(self):
318        return self.context.call_conv
319
320    @property
321    def signature(self):
322        return self.cres.signature
323
324    @property
325    def fndesc(self):
326        return self.cres.fndesc
327
328    @property
329    def env(self):
330        return self.cres.environment
331
332    def _wrapper_function_type(self):
333        byte_t = Type.int(8)
334        byte_ptr_t = Type.pointer(byte_t)
335        byte_ptr_ptr_t = Type.pointer(byte_ptr_t)
336        intp_t = self.context.get_value_type(types.intp)
337        intp_ptr_t = Type.pointer(intp_t)
338
339        fnty = Type.function(Type.void(), [byte_ptr_ptr_t, intp_ptr_t,
340                                           intp_ptr_t, byte_ptr_t])
341        return fnty
342
343    def _build_wrapper(self, library, name):
344        """
345        The LLVM IRBuilder code to create the gufunc wrapper.
346        The *library* arg is the CodeLibrary to which the wrapper should
347        be added.  The *name* arg is the name of the wrapper function being
348        created.
349        """
350        intp_t = self.context.get_value_type(types.intp)
351        fnty = self._wrapper_function_type()
352
353        wrapper_module = library.create_ir_module('_gufunc_wrapper')
354        func_type = self.call_conv.get_function_type(self.fndesc.restype,
355                                                     self.fndesc.argtypes)
356        fname = self.fndesc.llvm_func_name
357        func = wrapper_module.add_function(func_type, name=fname)
358
359        func.attributes.add("alwaysinline")
360        wrapper = wrapper_module.add_function(fnty, name)
361        # The use of weak_odr linkage avoids the function being dropped due
362        # to the order in which the wrappers and the user function are linked.
363        wrapper.linkage = 'weak_odr'
364        arg_args, arg_dims, arg_steps, arg_data = wrapper.args
365        arg_args.name = "args"
366        arg_dims.name = "dims"
367        arg_steps.name = "steps"
368        arg_data.name = "data"
369
370        builder = Builder(wrapper.append_basic_block("entry"))
371        loopcount = builder.load(arg_dims, name="loopcount")
372        pyapi = self.context.get_python_api(builder)
373
374        # Unpack shapes
375        unique_syms = set()
376        for grp in (self.sin, self.sout):
377            for syms in grp:
378                unique_syms |= set(syms)
379
380        sym_map = {}
381        for syms in self.sin:
382            for s in syms:
383                if s not in sym_map:
384                    sym_map[s] = len(sym_map)
385
386        sym_dim = {}
387        for s, i in sym_map.items():
388            sym_dim[s] = builder.load(builder.gep(arg_dims,
389                                                  [self.context.get_constant(
390                                                      types.intp,
391                                                      i + 1)]))
392
393        # Prepare inputs
394        arrays = []
395        step_offset = len(self.sin) + len(self.sout)
396        for i, (typ, sym) in enumerate(zip(self.signature.args,
397                                           self.sin + self.sout)):
398            ary = GUArrayArg(self.context, builder, arg_args,
399                             arg_steps, i, step_offset, typ, sym, sym_dim)
400            step_offset += len(sym)
401            arrays.append(ary)
402
403        bbreturn = builder.append_basic_block('.return')
404
405        # Prologue
406        self.gen_prologue(builder, pyapi)
407
408        # Loop
409        with cgutils.for_range(builder, loopcount, intp=intp_t) as loop:
410            args = [a.get_array_at_offset(loop.index) for a in arrays]
411            innercall, error = self.gen_loop_body(builder, pyapi, func, args)
412            # If error, escape
413            cgutils.cbranch_or_continue(builder, error, bbreturn)
414
415        builder.branch(bbreturn)
416        builder.position_at_end(bbreturn)
417
418        # Epilogue
419        self.gen_epilogue(builder, pyapi)
420
421        builder.ret_void()
422
423        # Link
424        library.add_ir_module(wrapper_module)
425        library.add_linking_library(self.library)
426
427    def _compile_wrapper(self, wrapper_name):
428        # Gufunc created by Parfors?
429        if self.is_parfors:
430            # No wrapper caching for parfors
431            wrapperlib = self.context.codegen().create_library(str(self))
432            # Build wrapper
433            self._build_wrapper(wrapperlib, wrapper_name)
434        # Non-parfors?
435        else:
436            # Use cache and compiler in a critical section
437            wrapperlib = self.cache.load_overload(
438                self.cres.signature, self.cres.target_context,
439            )
440            if wrapperlib is None:
441                # Create library and enable caching
442                wrapperlib = self.context.codegen().create_library(str(self))
443                wrapperlib.enable_object_caching()
444                # Build wrapper
445                self._build_wrapper(wrapperlib, wrapper_name)
446                # Cache
447                self.cache.save_overload(self.cres.signature, wrapperlib)
448
449        return wrapperlib
450
451    @global_compiler_lock
452    def build(self):
453        wrapper_name = "__gufunc__." + self.fndesc.mangled_name
454        wrapperlib = self._compile_wrapper(wrapper_name)
455        return _wrapper_info(
456            library=wrapperlib, env=self.env, name=wrapper_name,
457        )
458
459    def gen_loop_body(self, builder, pyapi, func, args):
460        status, retval = self.call_conv.call_function(
461            builder, func, self.signature.return_type, self.signature.args,
462            args)
463
464        with builder.if_then(status.is_error, likely=False):
465            gil = pyapi.gil_ensure()
466            self.context.call_conv.raise_error(builder, pyapi, status)
467            pyapi.gil_release(gil)
468
469        return status.code, status.is_error
470
471    def gen_prologue(self, builder, pyapi):
472        pass        # Do nothing
473
474    def gen_epilogue(self, builder, pyapi):
475        pass        # Do nothing
476
477
478class _GufuncObjectWrapper(_GufuncWrapper):
479    def gen_loop_body(self, builder, pyapi, func, args):
480        innercall, error = _prepare_call_to_object_mode(self.context,
481                                                        builder, pyapi, func,
482                                                        self.signature,
483                                                        args)
484        return innercall, error
485
486    def gen_prologue(self, builder, pyapi):
487        # Acquire the GIL
488        self.gil = pyapi.gil_ensure()
489
490    def gen_epilogue(self, builder, pyapi):
491        # Release GIL
492        pyapi.gil_release(self.gil)
493
494
495def build_gufunc_wrapper(py_func, cres, sin, sout, cache, is_parfors):
496    signature = cres.signature
497    wrapcls = (_GufuncObjectWrapper
498               if signature.return_type == types.pyobject
499               else _GufuncWrapper)
500    return wrapcls(
501        py_func, cres, sin, sout, cache, is_parfors=is_parfors,
502    ).build()
503
504
505def _prepare_call_to_object_mode(context, builder, pyapi, func,
506                                 signature, args):
507    mod = builder.module
508
509    bb_core_return = builder.append_basic_block('ufunc.core.return')
510
511    # Call to
512    # PyObject* ndarray_new(int nd,
513    #       npy_intp *dims,   /* shape */
514    #       npy_intp *strides,
515    #       void* data,
516    #       int type_num,
517    #       int itemsize)
518
519    ll_int = context.get_value_type(types.int32)
520    ll_intp = context.get_value_type(types.intp)
521    ll_intp_ptr = Type.pointer(ll_intp)
522    ll_voidptr = context.get_value_type(types.voidptr)
523    ll_pyobj = context.get_value_type(types.pyobject)
524    fnty = Type.function(ll_pyobj, [ll_int, ll_intp_ptr,
525                                    ll_intp_ptr, ll_voidptr,
526                                    ll_int, ll_int])
527
528    fn_array_new = mod.get_or_insert_function(fnty, name="numba_ndarray_new")
529
530    # Convert each llarray into pyobject
531    error_pointer = cgutils.alloca_once(builder, Type.int(1), name='error')
532    builder.store(cgutils.true_bit, error_pointer)
533
534    # The PyObject* arguments to the kernel function
535    object_args = []
536    object_pointers = []
537
538    for i, (arg, argty) in enumerate(zip(args, signature.args)):
539        # Allocate NULL-initialized slot for this argument
540        objptr = cgutils.alloca_once(builder, ll_pyobj, zfill=True)
541        object_pointers.append(objptr)
542
543        if isinstance(argty, types.Array):
544            # Special case arrays: we don't need full-blown NRT reflection
545            # since the argument will be gone at the end of the kernel
546            arycls = context.make_array(argty)
547            array = arycls(context, builder, value=arg)
548
549            zero = Constant.int(ll_int, 0)
550
551            # Extract members of the llarray
552            nd = Constant.int(ll_int, argty.ndim)
553            dims = builder.gep(array._get_ptr_by_name('shape'), [zero, zero])
554            strides = builder.gep(array._get_ptr_by_name('strides'),
555                                  [zero, zero])
556            data = builder.bitcast(array.data, ll_voidptr)
557            dtype = np.dtype(str(argty.dtype))
558
559            # Prepare other info for reconstruction of the PyArray
560            type_num = Constant.int(ll_int, dtype.num)
561            itemsize = Constant.int(ll_int, dtype.itemsize)
562
563            # Call helper to reconstruct PyArray objects
564            obj = builder.call(fn_array_new, [nd, dims, strides, data,
565                                              type_num, itemsize])
566        else:
567            # Other argument types => use generic boxing
568            obj = pyapi.from_native_value(argty, arg)
569
570        builder.store(obj, objptr)
571        object_args.append(obj)
572
573        obj_is_null = cgutils.is_null(builder, obj)
574        builder.store(obj_is_null, error_pointer)
575        cgutils.cbranch_or_continue(builder, obj_is_null, bb_core_return)
576
577    # Call ufunc core function
578    object_sig = [types.pyobject] * len(object_args)
579
580    status, retval = context.call_conv.call_function(
581        builder, func, types.pyobject, object_sig,
582        object_args)
583    builder.store(status.is_error, error_pointer)
584
585    # Release returned object
586    pyapi.decref(retval)
587
588    builder.branch(bb_core_return)
589    # At return block
590    builder.position_at_end(bb_core_return)
591
592    # Release argument objects
593    for objptr in object_pointers:
594        pyapi.decref(builder.load(objptr))
595
596    innercall = status.code
597    return innercall, builder.load(error_pointer)
598
599
600class GUArrayArg(object):
601    def __init__(self, context, builder, args, steps, i, step_offset,
602                 typ, syms, sym_dim):
603
604        self.context = context
605        self.builder = builder
606
607        offset = context.get_constant(types.intp, i)
608
609        data = builder.load(builder.gep(args, [offset], name="data.ptr"),
610                            name="data")
611        self.data = data
612
613        core_step_ptr = builder.gep(steps, [offset], name="core.step.ptr")
614        core_step = builder.load(core_step_ptr)
615
616        if isinstance(typ, types.Array):
617            as_scalar = not syms
618
619            # number of symbol in the shape spec should match the dimension
620            # of the array type.
621            if len(syms) != typ.ndim:
622                if len(syms) == 0 and typ.ndim == 1:
623                    # This is an exception for handling scalar argument.
624                    # The type can be 1D array for scalar.
625                    # In the future, we may deprecate this exception.
626                    pass
627                else:
628                    raise TypeError("type and shape signature mismatch for arg "
629                                    "#{0}".format(i + 1))
630
631            ndim = typ.ndim
632            shape = [sym_dim[s] for s in syms]
633            strides = []
634
635            for j in range(ndim):
636                stepptr = builder.gep(steps,
637                                      [context.get_constant(types.intp,
638                                                            step_offset + j)],
639                                      name="step.ptr")
640                step = builder.load(stepptr)
641                strides.append(step)
642
643            ldcls = (_ArrayAsScalarArgLoader
644                     if as_scalar
645                     else _ArrayArgLoader)
646
647            self._loader = ldcls(dtype=typ.dtype,
648                                 ndim=ndim,
649                                 core_step=core_step,
650                                 as_scalar=as_scalar,
651                                 shape=shape,
652                                 strides=strides)
653        else:
654            # If typ is not an array
655            if syms:
656                raise TypeError("scalar type {0} given for non scalar "
657                                "argument #{1}".format(typ, i + 1))
658            self._loader = _ScalarArgLoader(dtype=typ, stride=core_step)
659
660    def get_array_at_offset(self, ind):
661        return self._loader.load(context=self.context, builder=self.builder,
662                                 data=self.data, ind=ind)
663
664
665class _ScalarArgLoader(object):
666    """
667    Handle GFunc argument loading where a scalar type is used in the core
668    function.
669    Note: It still has a stride because the input to the gufunc can be an array
670          for this argument.
671    """
672
673    def __init__(self, dtype, stride):
674        self.dtype = dtype
675        self.stride = stride
676
677    def load(self, context, builder, data, ind):
678        # Load at base + ind * stride
679        data = builder.gep(data, [builder.mul(ind, self.stride)])
680        dptr = builder.bitcast(data,
681                               context.get_data_type(self.dtype).as_pointer())
682        return builder.load(dptr)
683
684
685class _ArrayArgLoader(object):
686    """
687    Handle GUFunc argument loading where an array is expected.
688    """
689
690    def __init__(self, dtype, ndim, core_step, as_scalar, shape, strides):
691        self.dtype = dtype
692        self.ndim = ndim
693        self.core_step = core_step
694        self.as_scalar = as_scalar
695        self.shape = shape
696        self.strides = strides
697
698    def load(self, context, builder, data, ind):
699        arytyp = types.Array(dtype=self.dtype, ndim=self.ndim, layout="A")
700        arycls = context.make_array(arytyp)
701
702        array = arycls(context, builder)
703        offseted_data = cgutils.pointer_add(builder,
704                                            data,
705                                            builder.mul(self.core_step,
706                                                        ind))
707
708        shape, strides = self._shape_and_strides(context, builder)
709
710        itemsize = context.get_abi_sizeof(context.get_data_type(self.dtype))
711        context.populate_array(array,
712                               data=builder.bitcast(offseted_data,
713                                                    array.data.type),
714                               shape=shape,
715                               strides=strides,
716                               itemsize=context.get_constant(types.intp,
717                                                             itemsize),
718                               meminfo=None)
719
720        return array._getvalue()
721
722    def _shape_and_strides(self, context, builder):
723        shape = cgutils.pack_array(builder, self.shape)
724        strides = cgutils.pack_array(builder, self.strides)
725        return shape, strides
726
727
728class _ArrayAsScalarArgLoader(_ArrayArgLoader):
729    """
730    Handle GUFunc argument loading where the shape signature specifies
731    a scalar "()" but a 1D array is used for the type of the core function.
732    """
733
734    def _shape_and_strides(self, context, builder):
735        # Set shape and strides for a 1D size 1 array
736        one = context.get_constant(types.intp, 1)
737        zero = context.get_constant(types.intp, 0)
738        shape = cgutils.pack_array(builder, [one])
739        strides = cgutils.pack_array(builder, [zero])
740        return shape, strides
741