| //===--- OpenCLOptions.h ----------------------------------------*- 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 |
| // |
| //===----------------------------------------------------------------------===// |
| /// |
| /// \file |
| /// Defines the clang::OpenCLOptions class. |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_CLANG_BASIC_OPENCLOPTIONS_H |
| #define LLVM_CLANG_BASIC_OPENCLOPTIONS_H |
| |
| #include "clang/Basic/LangOptions.h" |
| #include "llvm/ADT/StringMap.h" |
| |
| namespace clang { |
| |
| class DiagnosticsEngine; |
| class TargetInfo; |
| |
| 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; |
| } |
| } |
| |
| // Check if OpenCL C version is contained in a given encoded OpenCL C version |
| // mask. |
| static inline bool isOpenCLVersionContainedInMask(const LangOptions &LO, |
| unsigned Mask) { |
| auto CLVer = LO.getOpenCLCompatibleVersion(); |
| OpenCLVersionID Code = encodeOpenCLVersion(CLVer); |
| return Mask & Code; |
| } |
| |
| } // end anonymous namespace |
| |
| /// OpenCL supported extensions and optional core features |
| class OpenCLOptions { |
| |
| public: |
| // OpenCL C v1.2 s6.5 - All program scope variables must be declared in the |
| // __constant address space. |
| // OpenCL C v2.0 s6.5.1 - Variables defined at program scope and static |
| // variables inside a function can also be declared in the global |
| // address space. |
| // OpenCL C v3.0 s6.7.1 - Variables at program scope or static or extern |
| // variables inside functions can be declared in global address space if |
| // the __opencl_c_program_scope_global_variables feature is supported |
| // C++ for OpenCL inherits rule from OpenCL C v2.0. |
| bool areProgramScopeVariablesSupported(const LangOptions &Opts) const { |
| return Opts.getOpenCLCompatibleVersion() == 200 || |
| (Opts.getOpenCLCompatibleVersion() == 300 && |
| isSupported("__opencl_c_program_scope_global_variables", Opts)); |
| } |
| |
| struct OpenCLOptionInfo { |
| // Does this option have pragma. |
| bool WithPragma = false; |
| |
| // Option starts to be available in this OpenCL version |
| unsigned Avail = 100U; |
| |
| // Option becomes core feature in this OpenCL versions |
| unsigned Core = 0U; |
| |
| // Option becomes optional core feature in this OpenCL versions |
| unsigned Opt = 0U; |
| |
| // Is this option supported |
| bool Supported = false; |
| |
| // Is this option enabled |
| bool Enabled = false; |
| |
| OpenCLOptionInfo() = default; |
| OpenCLOptionInfo(bool Pragma, unsigned AvailV, unsigned CoreV, |
| unsigned OptV) |
| : WithPragma(Pragma), Avail(AvailV), Core(CoreV), Opt(OptV) {} |
| |
| 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. |
| return LO.getOpenCLCompatibleVersion() >= Avail; |
| } |
| |
| // Is core option in OpenCL version \p LO. |
| bool isCoreIn(const LangOptions &LO) const { |
| return isAvailableIn(LO) && isOpenCLVersionContainedInMask(LO, Core); |
| } |
| |
| // Is optional core option in OpenCL version \p LO. |
| bool isOptionalCoreIn(const LangOptions &LO) const { |
| return isAvailableIn(LO) && isOpenCLVersionContainedInMask(LO, Opt); |
| } |
| }; |
| |
| bool isKnown(llvm::StringRef Ext) const; |
| |
| // For core or optional core feature check that it is supported |
| // by a target, for any other option (extension) check that it is |
| // enabled via pragma |
| bool isAvailableOption(llvm::StringRef Ext, const LangOptions &LO) const; |
| |
| bool isWithPragma(llvm::StringRef Ext) const; |
| |
| // 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; |
| |
| // Is supported OpenCL core feature for OpenCL version \p LO. |
| // For supported extension, return false. |
| bool isSupportedCore(llvm::StringRef Ext, const LangOptions &LO) const; |
| |
| // 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; |
| |
| // 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; |
| |
| // 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; |
| |
| // FIXME: Whether extension should accept pragma should not |
| // be reset dynamically. But it currently required when |
| // registering new extensions via pragmas. |
| void acceptsPragma(llvm::StringRef Ext, bool V = true); |
| |
| void enable(llvm::StringRef Ext, bool V = 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(); |
| |
| // Set supported options based on target settings and language version |
| void addSupport(const llvm::StringMap<bool> &FeaturesMap, |
| const LangOptions &Opts); |
| |
| // Disable all extensions |
| void disableAll(); |
| |
| friend class ASTWriter; |
| friend class ASTReader; |
| |
| using OpenCLOptionInfoMap = llvm::StringMap<OpenCLOptionInfo>; |
| |
| template <typename... Args> |
| static bool isOpenCLOptionCoreIn(const LangOptions &LO, Args &&... args) { |
| return OpenCLOptionInfo(std::forward<Args>(args)...).isCoreIn(LO); |
| } |
| |
| template <typename... Args> |
| static bool isOpenCLOptionAvailableIn(const LangOptions &LO, |
| Args &&... args) { |
| return OpenCLOptionInfo(std::forward<Args>(args)...).isAvailableIn(LO); |
| } |
| |
| // Diagnose feature dependencies for OpenCL C 3.0. Return false if target |
| // doesn't follow these requirements. |
| static bool diagnoseUnsupportedFeatureDependencies(const TargetInfo &TI, |
| DiagnosticsEngine &Diags); |
| |
| // Diagnose that features and equivalent extension are set to same values. |
| // Return false if target doesn't follow these requirements. |
| static bool diagnoseFeatureExtensionDifferences(const TargetInfo &TI, |
| DiagnosticsEngine &Diags); |
| |
| private: |
| // Option is enabled via pragma |
| bool isEnabled(llvm::StringRef Ext) const; |
| |
| OpenCLOptionInfoMap OptMap; |
| |
| // First feature in a pair requires the second one to be supported. |
| using FeatureDepEntry = std::pair<llvm::StringRef, llvm::StringRef>; |
| using FeatureDepList = llvm::SmallVector<FeatureDepEntry, 8>; |
| |
| static const FeatureDepList DependentFeaturesList; |
| |
| // Extensions and equivalent feature pairs. |
| static const llvm::StringMap<llvm::StringRef> FeatureExtensionMap; |
| }; |
| |
| } // end namespace clang |
| |
| #endif |