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
encodeOpenCLVersion(unsigned OpenCLVersion)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.
isOpenCLVersionContainedInMask(const LangOptions & LO,unsigned 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.
areProgramScopeVariablesSupported(const LangOptions & Opts)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;
OpenCLOptionInfoOpenCLOptionInfo107 OpenCLOptionInfo(bool Pragma, unsigned AvailV, unsigned CoreV,
108 unsigned OptV)
109 : WithPragma(Pragma), Avail(AvailV), Core(CoreV), Opt(OptV) {}
110
isCoreOpenCLOptionInfo111 bool isCore() const { return Core != 0U; }
112
isOptionalCoreOpenCLOptionInfo113 bool isOptionalCore() const { return Opt != 0U; }
114
115 // Is option available in OpenCL version \p LO.
isAvailableInOpenCLOptionInfo116 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.
isCoreInOpenCLOptionInfo122 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.
isOptionalCoreInOpenCLOptionInfo127 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>
isOpenCLOptionCoreIn(const LangOptions & LO,Args &&...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>
isOpenCLOptionAvailableIn(const LangOptions & LO,Args &&...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