diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -360,4 +360,8 @@ def warn_poison_system_directories : Warning < "include location '%0' is unsafe for cross-compilation">, InGroup>, DefaultIgnore; + +def warn_opencl_unsupported_core_feature : Warning< + "%0 is a core feature in %select{OpenCL C|C++ for OpenCL}1 version %2 but not supported on this target">, + InGroup, DefaultIgnore; } diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1286,3 +1286,5 @@ def WebAssemblyExceptionSpec : DiagGroup<"wasm-exception-spec">; def RTTI : DiagGroup<"rtti">; + +def OpenCLCoreFeaturesDiagGroup : DiagGroup<"pedantic-core-features">; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1246,7 +1246,8 @@ def warn_pragma_unsupported_extension : Warning< "unsupported OpenCL extension %0 - ignoring">, InGroup; def warn_pragma_extension_is_core : Warning< - "OpenCL extension %0 is core feature or supported optional core feature - ignoring">, InGroup>, DefaultIgnore; + "OpenCL extension %0 is core feature or supported optional core feature - ignoring">, + InGroup, DefaultIgnore; // OpenCL errors. def err_opencl_taking_function_address_parser : Error< 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 @@ -59,6 +59,7 @@ OpenCLVersionID Code = encodeOpenCLVersion(CLVer); return Mask & Code; } + } // end anonymous namespace /// OpenCL supported extensions and optional core features @@ -167,6 +168,17 @@ using OpenCLOptionInfoMap = llvm::StringMap; + template + static bool isOpenCLOptionCoreIn(const LangOptions &LO, Args &&... args) { + return OpenCLOptionInfo(std::forward(args)...).isCoreIn(LO); + } + + template + static bool isOpenCLOptionAvailableIn(const LangOptions &LO, + Args &&... args) { + return OpenCLOptionInfo(std::forward(args)...).isAvailableIn(LO); + } + private: // Option is enabled via pragma bool isEnabled(llvm::StringRef Ext) const; 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 @@ -1234,6 +1234,12 @@ return false; } + /// Check if target has a given feature enabled + virtual bool hasFeatureEnabled(const llvm::StringMap &Features, + StringRef Name) const { + return Features.lookup(Name); + } + /// Enable or disable a specific target feature; /// the feature name must be valid. virtual void setFeatureEnabled(llvm::StringMap &Features, @@ -1481,7 +1487,8 @@ virtual void setSupportedOpenCLOpts() {} virtual void supportAllOpenCLOpts(bool V = true) { -#define OPENCLEXTNAME(Ext) getTargetOpts().OpenCLFeaturesMap[#Ext] = V; +#define OPENCLEXTNAME(Ext) \ + setFeatureEnabled(getTargetOpts().OpenCLFeaturesMap, #Ext, V); #include "clang/Basic/OpenCLExtensions.def" } @@ -1501,10 +1508,6 @@ } } - /// 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. llvm::StringMap &getSupportedOpenCLOpts() { return getTargetOpts().OpenCLFeaturesMap; @@ -1544,6 +1547,11 @@ return true; } + /// Check that OpenCL target has valid options setting based on OpenCL + /// version. + virtual bool validateOpenCLTarget(const LangOptions &Opts, + DiagnosticsEngine &Diags) const; + virtual void setAuxTarget(const TargetInfo *Aux) {} /// Whether target allows debuginfo types for decl only variables/functions. diff --git a/clang/lib/Basic/OpenCLOptions.cpp b/clang/lib/Basic/OpenCLOptions.cpp --- a/clang/lib/Basic/OpenCLOptions.cpp +++ b/clang/lib/Basic/OpenCLOptions.cpp @@ -85,9 +85,8 @@ } OpenCLOptions::OpenCLOptions() { -#define OPENCL_GENERIC_EXTENSION(Ext, WithPragma, AvailVer, CoreVer, OptVer) \ - OptMap.insert_or_assign( \ - #Ext, OpenCLOptionInfo{WithPragma, AvailVer, CoreVer, OptVer}); +#define OPENCL_GENERIC_EXTENSION(Ext, ...) \ + OptMap.insert_or_assign(#Ext, OpenCLOptionInfo{__VA_ARGS__}); #include "clang/Basic/OpenCLExtensions.def" } 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 @@ -726,30 +726,24 @@ return Target.release(); } - -/// getOpenCLFeatureDefines - Define OpenCL macros based on target settings -/// and language version -void TargetInfo::getOpenCLFeatureDefines(const LangOptions &Opts, - MacroBuilder &Builder) const { - // 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. - 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(false, AvailVer, CoreVersions, - OptionalVersions) - .isAvailableIn(Opts)) - Builder.defineMacro(Name); +/// validateOpenCLTarget - Check that OpenCL target has valid +/// options setting based on OpenCL version. +bool TargetInfo::validateOpenCLTarget(const LangOptions &Opts, + DiagnosticsEngine &Diags) const { + const llvm::StringMap &OpenCLFeaturesMap = getSupportedOpenCLOpts(); + + auto diagnoseNotSupportedCore = [&](llvm::StringRef Name, auto... OptArgs) { + if (OpenCLOptions::isOpenCLOptionCoreIn(Opts, OptArgs...) && + !hasFeatureEnabled(OpenCLFeaturesMap, Name)) + Diags.Report(diag::warn_opencl_unsupported_core_feature) + << Name << Opts.OpenCLCPlusPlus + << Opts.getOpenCLVersionTuple().getAsString(); }; -#define OPENCL_GENERIC_EXTENSION(Ext, WithPragma, Avail, Core, Opt) \ - defineOpenCLExtMacro(#Ext, Avail, Core, Opt); +#define OPENCL_GENERIC_EXTENSION(Ext, ...) \ + diagnoseNotSupportedCore(#Ext, __VA_ARGS__); #include "clang/Basic/OpenCLExtensions.def" - // Assume compiling for FULL profile - Builder.defineMacro("__opencl_c_int64"); + // For now assume that OpenCL target is always + // valid and just provide necessary diagnostics + return true; } diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -1398,13 +1398,13 @@ return Size <= 64; case 'z': // XMM0/YMM/ZMM0 - if (FeatureMap.lookup("avx512f")) + if (hasFeatureEnabled(FeatureMap, "avx512f")) // ZMM0 can be used if target supports AVX512F. return Size <= 512U; - else if (FeatureMap.lookup("avx")) + else if (hasFeatureEnabled(FeatureMap, "avx")) // YMM0 can be used if target supports AVX. return Size <= 256U; - else if (FeatureMap.lookup("sse")) + else if (hasFeatureEnabled(FeatureMap, "sse")) return Size <= 128U; return false; case 'i': @@ -1418,10 +1418,10 @@ break; case 'v': case 'x': - if (FeatureMap.lookup("avx512f")) + if (hasFeatureEnabled(FeatureMap, "avx512f")) // 512-bit zmm registers can be used if target supports AVX512F. return Size <= 512U; - else if (FeatureMap.lookup("avx")) + else if (hasFeatureEnabled(FeatureMap, "avx")) // 256-bit ymm registers can be used if target supports AVX. return Size <= 256U; return Size <= 128U; diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -133,6 +133,11 @@ // FIXME: can we disable FEnvAccess? } + // We should do it here because target knows nothing about + // language options when it's being created. + if (getLangOpts().OpenCL) + getTarget().validateOpenCLTarget(getLangOpts(), getDiagnostics()); + // Inform the target of the language options. // FIXME: We shouldn't need to do this, the target should be immutable once // created. This complexity should be lifted elsewhere. 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 @@ -601,6 +601,29 @@ Builder.defineMacro("__cpp_coroutines", "201703L"); } +/// InitializeOpenCLFeatureTestMacros - Define OpenCL macros based on target +/// settings and language version +void InitializeOpenCLFeatureTestMacros(const TargetInfo &TI, + const LangOptions &Opts, + MacroBuilder &Builder) { + const llvm::StringMap &OpenCLFeaturesMap = TI.getSupportedOpenCLOpts(); + // FIXME: OpenCL options which affect language semantics/syntax + // should be moved into LangOptions. + auto defineOpenCLExtMacro = [&](llvm::StringRef Name, auto... OptArgs) { + // Check if extension is supported by target and is available in this + // OpenCL version + if (TI.hasFeatureEnabled(OpenCLFeaturesMap, Name) && + OpenCLOptions::isOpenCLOptionAvailableIn(Opts, OptArgs...)) + Builder.defineMacro(Name); + }; +#define OPENCL_GENERIC_EXTENSION(Ext, ...) \ + defineOpenCLExtMacro(#Ext, __VA_ARGS__); +#include "clang/Basic/OpenCLExtensions.def" + + // Assume compiling for FULL profile + Builder.defineMacro("__opencl_c_int64"); +} + static void InitializePredefinedMacros(const TargetInfo &TI, const LangOptions &LangOpts, const FrontendOptions &FEOpts, @@ -1137,7 +1160,7 @@ // OpenCL definitions. if (LangOpts.OpenCL) { - TI.getOpenCLFeatureDefines(LangOpts, Builder); + InitializeOpenCLFeatureTestMacros(TI, LangOpts, Builder); if (TI.getTriple().isSPIR()) Builder.defineMacro("__IMAGE_SUPPORT__"); diff --git a/clang/test/Misc/nvptx.unsupported_core.cl b/clang/test/Misc/nvptx.unsupported_core.cl new file mode 100644 --- /dev/null +++ b/clang/test/Misc/nvptx.unsupported_core.cl @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -cl-std=CL2.0 -triple nvptx-unknown-unknown -Wpedantic-core-features %s 2> %t +// RUN: FileCheck --check-prefixes=CHECK-C < %t %s +// RUN: %clang_cc1 -cl-std=CLC++ -triple nvptx-unknown-unknown -Wpedantic-core-features %s 2> %t +// RUN: FileCheck --check-prefixes=CHECK-CPP < %t %s + +// CHECK-C: cl_khr_3d_image_writes is a core feature in OpenCL C version 2.0 but not supported on this target +// CHECK-CPP: cl_khr_3d_image_writes is a core feature in C++ for OpenCL version 1.0 but not supported on this target diff --git a/clang/test/Misc/r600.unsupported_core.cl b/clang/test/Misc/r600.unsupported_core.cl new file mode 100644 --- /dev/null +++ b/clang/test/Misc/r600.unsupported_core.cl @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -cl-std=CL2.0 -triple r600-unknown-unknown -Wpedantic-core-features %s 2> %t +// RUN: FileCheck < %t %s + +// CHECK: cl_khr_byte_addressable_store is a core feature in OpenCL C version 2.0 but not supported on this target +// CHECK: cl_khr_global_int32_base_atomics is a core feature in OpenCL C version 2.0 but not supported on this target +// CHECK: cl_khr_global_int32_extended_atomics is a core feature in OpenCL C version 2.0 but not supported on this target +// CHECK: cl_khr_local_int32_base_atomics is a core feature in OpenCL C version 2.0 but not supported on this target +// CHECK: cl_khr_local_int32_extended_atomics is a core feature in OpenCL C version 2.0 but not supported on this target +// CHECK: cl_khr_3d_image_writes is a core feature in OpenCL C version 2.0 but not supported on this target