From 6475c9fb99547ff1a820f92c680e7724a6f18831 Mon Sep 17 00:00:00 2001
From: Andreas Kloeckner <inform@tiker.net>
Date: Tue, 6 Feb 2018 17:46:05 -0600
Subject: [PATCH] Allow lang version setting with LOOPY_KERNEL_LANGUAGE_VERSION
 global in make_kernel caller's global space

---
 examples/python/hello-loopy.py       |  6 ++--
 loopy/frontend/fortran/translator.py |  2 ++
 loopy/kernel/creation.py             | 43 ++++++++++++++++++++--------
 loopy/version.py                     |  8 ++++--
 test/test_apps.py                    |  3 ++
 test/test_c_execution.py             |  3 ++
 test/test_dg.py                      |  3 ++
 test/test_diff.py                    |  3 ++
 test/test_domain.py                  |  3 ++
 test/test_linalg.py                  |  3 ++
 test/test_loopy.py                   | 16 +++++------
 test/test_misc.py                    |  3 ++
 test/test_nbody.py                   |  3 ++
 test/test_numa_diff.py               |  3 ++
 test/test_reduction.py               |  3 ++
 test/test_scan.py                    |  3 ++
 test/test_sem_reagan.py              |  3 ++
 test/test_statistics.py              |  3 ++
 test/test_target.py                  |  3 ++
 test/test_transform.py               |  3 ++
 20 files changed, 95 insertions(+), 25 deletions(-)

diff --git a/examples/python/hello-loopy.py b/examples/python/hello-loopy.py
index e7ab13c16..da1273d2b 100644
--- a/examples/python/hello-loopy.py
+++ b/examples/python/hello-loopy.py
@@ -8,6 +8,9 @@ import pyopencl.array
 ctx = cl.create_some_context()
 queue = cl.CommandQueue(ctx)
 
+# for make_kernel calls from this file
+LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+
 n = 15 * 10**6
 a = cl.array.arange(queue, n, dtype=np.float32)
 
@@ -15,8 +18,7 @@ a = cl.array.arange(queue, n, dtype=np.float32)
 # ------
 knl = lp.make_kernel(
         "{ [i]: 0<=i<n }",
-        "out[i] = 2*a[i]",
-        lang_version=(2018, 1))
+        "out[i] = 2*a[i]")
 
 # transform
 # ---------
diff --git a/loopy/frontend/fortran/translator.py b/loopy/frontend/fortran/translator.py
index e801d09dc..bcbe41874 100644
--- a/loopy/frontend/fortran/translator.py
+++ b/loopy/frontend/fortran/translator.py
@@ -708,6 +708,7 @@ class F2LoopyTranslator(FTreeWalkerBase):
 
             # }}}
 
+            from loopy.version import MOST_RECENT_LANGUAGE_VERSION
             knl = lp.make_kernel(
                     sub.index_sets,
                     sub.instructions,
@@ -717,6 +718,7 @@ class F2LoopyTranslator(FTreeWalkerBase):
                     index_dtype=self.index_dtype,
                     target=self.target,
                     seq_dependencies=seq_dependencies,
+                    lang_version=MOST_RECENT_LANGUAGE_VERSION
                     )
 
             from loopy.loop import fuse_loop_domains
diff --git a/loopy/kernel/creation.py b/loopy/kernel/creation.py
index 15cb29c22..f43bf8490 100644
--- a/loopy/kernel/creation.py
+++ b/loopy/kernel/creation.py
@@ -1920,6 +1920,11 @@ def make_kernel(domains, instructions, kernel_data=["..."], **kwargs):
         If not given, this value defaults to version **(2017, 2, 1)** and
         a warning will be issued.
 
+        If this is impractical, you may also place a global variable
+        ``LOOPY_KERNEL_LANGUAGE_VERSION`` in the global namespace of the
+        function calling :func:`make_kernel`. If *lang_version* is not
+        explicitly given, that its value will be used.
+
         See also :ref:`language-versioning`.
 
     .. versionchanged:: 2017.2.1
@@ -1972,18 +1977,32 @@ def make_kernel(domains, instructions, kernel_data=["..."], **kwargs):
 
     lang_version = kwargs.pop("lang_version", None)
     if lang_version is None:
-        from warnings import warn
-        from loopy.diagnostic import LoopyWarning
-        from loopy.version import (
-                MOST_RECENT_LANGUAGE_VERSION,
-                FALLBACK_LANGUAGE_VERSION)
-        warn("'lang_version' was not passed to make_kernel(). "
-                "To avoid this warning, pass "
-                "lang_version=%r in this invocation."
-                % (MOST_RECENT_LANGUAGE_VERSION,),
-                LoopyWarning, stacklevel=2)
-
-        lang_version = FALLBACK_LANGUAGE_VERSION
+        # {{{ peek into caller's module to look for LOOPY_KERNEL_LANGUAGE_VERSION
+
+        # This *is* gross. But it seems like the right thing interface-wise.
+        import inspect
+        caller_globals = inspect.currentframe().f_back.f_globals
+
+        try:
+            lang_version = caller_globals["LOOPY_KERNEL_LANGUAGE_VERSION"]
+        except KeyError:
+            pass
+
+        # }}}
+
+        if lang_version is None:
+            from warnings import warn
+            from loopy.diagnostic import LoopyWarning
+            from loopy.version import (
+                    MOST_RECENT_LANGUAGE_VERSION,
+                    FALLBACK_LANGUAGE_VERSION)
+            warn("'lang_version' was not passed to make_kernel(). "
+                    "To avoid this warning, pass "
+                    "lang_version=%r in this invocation."
+                    % (MOST_RECENT_LANGUAGE_VERSION,),
+                    LoopyWarning, stacklevel=2)
+
+            lang_version = FALLBACK_LANGUAGE_VERSION
 
     if lang_version >= (2018, 1):
         options = options.copy(enforce_check_variable_access_ordered=True)
diff --git a/loopy/version.py b/loopy/version.py
index 21c920ce4..49dca90fe 100644
--- a/loopy/version.py
+++ b/loopy/version.py
@@ -62,8 +62,12 @@ break existing programs, kernels now have to declare support for a given
 language version to let them take advantage of this check.
 
 As a result, :mod:`loopy` will now issue a warning when a call to
-:func:`loopy.make_kernel` does not declare a language version. Such kernels will
-(indefinitely) default to language version 2017.2.1.
+:func:`loopy.make_kernel` does not declare a language version. Such kernels
+will (indefinitely) default to language version 2017.2.1.  If passing a
+language version to :func:`make_kernel` is impractical, you may also place a
+global variable ``LOOPY_KERNEL_LANGUAGE_VERSION`` in the global namespace of
+the function calling :func:`make_kernel`. If *lang_version* is not explicitly
+given, that its value will be used.
 
 Language versions will generally reflect the version number of :mod:`loopy` in
 which they were introduced, though it is possible that some versions of
diff --git a/test/test_apps.py b/test/test_apps.py
index c4844d3a3..55eecdf2b 100644
--- a/test/test_apps.py
+++ b/test/test_apps.py
@@ -49,6 +49,9 @@ __all__ = [
         ]
 
 
+LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+
+
 # {{{ convolutions
 
 def test_convolution(ctx_factory):
diff --git a/test/test_c_execution.py b/test/test_c_execution.py
index d1b3c95ca..582f3a105 100644
--- a/test/test_c_execution.py
+++ b/test/test_c_execution.py
@@ -40,6 +40,9 @@ else:
     faulthandler.enable()
 
 
+LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+
+
 def test_c_target():
     from loopy.target.c import ExecutableCTarget
 
diff --git a/test/test_dg.py b/test/test_dg.py
index ef4a31373..6688362aa 100644
--- a/test/test_dg.py
+++ b/test/test_dg.py
@@ -34,6 +34,9 @@ from pyopencl.tools import (  # noqa
         pytest_generate_tests_for_pyopencl as pytest_generate_tests)
 
 
+LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+
+
 def test_dg_volume(ctx_factory):
     #logging.basicConfig(level=logging.DEBUG)
 
diff --git a/test/test_diff.py b/test/test_diff.py
index 95471f9b1..8a4fe9587 100644
--- a/test/test_diff.py
+++ b/test/test_diff.py
@@ -48,6 +48,9 @@ __all__ = [
         ]
 
 
+LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+
+
 def test_diff(ctx_factory):
     ctx = ctx_factory()
     queue = cl.CommandQueue(ctx)
diff --git a/test/test_domain.py b/test/test_domain.py
index 9d0379a50..d8a83007a 100644
--- a/test/test_domain.py
+++ b/test/test_domain.py
@@ -52,6 +52,9 @@ __all__ = [
         ]
 
 
+LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+
+
 def test_assume(ctx_factory):
     ctx = ctx_factory()
 
diff --git a/test/test_linalg.py b/test/test_linalg.py
index 3d422f1d8..7eba5facb 100644
--- a/test/test_linalg.py
+++ b/test/test_linalg.py
@@ -62,6 +62,9 @@ def check_float4(result, ref_result):
                 ref_result[comp], result[comp], rtol=1e-3, atol=1e-3), None
 
 
+LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+
+
 def test_axpy(ctx_factory):
     logging.basicConfig(level="INFO")
     ctx = ctx_factory()
diff --git a/test/test_loopy.py b/test/test_loopy.py
index 02002c5cd..d9bc3d271 100644
--- a/test/test_loopy.py
+++ b/test/test_loopy.py
@@ -52,6 +52,9 @@ __all__ = [
         ]
 
 
+LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+
+
 def test_globals_decl_once_with_multi_subprogram(ctx_factory):
     ctx = ctx_factory()
     queue = cl.CommandQueue(ctx)
@@ -67,8 +70,7 @@ def test_globals_decl_once_with_multi_subprogram(ctx_factory):
             [lp.TemporaryVariable(
                 'cnst', shape=('n'), initializer=cnst,
                 scope=lp.temp_var_scope.GLOBAL,
-                read_only=True), '...'],
-            lang_version=(2018, 1))
+                read_only=True), '...'])
     knl = lp.fix_parameters(knl, n=16)
     knl = lp.add_barrier(knl, "id:first", "id:second")
 
@@ -89,8 +91,7 @@ def test_complicated_subst(ctx_factory):
                 h(x) := 1 + g(x) + 20*g$two(x)
 
                 a[i] = h$one(i) * h$two(i)
-                """,
-            lang_version=(2018, 1))
+                """)
 
     knl = lp.expand_subst(knl, "... > id:h and tag:two > id:g and tag:two")
 
@@ -121,8 +122,7 @@ def test_type_inference_no_artificial_doubles(ctx_factory):
                 lp.GlobalArg("c", np.float32, shape=("n",)),
                 lp.ValueArg("n", np.int32),
                 ],
-            assumptions="n>=1",
-            lang_version=(2018, 1))
+            assumptions="n>=1")
 
     knl = lp.preprocess_kernel(knl, ctx.devices[0])
     for k in lp.generate_loop_schedules(knl):
@@ -142,9 +142,7 @@ def test_type_inference_with_type_dependencies():
             c = b + c
             <>d = b + 2 + 1j
             """,
-            "...",
-            lang_version=(2018, 1))
-
+            "...")
     knl = lp.infer_unknown_types(knl)
 
     from loopy.types import to_loopy_type
diff --git a/test/test_misc.py b/test/test_misc.py
index 0273948b3..c1ae6c532 100644
--- a/test/test_misc.py
+++ b/test/test_misc.py
@@ -32,6 +32,9 @@ import logging
 logger = logging.getLogger(__name__)
 
 
+LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+
+
 def test_compute_sccs():
     from loopy.tools import compute_sccs
     import random
diff --git a/test/test_nbody.py b/test/test_nbody.py
index e118b04b9..f231dfd5b 100644
--- a/test/test_nbody.py
+++ b/test/test_nbody.py
@@ -34,6 +34,9 @@ import logging
 logger = logging.getLogger(__name__)
 
 
+LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+
+
 def test_nbody(ctx_factory):
     logging.basicConfig(level=logging.INFO)
 
diff --git a/test/test_numa_diff.py b/test/test_numa_diff.py
index eff3dbd0e..a5c69020a 100644
--- a/test/test_numa_diff.py
+++ b/test/test_numa_diff.py
@@ -44,6 +44,9 @@ __all__ = [
         ]
 
 
+LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+
+
 @pytest.mark.parametrize("Nq", [7])
 @pytest.mark.parametrize("ilp_multiple", [1, 2])
 @pytest.mark.parametrize("opt_level", [11])
diff --git a/test/test_reduction.py b/test/test_reduction.py
index 909a800b2..1ddbbfebf 100644
--- a/test/test_reduction.py
+++ b/test/test_reduction.py
@@ -49,6 +49,9 @@ __all__ = [
         ]
 
 
+LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+
+
 def test_nonsense_reduction(ctx_factory):
     ctx = ctx_factory()
 
diff --git a/test/test_scan.py b/test/test_scan.py
index 08754819c..228453fd8 100644
--- a/test/test_scan.py
+++ b/test/test_scan.py
@@ -56,6 +56,9 @@ __all__ = [
 # - scan(a) + scan(b)
 # - test for badly tagged inames
 
+LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+
+
 @pytest.mark.parametrize("n", [1, 2, 3, 16])
 @pytest.mark.parametrize("stride", [1, 2])
 def test_sequential_scan(ctx_factory, n, stride):
diff --git a/test/test_sem_reagan.py b/test/test_sem_reagan.py
index 0571e4191..a92f2b2ab 100644
--- a/test/test_sem_reagan.py
+++ b/test/test_sem_reagan.py
@@ -31,6 +31,9 @@ from pyopencl.tools import (  # noqa
         pytest_generate_tests_for_pyopencl as pytest_generate_tests)
 
 
+LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+
+
 def test_tim2d(ctx_factory):
     dtype = np.float32
     ctx = ctx_factory()
diff --git a/test/test_statistics.py b/test/test_statistics.py
index eeb4a5a28..9427a4edf 100644
--- a/test/test_statistics.py
+++ b/test/test_statistics.py
@@ -34,6 +34,9 @@ import numpy as np
 from pymbolic.primitives import Variable
 
 
+LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+
+
 def test_op_counter_basic():
 
     knl = lp.make_kernel(
diff --git a/test/test_target.py b/test/test_target.py
index d3cf2670c..8fd565a81 100644
--- a/test/test_target.py
+++ b/test/test_target.py
@@ -52,6 +52,9 @@ __all__ = [
         ]
 
 
+LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+
+
 def test_ispc_target(occa_mode=False):
     from loopy.target.ispc import ISPCTarget
 
diff --git a/test/test_transform.py b/test/test_transform.py
index 0e10db362..feb8bf9df 100644
--- a/test/test_transform.py
+++ b/test/test_transform.py
@@ -49,6 +49,9 @@ __all__ = [
         ]
 
 
+LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+
+
 def test_chunk_iname(ctx_factory):
     ctx = ctx_factory()
 
-- 
GitLab