]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp
MFC r355940:
[FreeBSD/FreeBSD.git] / contrib / llvm-project / clang / utils / TableGen / ClangOpenCLBuiltinEmitter.cpp
1 //===- ClangOpenCLBuiltinEmitter.cpp - Generate Clang OpenCL Builtin handling
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
6 // See https://llvm.org/LICENSE.txt for license information.
7 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8 //
9 //===----------------------------------------------------------------------===//
10 //
11 // This tablegen backend emits code for checking whether a function is an
12 // OpenCL builtin function. If so, all overloads of this function are
13 // added to the LookupResult. The generated include file is used by
14 // SemaLookup.cpp
15 //
16 // For a successful lookup of e.g. the "cos" builtin, isOpenCLBuiltin("cos")
17 // returns a pair <Index, Len>.
18 // OpenCLBuiltins[Index] to OpenCLBuiltins[Index + Len] contains the pairs
19 // <SigIndex, SigLen> of the overloads of "cos".
20 // OpenCLSignature[SigIndex] to OpenCLSignature[SigIndex + SigLen] contains
21 // one of the signatures of "cos". The OpenCLSignature entry can be
22 // referenced by other functions, i.e. "sin", since multiple OpenCL builtins
23 // share the same signature.
24 //===----------------------------------------------------------------------===//
25
26 #include "llvm/ADT/MapVector.h"
27 #include "llvm/ADT/STLExtras.h"
28 #include "llvm/ADT/SmallString.h"
29 #include "llvm/ADT/StringExtras.h"
30 #include "llvm/ADT/StringRef.h"
31 #include "llvm/ADT/StringSet.h"
32 #include "llvm/Support/ErrorHandling.h"
33 #include "llvm/Support/raw_ostream.h"
34 #include "llvm/TableGen/Error.h"
35 #include "llvm/TableGen/Record.h"
36 #include "llvm/TableGen/StringMatcher.h"
37 #include "llvm/TableGen/TableGenBackend.h"
38 #include <set>
39
40 using namespace llvm;
41
42 namespace {
43 class BuiltinNameEmitter {
44 public:
45   BuiltinNameEmitter(RecordKeeper &Records, raw_ostream &OS)
46       : Records(Records), OS(OS) {}
47
48   // Entrypoint to generate the functions and structures for checking
49   // whether a function is an OpenCL builtin function.
50   void Emit();
51
52 private:
53   // Contains OpenCL builtin functions and related information, stored as
54   // Record instances. They are coming from the associated TableGen file.
55   RecordKeeper &Records;
56
57   // The output file.
58   raw_ostream &OS;
59
60   // Emit the enums and structs.
61   void EmitDeclarations();
62
63   // Parse the Records generated by TableGen and populate OverloadInfo and
64   // SignatureSet.
65   void GetOverloads();
66
67   // Emit the OpenCLSignature table. This table contains all possible
68   // signatures, and is a struct OpenCLType. A signature is composed of a
69   // return type (mandatory), followed by zero or more argument types.
70   // E.g.:
71   // // 12
72   // { OCLT_uchar, 4, clang::LangAS::Default, false },
73   // { OCLT_float, 4, clang::LangAS::Default, false },
74   // This means that index 12 represents a signature
75   //   - returning a uchar vector of 4 elements, and
76   //   - taking as first argument a float vector of 4 elements.
77   void EmitSignatureTable();
78
79   // Emit the OpenCLBuiltins table. This table contains all overloads of
80   // each function, and is a struct OpenCLBuiltinDecl.
81   // E.g.:
82   // // acos
83   //   { 2, 0, "", 100 },
84   // This means that the signature of this acos overload is defined in OpenCL
85   // version 1.0 (100) and does not belong to any extension ("").  It has a
86   // 1 argument (+1 for the return type), stored at index 0 in the
87   // OpenCLSignature table.
88   void EmitBuiltinTable();
89
90   // Emit a StringMatcher function to check whether a function name is an
91   // OpenCL builtin function name.
92   void EmitStringMatcher();
93
94   // Emit a function returning the clang QualType instance associated with
95   // the TableGen Record Type.
96   void EmitQualTypeFinder();
97
98   // Contains a list of the available signatures, without the name of the
99   // function. Each pair consists of a signature and a cumulative index.
100   // E.g.:  <<float, float>, 0>,
101   //        <<float, int, int, 2>>,
102   //        <<float>, 5>,
103   //        ...
104   //        <<double, double>, 35>.
105   std::vector<std::pair<std::vector<Record *>, unsigned>> SignatureSet;
106
107   // Map the name of a builtin function to its prototypes (instances of the
108   // TableGen "Builtin" class).
109   // Each prototype is registered as a pair of:
110   //   <pointer to the "Builtin" instance,
111   //    cumulative index of the associated signature in the SignatureSet>
112   // E.g.:  The function cos: (float cos(float), double cos(double), ...)
113   //        <"cos", <<ptrToPrototype0, 5>,
114   //                <ptrToPrototype1, 35>>
115   //                <ptrToPrototype2, 79>>
116   // ptrToPrototype1 has the following signature: <double, double>
117   MapVector<StringRef, std::vector<std::pair<const Record *, unsigned>>>
118       OverloadInfo;
119 };
120 } // namespace
121
122 void BuiltinNameEmitter::Emit() {
123   emitSourceFileHeader("OpenCL Builtin handling", OS);
124
125   OS << "#include \"llvm/ADT/StringRef.h\"\n";
126   OS << "using namespace clang;\n\n";
127
128   EmitDeclarations();
129
130   GetOverloads();
131
132   EmitSignatureTable();
133
134   EmitBuiltinTable();
135
136   EmitStringMatcher();
137
138   EmitQualTypeFinder();
139 }
140
141 void BuiltinNameEmitter::EmitDeclarations() {
142   OS << "enum OpenCLTypeID {\n";
143   std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type");
144   StringMap<bool> TypesSeen;
145   for (const auto *T : Types) {
146     if (TypesSeen.find(T->getValueAsString("Name")) == TypesSeen.end())
147       OS << "  OCLT_" + T->getValueAsString("Name") << ",\n";
148     TypesSeen.insert(std::make_pair(T->getValueAsString("Name"), true));
149   }
150   OS << "};\n";
151
152   OS << R"(
153
154 // Type used in a prototype of an OpenCL builtin function.
155 struct OpenCLType {
156   // A type (e.g.: float, int, ...)
157   OpenCLTypeID ID;
158   // Size of vector (if applicable)
159   unsigned VectorWidth;
160   // Address space of the pointer (if applicable)
161   LangAS AS;
162   // Whether the type is a pointer
163   bool isPointer;
164 };
165
166 // One overload of an OpenCL builtin function.
167 struct OpenCLBuiltinDecl {
168   // Number of arguments for the signature
169   unsigned NumArgs;
170   // Index in the OpenCLSignature table to get the required types
171   unsigned ArgTableIndex;
172   // Extension to which it belongs (e.g. cl_khr_subgroups)
173   const char *Extension;
174   // Version in which it was introduced (e.g. CL20)
175   unsigned Version;
176 };
177
178 )";
179 }
180
181 void BuiltinNameEmitter::GetOverloads() {
182   unsigned CumulativeSignIndex = 0;
183   std::vector<Record *> Builtins = Records.getAllDerivedDefinitions("Builtin");
184   for (const auto *B : Builtins) {
185     StringRef BName = B->getValueAsString("Name");
186     if (OverloadInfo.find(BName) == OverloadInfo.end()) {
187       OverloadInfo.insert(std::make_pair(
188           BName, std::vector<std::pair<const Record *, unsigned>>{}));
189     }
190
191     auto Signature = B->getValueAsListOfDefs("Signature");
192     auto it =
193         std::find_if(SignatureSet.begin(), SignatureSet.end(),
194                      [&](const std::pair<std::vector<Record *>, unsigned> &a) {
195                        return a.first == Signature;
196                      });
197     unsigned SignIndex;
198     if (it == SignatureSet.end()) {
199       SignatureSet.push_back(std::make_pair(Signature, CumulativeSignIndex));
200       SignIndex = CumulativeSignIndex;
201       CumulativeSignIndex += Signature.size();
202     } else {
203       SignIndex = it->second;
204     }
205     OverloadInfo[BName].push_back(std::make_pair(B, SignIndex));
206   }
207 }
208
209 void BuiltinNameEmitter::EmitSignatureTable() {
210   OS << "static const OpenCLType OpenCLSignature[] = {\n";
211   for (auto &P : SignatureSet) {
212     OS << "// " << P.second << "\n";
213     for (Record *R : P.first) {
214       OS << "{ OCLT_" << R->getValueAsString("Name") << ", "
215          << R->getValueAsInt("VecWidth") << ", "
216          << R->getValueAsString("AddrSpace") << ", "
217          << R->getValueAsBit("IsPointer") << "},";
218       OS << "\n";
219     }
220   }
221   OS << "};\n\n";
222 }
223
224 void BuiltinNameEmitter::EmitBuiltinTable() {
225   OS << "static const OpenCLBuiltinDecl OpenCLBuiltins[] = {\n";
226   for (auto &i : OverloadInfo) {
227     StringRef Name = i.first;
228     OS << "// " << Name << "\n";
229     for (auto &Overload : i.second) {
230       OS << "  { " << Overload.first->getValueAsListOfDefs("Signature").size()
231          << ", " << Overload.second << ", " << '"'
232          << Overload.first->getValueAsString("Extension") << "\", "
233          << Overload.first->getValueAsDef("Version")->getValueAsInt("Version")
234          << " },\n";
235     }
236   }
237   OS << "};\n\n";
238 }
239
240 void BuiltinNameEmitter::EmitStringMatcher() {
241   std::vector<StringMatcher::StringPair> ValidBuiltins;
242   unsigned CumulativeIndex = 1;
243   for (auto &i : OverloadInfo) {
244     auto &Ov = i.second;
245     std::string RetStmt;
246     raw_string_ostream SS(RetStmt);
247     SS << "return std::make_pair(" << CumulativeIndex << ", " << Ov.size()
248        << ");";
249     SS.flush();
250     CumulativeIndex += Ov.size();
251
252     ValidBuiltins.push_back(StringMatcher::StringPair(i.first, RetStmt));
253   }
254
255   OS << R"(
256 // Return 0 if name is not a recognized OpenCL builtin, or an index
257 // into a table of declarations if it is an OpenCL builtin.
258 static std::pair<unsigned, unsigned> isOpenCLBuiltin(llvm::StringRef name) {
259
260 )";
261
262   StringMatcher("name", ValidBuiltins, OS).Emit(0, true);
263
264   OS << "  return std::make_pair(0, 0);\n";
265   OS << "}\n";
266 }
267
268 void BuiltinNameEmitter::EmitQualTypeFinder() {
269   OS << R"(
270
271 static QualType OCL2Qual(ASTContext &Context, OpenCLType Ty) {
272   QualType RT = Context.VoidTy;
273   switch (Ty.ID) {
274 )";
275
276   std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type");
277   StringMap<bool> TypesSeen;
278
279   for (const auto *T : Types) {
280     // Check we have not seen this Type
281     if (TypesSeen.find(T->getValueAsString("Name")) != TypesSeen.end())
282       continue;
283     TypesSeen.insert(std::make_pair(T->getValueAsString("Name"), true));
284
285     // Check the Type does not have an "abstract" QualType
286     auto QT = T->getValueAsDef("QTName");
287     if (QT->getValueAsString("Name") == "null")
288       continue;
289
290     OS << "  case OCLT_" << T->getValueAsString("Name") << ":\n";
291     OS << "    RT = Context." << QT->getValueAsString("Name") << ";\n";
292     OS << "    break;\n";
293   }
294   OS << "  }\n";
295
296   // Special cases
297   OS << R"(
298   if (Ty.VectorWidth > 0)
299     RT = Context.getExtVectorType(RT, Ty.VectorWidth);
300
301   if (Ty.isPointer) {
302     RT = Context.getAddrSpaceQualType(RT, Ty.AS);
303     RT = Context.getPointerType(RT);
304   }
305
306   return RT;
307 }
308 )";
309 }
310
311 namespace clang {
312
313 void EmitClangOpenCLBuiltins(RecordKeeper &Records, raw_ostream &OS) {
314   BuiltinNameEmitter NameChecker(Records, OS);
315   NameChecker.Emit();
316 }
317
318 } // end namespace clang