1 //===--- OpenCLOptions.h ----------------------------------------*- 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 /// \file
10 /// Defines the clang::OpenCLOptions class.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_CLANG_BASIC_OPENCLOPTIONS_H
15 #define LLVM_CLANG_BASIC_OPENCLOPTIONS_H
16 
17 #include "clang/Basic/LangOptions.h"
18 #include "llvm/ADT/StringMap.h"
19 
20 namespace clang {
21 
22 class DiagnosticsEngine;
23 class TargetInfo;
24 
25 namespace {
26 // This enum maps OpenCL version(s) into value. These values are used as
27 // a mask to indicate in which OpenCL version(s) extension is a core or
28 // optional core feature.
29 enum OpenCLVersionID : unsigned int {
30   OCL_C_10 = 0x1,
31   OCL_C_11 = 0x2,
32   OCL_C_12 = 0x4,
33   OCL_C_20 = 0x8,
34   OCL_C_30 = 0x10,
35   OCL_C_ALL = 0x1f,
36   OCL_C_11P = OCL_C_ALL ^ OCL_C_10,              // OpenCL C 1.1+
37   OCL_C_12P = OCL_C_ALL ^ (OCL_C_10 | OCL_C_11), // OpenCL C 1.2+
38 };
39 
40 static inline OpenCLVersionID encodeOpenCLVersion(unsigned OpenCLVersion) {
41   switch (OpenCLVersion) {
42   default:
43     llvm_unreachable("Unknown OpenCL version code");
44   case 100:
45     return OCL_C_10;
46   case 110:
47     return OCL_C_11;
48   case 120:
49     return OCL_C_12;
50   case 200:
51     return OCL_C_20;
52   case 300:
53     return OCL_C_30;
54   }
55 }
56 
57 // Check if OpenCL C version is contained in a given encoded OpenCL C version
58 // mask.
59 static inline bool isOpenCLVersionContainedInMask(const LangOptions &LO,
60                                                   unsigned Mask) {
61   auto CLVer = LO.OpenCLCPlusPlus ? 200 : LO.OpenCLVersion;
62   OpenCLVersionID Code = encodeOpenCLVersion(CLVer);
63   return Mask & Code;
64 }
65 
66 } // end anonymous namespace
67 
68 /// OpenCL supported extensions and optional core features
69 class OpenCLOptions {
70 
71 public:
72   // OpenCL C v1.2 s6.5 - All program scope variables must be declared in the
73   // __constant address space.
74   // OpenCL C v2.0 s6.5.1 - Variables defined at program scope and static
75   // variables inside a function can also be declared in the global
76   // address space.
77   // OpenCL C v3.0 s6.7.1 - Variables at program scope or static or extern
78   // variables inside functions can be declared in global address space if
79   // the __opencl_c_program_scope_global_variables feature is supported
80   // C++ for OpenCL inherits rule from OpenCL C v2.0.
81   bool areProgramScopeVariablesSupported(const LangOptions &Opts) const {
82     return Opts.OpenCLCPlusPlus || Opts.OpenCLVersion == 200 ||
83            (Opts.OpenCLVersion == 300 &&
84             isSupported("__opencl_c_program_scope_global_variables", Opts));
85   }
86 
87   struct OpenCLOptionInfo {
88     // Does this option have pragma.
89     bool WithPragma = false;
90 
91     // Option starts to be available in this OpenCL version
92     unsigned Avail = 100U;
93 
94     // Option becomes core feature in this OpenCL versions
95     unsigned Core = 0U;
96 
97     // Option becomes optional core feature in this OpenCL versions
98     unsigned Opt = 0U;
99 
100     // Is this option supported
101     bool Supported = false;
102 
103     // Is this option enabled
104     bool Enabled = false;
105 
106     OpenCLOptionInfo() = default;
107     OpenCLOptionInfo(bool Pragma, unsigned AvailV, unsigned CoreV,
108                      unsigned OptV)
109         : WithPragma(Pragma), Avail(AvailV), Core(CoreV), Opt(OptV) {}
110 
111     bool isCore() const { return Core != 0U; }
112 
113     bool isOptionalCore() const { return Opt != 0U; }
114 
115     // Is option available in OpenCL version \p LO.
116     bool isAvailableIn(const LangOptions &LO) const {
117       // In C++ mode all extensions should work at least as in v2.0.
118       auto CLVer = LO.OpenCLCPlusPlus ? 200 : LO.OpenCLVersion;
119       return CLVer >= Avail;
120     }
121 
122     // Is core option in OpenCL version \p LO.
123     bool isCoreIn(const LangOptions &LO) const {
124       return isAvailableIn(LO) && isOpenCLVersionContainedInMask(LO, Core);
125     }
126 
127     // Is optional core option in OpenCL version \p LO.
128     bool isOptionalCoreIn(const LangOptions &LO) const {
129       return isAvailableIn(LO) && isOpenCLVersionContainedInMask(LO, Opt);
130     }
131   };
132 
133   bool isKnown(llvm::StringRef Ext) const;
134 
135   // For core or optional core feature check that it is supported
136   // by a target, for any other option (extension) check that it is
137   // enabled via pragma
138   bool isAvailableOption(llvm::StringRef Ext, const LangOptions &LO) const;
139 
140   bool isWithPragma(llvm::StringRef Ext) const;
141 
142   // Is supported as either an extension or an (optional) core feature for
143   // OpenCL version \p LO.
144   bool isSupported(llvm::StringRef Ext, const LangOptions &LO) const;
145 
146   // Is supported OpenCL core feature for OpenCL version \p LO.
147   // For supported extension, return false.
148   bool isSupportedCore(llvm::StringRef Ext, const LangOptions &LO) const;
149 
150   // Is supported optional core OpenCL feature for OpenCL version \p LO.
151   // For supported extension, return false.
152   bool isSupportedOptionalCore(llvm::StringRef Ext,
153                                const LangOptions &LO) const;
154 
155   // Is supported optional core or core OpenCL feature for OpenCL version \p
156   // LO. For supported extension, return false.
157   bool isSupportedCoreOrOptionalCore(llvm::StringRef Ext,
158                                      const LangOptions &LO) const;
159 
160   // Is supported OpenCL extension for OpenCL version \p LO.
161   // For supported core or optional core feature, return false.
162   bool isSupportedExtension(llvm::StringRef Ext, const LangOptions &LO) const;
163 
164   // FIXME: Whether extension should accept pragma should not
165   // be reset dynamically. But it currently required when
166   // registering new extensions via pragmas.
167   void acceptsPragma(llvm::StringRef Ext, bool V = true);
168 
169   void enable(llvm::StringRef Ext, bool V = true);
170 
171   /// Enable or disable support for OpenCL extensions
172   /// \param Ext name of the extension (not prefixed with '+' or '-')
173   /// \param V value to set for a extension
174   void support(llvm::StringRef Ext, bool V = true);
175 
176   OpenCLOptions();
177 
178   // Set supported options based on target settings and language version
179   void addSupport(const llvm::StringMap<bool> &FeaturesMap,
180                   const LangOptions &Opts);
181 
182   // Disable all extensions
183   void disableAll();
184 
185   friend class ASTWriter;
186   friend class ASTReader;
187 
188   using OpenCLOptionInfoMap = llvm::StringMap<OpenCLOptionInfo>;
189 
190   template <typename... Args>
191   static bool isOpenCLOptionCoreIn(const LangOptions &LO, Args &&... args) {
192     return OpenCLOptionInfo(std::forward<Args>(args)...).isCoreIn(LO);
193   }
194 
195   template <typename... Args>
196   static bool isOpenCLOptionAvailableIn(const LangOptions &LO,
197                                         Args &&... args) {
198     return OpenCLOptionInfo(std::forward<Args>(args)...).isAvailableIn(LO);
199   }
200 
201   // Diagnose feature dependencies for OpenCL C 3.0. Return false if target
202   // doesn't follow these requirements.
203   static bool diagnoseUnsupportedFeatureDependencies(const TargetInfo &TI,
204                                                      DiagnosticsEngine &Diags);
205 
206   // Diagnose that features and equivalent extension are set to same values.
207   // Return false if target doesn't follow these requirements.
208   static bool diagnoseFeatureExtensionDifferences(const TargetInfo &TI,
209                                                   DiagnosticsEngine &Diags);
210 
211 private:
212   // Option is enabled via pragma
213   bool isEnabled(llvm::StringRef Ext) const;
214 
215   OpenCLOptionInfoMap OptMap;
216 };
217 
218 } // end namespace clang
219 
220 #endif
221