From 93438027704e49dec7cccca9ce76fd1f78cfd4b2 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Wed, 27 Dec 2017 17:27:37 -0600 Subject: [PATCH 1/3] Make unknown dtypes 'None' rather than lp.auto, uniformly across ArrayBase subclasses and ValueArg --- loopy/kernel/array.py | 105 ++++++++++++++++++++++------------------ loopy/kernel/data.py | 21 ++++++-- loopy/preprocess.py | 5 +- loopy/type_inference.py | 15 ++---- 4 files changed, 81 insertions(+), 65 deletions(-) diff --git a/loopy/kernel/array.py b/loopy/kernel/array.py index 5d4240b9a..34f58e286 100644 --- a/loopy/kernel/array.py +++ b/loopy/kernel/array.py @@ -549,15 +549,55 @@ class ArrayBase(ImmutableRecord): .. attribute :: name .. attribute :: dtype + the :class:`loopy.loopytype` of the array. + if this is *none*, :mod:`loopy` will try to continue without + knowing the type of this array, where the idea is that precise + knowledge of the type will become available at invocation time. + :class:`loopy.compiledkernel` (and thereby + :meth:`loopy.loopkernel.__call__`) automatically add this type + information based on invocation arguments. + + note that some transformations, such as :func:`loopy.add_padding` + cannot be performed without knowledge of the exact *dtype*. .. attribute :: shape + May be one of the following: + + * *None*. In this case, no shape is intended to be specified, + only the strides will be used to access the array. Bounds checking + will not be performed. + + * :class:`loopy.auto`. The shape will be determined by finding the + access footprint. + + * a tuple like like :attr:`numpy.ndarray.shape`. + + Each entry of the tuple is also allowed to be a :mod:`pymbolic` + expression involving kernel parameters, or a (potentially-comma + separated) or a string that can be parsed to such an expression. + + Any element of the shape tuple not used to compute strides + may be *None*. + .. attribute:: dim_tags See :ref:`data-dim-tags`. .. attribute:: offset + Offset from the beginning of the buffer to the point from + which the strides are counted. May be one of + + * 0 or None + * a string (that is interpreted as an argument name). + * a pymbolic expression + * :class:`loopy.auto`, in which case an offset argument + is added automatically, immediately following this argument. + :class:`loopy.CompiledKernel` is even smarter in its treatment of + this case and will compile custom versions of the kernel based on + whether the passed arrays have offsets or not. + .. attribute:: dim_names A tuple of strings providing names for the array axes, or *None*. @@ -590,40 +630,12 @@ class ArrayBase(ImmutableRecord): All of the following (except *name*) are optional. Specify either strides or shape. - :arg name: May contain multiple names separated by - commas, in which case multiple arguments, - each with identical properties, are created - for each name. - :arg dtype: the :class:`numpy.dtype` of the array. - If this is *None*, :mod:`loopy` will try to continue without - knowing the type of this array, where the idea is that precise - knowledge of the type will become available at invocation time. - :class:`loopy.CompiledKernel` (and thereby - :meth:`loopy.LoopKernel.__call__`) automatically add this type - information based on invocation arguments. - - Note that some transformations, such as :func:`loopy.add_padding` - cannot be performed without knowledge of the exact *dtype*. - - :arg shape: May be one of the following: + :arg name: When passed to :class:`loopy.make_kernel`, this may contain + multiple names separated by commas, in which case multiple arguments, + each with identical properties, are created for each name. - * *None*. In this case, no shape is intended to be specified, - only the strides will be used to access the array. Bounds checking - will not be performed. - - * :class:`loopy.auto`. The shape will be determined by finding the - access footprint. - - * a tuple like like :attr:`numpy.ndarray.shape`. - - Each entry of the tuple is also allowed to be a :mod:`pymbolic` - expression involving kernel parameters, or a (potentially-comma - separated) or a string that can be parsed to such an expression. - - Any element of the shape tuple not used to compute strides - may be *None*. - - * A string which can be parsed into the previous form. + :arg shape: May be any of the things specified under :attr:`shape`, + or a string which can be parsed into the previous form. :arg dim_tags: A comma-separated list of tags as understood by :func:`parse_array_dim_tag`. @@ -649,17 +661,8 @@ class ArrayBase(ImmutableRecord): :arg for_atomic: Whether the array is declared for atomic access, and, if necessary, using atomic-capable data types. - :arg offset: Offset from the beginning of the buffer to the point from - which the strides are counted. May be one of + :arg offset: (See :attr:`offset`) - * 0 or None - * a string (that is interpreted as an argument name). - * a pymbolic expression - * :class:`loopy.auto`, in which case an offset argument - is added automatically, immediately following this argument. - :class:`loopy.CompiledKernel` is even smarter in its treatment of - this case and will compile custom versions of the kernel based on - whether the passed arrays have offsets or not. """ for kwarg_name in kwargs: @@ -672,6 +675,14 @@ class ArrayBase(ImmutableRecord): dtype = to_loopy_type(dtype, allow_auto=True, allow_none=True, for_atomic=for_atomic, target=target) + if dtype is lp.auto: + from warnings import warn + warn("Argument/temporary data type should be None if unspecified, " + "not auto. This usage will be disallowed in 2018.", + DeprecationWarning, stacklevel=2) + + dtype = None + strides_known = strides is not None and strides is not lp.auto shape_known = shape is not None and shape is not lp.auto @@ -832,10 +843,10 @@ class ArrayBase(ImmutableRecord): if include_typename: info_entries.append(type(self).__name__) - if self.dtype is lp.auto: - type_str = "" - elif self.dtype is None: - type_str = "" + assert self.dtype is not lp.auto + + if self.dtype is None: + type_str = "" else: type_str = str(self.dtype) diff --git a/loopy/kernel/data.py b/loopy/kernel/data.py index a4e6036cb..63f5ce711 100644 --- a/loopy/kernel/data.py +++ b/loopy/kernel/data.py @@ -219,9 +219,20 @@ class KernelArgument(ImmutableRecord): dtype = kwargs.pop("dtype", None) from loopy.types import to_loopy_type - kwargs["dtype"] = to_loopy_type( + dtype = to_loopy_type( dtype, allow_auto=True, allow_none=True, target=target) + import loopy as lp + if dtype is lp.auto: + from warnings import warn + warn("Argument/temporary data type should be None if unspecified, " + "not auto. This usage will be disallowed in 2018.", + DeprecationWarning, stacklevel=2) + + dtype = None + + kwargs["dtype"] = dtype + ImmutableRecord.__init__(self, **kwargs) @@ -268,10 +279,10 @@ class ValueArg(KernelArgument): def __str__(self): import loopy as lp - if self.dtype is lp.auto: - type_str = "" - elif self.dtype is None: - type_str = "" + assert self.dtype is not lp.auto + + if self.dtype is None: + type_str = "" else: type_str = str(self.dtype) diff --git a/loopy/preprocess.py b/loopy/preprocess.py index f2b5e7a87..ad119e94e 100644 --- a/loopy/preprocess.py +++ b/loopy/preprocess.py @@ -797,11 +797,10 @@ def _hackily_ensure_multi_assignment_return_values_are_scoped_private(kernel): newly_added_assignments_ids.add(new_assignment_id) - import loopy as lp new_temporaries[new_assignee_name] = ( TemporaryVariable( name=new_assignee_name, - dtype=lp.auto, + dtype=None, scope=temp_var_scope.PRIVATE)) from pymbolic import var @@ -987,7 +986,7 @@ def realize_reduction(kernel, insn_id_filter=None, unknown_types_ok=True, new_temporary_variables[name] = TemporaryVariable( name=name, shape=(), - dtype=lp.auto, + dtype=None, scope=temp_var_scope.PRIVATE) from pymbolic import var diff --git a/loopy/type_inference.py b/loopy/type_inference.py index 0f58ae64e..fcf8f965b 100644 --- a/loopy/type_inference.py +++ b/loopy/type_inference.py @@ -312,15 +312,8 @@ class TypeInferenceMapper(CombineMapper): from loopy.kernel.data import TemporaryVariable, KernelArgument import loopy as lp - if isinstance(obj, TemporaryVariable): - result = [obj.dtype] - if result[0] is lp.auto: - self.symbols_with_unknown_types.add(expr.name) - return [] - else: - return result - - elif isinstance(obj, KernelArgument): + if isinstance(obj, (KernelArgument, TemporaryVariable)): + assert obj.dtype is not lp.auto result = [obj.dtype] if result[0] is None: self.symbols_with_unknown_types.add(expr.name) @@ -515,10 +508,12 @@ def infer_unknown_types(kernel, expect_completion=False): import loopy as lp for tv in six.itervalues(kernel.temporary_variables): - if tv.dtype is lp.auto: + assert tv.dtype is not lp.auto + if tv.dtype is None: names_for_type_inference.append(tv.name) for arg in kernel.args: + assert arg.dtype is not lp.auto if arg.dtype is None: names_for_type_inference.append(arg.name) -- GitLab From 2c9486ffb15da0c28afbe388ab8666044ed1f8de Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Wed, 27 Dec 2017 17:28:46 -0600 Subject: [PATCH 2/3] Improve error reporting in to_loopy_type for allow_{auto,none}=False --- loopy/types.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/loopy/types.py b/loopy/types.py index f095d1d58..8f0f310c3 100644 --- a/loopy/types.py +++ b/loopy/types.py @@ -177,13 +177,20 @@ class AtomicNumpyType(NumpyType, AtomicType): # }}} -def to_loopy_type(dtype, allow_none=False, allow_auto=False, for_atomic=False, +def to_loopy_type(dtype, allow_auto=False, allow_none=False, for_atomic=False, target=None): from loopy.kernel.data import auto - if allow_none and dtype is None: - return dtype - elif allow_auto and dtype is auto: - return dtype + if dtype is None: + if allow_none: + return None + else: + raise LoopyError("dtype may not be none") + + elif dtype is auto: + if allow_auto: + return dtype + else: + raise LoopyError("dtype may not be auto") numpy_dtype = None -- GitLab From 9bf4a8928c069ae0a38825c46b715c145d183944 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Wed, 27 Dec 2017 18:34:28 -0600 Subject: [PATCH 3/3] Fix doctests for auto/runtime unification --- doc/tutorial.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/tutorial.rst b/doc/tutorial.rst index 69f895486..7196dad86 100644 --- a/doc/tutorial.rst +++ b/doc/tutorial.rst @@ -111,9 +111,9 @@ always see loopy's view of a kernel by printing it. KERNEL: loopy_kernel --------------------------------------------------------------------------- ARGUMENTS: - a: GlobalArg, type: , shape: (n), dim_tags: (N0:stride:1) - n: ValueArg, type: - out: GlobalArg, type: , shape: (n), dim_tags: (N0:stride:1) + a: GlobalArg, type: , shape: (n), dim_tags: (N0:stride:1) + n: ValueArg, type: + out: GlobalArg, type: , shape: (n), dim_tags: (N0:stride:1) --------------------------------------------------------------------------- DOMAINS: [n] -> { [i] : 0 <= i < n } @@ -154,7 +154,7 @@ following: See :ref:`specifying-arguments`. * Loopy has not determined the type of ``a`` and ``out``. The data type is - given as ````, which means that these types will be determined + given as ````, which means that these types will be determined by the data passed in when the kernel is invoked. Loopy generates (and caches!) a copy of the kernel for each combination of types passed in. -- GitLab