Example #1
0
    def _construct_args(self, kwargs) -> Tuple[Tuple[Any], Tuple[Any]]:
        """ Main function that controls argument construction for calling
            the C prototype of the SDFG.

            Organizes arguments first by `sdfg.arglist`, then data descriptors
            by alphabetical order, then symbols by alphabetical order.
        """
        # Return value initialization (for values that have not been given)
        self._initialize_return_values(kwargs)
        if self._return_arrays is not None:
            if len(self._retarray_shapes) == 1:
                kwargs[self._retarray_shapes[0][0]] = self._return_arrays
            else:
                for desc, arr in zip(self._retarray_shapes,
                                     self._return_arrays):
                    kwargs[desc[0]] = arr

        # Argument construction
        sig = self._sig
        typedict = self._typedict
        if len(kwargs) > 0:
            # Construct mapping from arguments to signature
            arglist = []
            argtypes = []
            argnames = []
            for a in sig:
                try:
                    arglist.append(kwargs[a])
                    argtypes.append(typedict[a])
                    argnames.append(a)
                except KeyError:
                    raise KeyError("Missing program argument \"{}\"".format(a))
        else:
            arglist = []
            argtypes = []
            argnames = []
            sig = []
        # Type checking
        for i, (a, arg, atype) in enumerate(zip(argnames, arglist, argtypes)):
            if not dtypes.is_array(arg) and isinstance(atype, dt.Array):
                if isinstance(arg, list):
                    print('WARNING: Casting list argument "%s" to ndarray' % a)
                elif arg is None:
                    # None values are passed as null pointers
                    pass
                else:
                    raise TypeError(
                        'Passing an object (type %s) to an array in argument "%s"'
                        % (type(arg).__name__, a))
            elif dtypes.is_array(arg) and not isinstance(atype, dt.Array):
                # GPU scalars are pointers, so this is fine
                if atype.storage != dtypes.StorageType.GPU_Global:
                    raise TypeError(
                        'Passing an array to a scalar (type %s) in argument "%s"'
                        % (atype.dtype.ctype, a))
            elif not isinstance(atype, dt.Array) and not isinstance(
                    atype.dtype, dtypes.callback) and not isinstance(
                        arg,
                        (atype.dtype.type,
                         sp.Basic)) and not (isinstance(arg, symbolic.symbol)
                                             and arg.dtype == atype.dtype):
                if isinstance(arg, int) and atype.dtype.type == np.int64:
                    pass
                elif isinstance(arg, float) and atype.dtype.type == np.float64:
                    pass
                elif (isinstance(arg, int) and atype.dtype.type == np.int32
                      and abs(arg) <= (1 << 31) - 1):
                    pass
                elif (isinstance(arg, int) and atype.dtype.type == np.uint32
                      and arg >= 0 and arg <= (1 << 32) - 1):
                    pass
                else:
                    warnings.warn(
                        f'Casting scalar argument "{a}" from {type(arg).__name__} to {atype.dtype.type}'
                    )
                    arglist[i] = atype.dtype.type(arg)
            elif (isinstance(atype, dt.Array) and isinstance(arg, np.ndarray)
                  and atype.dtype.as_numpy_dtype() != arg.dtype):
                # Make exception for vector types
                if (isinstance(atype.dtype, dtypes.vector)
                        and atype.dtype.vtype.as_numpy_dtype() == arg.dtype):
                    pass
                else:
                    print(
                        'WARNING: Passing %s array argument "%s" to a %s array'
                        % (arg.dtype, a, atype.dtype.type.__name__))
            elif (isinstance(atype, dt.Array) and isinstance(arg, np.ndarray)
                  and arg.base is not None and not '__return' in a
                  and not Config.get_bool('compiler', 'allow_view_arguments')):
                raise TypeError(
                    f'Passing a numpy view (e.g., sub-array or "A.T") "{a}" to DaCe '
                    'programs is not allowed in order to retain analyzability. '
                    'Please make a copy with "numpy.copy(...)". If you know what '
                    'you are doing, you can override this error in the '
                    'configuration by setting compiler.allow_view_arguments '
                    'to True.')

        # Explicit casting
        for index, (arg, argtype) in enumerate(zip(arglist, argtypes)):
            # Call a wrapper function to make NumPy arrays from pointers.
            if isinstance(argtype.dtype, dtypes.callback):
                arglist[index] = argtype.dtype.get_trampoline(arg, kwargs)
            # List to array
            elif isinstance(arg, list) and isinstance(argtype, dt.Array):
                arglist[index] = np.array(arg, dtype=argtype.dtype.type)
            # Null pointer
            elif arg is None and isinstance(argtype, dt.Array):
                arglist[index] = ctypes.c_void_p(0)

        # Retain only the element datatype for upcoming checks and casts
        arg_ctypes = [t.dtype.as_ctypes() for t in argtypes]

        sdfg = self._sdfg

        # Obtain SDFG constants
        constants = sdfg.constants

        # Remove symbolic constants from arguments
        callparams = tuple(
            (arg, actype, atype, aname) for arg, actype, atype, aname in zip(
                arglist, arg_ctypes, argtypes, argnames)
            if not symbolic.issymbolic(arg) or (
                hasattr(arg, 'name') and arg.name not in constants))

        # Replace symbols with their values
        callparams = tuple(
            (actype(arg.get()) if isinstance(arg, symbolic.symbol) else arg,
             actype, atype, aname) for arg, actype, atype, aname in callparams)

        # Construct init args, which only consist of the symbols
        symbols = self._free_symbols
        initargs = tuple(
            actype(arg) if (not isinstance(arg, ctypes._SimpleCData)) else arg
            for arg, actype, atype, aname in callparams if aname in symbols)

        # Replace arrays with their base host/device pointers
        newargs = tuple(
            (ctypes.c_void_p(_array_interface_ptr(arg, atype)), actype,
             atype) if dtypes.is_array(arg) else (arg, actype, atype)
            for arg, actype, atype, _ in callparams)

        try:
            newargs = tuple(
                actype(arg) if (
                    not isinstance(arg, ctypes._SimpleCData)) else arg
                for arg, actype, atype in newargs)
        except TypeError:
            # Pinpoint bad argument
            for i, (arg, actype, _) in enumerate(newargs):
                try:
                    if not isinstance(arg, ctypes._SimpleCData):
                        actype(arg)
                except TypeError as ex:
                    raise TypeError(
                        f'Invalid type for scalar argument "{callparams[i][3]}": {ex}'
                    )

        self._lastargs = newargs, initargs
        return self._lastargs
Example #2
0
    def _construct_args(self, kwargs) -> Tuple[Tuple[Any], Tuple[Any]]:
        """ Main function that controls argument construction for calling
            the C prototype of the SDFG.

            Organizes arguments first by `sdfg.arglist`, then data descriptors
            by alphabetical order, then symbols by alphabetical order.
        """
        # Return value initialization (for values that have not been given)
        self._initialize_return_values(kwargs)
        if self._return_arrays is not None:
            if len(self._retarray_shapes) == 1:
                kwargs[self._retarray_shapes[0][0]] = self._return_arrays
            else:
                for desc, arr in zip(self._retarray_shapes,
                                     self._return_arrays):
                    kwargs[desc[0]] = arr

        # Argument construction
        sig = self._sig
        typedict = self._typedict
        if len(kwargs) > 0:
            # Construct mapping from arguments to signature
            arglist = []
            argtypes = []
            argnames = []
            for a in sig:
                try:
                    arglist.append(kwargs[a])
                    argtypes.append(typedict[a])
                    argnames.append(a)
                except KeyError:
                    raise KeyError("Missing program argument \"{}\"".format(a))
        else:
            arglist = []
            argtypes = []
            argnames = []
            sig = []
        # Type checking
        for a, arg, atype in zip(argnames, arglist, argtypes):
            if not dtypes.is_array(arg) and isinstance(atype, dt.Array):
                if isinstance(arg, list):
                    print('WARNING: Casting list argument "%s" to ndarray' % a)
                else:
                    raise TypeError(
                        'Passing an object (type %s) to an array in argument "%s"'
                        % (type(arg).__name__, a))
            elif dtypes.is_array(arg) and not isinstance(atype, dt.Array):
                # GPU scalars are pointers, so this is fine
                if atype.storage != dtypes.StorageType.GPU_Global:
                    raise TypeError(
                        'Passing an array to a scalar (type %s) in argument "%s"'
                        % (atype.dtype.ctype, a))
            elif not isinstance(atype, dt.Array) and not isinstance(
                    atype.dtype, dtypes.callback) and not isinstance(
                        arg,
                        (atype.dtype.type,
                         sp.Basic)) and not (isinstance(arg, symbolic.symbol)
                                             and arg.dtype == atype.dtype):
                if isinstance(arg, int) and atype.dtype.type == np.int64:
                    pass
                elif isinstance(arg, float) and atype.dtype.type == np.float64:
                    pass
                elif (isinstance(arg, int) and atype.dtype.type == np.int32
                      and abs(arg) <= (1 << 31) - 1):
                    pass
                elif (isinstance(arg, int) and atype.dtype.type == np.uint32
                      and arg >= 0 and arg <= (1 << 32) - 1):
                    pass
                else:
                    print(
                        'WARNING: Casting scalar argument "%s" from %s to %s' %
                        (a, type(arg).__name__, atype.dtype.type))
            elif (isinstance(atype, dt.Array) and isinstance(arg, np.ndarray)
                  and atype.dtype.as_numpy_dtype() != arg.dtype):
                # Make exception for vector types
                if (isinstance(atype.dtype, dtypes.vector)
                        and atype.dtype.vtype.as_numpy_dtype() == arg.dtype):
                    pass
                else:
                    print(
                        'WARNING: Passing %s array argument "%s" to a %s array'
                        % (arg.dtype, a, atype.dtype.type.__name__))

        # Explicit casting
        for index, (arg, argtype) in enumerate(zip(arglist, argtypes)):
            # Call a wrapper function to make NumPy arrays from pointers.
            if isinstance(argtype.dtype, dtypes.callback):
                arglist[index] = argtype.dtype.get_trampoline(arg, kwargs)
            # List to array
            elif isinstance(arg, list) and isinstance(argtype, dt.Array):
                arglist[index] = np.array(arg, dtype=argtype.dtype.type)

        # Retain only the element datatype for upcoming checks and casts
        arg_ctypes = [t.dtype.as_ctypes() for t in argtypes]

        sdfg = self._sdfg

        # Obtain SDFG constants
        constants = sdfg.constants

        # Remove symbolic constants from arguments
        callparams = tuple(
            (arg, actype, atype)
            for arg, actype, atype in zip(arglist, arg_ctypes, argtypes)
            if not symbolic.issymbolic(arg) or (
                hasattr(arg, 'name') and arg.name not in constants))

        # Replace symbols with their values
        callparams = tuple(
            (actype(arg.get()), actype,
             atype) if isinstance(arg, symbolic.symbol) else (arg, actype,
                                                              atype)
            for arg, actype, atype in callparams)

        # Replace arrays with their base host/device pointers
        newargs = tuple(
            (ctypes.c_void_p(_array_interface_ptr(arg, atype)), actype,
             atype) if dtypes.is_array(arg) else (arg, actype, atype)
            for arg, actype, atype in callparams)

        initargs = tuple(atup for atup in callparams
                         if not dtypes.is_array(atup[0]))

        newargs = tuple(
            actype(arg) if (not isinstance(arg, ctypes._SimpleCData)) else arg
            for arg, actype, atype in newargs)

        initargs = tuple(
            actype(arg) if (not isinstance(arg, ctypes._SimpleCData)) else arg
            for arg, actype, atype in initargs)

        self._lastargs = newargs, initargs
        return self._lastargs
Example #3
0
    def _construct_args(self, **kwargs):
        """ Main function that controls argument construction for calling
            the C prototype of the SDFG.

            Organizes arguments first by `sdfg.arglist`, then data descriptors
            by alphabetical order, then symbols by alphabetical order.
        """
        # Return value initialization (for values that have not been given)
        kwargs.update({
            k: v
            for k, v in self._initialize_return_values(kwargs).items()
            if k not in kwargs
        })

        # Argument construction
        sig = self._sdfg.signature_arglist(with_types=False)
        typedict = self._sdfg.arglist()
        if len(kwargs) > 0:
            # Construct mapping from arguments to signature
            arglist = []
            argtypes = []
            argnames = []
            for a in sig:
                try:
                    arglist.append(kwargs[a])
                    argtypes.append(typedict[a])
                    argnames.append(a)
                except KeyError:
                    raise KeyError("Missing program argument \"{}\"".format(a))
        else:
            arglist = []
            argtypes = []
            argnames = []
            sig = []

        # Type checking
        for a, arg, atype in zip(argnames, arglist, argtypes):
            if not dtypes.is_array(arg) and isinstance(atype, dt.Array):
                raise TypeError(
                    'Passing an object (type %s) to an array in argument "%s"'
                    % (type(arg).__name__, a))
            elif dtypes.is_array(arg) and not isinstance(atype, dt.Array):
                raise TypeError(
                    'Passing an array to a scalar (type %s) in argument "%s"' %
                    (atype.dtype.ctype, a))
            elif not isinstance(atype, dt.Array) and not isinstance(
                    atype.dtype, dace.callback) and not isinstance(
                        arg,
                        (atype.dtype.type,
                         sp.Basic)) and not (isinstance(arg, symbolic.symbol)
                                             and arg.dtype == atype.dtype):
                if isinstance(arg, int) and atype.dtype.type == np.int64:
                    pass
                elif isinstance(arg, float) and atype.dtype.type == np.float64:
                    pass
                else:
                    print(
                        'WARNING: Casting scalar argument "%s" from %s to %s' %
                        (a, type(arg).__name__, atype.dtype.type))
            elif (isinstance(atype, dt.Array) and isinstance(arg, np.ndarray)
                  and atype.dtype.as_numpy_dtype() != arg.dtype):
                # Make exception for vector types
                if (isinstance(atype.dtype, dtypes.vector)
                        and atype.dtype.vtype.as_numpy_dtype() != arg.dtype):
                    print(
                        'WARNING: Passing %s array argument "%s" to a %s array'
                        % (arg.dtype, a, atype.dtype.type.__name__))

        # Call a wrapper function to make NumPy arrays from pointers.
        for index, (arg, argtype) in enumerate(zip(arglist, argtypes)):
            if isinstance(argtype.dtype, dace.callback):
                arglist[index] = argtype.dtype.get_trampoline(arg, kwargs)

        # Retain only the element datatype for upcoming checks and casts
        arg_ctypes = [t.dtype.as_ctypes() for t in argtypes]

        sdfg = self._sdfg

        # Obtain SDFG constants
        constants = sdfg.constants

        # Remove symbolic constants from arguments
        callparams = tuple(
            (arg, actype, atype)
            for arg, actype, atype in zip(arglist, arg_ctypes, argtypes)
            if not symbolic.issymbolic(arg) or (
                hasattr(arg, 'name') and arg.name not in constants))

        # Replace symbols with their values
        callparams = tuple(
            (actype(arg.get()), actype,
             atype) if isinstance(arg, symbolic.symbol) else (arg, actype,
                                                              atype)
            for arg, actype, atype in callparams)

        # Replace arrays with their base host/device pointers
        newargs = tuple(
            (ctypes.c_void_p(_array_interface_ptr(arg, atype)), actype,
             atype) if dtypes.is_array(arg) else (arg, actype, atype)
            for arg, actype, atype in callparams)

        newargs = tuple(
            actype(arg) if (not isinstance(arg, ctypes._SimpleCData)) else arg
            for arg, actype, atype in newargs)

        self._lastargs = newargs
        return self._lastargs