clover/llvm: Add get_[cl|language]_version, validation and some helpers
authorAaron Watry <awatry@gmail.com>
Sat, 22 Jul 2017 02:43:38 +0000 (21:43 -0500)
committerAaron Watry <awatry@gmail.com>
Wed, 21 Mar 2018 11:59:37 +0000 (06:59 -0500)
Used to calculate the default CLC language version based on the --cl-std in build args
and the device capabilities.

According to section 5.8.4.5 of the 2.0 spec, the CL C version is chosen by:
 1) If you have -cl-std=CL1.1+ use the version specified
 2) If not, use the highest 1.x version that the device supports

Curiously, there is no valid value for -cl-std=CL1.0

Validates requested cl-std against device_clc_version

Signed-off-by: Aaron Watry <awatry@gmail.com>
Reviewed-by: Pierre Moreau <pierre.morrow@free.fr>
v7: (Pierre) Split cl/clc versions into separate lists and
    make more references const.

v6: (Pierre) Add more const and fix some whitespace

v5: (Aaron) Use a collection of cl versions instead of switch cases
    Consolidates the string, numeric version, and clc langstandard::kind

v4: (Pierre) Split get_language_version addition and use into separate patches
    Squash patches that add the helpers and validate the language standard

v3: Change device_version to device_clc_version

v2: (Pierre) Move create_compiler_instance changes to correct patch
    to prevent temporary build breakage.
    Convert version_str into unsigned and use it to find language version
    Add build_error for unknown language version string
    Whitespace fixes

src/gallium/state_trackers/clover/llvm/invocation.cpp

index 0bc0cccc6e7ad5bad5f423f3af9f6228b3a2b4b0..a485380a036d05cad9022e6434aa80059d08311f 100644 (file)
@@ -63,6 +63,34 @@ using ::llvm::Module;
 using ::llvm::raw_string_ostream;
 
 namespace {
+
+    struct cl_version {
+        std::string version_str; // CL Version
+        unsigned version_number; // Numeric CL Version
+    };
+
+   static const unsigned ANY_VERSION = 999;
+   const cl_version cl_versions[] = {
+      { "1.0", 100},
+      { "1.1", 110},
+      { "1.2", 120},
+      { "2.0", 200},
+      { "2.1", 210},
+      { "2.2", 220},
+   };
+
+    struct clc_version_lang_std {
+        unsigned version_number; // CLC Version
+        clang::LangStandard::Kind clc_lang_standard;
+    };
+
+    const clc_version_lang_std cl_version_lang_stds[] = {
+       { 100, clang::LangStandard::lang_opencl10},
+       { 110, clang::LangStandard::lang_opencl11},
+       { 120, clang::LangStandard::lang_opencl12},
+       { 200, clang::LangStandard::lang_opencl20},
+    };
+
    void
    init_targets() {
       static bool targets_initialized = false;
@@ -93,6 +121,66 @@ namespace {
       return ctx;
    }
 
+   const struct clc_version_lang_std&
+   get_cl_lang_standard(unsigned requested, unsigned max = ANY_VERSION) {
+       for (const struct clc_version_lang_std &version : cl_version_lang_stds) {
+           if (version.version_number == max ||
+                   version.version_number == requested) {
+               return version;
+           }
+       }
+       throw build_error("Unknown/Unsupported language version");
+   }
+
+   const struct cl_version&
+   get_cl_version(const std::string &version_str,
+                  unsigned max = ANY_VERSION) {
+      for (const struct cl_version &version : cl_versions) {
+         if (version.version_number == max || version.version_str == version_str) {
+            return version;
+         }
+      }
+      throw build_error("Unknown/Unsupported language version");
+   }
+
+   clang::LangStandard::Kind
+   get_lang_standard_from_version_str(const std::string &version_str,
+                                      bool is_build_opt = false) {
+
+       //Per CL 2.0 spec, section 5.8.4.5:
+       //  If it's an option, use the value directly.
+       //  If it's a device version, clamp to max 1.x version, a.k.a. 1.2
+      const cl_version version =
+         get_cl_version(version_str, is_build_opt ? ANY_VERSION : 120);
+
+      const struct clc_version_lang_std standard =
+         get_cl_lang_standard(version.version_number);
+
+      return standard.clc_lang_standard;
+   }
+
+   clang::LangStandard::Kind
+   get_language_version(const std::vector<std::string> &opts,
+                        const std::string &device_version) {
+
+      const std::string search = "-cl-std=CL";
+
+      for (auto &opt: opts) {
+         auto pos = opt.find(search);
+         if (pos == 0){
+            const auto ver = opt.substr(pos + search.size());
+            const auto device_ver = get_cl_version(device_version);
+            const auto requested = get_cl_version(ver);
+            if (requested.version_number > device_ver.version_number) {
+               throw build_error();
+            }
+            return get_lang_standard_from_version_str(ver, true);
+         }
+      }
+
+      return get_lang_standard_from_version_str(device_version);
+   }
+
    std::unique_ptr<clang::CompilerInstance>
    create_compiler_instance(const device &dev,
                             const std::vector<std::string> &opts,