//===--- 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;
};
} // end namespace clang
#endif