ClangOpenCLBuiltinEmitter.cpp revision 1.1 1 1.1 joerg //===- ClangOpenCLBuiltinEmitter.cpp - Generate Clang OpenCL Builtin handling
2 1.1 joerg //
3 1.1 joerg // The LLVM Compiler Infrastructure
4 1.1 joerg //
5 1.1 joerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
6 1.1 joerg // See https://llvm.org/LICENSE.txt for license information.
7 1.1 joerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8 1.1 joerg //
9 1.1 joerg //===----------------------------------------------------------------------===//
10 1.1 joerg //
11 1.1 joerg // This tablegen backend emits code for checking whether a function is an
12 1.1 joerg // OpenCL builtin function. If so, all overloads of this function are
13 1.1 joerg // added to the LookupResult. The generated include file is used by
14 1.1 joerg // SemaLookup.cpp
15 1.1 joerg //
16 1.1 joerg // For a successful lookup of e.g. the "cos" builtin, isOpenCLBuiltin("cos")
17 1.1 joerg // returns a pair <Index, Len>.
18 1.1 joerg // BuiltinTable[Index] to BuiltinTable[Index + Len] contains the pairs
19 1.1 joerg // <SigIndex, SigLen> of the overloads of "cos".
20 1.1 joerg // SignatureTable[SigIndex] to SignatureTable[SigIndex + SigLen] contains
21 1.1 joerg // one of the signatures of "cos". The SignatureTable entry can be
22 1.1 joerg // referenced by other functions, e.g. "sin", to exploit the fact that
23 1.1 joerg // many OpenCL builtins share the same signature.
24 1.1 joerg //
25 1.1 joerg // The file generated by this TableGen emitter contains the following:
26 1.1 joerg //
27 1.1 joerg // * Structs and enums to represent types and function signatures.
28 1.1 joerg //
29 1.1 joerg // * OpenCLTypeStruct TypeTable[]
30 1.1 joerg // Type information for return types and arguments.
31 1.1 joerg //
32 1.1 joerg // * unsigned SignatureTable[]
33 1.1 joerg // A list of types representing function signatures. Each entry is an index
34 1.1 joerg // into the above TypeTable. Multiple entries following each other form a
35 1.1 joerg // signature, where the first entry is the return type and subsequent
36 1.1 joerg // entries are the argument types.
37 1.1 joerg //
38 1.1 joerg // * OpenCLBuiltinStruct BuiltinTable[]
39 1.1 joerg // Each entry represents one overload of an OpenCL builtin function and
40 1.1 joerg // consists of an index into the SignatureTable and the number of arguments.
41 1.1 joerg //
42 1.1 joerg // * std::pair<unsigned, unsigned> isOpenCLBuiltin(llvm::StringRef Name)
43 1.1 joerg // Find out whether a string matches an existing OpenCL builtin function
44 1.1 joerg // name and return an index into BuiltinTable and the number of overloads.
45 1.1 joerg //
46 1.1 joerg // * void OCL2Qual(ASTContext&, OpenCLTypeStruct, std::vector<QualType>&)
47 1.1 joerg // Convert an OpenCLTypeStruct type to a list of QualType instances.
48 1.1 joerg // One OpenCLTypeStruct can represent multiple types, primarily when using
49 1.1 joerg // GenTypes.
50 1.1 joerg //
51 1.1 joerg //===----------------------------------------------------------------------===//
52 1.1 joerg
53 1.1 joerg #include "TableGenBackends.h"
54 1.1 joerg #include "llvm/ADT/MapVector.h"
55 1.1 joerg #include "llvm/ADT/STLExtras.h"
56 1.1 joerg #include "llvm/ADT/SmallString.h"
57 1.1 joerg #include "llvm/ADT/StringExtras.h"
58 1.1 joerg #include "llvm/ADT/StringRef.h"
59 1.1 joerg #include "llvm/ADT/StringSet.h"
60 1.1 joerg #include "llvm/ADT/StringSwitch.h"
61 1.1 joerg #include "llvm/Support/ErrorHandling.h"
62 1.1 joerg #include "llvm/Support/raw_ostream.h"
63 1.1 joerg #include "llvm/TableGen/Error.h"
64 1.1 joerg #include "llvm/TableGen/Record.h"
65 1.1 joerg #include "llvm/TableGen/StringMatcher.h"
66 1.1 joerg #include "llvm/TableGen/TableGenBackend.h"
67 1.1 joerg #include <set>
68 1.1 joerg
69 1.1 joerg using namespace llvm;
70 1.1 joerg
71 1.1 joerg namespace {
72 1.1 joerg class BuiltinNameEmitter {
73 1.1 joerg public:
74 1.1 joerg BuiltinNameEmitter(RecordKeeper &Records, raw_ostream &OS)
75 1.1 joerg : Records(Records), OS(OS) {}
76 1.1 joerg
77 1.1 joerg // Entrypoint to generate the functions and structures for checking
78 1.1 joerg // whether a function is an OpenCL builtin function.
79 1.1 joerg void Emit();
80 1.1 joerg
81 1.1 joerg private:
82 1.1 joerg // Contains OpenCL builtin functions and related information, stored as
83 1.1 joerg // Record instances. They are coming from the associated TableGen file.
84 1.1 joerg RecordKeeper &Records;
85 1.1 joerg
86 1.1 joerg // The output file.
87 1.1 joerg raw_ostream &OS;
88 1.1 joerg
89 1.1 joerg // Helper function for BuiltinNameEmitter::EmitDeclarations. Generate enum
90 1.1 joerg // definitions in the Output string parameter, and save their Record instances
91 1.1 joerg // in the List parameter.
92 1.1 joerg // \param Types (in) List containing the Types to extract.
93 1.1 joerg // \param TypesSeen (inout) List containing the Types already extracted.
94 1.1 joerg // \param Output (out) String containing the enums to emit in the output file.
95 1.1 joerg // \param List (out) List containing the extracted Types, except the Types in
96 1.1 joerg // TypesSeen.
97 1.1 joerg void ExtractEnumTypes(std::vector<Record *> &Types,
98 1.1 joerg StringMap<bool> &TypesSeen, std::string &Output,
99 1.1 joerg std::vector<const Record *> &List);
100 1.1 joerg
101 1.1 joerg // Emit the enum or struct used in the generated file.
102 1.1 joerg // Populate the TypeList at the same time.
103 1.1 joerg void EmitDeclarations();
104 1.1 joerg
105 1.1 joerg // Parse the Records generated by TableGen to populate the SignaturesList,
106 1.1 joerg // FctOverloadMap and TypeMap.
107 1.1 joerg void GetOverloads();
108 1.1 joerg
109 1.1 joerg // Emit the TypeTable containing all types used by OpenCL builtins.
110 1.1 joerg void EmitTypeTable();
111 1.1 joerg
112 1.1 joerg // Emit the SignatureTable. This table contains all the possible signatures.
113 1.1 joerg // A signature is stored as a list of indexes of the TypeTable.
114 1.1 joerg // The first index references the return type (mandatory), and the followings
115 1.1 joerg // reference its arguments.
116 1.1 joerg // E.g.:
117 1.1 joerg // 15, 2, 15 can represent a function with the signature:
118 1.1 joerg // int func(float, int)
119 1.1 joerg // The "int" type being at the index 15 in the TypeTable.
120 1.1 joerg void EmitSignatureTable();
121 1.1 joerg
122 1.1 joerg // Emit the BuiltinTable table. This table contains all the overloads of
123 1.1 joerg // each function, and is a struct OpenCLBuiltinDecl.
124 1.1 joerg // E.g.:
125 1.1 joerg // // 891 convert_float2_rtn
126 1.1 joerg // { 58, 2, 100, 0 },
127 1.1 joerg // This means that the signature of this convert_float2_rtn overload has
128 1.1 joerg // 1 argument (+1 for the return type), stored at index 58 in
129 1.1 joerg // the SignatureTable. The last two values represent the minimum (1.0) and
130 1.1 joerg // maximum (0, meaning no max version) OpenCL version in which this overload
131 1.1 joerg // is supported.
132 1.1 joerg void EmitBuiltinTable();
133 1.1 joerg
134 1.1 joerg // Emit a StringMatcher function to check whether a function name is an
135 1.1 joerg // OpenCL builtin function name.
136 1.1 joerg void EmitStringMatcher();
137 1.1 joerg
138 1.1 joerg // Emit a function returning the clang QualType instance associated with
139 1.1 joerg // the TableGen Record Type.
140 1.1 joerg void EmitQualTypeFinder();
141 1.1 joerg
142 1.1 joerg // Contains a list of the available signatures, without the name of the
143 1.1 joerg // function. Each pair consists of a signature and a cumulative index.
144 1.1 joerg // E.g.: <<float, float>, 0>,
145 1.1 joerg // <<float, int, int, 2>>,
146 1.1 joerg // <<float>, 5>,
147 1.1 joerg // ...
148 1.1 joerg // <<double, double>, 35>.
149 1.1 joerg std::vector<std::pair<std::vector<Record *>, unsigned>> SignaturesList;
150 1.1 joerg
151 1.1 joerg // Map the name of a builtin function to its prototypes (instances of the
152 1.1 joerg // TableGen "Builtin" class).
153 1.1 joerg // Each prototype is registered as a pair of:
154 1.1 joerg // <pointer to the "Builtin" instance,
155 1.1 joerg // cumulative index of the associated signature in the SignaturesList>
156 1.1 joerg // E.g.: The function cos: (float cos(float), double cos(double), ...)
157 1.1 joerg // <"cos", <<ptrToPrototype0, 5>,
158 1.1 joerg // <ptrToPrototype1, 35>,
159 1.1 joerg // <ptrToPrototype2, 79>>
160 1.1 joerg // ptrToPrototype1 has the following signature: <double, double>
161 1.1 joerg MapVector<StringRef, std::vector<std::pair<const Record *, unsigned>>>
162 1.1 joerg FctOverloadMap;
163 1.1 joerg
164 1.1 joerg // Contains the map of OpenCL types to their index in the TypeTable.
165 1.1 joerg MapVector<const Record *, unsigned> TypeMap;
166 1.1 joerg
167 1.1 joerg // List of OpenCL type names in the same order as in enum OpenCLTypeID.
168 1.1 joerg // This list does not contain generic types.
169 1.1 joerg std::vector<const Record *> TypeList;
170 1.1 joerg
171 1.1 joerg // Same as TypeList, but for generic types only.
172 1.1 joerg std::vector<const Record *> GenTypeList;
173 1.1 joerg };
174 1.1 joerg } // namespace
175 1.1 joerg
176 1.1 joerg void BuiltinNameEmitter::Emit() {
177 1.1 joerg emitSourceFileHeader("OpenCL Builtin handling", OS);
178 1.1 joerg
179 1.1 joerg OS << "#include \"llvm/ADT/StringRef.h\"\n";
180 1.1 joerg OS << "using namespace clang;\n\n";
181 1.1 joerg
182 1.1 joerg // Emit enums and structs.
183 1.1 joerg EmitDeclarations();
184 1.1 joerg
185 1.1 joerg GetOverloads();
186 1.1 joerg
187 1.1 joerg // Emit tables.
188 1.1 joerg EmitTypeTable();
189 1.1 joerg EmitSignatureTable();
190 1.1 joerg EmitBuiltinTable();
191 1.1 joerg
192 1.1 joerg EmitStringMatcher();
193 1.1 joerg
194 1.1 joerg EmitQualTypeFinder();
195 1.1 joerg }
196 1.1 joerg
197 1.1 joerg void BuiltinNameEmitter::ExtractEnumTypes(std::vector<Record *> &Types,
198 1.1 joerg StringMap<bool> &TypesSeen,
199 1.1 joerg std::string &Output,
200 1.1 joerg std::vector<const Record *> &List) {
201 1.1 joerg raw_string_ostream SS(Output);
202 1.1 joerg
203 1.1 joerg for (const auto *T : Types) {
204 1.1 joerg if (TypesSeen.find(T->getValueAsString("Name")) == TypesSeen.end()) {
205 1.1 joerg SS << " OCLT_" + T->getValueAsString("Name") << ",\n";
206 1.1 joerg // Save the type names in the same order as their enum value. Note that
207 1.1 joerg // the Record can be a VectorType or something else, only the name is
208 1.1 joerg // important.
209 1.1 joerg List.push_back(T);
210 1.1 joerg TypesSeen.insert(std::make_pair(T->getValueAsString("Name"), true));
211 1.1 joerg }
212 1.1 joerg }
213 1.1 joerg SS.flush();
214 1.1 joerg }
215 1.1 joerg
216 1.1 joerg void BuiltinNameEmitter::EmitDeclarations() {
217 1.1 joerg // Enum of scalar type names (float, int, ...) and generic type sets.
218 1.1 joerg OS << "enum OpenCLTypeID {\n";
219 1.1 joerg
220 1.1 joerg StringMap<bool> TypesSeen;
221 1.1 joerg std::string GenTypeEnums;
222 1.1 joerg std::string TypeEnums;
223 1.1 joerg
224 1.1 joerg // Extract generic types and non-generic types separately, to keep
225 1.1 joerg // gentypes at the end of the enum which simplifies the special handling
226 1.1 joerg // for gentypes in SemaLookup.
227 1.1 joerg std::vector<Record *> GenTypes =
228 1.1 joerg Records.getAllDerivedDefinitions("GenericType");
229 1.1 joerg ExtractEnumTypes(GenTypes, TypesSeen, GenTypeEnums, GenTypeList);
230 1.1 joerg
231 1.1 joerg std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type");
232 1.1 joerg ExtractEnumTypes(Types, TypesSeen, TypeEnums, TypeList);
233 1.1 joerg
234 1.1 joerg OS << TypeEnums;
235 1.1 joerg OS << GenTypeEnums;
236 1.1 joerg OS << "};\n";
237 1.1 joerg
238 1.1 joerg // Structure definitions.
239 1.1 joerg OS << R"(
240 1.1 joerg // Image access qualifier.
241 1.1 joerg enum OpenCLAccessQual : unsigned char {
242 1.1 joerg OCLAQ_None,
243 1.1 joerg OCLAQ_ReadOnly,
244 1.1 joerg OCLAQ_WriteOnly,
245 1.1 joerg OCLAQ_ReadWrite
246 1.1 joerg };
247 1.1 joerg
248 1.1 joerg // Represents a return type or argument type.
249 1.1 joerg struct OpenCLTypeStruct {
250 1.1 joerg // A type (e.g. float, int, ...).
251 1.1 joerg const OpenCLTypeID ID;
252 1.1 joerg // Vector size (if applicable; 0 for scalars and generic types).
253 1.1 joerg const unsigned VectorWidth;
254 1.1 joerg // 0 if the type is not a pointer.
255 1.1 joerg const bool IsPointer;
256 1.1 joerg // 0 if the type is not const.
257 1.1 joerg const bool IsConst;
258 1.1 joerg // 0 if the type is not volatile.
259 1.1 joerg const bool IsVolatile;
260 1.1 joerg // Access qualifier.
261 1.1 joerg const OpenCLAccessQual AccessQualifier;
262 1.1 joerg // Address space of the pointer (if applicable).
263 1.1 joerg const LangAS AS;
264 1.1 joerg };
265 1.1 joerg
266 1.1 joerg // One overload of an OpenCL builtin function.
267 1.1 joerg struct OpenCLBuiltinStruct {
268 1.1 joerg // Index of the signature in the OpenCLTypeStruct table.
269 1.1 joerg const unsigned SigTableIndex;
270 1.1 joerg // Entries between index SigTableIndex and (SigTableIndex + NumTypes - 1) in
271 1.1 joerg // the SignatureTable represent the complete signature. The first type at
272 1.1 joerg // index SigTableIndex is the return type.
273 1.1 joerg const unsigned NumTypes;
274 1.1 joerg // First OpenCL version in which this overload was introduced (e.g. CL20).
275 1.1 joerg const unsigned short MinVersion;
276 1.1 joerg // First OpenCL version in which this overload was removed (e.g. CL20).
277 1.1 joerg const unsigned short MaxVersion;
278 1.1 joerg };
279 1.1 joerg
280 1.1 joerg )";
281 1.1 joerg }
282 1.1 joerg
283 1.1 joerg // Verify that the combination of GenTypes in a signature is supported.
284 1.1 joerg // To simplify the logic for creating overloads in SemaLookup, only allow
285 1.1 joerg // a signature to contain different GenTypes if these GenTypes represent
286 1.1 joerg // the same number of actual scalar or vector types.
287 1.1 joerg //
288 1.1 joerg // Exit with a fatal error if an unsupported construct is encountered.
289 1.1 joerg static void VerifySignature(const std::vector<Record *> &Signature,
290 1.1 joerg const Record *BuiltinRec) {
291 1.1 joerg unsigned GenTypeVecSizes = 1;
292 1.1 joerg unsigned GenTypeTypes = 1;
293 1.1 joerg
294 1.1 joerg for (const auto *T : Signature) {
295 1.1 joerg // Check all GenericType arguments in this signature.
296 1.1 joerg if (T->isSubClassOf("GenericType")) {
297 1.1 joerg // Check number of vector sizes.
298 1.1 joerg unsigned NVecSizes =
299 1.1 joerg T->getValueAsDef("VectorList")->getValueAsListOfInts("List").size();
300 1.1 joerg if (NVecSizes != GenTypeVecSizes && NVecSizes != 1) {
301 1.1 joerg if (GenTypeVecSizes > 1) {
302 1.1 joerg // We already saw a gentype with a different number of vector sizes.
303 1.1 joerg PrintFatalError(BuiltinRec->getLoc(),
304 1.1 joerg "number of vector sizes should be equal or 1 for all gentypes "
305 1.1 joerg "in a declaration");
306 1.1 joerg }
307 1.1 joerg GenTypeVecSizes = NVecSizes;
308 1.1 joerg }
309 1.1 joerg
310 1.1 joerg // Check number of data types.
311 1.1 joerg unsigned NTypes =
312 1.1 joerg T->getValueAsDef("TypeList")->getValueAsListOfDefs("List").size();
313 1.1 joerg if (NTypes != GenTypeTypes && NTypes != 1) {
314 1.1 joerg if (GenTypeTypes > 1) {
315 1.1 joerg // We already saw a gentype with a different number of types.
316 1.1 joerg PrintFatalError(BuiltinRec->getLoc(),
317 1.1 joerg "number of types should be equal or 1 for all gentypes "
318 1.1 joerg "in a declaration");
319 1.1 joerg }
320 1.1 joerg GenTypeTypes = NTypes;
321 1.1 joerg }
322 1.1 joerg }
323 1.1 joerg }
324 1.1 joerg }
325 1.1 joerg
326 1.1 joerg void BuiltinNameEmitter::GetOverloads() {
327 1.1 joerg // Populate the TypeMap.
328 1.1 joerg std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type");
329 1.1 joerg unsigned I = 0;
330 1.1 joerg for (const auto &T : Types) {
331 1.1 joerg TypeMap.insert(std::make_pair(T, I++));
332 1.1 joerg }
333 1.1 joerg
334 1.1 joerg // Populate the SignaturesList and the FctOverloadMap.
335 1.1 joerg unsigned CumulativeSignIndex = 0;
336 1.1 joerg std::vector<Record *> Builtins = Records.getAllDerivedDefinitions("Builtin");
337 1.1 joerg for (const auto *B : Builtins) {
338 1.1 joerg StringRef BName = B->getValueAsString("Name");
339 1.1 joerg if (FctOverloadMap.find(BName) == FctOverloadMap.end()) {
340 1.1 joerg FctOverloadMap.insert(std::make_pair(
341 1.1 joerg BName, std::vector<std::pair<const Record *, unsigned>>{}));
342 1.1 joerg }
343 1.1 joerg
344 1.1 joerg auto Signature = B->getValueAsListOfDefs("Signature");
345 1.1 joerg // Reuse signatures to avoid unnecessary duplicates.
346 1.1 joerg auto it =
347 1.1 joerg std::find_if(SignaturesList.begin(), SignaturesList.end(),
348 1.1 joerg [&](const std::pair<std::vector<Record *>, unsigned> &a) {
349 1.1 joerg return a.first == Signature;
350 1.1 joerg });
351 1.1 joerg unsigned SignIndex;
352 1.1 joerg if (it == SignaturesList.end()) {
353 1.1 joerg VerifySignature(Signature, B);
354 1.1 joerg SignaturesList.push_back(std::make_pair(Signature, CumulativeSignIndex));
355 1.1 joerg SignIndex = CumulativeSignIndex;
356 1.1 joerg CumulativeSignIndex += Signature.size();
357 1.1 joerg } else {
358 1.1 joerg SignIndex = it->second;
359 1.1 joerg }
360 1.1 joerg FctOverloadMap[BName].push_back(std::make_pair(B, SignIndex));
361 1.1 joerg }
362 1.1 joerg }
363 1.1 joerg
364 1.1 joerg void BuiltinNameEmitter::EmitTypeTable() {
365 1.1 joerg OS << "static const OpenCLTypeStruct TypeTable[] = {\n";
366 1.1 joerg for (const auto &T : TypeMap) {
367 1.1 joerg const char *AccessQual =
368 1.1 joerg StringSwitch<const char *>(T.first->getValueAsString("AccessQualifier"))
369 1.1 joerg .Case("RO", "OCLAQ_ReadOnly")
370 1.1 joerg .Case("WO", "OCLAQ_WriteOnly")
371 1.1 joerg .Case("RW", "OCLAQ_ReadWrite")
372 1.1 joerg .Default("OCLAQ_None");
373 1.1 joerg
374 1.1 joerg OS << " // " << T.second << "\n"
375 1.1 joerg << " {OCLT_" << T.first->getValueAsString("Name") << ", "
376 1.1 joerg << T.first->getValueAsInt("VecWidth") << ", "
377 1.1 joerg << T.first->getValueAsBit("IsPointer") << ", "
378 1.1 joerg << T.first->getValueAsBit("IsConst") << ", "
379 1.1 joerg << T.first->getValueAsBit("IsVolatile") << ", "
380 1.1 joerg << AccessQual << ", "
381 1.1 joerg << T.first->getValueAsString("AddrSpace") << "},\n";
382 1.1 joerg }
383 1.1 joerg OS << "};\n\n";
384 1.1 joerg }
385 1.1 joerg
386 1.1 joerg void BuiltinNameEmitter::EmitSignatureTable() {
387 1.1 joerg // Store a type (e.g. int, float, int2, ...). The type is stored as an index
388 1.1 joerg // of a struct OpenCLType table. Multiple entries following each other form a
389 1.1 joerg // signature.
390 1.1 joerg OS << "static const unsigned SignatureTable[] = {\n";
391 1.1 joerg for (const auto &P : SignaturesList) {
392 1.1 joerg OS << " // " << P.second << "\n ";
393 1.1 joerg for (const Record *R : P.first) {
394 1.1 joerg OS << TypeMap.find(R)->second << ", ";
395 1.1 joerg }
396 1.1 joerg OS << "\n";
397 1.1 joerg }
398 1.1 joerg OS << "};\n\n";
399 1.1 joerg }
400 1.1 joerg
401 1.1 joerg void BuiltinNameEmitter::EmitBuiltinTable() {
402 1.1 joerg unsigned Index = 0;
403 1.1 joerg
404 1.1 joerg OS << "static const OpenCLBuiltinStruct BuiltinTable[] = {\n";
405 1.1 joerg for (const auto &FOM : FctOverloadMap) {
406 1.1 joerg
407 1.1 joerg OS << " // " << (Index + 1) << ": " << FOM.first << "\n";
408 1.1 joerg
409 1.1 joerg for (const auto &Overload : FOM.second) {
410 1.1 joerg OS << " { " << Overload.second << ", "
411 1.1 joerg << Overload.first->getValueAsListOfDefs("Signature").size() << ", "
412 1.1 joerg << Overload.first->getValueAsDef("MinVersion")->getValueAsInt("ID")
413 1.1 joerg << ", "
414 1.1 joerg << Overload.first->getValueAsDef("MaxVersion")->getValueAsInt("ID")
415 1.1 joerg << " },\n";
416 1.1 joerg Index++;
417 1.1 joerg }
418 1.1 joerg }
419 1.1 joerg OS << "};\n\n";
420 1.1 joerg }
421 1.1 joerg
422 1.1 joerg void BuiltinNameEmitter::EmitStringMatcher() {
423 1.1 joerg std::vector<StringMatcher::StringPair> ValidBuiltins;
424 1.1 joerg unsigned CumulativeIndex = 1;
425 1.1 joerg for (auto &i : FctOverloadMap) {
426 1.1 joerg auto &Ov = i.second;
427 1.1 joerg std::string RetStmt;
428 1.1 joerg raw_string_ostream SS(RetStmt);
429 1.1 joerg SS << "return std::make_pair(" << CumulativeIndex << ", " << Ov.size()
430 1.1 joerg << ");";
431 1.1 joerg SS.flush();
432 1.1 joerg CumulativeIndex += Ov.size();
433 1.1 joerg
434 1.1 joerg ValidBuiltins.push_back(StringMatcher::StringPair(i.first, RetStmt));
435 1.1 joerg }
436 1.1 joerg
437 1.1 joerg OS << R"(
438 1.1 joerg // Find out whether a string matches an existing OpenCL builtin function name.
439 1.1 joerg // Returns: A pair <0, 0> if no name matches.
440 1.1 joerg // A pair <Index, Len> indexing the BuiltinTable if the name is
441 1.1 joerg // matching an OpenCL builtin function.
442 1.1 joerg static std::pair<unsigned, unsigned> isOpenCLBuiltin(llvm::StringRef Name) {
443 1.1 joerg
444 1.1 joerg )";
445 1.1 joerg
446 1.1 joerg StringMatcher("Name", ValidBuiltins, OS).Emit(0, true);
447 1.1 joerg
448 1.1 joerg OS << " return std::make_pair(0, 0);\n";
449 1.1 joerg OS << "} // isOpenCLBuiltin\n";
450 1.1 joerg }
451 1.1 joerg
452 1.1 joerg void BuiltinNameEmitter::EmitQualTypeFinder() {
453 1.1 joerg OS << R"(
454 1.1 joerg
455 1.1 joerg // Convert an OpenCLTypeStruct type to a list of QualTypes.
456 1.1 joerg // Generic types represent multiple types and vector sizes, thus a vector
457 1.1 joerg // is returned. The conversion is done in two steps:
458 1.1 joerg // Step 1: A switch statement fills a vector with scalar base types for the
459 1.1 joerg // Cartesian product of (vector sizes) x (types) for generic types,
460 1.1 joerg // or a single scalar type for non generic types.
461 1.1 joerg // Step 2: Qualifiers and other type properties such as vector size are
462 1.1 joerg // applied.
463 1.1 joerg static void OCL2Qual(ASTContext &Context, const OpenCLTypeStruct &Ty,
464 1.1 joerg llvm::SmallVectorImpl<QualType> &QT) {
465 1.1 joerg // Number of scalar types in the GenType.
466 1.1 joerg unsigned GenTypeNumTypes;
467 1.1 joerg // Pointer to the list of vector sizes for the GenType.
468 1.1 joerg llvm::ArrayRef<unsigned> GenVectorSizes;
469 1.1 joerg )";
470 1.1 joerg
471 1.1 joerg // Generate list of vector sizes for each generic type.
472 1.1 joerg for (const auto *VectList : Records.getAllDerivedDefinitions("IntList")) {
473 1.1 joerg OS << " constexpr unsigned List"
474 1.1 joerg << VectList->getValueAsString("Name") << "[] = {";
475 1.1 joerg for (const auto V : VectList->getValueAsListOfInts("List")) {
476 1.1 joerg OS << V << ", ";
477 1.1 joerg }
478 1.1 joerg OS << "};\n";
479 1.1 joerg }
480 1.1 joerg
481 1.1 joerg // Step 1.
482 1.1 joerg // Start of switch statement over all types.
483 1.1 joerg OS << "\n switch (Ty.ID) {\n";
484 1.1 joerg
485 1.1 joerg // Switch cases for image types (Image2d, Image3d, ...)
486 1.1 joerg std::vector<Record *> ImageTypes =
487 1.1 joerg Records.getAllDerivedDefinitions("ImageType");
488 1.1 joerg
489 1.1 joerg // Map an image type name to its 3 access-qualified types (RO, WO, RW).
490 1.1 joerg std::map<StringRef, SmallVector<Record *, 3>> ImageTypesMap;
491 1.1 joerg for (auto *IT : ImageTypes) {
492 1.1 joerg auto Entry = ImageTypesMap.find(IT->getValueAsString("Name"));
493 1.1 joerg if (Entry == ImageTypesMap.end()) {
494 1.1 joerg SmallVector<Record *, 3> ImageList;
495 1.1 joerg ImageList.push_back(IT);
496 1.1 joerg ImageTypesMap.insert(
497 1.1 joerg std::make_pair(IT->getValueAsString("Name"), ImageList));
498 1.1 joerg } else {
499 1.1 joerg Entry->second.push_back(IT);
500 1.1 joerg }
501 1.1 joerg }
502 1.1 joerg
503 1.1 joerg // Emit the cases for the image types. For an image type name, there are 3
504 1.1 joerg // corresponding QualTypes ("RO", "WO", "RW"). The "AccessQualifier" field
505 1.1 joerg // tells which one is needed. Emit a switch statement that puts the
506 1.1 joerg // corresponding QualType into "QT".
507 1.1 joerg for (const auto &ITE : ImageTypesMap) {
508 1.1 joerg OS << " case OCLT_" << ITE.first.str() << ":\n"
509 1.1 joerg << " switch (Ty.AccessQualifier) {\n"
510 1.1 joerg << " case OCLAQ_None:\n"
511 1.1 joerg << " llvm_unreachable(\"Image without access qualifier\");\n";
512 1.1 joerg for (const auto &Image : ITE.second) {
513 1.1 joerg OS << StringSwitch<const char *>(
514 1.1 joerg Image->getValueAsString("AccessQualifier"))
515 1.1 joerg .Case("RO", " case OCLAQ_ReadOnly:\n")
516 1.1 joerg .Case("WO", " case OCLAQ_WriteOnly:\n")
517 1.1 joerg .Case("RW", " case OCLAQ_ReadWrite:\n")
518 1.1 joerg << " QT.push_back(Context."
519 1.1 joerg << Image->getValueAsDef("QTName")->getValueAsString("Name") << ");\n"
520 1.1 joerg << " break;\n";
521 1.1 joerg }
522 1.1 joerg OS << " }\n"
523 1.1 joerg << " break;\n";
524 1.1 joerg }
525 1.1 joerg
526 1.1 joerg // Switch cases for generic types.
527 1.1 joerg for (const auto *GenType : Records.getAllDerivedDefinitions("GenericType")) {
528 1.1 joerg OS << " case OCLT_" << GenType->getValueAsString("Name") << ":\n";
529 1.1 joerg OS << " QT.append({";
530 1.1 joerg
531 1.1 joerg // Build the Cartesian product of (vector sizes) x (types). Only insert
532 1.1 joerg // the plain scalar types for now; other type information such as vector
533 1.1 joerg // size and type qualifiers will be added after the switch statement.
534 1.1 joerg for (unsigned I = 0; I < GenType->getValueAsDef("VectorList")
535 1.1 joerg ->getValueAsListOfInts("List")
536 1.1 joerg .size();
537 1.1 joerg I++) {
538 1.1 joerg for (const auto *T :
539 1.1 joerg GenType->getValueAsDef("TypeList")->getValueAsListOfDefs("List")) {
540 1.1 joerg OS << "Context."
541 1.1 joerg << T->getValueAsDef("QTName")->getValueAsString("Name") << ", ";
542 1.1 joerg }
543 1.1 joerg }
544 1.1 joerg OS << "});\n";
545 1.1 joerg // GenTypeNumTypes is the number of types in the GenType
546 1.1 joerg // (e.g. float/double/half).
547 1.1 joerg OS << " GenTypeNumTypes = "
548 1.1 joerg << GenType->getValueAsDef("TypeList")->getValueAsListOfDefs("List")
549 1.1 joerg .size()
550 1.1 joerg << ";\n";
551 1.1 joerg // GenVectorSizes is the list of vector sizes for this GenType.
552 1.1 joerg // QT contains GenTypeNumTypes * #GenVectorSizes elements.
553 1.1 joerg OS << " GenVectorSizes = List"
554 1.1 joerg << GenType->getValueAsDef("VectorList")->getValueAsString("Name")
555 1.1 joerg << ";\n";
556 1.1 joerg OS << " break;\n";
557 1.1 joerg }
558 1.1 joerg
559 1.1 joerg // Switch cases for non generic, non image types (int, int4, float, ...).
560 1.1 joerg // Only insert the plain scalar type; vector information and type qualifiers
561 1.1 joerg // are added in step 2.
562 1.1 joerg std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type");
563 1.1 joerg StringMap<bool> TypesSeen;
564 1.1 joerg
565 1.1 joerg for (const auto *T : Types) {
566 1.1 joerg // Check this is not an image type
567 1.1 joerg if (ImageTypesMap.find(T->getValueAsString("Name")) != ImageTypesMap.end())
568 1.1 joerg continue;
569 1.1 joerg // Check we have not seen this Type
570 1.1 joerg if (TypesSeen.find(T->getValueAsString("Name")) != TypesSeen.end())
571 1.1 joerg continue;
572 1.1 joerg TypesSeen.insert(std::make_pair(T->getValueAsString("Name"), true));
573 1.1 joerg
574 1.1 joerg // Check the Type does not have an "abstract" QualType
575 1.1 joerg auto QT = T->getValueAsDef("QTName");
576 1.1 joerg if (QT->getValueAsBit("IsAbstract") == 1)
577 1.1 joerg continue;
578 1.1 joerg // Emit the cases for non generic, non image types.
579 1.1 joerg OS << " case OCLT_" << T->getValueAsString("Name") << ":\n";
580 1.1 joerg OS << " QT.push_back(Context." << QT->getValueAsString("Name")
581 1.1 joerg << ");\n";
582 1.1 joerg OS << " break;\n";
583 1.1 joerg }
584 1.1 joerg
585 1.1 joerg // End of switch statement.
586 1.1 joerg OS << " default:\n"
587 1.1 joerg << " llvm_unreachable(\"OpenCL builtin type not handled yet\");\n"
588 1.1 joerg << " } // end of switch (Ty.ID)\n\n";
589 1.1 joerg
590 1.1 joerg // Step 2.
591 1.1 joerg // Add ExtVector types if this was a generic type, as the switch statement
592 1.1 joerg // above only populated the list with scalar types. This completes the
593 1.1 joerg // construction of the Cartesian product of (vector sizes) x (types).
594 1.1 joerg OS << " // Construct the different vector types for each generic type.\n";
595 1.1 joerg OS << " if (Ty.ID >= " << TypeList.size() << ") {";
596 1.1 joerg OS << R"(
597 1.1 joerg for (unsigned I = 0; I < QT.size(); I++) {
598 1.1 joerg // For scalars, size is 1.
599 1.1 joerg if (GenVectorSizes[I / GenTypeNumTypes] != 1) {
600 1.1 joerg QT[I] = Context.getExtVectorType(QT[I],
601 1.1 joerg GenVectorSizes[I / GenTypeNumTypes]);
602 1.1 joerg }
603 1.1 joerg }
604 1.1 joerg }
605 1.1 joerg )";
606 1.1 joerg
607 1.1 joerg // Assign the right attributes to the types (e.g. vector size).
608 1.1 joerg OS << R"(
609 1.1 joerg // Set vector size for non-generic vector types.
610 1.1 joerg if (Ty.VectorWidth > 1) {
611 1.1 joerg for (unsigned Index = 0; Index < QT.size(); Index++) {
612 1.1 joerg QT[Index] = Context.getExtVectorType(QT[Index], Ty.VectorWidth);
613 1.1 joerg }
614 1.1 joerg }
615 1.1 joerg
616 1.1 joerg if (Ty.IsVolatile != 0) {
617 1.1 joerg for (unsigned Index = 0; Index < QT.size(); Index++) {
618 1.1 joerg QT[Index] = Context.getVolatileType(QT[Index]);
619 1.1 joerg }
620 1.1 joerg }
621 1.1 joerg
622 1.1 joerg if (Ty.IsConst != 0) {
623 1.1 joerg for (unsigned Index = 0; Index < QT.size(); Index++) {
624 1.1 joerg QT[Index] = Context.getConstType(QT[Index]);
625 1.1 joerg }
626 1.1 joerg }
627 1.1 joerg
628 1.1 joerg // Transform the type to a pointer as the last step, if necessary.
629 1.1 joerg // Builtin functions only have pointers on [const|volatile], no
630 1.1 joerg // [const|volatile] pointers, so this is ok to do it as a last step.
631 1.1 joerg if (Ty.IsPointer != 0) {
632 1.1 joerg for (unsigned Index = 0; Index < QT.size(); Index++) {
633 1.1 joerg QT[Index] = Context.getAddrSpaceQualType(QT[Index], Ty.AS);
634 1.1 joerg QT[Index] = Context.getPointerType(QT[Index]);
635 1.1 joerg }
636 1.1 joerg }
637 1.1 joerg )";
638 1.1 joerg
639 1.1 joerg // End of the "OCL2Qual" function.
640 1.1 joerg OS << "\n} // OCL2Qual\n";
641 1.1 joerg }
642 1.1 joerg
643 1.1 joerg void clang::EmitClangOpenCLBuiltins(RecordKeeper &Records, raw_ostream &OS) {
644 1.1 joerg BuiltinNameEmitter NameChecker(Records, OS);
645 1.1 joerg NameChecker.Emit();
646 1.1 joerg }
647