diff --git a/clang/include/clang/Basic/OpenCLExtensions.def b/clang/include/clang/Basic/OpenCLExtensions.def --- a/clang/include/clang/Basic/OpenCLExtensions.def +++ b/clang/include/clang/Basic/OpenCLExtensions.def @@ -10,19 +10,25 @@ // //===----------------------------------------------------------------------===// -// Macro OPENCLEXT or OPENCLEXT_INTERNAL can be defined to enumerate the +// Macro OPENCLEXTNAME or OPENCL_GENERIC_EXTENSION can be defined to enumerate all // OpenCL extensions listed in this file. // -// If the extensions are to be enumerated without the supported OpenCL version, -// define OPENCLEXT(ext) where ext is the name of the extension. -// -// If the extensions are to be enumerated with supported OpenCL version, -// define OPENCLEXT_INTERNAL(ext, avail, core) where +// If extensions are to be enumerated with information about whether +// an extension is core or optional core and minimum OpenCL version +// when an extension becomes available, +// define OPENCL_GENERIC_EXTENSION(ext, avail, core, opt) where // ext - name of the extension or optional core feature. // avail - minimum OpenCL version supporting it. -// core - minimum OpenCL version when the extension becomes optional core -// feature or core feature. ~0U indicates not a core feature or an -// optional core feature. +// core - OpenCL versions mask when the extension becomes core feature. +// 0U indicates not a core feature. +// opt - OpenCL versions mask when the extension becomes optional core +// feature. 0U indicates not a optional core feature. +// +// If extensions are to be enumerated without any information, +// define OPENCLEXTNAME(ext) where ext is the name of the extension. +// +// Difference between optional core feature and core feature is that the +// later is unconditionally supported in specific OpenCL version. // // As per The OpenCL Extension Specification, Section 1.2, in this file, an // extension is defined if and only it either: @@ -32,63 +38,72 @@ // For such an extension, a preprocessor #define that matches the extension // name must be created and a #pragma is required if and only if the // compilation flow is impacted, e.g. due to a difference of syntax or -// semantics in the language compared to the core standard. +// semantics in the language compared to the core standard. #pragma directive +// has no effect for optional core and core features. -#ifndef OPENCLEXT_INTERNAL -#ifndef OPENCLEXT -#pragma error "macro OPENCLEXT or OPENCLEXT_INTERNAL is required" +#ifndef OPENCL_GENERIC_EXTENSION +#ifndef OPENCLEXTNAME +#pragma error "macro OPENCLEXTNAME or OPENCL_GENERIC_EXTENSION is required" #else -#define OPENCLEXT_INTERNAL(ext, ...) OPENCLEXT(ext) -#endif // OPENCLEXT -#endif // OPENCLEXT_INTERNAL +#define OPENCL_GENERIC_EXTENSION(ext, ...) OPENCLEXTNAME(ext) +#endif // OPENCLEXTNAME +#endif // OPENCL_GENERIC_EXTENSION + +// Declaration helpers +#define OPENCL_EXTENSION(ext, avail) OPENCL_GENERIC_EXTENSION(ext, avail, 0U, 0U) +#define OPENCL_COREFEATURE(ext, avail, core) OPENCL_GENERIC_EXTENSION(ext, avail, core, 0U) +#define OPENCL_OPTIONALCOREFEATURE(ext, avail, opt) OPENCL_GENERIC_EXTENSION(ext, avail, 0U, opt) // OpenCL 1.0. -OPENCLEXT_INTERNAL(cl_khr_3d_image_writes, 100, 200) -OPENCLEXT_INTERNAL(cl_khr_byte_addressable_store, 100, 110) -OPENCLEXT_INTERNAL(cl_khr_fp16, 100, ~0U) -OPENCLEXT_INTERNAL(cl_khr_fp64, 100, 120) -OPENCLEXT_INTERNAL(cl_khr_global_int32_base_atomics, 100, 110) -OPENCLEXT_INTERNAL(cl_khr_global_int32_extended_atomics, 100, 110) -OPENCLEXT_INTERNAL(cl_khr_local_int32_base_atomics, 100, 110) -OPENCLEXT_INTERNAL(cl_khr_local_int32_extended_atomics, 100, 110) -OPENCLEXT_INTERNAL(cl_khr_int64_base_atomics, 100, ~0U) -OPENCLEXT_INTERNAL(cl_khr_int64_extended_atomics, 100, ~0U) +OPENCL_COREFEATURE(cl_khr_byte_addressable_store, 100, OCL_C_11P) +OPENCL_COREFEATURE(cl_khr_global_int32_base_atomics, 100, OCL_C_11P) +OPENCL_COREFEATURE(cl_khr_global_int32_extended_atomics, 100, OCL_C_11P) +OPENCL_COREFEATURE(cl_khr_local_int32_base_atomics, 100, OCL_C_11P) +OPENCL_COREFEATURE(cl_khr_local_int32_extended_atomics, 100, OCL_C_11P) +OPENCL_OPTIONALCOREFEATURE(cl_khr_fp64, 100, OCL_C_12P) +OPENCL_EXTENSION(cl_khr_fp16, 100) +OPENCL_EXTENSION(cl_khr_int64_base_atomics, 100) +OPENCL_EXTENSION(cl_khr_int64_extended_atomics, 100) +OPENCL_GENERIC_EXTENSION(cl_khr_3d_image_writes, 100, OCL_C_20, OCL_C_30) // EMBEDDED_PROFILE -OPENCLEXT_INTERNAL(cles_khr_int64, 110, ~0U) +OPENCL_EXTENSION(cles_khr_int64, 110) // OpenCL 1.2. -OPENCLEXT_INTERNAL(cl_khr_depth_images, 120, ~0U) -OPENCLEXT_INTERNAL(cl_khr_gl_msaa_sharing, 120, ~0U) +OPENCL_EXTENSION(cl_khr_depth_images, 120) +OPENCL_EXTENSION(cl_khr_gl_msaa_sharing, 120) // OpenCL 2.0. -OPENCLEXT_INTERNAL(cl_khr_mipmap_image, 200, ~0U) -OPENCLEXT_INTERNAL(cl_khr_mipmap_image_writes, 200, ~0U) -OPENCLEXT_INTERNAL(cl_khr_srgb_image_writes, 200, ~0U) -OPENCLEXT_INTERNAL(cl_khr_subgroups, 200, ~0U) +OPENCL_EXTENSION(cl_khr_mipmap_image, 200) +OPENCL_EXTENSION(cl_khr_mipmap_image_writes, 200) +OPENCL_EXTENSION(cl_khr_srgb_image_writes, 200) +OPENCL_EXTENSION(cl_khr_subgroups, 200) // Clang Extensions. -OPENCLEXT_INTERNAL(cl_clang_storage_class_specifiers, 100, ~0U) -OPENCLEXT_INTERNAL(__cl_clang_function_pointers, 100, ~0U) -OPENCLEXT_INTERNAL(__cl_clang_variadic_functions, 100, ~0U) +OPENCL_EXTENSION(cl_clang_storage_class_specifiers, 100) +OPENCL_EXTENSION(__cl_clang_function_pointers, 100) +OPENCL_EXTENSION(__cl_clang_variadic_functions, 100) // AMD OpenCL extensions -OPENCLEXT_INTERNAL(cl_amd_media_ops, 100, ~0U) -OPENCLEXT_INTERNAL(cl_amd_media_ops2, 100, ~0U) +OPENCL_EXTENSION(cl_amd_media_ops, 100) +OPENCL_EXTENSION(cl_amd_media_ops2, 100) // ARM OpenCL extensions -OPENCLEXT_INTERNAL(cl_arm_integer_dot_product_int8, 120, ~0U) -OPENCLEXT_INTERNAL(cl_arm_integer_dot_product_accumulate_int8, 120, ~0U) -OPENCLEXT_INTERNAL(cl_arm_integer_dot_product_accumulate_int16, 120, ~0U) -OPENCLEXT_INTERNAL(cl_arm_integer_dot_product_accumulate_saturate_int8, 120, ~0U) +OPENCL_EXTENSION(cl_arm_integer_dot_product_int8, 120) +OPENCL_EXTENSION(cl_arm_integer_dot_product_accumulate_int8, 120) +OPENCL_EXTENSION(cl_arm_integer_dot_product_accumulate_int16, 120) +OPENCL_EXTENSION(cl_arm_integer_dot_product_accumulate_saturate_int8, 120) // Intel OpenCL extensions -OPENCLEXT_INTERNAL(cl_intel_subgroups, 120, ~0U) -OPENCLEXT_INTERNAL(cl_intel_subgroups_short, 120, ~0U) -OPENCLEXT_INTERNAL(cl_intel_device_side_avc_motion_estimation, 120, ~0U) +OPENCL_EXTENSION(cl_intel_subgroups, 120) +OPENCL_EXTENSION(cl_intel_subgroups_short, 120) +OPENCL_EXTENSION(cl_intel_device_side_avc_motion_estimation, 120) + -#undef OPENCLEXT_INTERNAL +#undef OPENCL_OPTIONALCOREFEATURE +#undef OPENCL_COREFEATURE +#undef OPENCL_GENERIC_EXTENSION -#ifdef OPENCLEXT -#undef OPENCLEXT +#ifdef OPENCLEXTNAME +#undef OPENCLEXTNAME #endif diff --git a/clang/include/clang/Basic/OpenCLOptions.h b/clang/include/clang/Basic/OpenCLOptions.h --- a/clang/include/clang/Basic/OpenCLOptions.h +++ b/clang/include/clang/Basic/OpenCLOptions.h @@ -19,155 +19,145 @@ namespace clang { +namespace { +// This enum maps OpenCL version(s) into value. These values are used as +// a mask to indicate in which OpenCL version(s) extension is a core or +// optional core feature. +enum OpenCLVersionID : unsigned int { + OCL_C_10 = 0x1, + OCL_C_11 = 0x2, + OCL_C_12 = 0x4, + OCL_C_20 = 0x8, + OCL_C_30 = 0x10, + OCL_C_ALL = 0x1f, + OCL_C_11P = OCL_C_ALL ^ OCL_C_10, // OpenCL C 1.1+ + OCL_C_12P = OCL_C_ALL ^ (OCL_C_10 | OCL_C_11), // OpenCL C 1.2+ +}; + +static inline OpenCLVersionID encodeOpenCLVersion(unsigned OpenCLVersion) { + switch (OpenCLVersion) { + default: + llvm_unreachable("Unknown OpenCL version code"); + case 100: + return OCL_C_10; + case 110: + return OCL_C_11; + case 120: + return OCL_C_12; + case 200: + return OCL_C_20; + case 300: + return OCL_C_30; + } +} + +// Simple helper to check if OpenCL C version is contained in a given encoded +// OpenCL C version mask +static inline bool isOpenCLVersionIsContainedInMask(const LangOptions &LO, + unsigned Mask) { + auto CLVer = LO.OpenCLCPlusPlus ? 200 : LO.OpenCLVersion; + OpenCLVersionID Code = encodeOpenCLVersion(CLVer); + return Mask & Code; +} +} // end anonymous namespace + /// OpenCL supported extensions and optional core features class OpenCLOptions { - struct Info { - bool Supported; // Is this option supported - bool Enabled; // Is this option enabled - unsigned Avail; // Option starts to be available in this OpenCL version - unsigned Core; // Option becomes (optional) core feature in this OpenCL - // version - Info(bool S = false, bool E = false, unsigned A = 100, unsigned C = ~0U) - :Supported(S), Enabled(E), Avail(A), Core(C){} - }; - llvm::StringMap OptMap; public: - /// Check if \c Ext is a recognized OpenCL extension. - /// - /// \param Ext - Extension to look up. - /// \returns \c true if \c Ext is known, \c false otherwise. - bool isKnown(llvm::StringRef Ext) const { - return OptMap.find(Ext) != OptMap.end(); - } + struct OpenCLOptionInfo { + // Option starts to be available in this OpenCL version + unsigned Avail; - /// Check if \c Ext is an enabled OpenCL extension. - /// - /// \param Ext - Extension to look up. - /// \returns \c true if \c Ext is known and enabled, \c false otherwise. - bool isEnabled(llvm::StringRef Ext) const { - auto E = OptMap.find(Ext); - return E != OptMap.end() && E->second.Enabled; - } + // Option becomes core feature in this OpenCL versions + unsigned Core; + + // Option becomes optional core feature in this OpenCL versions + unsigned Opt; + + // Is this option supported + bool Supported = false; - /// Check if \c Ext is supported as either an extension or an (optional) core - /// feature for the given OpenCL version. - /// - /// \param Ext - Extension to look up. - /// \param LO - \c LangOptions specifying the OpenCL version. - /// \returns \c true if \c Ext is known and supported, \c false otherwise. - bool isSupported(llvm::StringRef Ext, const LangOptions &LO) const { - auto E = OptMap.find(Ext); - if (E == OptMap.end()) { - return false; + // Is this option enabled + bool Enabled = false; + + OpenCLOptionInfo(unsigned A = 100, unsigned C = 0U, unsigned O = 0U) + : Avail(A), Core(C), Opt(O) {} + + bool isCore() const { return Core != 0U; } + + bool isOptionalCore() const { return Opt != 0U; } + + // Is option available in OpenCL version \p LO. + bool isAvailableIn(const LangOptions &LO) const { + // In C++ mode all extensions should work at least as in v2.0. + auto CLVer = LO.OpenCLCPlusPlus ? 200 : LO.OpenCLVersion; + return CLVer >= Avail; } - // In C++ mode all extensions should work at least as in v2.0. - auto CLVer = LO.OpenCLCPlusPlus ? 200 : LO.OpenCLVersion; - auto I = E->getValue(); - return I.Supported && I.Avail <= CLVer; - } - /// Check if \c Ext is supported as an (optional) OpenCL core features for - /// the given OpenCL version. - /// - /// \param Ext - Extension to look up. - /// \param LO - \c LangOptions specifying the OpenCL version. - /// \returns \c true if \c Ext is known and supported, \c false otherwise. - bool isSupportedCore(llvm::StringRef Ext, const LangOptions &LO) const { - auto E = OptMap.find(Ext); - if (E == OptMap.end()) { - return false; + // Is core option in OpenCL version \p LO. + bool isCoreIn(const LangOptions &LO) const { + return isAvailableIn(LO) && isOpenCLVersionIsContainedInMask(LO, Core); } - // In C++ mode all extensions should work at least as in v2.0. - auto CLVer = LO.OpenCLCPlusPlus ? 200 : LO.OpenCLVersion; - auto I = E->getValue(); - return I.Supported && I.Avail <= CLVer && I.Core != ~0U && CLVer >= I.Core; - } - /// Check if \c Ext is a supported OpenCL extension for the given OpenCL - /// version. - /// - /// \param Ext - Extension to look up. - /// \param LO - \c LangOptions specifying the OpenCL version. - /// \returns \c true if \c Ext is known and supported, \c false otherwise. - bool isSupportedExtension(llvm::StringRef Ext, const LangOptions &LO) const { - auto E = OptMap.find(Ext); - if (E == OptMap.end()) { - return false; + // Is optional core option in OpenCL version \p LO. + bool isOptionalCoreIn(const LangOptions &LO) const { + return isAvailableIn(LO) && isOpenCLVersionIsContainedInMask(LO, Opt); } - // In C++ mode all extensions should work at least as in v2.0. - auto CLVer = LO.OpenCLCPlusPlus ? 200 : LO.OpenCLVersion; - auto I = E->getValue(); - return I.Supported && I.Avail <= CLVer && (I.Core == ~0U || CLVer < I.Core); - } + }; - void enable(llvm::StringRef Ext, bool V = true) { - OptMap[Ext].Enabled = V; - } + bool isKnown(llvm::StringRef Ext) const; - /// Enable or disable support for OpenCL extensions - /// \param Ext name of the extension optionally prefixed with - /// '+' or '-' - /// \param V used when \p Ext is not prefixed by '+' or '-' - void support(llvm::StringRef Ext, bool V = true) { - assert(!Ext.empty() && "Extension is empty."); - - switch (Ext[0]) { - case '+': - V = true; - Ext = Ext.drop_front(); - break; - case '-': - V = false; - Ext = Ext.drop_front(); - break; - } + bool isEnabled(llvm::StringRef Ext) const; - if (Ext.equals("all")) { - supportAll(V); - return; - } - OptMap[Ext].Supported = V; - } + // Is supported as either an extension or an (optional) core feature for + // OpenCL version \p LO. + bool isSupported(llvm::StringRef Ext, const LangOptions &LO) const; - OpenCLOptions(){ -#define OPENCLEXT_INTERNAL(Ext, AvailVer, CoreVer) \ - OptMap[#Ext].Avail = AvailVer; \ - OptMap[#Ext].Core = CoreVer; -#include "clang/Basic/OpenCLExtensions.def" - } + // Is supported OpenCL core feature for OpenCL version \p LO. + // For supported extension, return false. + bool isSupportedCore(llvm::StringRef Ext, const LangOptions &LO) const; - void addSupport(const OpenCLOptions &Opts) { - for (auto &I:Opts.OptMap) - if (I.second.Supported) - OptMap[I.getKey()].Supported = true; - } + // Is supported optional core OpenCL feature for OpenCL version \p LO. + // For supported extension, return false. + bool isSupportedOptionalCore(llvm::StringRef Ext, + const LangOptions &LO) const; - void copy(const OpenCLOptions &Opts) { - OptMap = Opts.OptMap; - } + // Is supported optional core or core OpenCL feature for OpenCL version \p + // LO. For supported extension, return false. + bool isSupportedCoreOrOptionalCore(llvm::StringRef Ext, + const LangOptions &LO) const; - // Turn on or off support of all options. - void supportAll(bool On = true) { - for (llvm::StringMap::iterator I = OptMap.begin(), - E = OptMap.end(); I != E; ++I) - I->second.Supported = On; - } + // Is supported OpenCL extension for OpenCL version \p LO. + // For supported core or optional core feature, return false. + bool isSupportedExtension(llvm::StringRef Ext, const LangOptions &LO) const; - void disableAll() { - for (llvm::StringMap::iterator I = OptMap.begin(), - E = OptMap.end(); I != E; ++I) - I->second.Enabled = false; - } + void enable(llvm::StringRef Ext, bool V = true); - void enableSupportedCore(LangOptions LO) { - for (llvm::StringMap::iterator I = OptMap.begin(), E = OptMap.end(); - I != E; ++I) - if (isSupportedCore(I->getKey(), LO)) - I->second.Enabled = true; - } + /// Enable or disable support for OpenCL extensions + /// \param Ext name of the extension (not prefixed with '+' or '-') + /// \param V value to set for a extension + void support(llvm::StringRef Ext, bool V = true); + + OpenCLOptions(); + OpenCLOptions(const OpenCLOptions &) = default; + + // Set supported options based on target settings and language version + void addSupport(const llvm::StringMap &FeaturesMap, + const LangOptions &Opts); + + // Disable all extensions + void disableAll(); + + // Enable supported core and optional core features + void enableSupportedCore(const LangOptions &LO); friend class ASTWriter; friend class ASTReader; + + using OpenCLOptionInfoMap = llvm::StringMap; + +private: + OpenCLOptionInfoMap OptMap; }; } // end namespace clang diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1438,21 +1438,39 @@ /// Set supported OpenCL extensions and optional core features. virtual void setSupportedOpenCLOpts() {} + virtual void supportAllOpenCLOpts(bool V = true) { +#define OPENCLEXTNAME(Ext) getTargetOpts().OpenCLFeaturesMap[#Ext] = V; +#include "clang/Basic/OpenCLExtensions.def" + } + /// Set supported OpenCL extensions as written on command line - virtual void setOpenCLExtensionOpts() { + virtual void setCommandLineOpenCLOpts() { for (const auto &Ext : getTargetOpts().OpenCLExtensionsAsWritten) { - getTargetOpts().SupportedOpenCLOptions.support(Ext); + bool IsPrefixed = (Ext[0] == '+' || Ext[0] == '-'); + std::string Name = IsPrefixed ? Ext.substr(1) : Ext; + bool V = IsPrefixed ? Ext[0] == '+' : true; + + if (Name == "all") { + supportAllOpenCLOpts(V); + continue; + } + + getTargetOpts().OpenCLFeaturesMap[Name] = V; } } + /// Define OpenCL macros based on target settings and language version + void getOpenCLFeatureDefines(const LangOptions &Opts, + MacroBuilder &Builder) const; + /// Get supported OpenCL extensions and optional core features. - OpenCLOptions &getSupportedOpenCLOpts() { - return getTargetOpts().SupportedOpenCLOptions; + llvm::StringMap &getSupportedOpenCLOpts() { + return getTargetOpts().OpenCLFeaturesMap; } /// Get const supported OpenCL extensions and optional core features. - const OpenCLOptions &getSupportedOpenCLOpts() const { - return getTargetOpts().SupportedOpenCLOptions; + const llvm::StringMap &getSupportedOpenCLOpts() const { + return getTargetOpts().OpenCLFeaturesMap; } /// Get address space for OpenCL type. diff --git a/clang/include/clang/Basic/TargetOptions.h b/clang/include/clang/Basic/TargetOptions.h --- a/clang/include/clang/Basic/TargetOptions.h +++ b/clang/include/clang/Basic/TargetOptions.h @@ -62,7 +62,7 @@ llvm::StringMap FeatureMap; /// Supported OpenCL extensions and optional core features. - OpenCLOptions SupportedOpenCLOptions; + llvm::StringMap OpenCLFeaturesMap; /// The list of OpenCL extensions to enable or disable, as written on /// the command line. diff --git a/clang/lib/Basic/CMakeLists.txt b/clang/lib/Basic/CMakeLists.txt --- a/clang/lib/Basic/CMakeLists.txt +++ b/clang/lib/Basic/CMakeLists.txt @@ -56,6 +56,7 @@ LangStandards.cpp Module.cpp ObjCRuntime.cpp + OpenCLOptions.cpp OpenMPKinds.cpp OperatorPrecedence.cpp SanitizerBlacklist.cpp diff --git a/clang/lib/Basic/OpenCLOptions.cpp b/clang/lib/Basic/OpenCLOptions.cpp new file mode 100644 --- /dev/null +++ b/clang/lib/Basic/OpenCLOptions.cpp @@ -0,0 +1,106 @@ +//===--- OpenCLOptions.cpp---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/OpenCLOptions.h" + +namespace clang { + +bool OpenCLOptions::isKnown(llvm::StringRef Ext) const { + return OptMap.find(Ext) != OptMap.end(); +} + +bool OpenCLOptions::isEnabled(llvm::StringRef Ext) const { + auto E = OptMap.find(Ext); + return E != OptMap.end() && E->second.Enabled; +} + +bool OpenCLOptions::isSupported(llvm::StringRef Ext, + const LangOptions &LO) const { + auto E = OptMap.find(Ext); + if (E == OptMap.end()) { + return false; + } + auto I = OptMap.find(Ext)->getValue(); + return I.Supported && I.isAvailableIn(LO); +} + +bool OpenCLOptions::isSupportedCore(llvm::StringRef Ext, + const LangOptions &LO) const { + auto E = OptMap.find(Ext); + if (E == OptMap.end()) { + return false; + } + auto I = OptMap.find(Ext)->getValue(); + return I.Supported && I.isCoreIn(LO); +} + +bool OpenCLOptions::isSupportedOptionalCore(llvm::StringRef Ext, + const LangOptions &LO) const { + auto E = OptMap.find(Ext); + if (E == OptMap.end()) { + return false; + } + auto I = OptMap.find(Ext)->getValue(); + return I.Supported && I.isOptionalCoreIn(LO); +} + +bool OpenCLOptions::isSupportedCoreOrOptionalCore(llvm::StringRef Ext, + const LangOptions &LO) const { + return isSupportedCore(Ext, LO) || isSupportedOptionalCore(Ext, LO); +} + +bool OpenCLOptions::isSupportedExtension(llvm::StringRef Ext, + const LangOptions &LO) const { + auto E = OptMap.find(Ext); + if (E == OptMap.end()) { + return false; + } + auto I = OptMap.find(Ext)->getValue(); + return I.Supported && I.isAvailableIn(LO) && + !isSupportedCoreOrOptionalCore(Ext, LO); +} + +void OpenCLOptions::enable(llvm::StringRef Ext, bool V) { + OptMap[Ext].Enabled = V; +} + +void OpenCLOptions::support(llvm::StringRef Ext, bool V) { + assert(!Ext.empty() && "Extension is empty."); + assert(Ext[0] != '+' && Ext[0] != '-'); + OptMap[Ext].Supported = V; +} + +OpenCLOptions::OpenCLOptions() { +#define OPENCL_GENERIC_EXTENSION(Ext, AvailVer, CoreVer, OptVer) \ + OptMap[#Ext].Avail = AvailVer; \ + OptMap[#Ext].Core = CoreVer; \ + OptMap[#Ext].Opt = OptVer; +#include "clang/Basic/OpenCLExtensions.def" +} + +void OpenCLOptions::addSupport(const llvm::StringMap &FeaturesMap, + const LangOptions &Opts) { + for (const auto &F : FeaturesMap) { + const auto &Name = F.getKey(); + if (F.getValue() && isKnown(Name) && OptMap[Name].isAvailableIn(Opts)) + support(Name); + } +} + +void OpenCLOptions::disableAll() { + for (auto &Opt : OptMap) + Opt.getValue().Enabled = false; +} + +void OpenCLOptions::enableSupportedCore(const LangOptions &LO) { + for (auto &Opt : OptMap) + if (isSupportedCoreOrOptionalCore(Opt.getKey(), LO)) + Opt.getValue().Enabled = true; +} + +} // end namespace clang diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -705,7 +705,7 @@ return nullptr; Target->setSupportedOpenCLOpts(); - Target->setOpenCLExtensionOpts(); + Target->setCommandLineOpenCLOpts(); Target->setMaxAtomicWidth(); if (!Target->validateTarget(Diags)) @@ -715,3 +715,29 @@ return Target.release(); } + +/// getOpenCLFeatureDefines - Define OpenCL macros based on target settings +/// and language version +void TargetInfo::getOpenCLFeatureDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + + auto defineOpenCLExtMacro = [&](llvm::StringRef Name, unsigned AvailVer, + unsigned CoreVersions, + unsigned OptionalVersions) { + // Check if extension is supported by target and is available in this + // OpenCL version + auto It = getTargetOpts().OpenCLFeaturesMap.find(Name); + if ((It != getTargetOpts().OpenCLFeaturesMap.end()) && It->getValue() && + OpenCLOptions::OpenCLOptionInfo(AvailVer, CoreVersions, + OptionalVersions) + .isAvailableIn(Opts)) + Builder.defineMacro(Name); + }; +#define OPENCL_GENERIC_EXTENSION(Ext, Avail, Core, Opt) \ + defineOpenCLExtMacro(#Ext, Avail, Core, Opt); +#include "clang/Basic/OpenCLExtensions.def" + + // FIXME: OpenCL options which affect language semantics/syntax + // should be moved into LangOptions, thus macro definitions of + // such options is better to be done in clang::InitializePreprocessor +} diff --git a/clang/lib/Basic/Targets/AMDGPU.h b/clang/lib/Basic/Targets/AMDGPU.h --- a/clang/lib/Basic/Targets/AMDGPU.h +++ b/clang/lib/Basic/Targets/AMDGPU.h @@ -284,33 +284,32 @@ void setSupportedOpenCLOpts() override { auto &Opts = getSupportedOpenCLOpts(); - Opts.support("cl_clang_storage_class_specifiers"); - Opts.support("__cl_clang_function_pointers"); - Opts.support("__cl_clang_variadic_functions"); + Opts["cl_clang_storage_class_specifiers"] = true; + Opts["__cl_clang_variadic_functions"] = true; + Opts["__cl_clang_function_pointers"] = true; bool IsAMDGCN = isAMDGCN(getTriple()); - if (hasFP64()) - Opts.support("cl_khr_fp64"); + Opts["cl_khr_fp64"] = hasFP64(); if (IsAMDGCN || GPUKind >= llvm::AMDGPU::GK_CEDAR) { - Opts.support("cl_khr_byte_addressable_store"); - Opts.support("cl_khr_global_int32_base_atomics"); - Opts.support("cl_khr_global_int32_extended_atomics"); - Opts.support("cl_khr_local_int32_base_atomics"); - Opts.support("cl_khr_local_int32_extended_atomics"); + Opts["cl_khr_byte_addressable_store"] = true; + Opts["cl_khr_global_int32_base_atomics"] = true; + Opts["cl_khr_global_int32_extended_atomics"] = true; + Opts["cl_khr_local_int32_base_atomics"] = true; + Opts["cl_khr_local_int32_extended_atomics"] = true; } if (IsAMDGCN) { - Opts.support("cl_khr_fp16"); - Opts.support("cl_khr_int64_base_atomics"); - Opts.support("cl_khr_int64_extended_atomics"); - Opts.support("cl_khr_mipmap_image"); - Opts.support("cl_khr_mipmap_image_writes"); - Opts.support("cl_khr_subgroups"); - Opts.support("cl_khr_3d_image_writes"); - Opts.support("cl_amd_media_ops"); - Opts.support("cl_amd_media_ops2"); + Opts["cl_khr_fp16"] = true; + Opts["cl_khr_int64_base_atomics"] = true; + Opts["cl_khr_int64_extended_atomics"] = true; + Opts["cl_khr_mipmap_image"] = true; + Opts["cl_khr_mipmap_image_writes"] = true; + Opts["cl_khr_subgroups"] = true; + Opts["cl_khr_3d_image_writes"] = true; + Opts["cl_amd_media_ops"] = true; + Opts["cl_amd_media_ops2"] = true; } } diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h --- a/clang/lib/Basic/Targets/NVPTX.h +++ b/clang/lib/Basic/Targets/NVPTX.h @@ -127,16 +127,16 @@ void setSupportedOpenCLOpts() override { auto &Opts = getSupportedOpenCLOpts(); - Opts.support("cl_clang_storage_class_specifiers"); - Opts.support("__cl_clang_function_pointers"); - Opts.support("__cl_clang_variadic_functions"); - - Opts.support("cl_khr_fp64"); - Opts.support("cl_khr_byte_addressable_store"); - Opts.support("cl_khr_global_int32_base_atomics"); - Opts.support("cl_khr_global_int32_extended_atomics"); - Opts.support("cl_khr_local_int32_base_atomics"); - Opts.support("cl_khr_local_int32_extended_atomics"); + Opts["cl_clang_storage_class_specifiers"] = true; + Opts["__cl_clang_function_pointers"] = true; + Opts["__cl_clang_variadic_functions"] = true; + + Opts["cl_khr_fp64"] = true; + Opts["cl_khr_byte_addressable_store"] = true; + Opts["cl_khr_global_int32_base_atomics"] = true; + Opts["cl_khr_global_int32_extended_atomics"] = true; + Opts["cl_khr_local_int32_base_atomics"] = true; + Opts["cl_khr_local_int32_extended_atomics"] = true; } /// \returns If a target requires an address within a target specific address diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h --- a/clang/lib/Basic/Targets/SPIR.h +++ b/clang/lib/Basic/Targets/SPIR.h @@ -100,7 +100,7 @@ void setSupportedOpenCLOpts() override { // Assume all OpenCL extensions and optional core features are supported // for SPIR since it is a generic target. - getSupportedOpenCLOpts().supportAll(); + supportAllOpenCLOpts(); } bool hasExtIntType() const override { return true; } diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -359,9 +359,7 @@ bool hasSjLjLowering() const override { return true; } - void setSupportedOpenCLOpts() override { - getSupportedOpenCLOpts().supportAll(); - } + void setSupportedOpenCLOpts() override { supportAllOpenCLOpts(); } uint64_t getPointerWidthV(unsigned AddrSpace) const override { if (AddrSpace == ptr32_sptr || AddrSpace == ptr32_uptr) diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -1120,10 +1120,7 @@ // OpenCL definitions. if (LangOpts.OpenCL) { -#define OPENCLEXT(Ext) \ - if (TI.getSupportedOpenCLOpts().isSupported(#Ext, LangOpts)) \ - Builder.defineMacro(#Ext); -#include "clang/Basic/OpenCLExtensions.def" + TI.getOpenCLFeatureDefines(LangOpts, Builder); if (TI.getTriple().isSPIR()) Builder.defineMacro("__IMAGE_SUPPORT__"); diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -790,7 +790,7 @@ PP.Diag(NameLoc, diag::warn_pragma_unknown_extension) << Ident; else if (Opt.isSupportedExtension(Name, getLangOpts())) Opt.enable(Name, State == Enable); - else if (Opt.isSupportedCore(Name, getLangOpts())) + else if (Opt.isSupportedCoreOrOptionalCore(Name, getLangOpts())) PP.Diag(NameLoc, diag::warn_pragma_extension_is_core) << Ident; else PP.Diag(NameLoc, diag::warn_pragma_unsupported_extension) << Ident; diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -297,7 +297,7 @@ // core features. if (getLangOpts().OpenCL) { getOpenCLOptions().addSupport( - Context.getTargetInfo().getSupportedOpenCLOpts()); + Context.getTargetInfo().getSupportedOpenCLOpts(), getLangOpts()); getOpenCLOptions().enableSupportedCore(getLangOpts()); addImplicitTypedef("sampler_t", Context.OCLSamplerTy); addImplicitTypedef("event_t", Context.OCLEventTy); diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -3609,11 +3609,12 @@ case OPENCL_EXTENSIONS: for (unsigned I = 0, E = Record.size(); I != E; ) { auto Name = ReadString(Record, I); - auto &Opt = OpenCLExtensions.OptMap[Name]; - Opt.Supported = Record[I++] != 0; - Opt.Enabled = Record[I++] != 0; - Opt.Avail = Record[I++]; - Opt.Core = Record[I++]; + auto &OptInfo = OpenCLExtensions.OptMap[Name]; + OptInfo.Supported = Record[I++] != 0; + OptInfo.Enabled = Record[I++] != 0; + OptInfo.Avail = Record[I++]; + OptInfo.Core = Record[I++]; + OptInfo.Opt = Record[I++]; } break; @@ -7868,7 +7869,7 @@ NewOverrides.applyOverrides(SemaObj->getLangOpts()); } - SemaObj->OpenCLFeatures.copy(OpenCLExtensions); + SemaObj->OpenCLFeatures = OpenCLExtensions; SemaObj->OpenCLTypeExtMap = OpenCLTypeExtMap; SemaObj->OpenCLDeclExtMap = OpenCLDeclExtMap; diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -3978,6 +3978,7 @@ Record.push_back(V.Enabled ? 1 : 0); Record.push_back(V.Avail); Record.push_back(V.Core); + Record.push_back(V.Opt); } Stream.EmitRecord(OPENCL_EXTENSIONS, Record); } diff --git a/clang/test/Misc/nvptx.languageOptsOpenCL.cl b/clang/test/Misc/nvptx.languageOptsOpenCL.cl --- a/clang/test/Misc/nvptx.languageOptsOpenCL.cl +++ b/clang/test/Misc/nvptx.languageOptsOpenCL.cl @@ -2,19 +2,15 @@ // RUN: %clang_cc1 -x cl -cl-std=CL %s -verify -triple nvptx-unknown-unknown // RUN: %clang_cc1 -x cl -cl-std=CL1.1 %s -verify -triple nvptx-unknown-unknown // RUN: %clang_cc1 -x cl -cl-std=CL1.2 %s -verify -triple nvptx-unknown-unknown -// RUN: %clang_cc1 -x cl -cl-std=CL2.0 %s -verify -triple nvptx-unknown-unknown // RUN: %clang_cc1 -x cl -cl-std=CL %s -verify -triple nvptx-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES // RUN: %clang_cc1 -x cl -cl-std=CL1.1 %s -verify -triple nvptx-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES // RUN: %clang_cc1 -x cl -cl-std=CL1.2 %s -verify -triple nvptx-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES -// RUN: %clang_cc1 -x cl -cl-std=CL2.0 %s -verify -triple nvptx-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES // RUN: %clang_cc1 -x cl -cl-std=CL %s -verify -triple nvptx64-unknown-unknown // RUN: %clang_cc1 -x cl -cl-std=CL1.1 %s -verify -triple nvptx64-unknown-unknown // RUN: %clang_cc1 -x cl -cl-std=CL1.2 %s -verify -triple nvptx64-unknown-unknown -// RUN: %clang_cc1 -x cl -cl-std=CL2.0 %s -verify -triple nvptx64-unknown-unknown // RUN: %clang_cc1 -x cl -cl-std=CL %s -verify -triple nvptx64-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES // RUN: %clang_cc1 -x cl -cl-std=CL1.1 %s -verify -triple nvptx64-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES // RUN: %clang_cc1 -x cl -cl-std=CL1.2 %s -verify -triple nvptx64-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES -// RUN: %clang_cc1 -x cl -cl-std=CL2.0 %s -verify -triple nvptx64-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES // Extensions in all versions #ifndef cl_clang_storage_class_specifiers diff --git a/clang/test/Misc/r600.languageOptsOpenCL.cl b/clang/test/Misc/r600.languageOptsOpenCL.cl --- a/clang/test/Misc/r600.languageOptsOpenCL.cl +++ b/clang/test/Misc/r600.languageOptsOpenCL.cl @@ -2,27 +2,21 @@ // RUN: %clang_cc1 -x cl -cl-std=CL %s -verify -triple r600-unknown-unknown -target-cpu cayman // RUN: %clang_cc1 -x cl -cl-std=CL1.1 %s -verify -triple r600-unknown-unknown -target-cpu cayman // RUN: %clang_cc1 -x cl -cl-std=CL1.2 %s -verify -triple r600-unknown-unknown -target-cpu cayman -// RUN: %clang_cc1 -x cl -cl-std=CL2.0 %s -verify -triple r600-unknown-unknown -target-cpu cayman // RUN: %clang_cc1 -x cl -cl-std=CL %s -verify -triple r600-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES -target-cpu cayman // RUN: %clang_cc1 -x cl -cl-std=CL1.1 %s -verify -triple r600-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES -target-cpu cayman // RUN: %clang_cc1 -x cl -cl-std=CL1.2 %s -verify -triple r600-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES -target-cpu cayman -// RUN: %clang_cc1 -x cl -cl-std=CL2.0 %s -verify -triple r600-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES -target-cpu cayman // RUN: %clang_cc1 -x cl -cl-std=CL %s -verify -triple r600-unknown-unknown -target-cpu cypress // RUN: %clang_cc1 -x cl -cl-std=CL1.1 %s -verify -triple r600-unknown-unknown -target-cpu cypress // RUN: %clang_cc1 -x cl -cl-std=CL1.2 %s -verify -triple r600-unknown-unknown -target-cpu cypress -// RUN: %clang_cc1 -x cl -cl-std=CL2.0 %s -verify -triple r600-unknown-unknown -target-cpu cypress // RUN: %clang_cc1 -x cl -cl-std=CL %s -verify -triple r600-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES -target-cpu cypress // RUN: %clang_cc1 -x cl -cl-std=CL1.1 %s -verify -triple r600-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES -target-cpu cypress // RUN: %clang_cc1 -x cl -cl-std=CL1.2 %s -verify -triple r600-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES -target-cpu cypress -// RUN: %clang_cc1 -x cl -cl-std=CL2.0 %s -verify -triple r600-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES -target-cpu cypress // RUN: %clang_cc1 -x cl -cl-std=CL %s -verify -triple r600-unknown-unknown -target-cpu turks // RUN: %clang_cc1 -x cl -cl-std=CL1.1 %s -verify -triple r600-unknown-unknown -target-cpu turks // RUN: %clang_cc1 -x cl -cl-std=CL1.2 %s -verify -triple r600-unknown-unknown -target-cpu turks -// RUN: %clang_cc1 -x cl -cl-std=CL2.0 %s -verify -triple r600-unknown-unknown -target-cpu turks // RUN: %clang_cc1 -x cl -cl-std=CL %s -verify -triple r600-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES -target-cpu turks // RUN: %clang_cc1 -x cl -cl-std=CL1.1 %s -verify -triple r600-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES -target-cpu turks // RUN: %clang_cc1 -x cl -cl-std=CL1.2 %s -verify -triple r600-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES -target-cpu turks -// RUN: %clang_cc1 -x cl -cl-std=CL2.0 %s -verify -triple r600-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES -target-cpu turks // Extensions in all versions #ifndef cl_clang_storage_class_specifiers