1 //===--- OpenCLOptions.cpp---------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "clang/Basic/OpenCLOptions.h"
10 #include "clang/Basic/Diagnostic.h"
11 #include "clang/Basic/TargetInfo.h"
12 
13 namespace clang {
14 
15 // First feature in a pair requires the second one to be supported.
16 static const std::pair<StringRef, StringRef> DependentFeaturesList[] = {
17     {"__opencl_c_read_write_images", "__opencl_c_images"},
18     {"__opencl_c_3d_image_writes", "__opencl_c_images"},
19     {"__opencl_c_pipes", "__opencl_c_generic_address_space"},
20     {"__opencl_c_device_enqueue", "__opencl_c_generic_address_space"},
21     {"__opencl_c_device_enqueue", "__opencl_c_program_scope_global_variables"}};
22 
23 // Extensions and equivalent feature pairs.
24 static const std::pair<StringRef, StringRef> FeatureExtensionMap[] = {
25     {"cl_khr_fp64", "__opencl_c_fp64"},
26     {"cl_khr_3d_image_writes", "__opencl_c_3d_image_writes"}};
27 
isKnown(llvm::StringRef Ext) const28 bool OpenCLOptions::isKnown(llvm::StringRef Ext) const {
29   return OptMap.contains(Ext);
30 }
31 
isAvailableOption(llvm::StringRef Ext,const LangOptions & LO) const32 bool OpenCLOptions::isAvailableOption(llvm::StringRef Ext,
33                                       const LangOptions &LO) const {
34   if (!isKnown(Ext))
35     return false;
36 
37   auto &OptInfo = OptMap.find(Ext)->getValue();
38   if (OptInfo.isCoreIn(LO) || OptInfo.isOptionalCoreIn(LO))
39     return isSupported(Ext, LO);
40 
41   return isEnabled(Ext);
42 }
43 
isEnabled(llvm::StringRef Ext) const44 bool OpenCLOptions::isEnabled(llvm::StringRef Ext) const {
45   auto I = OptMap.find(Ext);
46   return I != OptMap.end() && I->getValue().Enabled;
47 }
48 
isWithPragma(llvm::StringRef Ext) const49 bool OpenCLOptions::isWithPragma(llvm::StringRef Ext) const {
50   auto E = OptMap.find(Ext);
51   return E != OptMap.end() && E->second.WithPragma;
52 }
53 
isSupported(llvm::StringRef Ext,const LangOptions & LO) const54 bool OpenCLOptions::isSupported(llvm::StringRef Ext,
55                                 const LangOptions &LO) const {
56   auto I = OptMap.find(Ext);
57   return I != OptMap.end() && I->getValue().Supported &&
58          I->getValue().isAvailableIn(LO);
59 }
60 
isSupportedCore(llvm::StringRef Ext,const LangOptions & LO) const61 bool OpenCLOptions::isSupportedCore(llvm::StringRef Ext,
62                                     const LangOptions &LO) const {
63   auto I = OptMap.find(Ext);
64   return I != OptMap.end() && I->getValue().Supported &&
65          I->getValue().isCoreIn(LO);
66 }
67 
isSupportedOptionalCore(llvm::StringRef Ext,const LangOptions & LO) const68 bool OpenCLOptions::isSupportedOptionalCore(llvm::StringRef Ext,
69                                             const LangOptions &LO) const {
70   auto I = OptMap.find(Ext);
71   return I != OptMap.end() && I->getValue().Supported &&
72          I->getValue().isOptionalCoreIn(LO);
73 }
74 
isSupportedCoreOrOptionalCore(llvm::StringRef Ext,const LangOptions & LO) const75 bool OpenCLOptions::isSupportedCoreOrOptionalCore(llvm::StringRef Ext,
76                                                   const LangOptions &LO) const {
77   return isSupportedCore(Ext, LO) || isSupportedOptionalCore(Ext, LO);
78 }
79 
isSupportedExtension(llvm::StringRef Ext,const LangOptions & LO) const80 bool OpenCLOptions::isSupportedExtension(llvm::StringRef Ext,
81                                          const LangOptions &LO) const {
82   auto I = OptMap.find(Ext);
83   return I != OptMap.end() && I->getValue().Supported &&
84          I->getValue().isAvailableIn(LO) &&
85          !isSupportedCoreOrOptionalCore(Ext, LO);
86 }
87 
enable(llvm::StringRef Ext,bool V)88 void OpenCLOptions::enable(llvm::StringRef Ext, bool V) {
89   OptMap[Ext].Enabled = V;
90 }
91 
acceptsPragma(llvm::StringRef Ext,bool V)92 void OpenCLOptions::acceptsPragma(llvm::StringRef Ext, bool V) {
93   OptMap[Ext].WithPragma = V;
94 }
95 
support(llvm::StringRef Ext,bool V)96 void OpenCLOptions::support(llvm::StringRef Ext, bool V) {
97   assert(!Ext.empty() && "Extension is empty.");
98   assert(Ext[0] != '+' && Ext[0] != '-');
99   OptMap[Ext].Supported = V;
100 }
101 
OpenCLOptions()102 OpenCLOptions::OpenCLOptions() {
103 #define OPENCL_GENERIC_EXTENSION(Ext, ...)                                     \
104   OptMap.insert_or_assign(#Ext, OpenCLOptionInfo{__VA_ARGS__});
105 #include "clang/Basic/OpenCLExtensions.def"
106 }
107 
addSupport(const llvm::StringMap<bool> & FeaturesMap,const LangOptions & Opts)108 void OpenCLOptions::addSupport(const llvm::StringMap<bool> &FeaturesMap,
109                                const LangOptions &Opts) {
110   for (const auto &F : FeaturesMap) {
111     const auto &Name = F.getKey();
112     if (F.getValue() && isKnown(Name) && OptMap[Name].isAvailableIn(Opts))
113       support(Name);
114   }
115 }
116 
disableAll()117 void OpenCLOptions::disableAll() {
118   for (auto &Opt : OptMap)
119     Opt.getValue().Enabled = false;
120 }
121 
diagnoseUnsupportedFeatureDependencies(const TargetInfo & TI,DiagnosticsEngine & Diags)122 bool OpenCLOptions::diagnoseUnsupportedFeatureDependencies(
123     const TargetInfo &TI, DiagnosticsEngine &Diags) {
124   auto OpenCLFeaturesMap = TI.getSupportedOpenCLOpts();
125 
126   bool IsValid = true;
127   for (auto &FeaturePair : DependentFeaturesList) {
128     auto Feature = FeaturePair.first;
129     auto Dep = FeaturePair.second;
130     if (TI.hasFeatureEnabled(OpenCLFeaturesMap, Feature) &&
131         !TI.hasFeatureEnabled(OpenCLFeaturesMap, Dep)) {
132       IsValid = false;
133       Diags.Report(diag::err_opencl_feature_requires) << Feature << Dep;
134     }
135   }
136   return IsValid;
137 }
138 
diagnoseFeatureExtensionDifferences(const TargetInfo & TI,DiagnosticsEngine & Diags)139 bool OpenCLOptions::diagnoseFeatureExtensionDifferences(
140     const TargetInfo &TI, DiagnosticsEngine &Diags) {
141   auto OpenCLFeaturesMap = TI.getSupportedOpenCLOpts();
142 
143   bool IsValid = true;
144   for (auto &ExtAndFeat : FeatureExtensionMap)
145     if (TI.hasFeatureEnabled(OpenCLFeaturesMap, ExtAndFeat.first) !=
146         TI.hasFeatureEnabled(OpenCLFeaturesMap, ExtAndFeat.second)) {
147       IsValid = false;
148       Diags.Report(diag::err_opencl_extension_and_feature_differs)
149           << ExtAndFeat.first << ExtAndFeat.second;
150     }
151   return IsValid;
152 }
153 
154 } // end namespace clang
155