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 bool OpenCLOptions::isKnown(llvm::StringRef Ext) const {
16   return OptMap.find(Ext) != OptMap.end();
17 }
18 
19 bool OpenCLOptions::isAvailableOption(llvm::StringRef Ext,
20                                       const LangOptions &LO) const {
21   if (!isKnown(Ext))
22     return false;
23 
24   auto &OptInfo = OptMap.find(Ext)->getValue();
25   if (OptInfo.isCoreIn(LO) || OptInfo.isOptionalCoreIn(LO))
26     return isSupported(Ext, LO);
27 
28   return isEnabled(Ext);
29 }
30 
31 bool OpenCLOptions::isEnabled(llvm::StringRef Ext) const {
32   auto I = OptMap.find(Ext);
33   return I != OptMap.end() && I->getValue().Enabled;
34 }
35 
36 bool OpenCLOptions::isWithPragma(llvm::StringRef Ext) const {
37   auto E = OptMap.find(Ext);
38   return E != OptMap.end() && E->second.WithPragma;
39 }
40 
41 bool OpenCLOptions::isSupported(llvm::StringRef Ext,
42                                 const LangOptions &LO) const {
43   auto I = OptMap.find(Ext);
44   return I != OptMap.end() && I->getValue().Supported &&
45          I->getValue().isAvailableIn(LO);
46 }
47 
48 bool OpenCLOptions::isSupportedCore(llvm::StringRef Ext,
49                                     const LangOptions &LO) const {
50   auto I = OptMap.find(Ext);
51   return I != OptMap.end() && I->getValue().Supported &&
52          I->getValue().isCoreIn(LO);
53 }
54 
55 bool OpenCLOptions::isSupportedOptionalCore(llvm::StringRef Ext,
56                                             const LangOptions &LO) const {
57   auto I = OptMap.find(Ext);
58   return I != OptMap.end() && I->getValue().Supported &&
59          I->getValue().isOptionalCoreIn(LO);
60 }
61 
62 bool OpenCLOptions::isSupportedCoreOrOptionalCore(llvm::StringRef Ext,
63                                                   const LangOptions &LO) const {
64   return isSupportedCore(Ext, LO) || isSupportedOptionalCore(Ext, LO);
65 }
66 
67 bool OpenCLOptions::isSupportedExtension(llvm::StringRef Ext,
68                                          const LangOptions &LO) const {
69   auto I = OptMap.find(Ext);
70   return I != OptMap.end() && I->getValue().Supported &&
71          I->getValue().isAvailableIn(LO) &&
72          !isSupportedCoreOrOptionalCore(Ext, LO);
73 }
74 
75 void OpenCLOptions::enable(llvm::StringRef Ext, bool V) {
76   OptMap[Ext].Enabled = V;
77 }
78 
79 void OpenCLOptions::acceptsPragma(llvm::StringRef Ext, bool V) {
80   OptMap[Ext].WithPragma = V;
81 }
82 
83 void OpenCLOptions::support(llvm::StringRef Ext, bool V) {
84   assert(!Ext.empty() && "Extension is empty.");
85   assert(Ext[0] != '+' && Ext[0] != '-');
86   OptMap[Ext].Supported = V;
87 }
88 
89 OpenCLOptions::OpenCLOptions() {
90 #define OPENCL_GENERIC_EXTENSION(Ext, ...)                                     \
91   OptMap.insert_or_assign(#Ext, OpenCLOptionInfo{__VA_ARGS__});
92 #include "clang/Basic/OpenCLExtensions.def"
93 }
94 
95 void OpenCLOptions::addSupport(const llvm::StringMap<bool> &FeaturesMap,
96                                const LangOptions &Opts) {
97   for (const auto &F : FeaturesMap) {
98     const auto &Name = F.getKey();
99     if (F.getValue() && isKnown(Name) && OptMap[Name].isAvailableIn(Opts))
100       support(Name);
101   }
102 }
103 
104 void OpenCLOptions::disableAll() {
105   for (auto &Opt : OptMap)
106     Opt.getValue().Enabled = false;
107 }
108 
109 bool OpenCLOptions::diagnoseUnsupportedFeatureDependencies(
110     const TargetInfo &TI, DiagnosticsEngine &Diags) {
111   // Feature pairs. First feature in a pair requires the second one to be
112   // supported.
113   static const llvm::StringMap<llvm::StringRef> DependentFeaturesMap = {
114       {"__opencl_c_read_write_images", "__opencl_c_images"},
115       {"__opencl_c_3d_image_writes", "__opencl_c_images"},
116       {"__opencl_c_pipes", "__opencl_c_generic_address_space"}};
117 
118   auto OpenCLFeaturesMap = TI.getSupportedOpenCLOpts();
119 
120   bool IsValid = true;
121   for (auto &FeaturePair : DependentFeaturesMap)
122     if (TI.hasFeatureEnabled(OpenCLFeaturesMap, FeaturePair.getKey()) &&
123         !TI.hasFeatureEnabled(OpenCLFeaturesMap, FeaturePair.getValue())) {
124       IsValid = false;
125       Diags.Report(diag::err_opencl_feature_requires)
126           << FeaturePair.getKey() << FeaturePair.getValue();
127     }
128   return IsValid;
129 }
130 
131 bool OpenCLOptions::diagnoseFeatureExtensionDifferences(
132     const TargetInfo &TI, DiagnosticsEngine &Diags) {
133   // Extensions and equivalent feature pairs.
134   static const llvm::StringMap<llvm::StringRef> FeatureExtensionMap = {
135       {"cl_khr_fp64", "__opencl_c_fp64"},
136       {"cl_khr_3d_image_writes", "__opencl_c_3d_image_writes"}};
137 
138   auto OpenCLFeaturesMap = TI.getSupportedOpenCLOpts();
139 
140   bool IsValid = true;
141   for (auto &ExtAndFeat : FeatureExtensionMap)
142     if (TI.hasFeatureEnabled(OpenCLFeaturesMap, ExtAndFeat.getKey()) !=
143         TI.hasFeatureEnabled(OpenCLFeaturesMap, ExtAndFeat.getValue())) {
144       IsValid = false;
145       Diags.Report(diag::err_opencl_extension_and_feature_differs)
146           << ExtAndFeat.getKey() << ExtAndFeat.getValue();
147     }
148   return IsValid;
149 }
150 
151 } // end namespace clang
152