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.getOpenCLCompatibleVersion();
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.getOpenCLCompatibleVersion() == 200 ||
83            (Opts.getOpenCLCompatibleVersion() == 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       return LO.getOpenCLCompatibleVersion() >= Avail;
119     }
120 
121     // Is core option in OpenCL version \p LO.
122     bool isCoreIn(const LangOptions &LO) const {
123       return isAvailableIn(LO) && isOpenCLVersionContainedInMask(LO, Core);
124     }
125 
126     // Is optional core option in OpenCL version \p LO.
127     bool isOptionalCoreIn(const LangOptions &LO) const {
128       return isAvailableIn(LO) && isOpenCLVersionContainedInMask(LO, Opt);
129     }
130   };
131 
132   bool isKnown(llvm::StringRef Ext) const;
133 
134   // For core or optional core feature check that it is supported
135   // by a target, for any other option (extension) check that it is
136   // enabled via pragma
137   bool isAvailableOption(llvm::StringRef Ext, const LangOptions &LO) const;
138 
139   bool isWithPragma(llvm::StringRef Ext) const;
140 
141   // Is supported as either an extension or an (optional) core feature for
142   // OpenCL version \p LO.
143   bool isSupported(llvm::StringRef Ext, const LangOptions &LO) const;
144 
145   // Is supported OpenCL core feature for OpenCL version \p LO.
146   // For supported extension, return false.
147   bool isSupportedCore(llvm::StringRef Ext, const LangOptions &LO) const;
148 
149   // Is supported optional core OpenCL feature for OpenCL version \p LO.
150   // For supported extension, return false.
151   bool isSupportedOptionalCore(llvm::StringRef Ext,
152                                const LangOptions &LO) const;
153 
154   // Is supported optional core or core OpenCL feature for OpenCL version \p
155   // LO. For supported extension, return false.
156   bool isSupportedCoreOrOptionalCore(llvm::StringRef Ext,
157                                      const LangOptions &LO) const;
158 
159   // Is supported OpenCL extension for OpenCL version \p LO.
160   // For supported core or optional core feature, return false.
161   bool isSupportedExtension(llvm::StringRef Ext, const LangOptions &LO) const;
162 
163   // FIXME: Whether extension should accept pragma should not
164   // be reset dynamically. But it currently required when
165   // registering new extensions via pragmas.
166   void acceptsPragma(llvm::StringRef Ext, bool V = true);
167 
168   void enable(llvm::StringRef Ext, bool V = true);
169 
170   /// Enable or disable support for OpenCL extensions
171   /// \param Ext name of the extension (not prefixed with '+' or '-')
172   /// \param V value to set for a extension
173   void support(llvm::StringRef Ext, bool V = true);
174 
175   OpenCLOptions();
176 
177   // Set supported options based on target settings and language version
178   void addSupport(const llvm::StringMap<bool> &FeaturesMap,
179                   const LangOptions &Opts);
180 
181   // Disable all extensions
182   void disableAll();
183 
184   friend class ASTWriter;
185   friend class ASTReader;
186 
187   using OpenCLOptionInfoMap = llvm::StringMap<OpenCLOptionInfo>;
188 
189   template <typename... Args>
190   static bool isOpenCLOptionCoreIn(const LangOptions &LO, Args &&... args) {
191     return OpenCLOptionInfo(std::forward<Args>(args)...).isCoreIn(LO);
192   }
193 
194   template <typename... Args>
195   static bool isOpenCLOptionAvailableIn(const LangOptions &LO,
196                                         Args &&... args) {
197     return OpenCLOptionInfo(std::forward<Args>(args)...).isAvailableIn(LO);
198   }
199 
200   // Diagnose feature dependencies for OpenCL C 3.0. Return false if target
201   // doesn't follow these requirements.
202   static bool diagnoseUnsupportedFeatureDependencies(const TargetInfo &TI,
203                                                      DiagnosticsEngine &Diags);
204 
205   // Diagnose that features and equivalent extension are set to same values.
206   // Return false if target doesn't follow these requirements.
207   static bool diagnoseFeatureExtensionDifferences(const TargetInfo &TI,
208                                                   DiagnosticsEngine &Diags);
209 
210 private:
211   // Option is enabled via pragma
212   bool isEnabled(llvm::StringRef Ext) const;
213 
214   OpenCLOptionInfoMap OptMap;
215 };
216 
217 } // end namespace clang
218 
219 #endif
220