From 93438027704e49dec7cccca9ce76fd1f78cfd4b2 Mon Sep 17 00:00:00 2001
From: Andreas Kloeckner <inform@tiker.net>
Date: Wed, 27 Dec 2017 17:27:37 -0600
Subject: [PATCH] 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 = "<auto>"
-        elif self.dtype is None:
-            type_str = "<runtime>"
+        assert self.dtype is not lp.auto
+
+        if self.dtype is None:
+            type_str = "<auto/runtime>"
         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 = "<auto>"
-        elif self.dtype is None:
-            type_str = "<runtime>"
+        assert self.dtype is not lp.auto
+
+        if self.dtype is None:
+            type_str = "<auto/runtime>"
         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