Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/DirectiveEmitter.cpp
35258 views
1
//===- DirectiveEmitter.cpp - Directive Language Emitter ------------------===//
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
// DirectiveEmitter uses the descriptions of directives and clauses to construct
10
// common code declarations to be used in Frontends.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "llvm/TableGen/DirectiveEmitter.h"
15
#include "llvm/ADT/DenseMap.h"
16
#include "llvm/ADT/DenseSet.h"
17
#include "llvm/ADT/STLExtras.h"
18
#include "llvm/ADT/SmallVector.h"
19
#include "llvm/ADT/StringSet.h"
20
#include "llvm/ADT/StringSwitch.h"
21
#include "llvm/TableGen/Error.h"
22
#include "llvm/TableGen/Record.h"
23
#include "llvm/TableGen/TableGenBackend.h"
24
25
#include <numeric>
26
#include <vector>
27
28
using namespace llvm;
29
30
namespace {
31
// Simple RAII helper for defining ifdef-undef-endif scopes.
32
class IfDefScope {
33
public:
34
IfDefScope(StringRef Name, raw_ostream &OS) : Name(Name), OS(OS) {
35
OS << "#ifdef " << Name << "\n"
36
<< "#undef " << Name << "\n";
37
}
38
39
~IfDefScope() { OS << "\n#endif // " << Name << "\n\n"; }
40
41
private:
42
StringRef Name;
43
raw_ostream &OS;
44
};
45
} // namespace
46
47
// Generate enum class. Entries are emitted in the order in which they appear
48
// in the `Records` vector.
49
static void GenerateEnumClass(const std::vector<Record *> &Records,
50
raw_ostream &OS, StringRef Enum, StringRef Prefix,
51
const DirectiveLanguage &DirLang,
52
bool ExportEnums) {
53
OS << "\n";
54
OS << "enum class " << Enum << " {\n";
55
for (const auto &R : Records) {
56
BaseRecord Rec{R};
57
OS << " " << Prefix << Rec.getFormattedName() << ",\n";
58
}
59
OS << "};\n";
60
OS << "\n";
61
OS << "static constexpr std::size_t " << Enum
62
<< "_enumSize = " << Records.size() << ";\n";
63
64
// Make the enum values available in the defined namespace. This allows us to
65
// write something like Enum_X if we have a `using namespace <CppNamespace>`.
66
// At the same time we do not loose the strong type guarantees of the enum
67
// class, that is we cannot pass an unsigned as Directive without an explicit
68
// cast.
69
if (ExportEnums) {
70
OS << "\n";
71
for (const auto &R : Records) {
72
BaseRecord Rec{R};
73
OS << "constexpr auto " << Prefix << Rec.getFormattedName() << " = "
74
<< "llvm::" << DirLang.getCppNamespace() << "::" << Enum
75
<< "::" << Prefix << Rec.getFormattedName() << ";\n";
76
}
77
}
78
}
79
80
// Generate enums for values that clauses can take.
81
// Also generate function declarations for get<Enum>Name(StringRef Str).
82
static void GenerateEnumClauseVal(const std::vector<Record *> &Records,
83
raw_ostream &OS,
84
const DirectiveLanguage &DirLang,
85
std::string &EnumHelperFuncs) {
86
for (const auto &R : Records) {
87
Clause C{R};
88
const auto &ClauseVals = C.getClauseVals();
89
if (ClauseVals.size() <= 0)
90
continue;
91
92
const auto &EnumName = C.getEnumName();
93
if (EnumName.size() == 0) {
94
PrintError("enumClauseValue field not set in Clause" +
95
C.getFormattedName() + ".");
96
return;
97
}
98
99
OS << "\n";
100
OS << "enum class " << EnumName << " {\n";
101
for (const auto &CV : ClauseVals) {
102
ClauseVal CVal{CV};
103
OS << " " << CV->getName() << "=" << CVal.getValue() << ",\n";
104
}
105
OS << "};\n";
106
107
if (DirLang.hasMakeEnumAvailableInNamespace()) {
108
OS << "\n";
109
for (const auto &CV : ClauseVals) {
110
OS << "constexpr auto " << CV->getName() << " = "
111
<< "llvm::" << DirLang.getCppNamespace() << "::" << EnumName
112
<< "::" << CV->getName() << ";\n";
113
}
114
EnumHelperFuncs += (llvm::Twine(EnumName) + llvm::Twine(" get") +
115
llvm::Twine(EnumName) + llvm::Twine("(StringRef);\n"))
116
.str();
117
118
EnumHelperFuncs +=
119
(llvm::Twine("llvm::StringRef get") + llvm::Twine(DirLang.getName()) +
120
llvm::Twine(EnumName) + llvm::Twine("Name(") +
121
llvm::Twine(EnumName) + llvm::Twine(");\n"))
122
.str();
123
}
124
}
125
}
126
127
static bool HasDuplicateClauses(const std::vector<Record *> &Clauses,
128
const Directive &Directive,
129
llvm::StringSet<> &CrtClauses) {
130
bool HasError = false;
131
for (const auto &C : Clauses) {
132
VersionedClause VerClause{C};
133
const auto insRes = CrtClauses.insert(VerClause.getClause().getName());
134
if (!insRes.second) {
135
PrintError("Clause " + VerClause.getClause().getRecordName() +
136
" already defined on directive " + Directive.getRecordName());
137
HasError = true;
138
}
139
}
140
return HasError;
141
}
142
143
// Check for duplicate clauses in lists. Clauses cannot appear twice in the
144
// three allowed list. Also, since required implies allowed, clauses cannot
145
// appear in both the allowedClauses and requiredClauses lists.
146
static bool
147
HasDuplicateClausesInDirectives(const std::vector<Record *> &Directives) {
148
bool HasDuplicate = false;
149
for (const auto &D : Directives) {
150
Directive Dir{D};
151
llvm::StringSet<> Clauses;
152
// Check for duplicates in the three allowed lists.
153
if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) ||
154
HasDuplicateClauses(Dir.getAllowedOnceClauses(), Dir, Clauses) ||
155
HasDuplicateClauses(Dir.getAllowedExclusiveClauses(), Dir, Clauses)) {
156
HasDuplicate = true;
157
}
158
// Check for duplicate between allowedClauses and required
159
Clauses.clear();
160
if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) ||
161
HasDuplicateClauses(Dir.getRequiredClauses(), Dir, Clauses)) {
162
HasDuplicate = true;
163
}
164
if (HasDuplicate)
165
PrintFatalError("One or more clauses are defined multiple times on"
166
" directive " +
167
Dir.getRecordName());
168
}
169
170
return HasDuplicate;
171
}
172
173
// Check consitency of records. Return true if an error has been detected.
174
// Return false if the records are valid.
175
bool DirectiveLanguage::HasValidityErrors() const {
176
if (getDirectiveLanguages().size() != 1) {
177
PrintFatalError("A single definition of DirectiveLanguage is needed.");
178
return true;
179
}
180
181
return HasDuplicateClausesInDirectives(getDirectives());
182
}
183
184
// Count the maximum number of leaf constituents per construct.
185
static size_t GetMaxLeafCount(const DirectiveLanguage &DirLang) {
186
size_t MaxCount = 0;
187
for (Record *R : DirLang.getDirectives()) {
188
size_t Count = Directive{R}.getLeafConstructs().size();
189
MaxCount = std::max(MaxCount, Count);
190
}
191
return MaxCount;
192
}
193
194
// Generate the declaration section for the enumeration in the directive
195
// language
196
static void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) {
197
const auto DirLang = DirectiveLanguage{Records};
198
if (DirLang.HasValidityErrors())
199
return;
200
201
OS << "#ifndef LLVM_" << DirLang.getName() << "_INC\n";
202
OS << "#define LLVM_" << DirLang.getName() << "_INC\n";
203
OS << "\n#include \"llvm/ADT/ArrayRef.h\"\n";
204
205
if (DirLang.hasEnableBitmaskEnumInNamespace())
206
OS << "#include \"llvm/ADT/BitmaskEnum.h\"\n";
207
208
OS << "#include <cstddef>\n"; // for size_t
209
OS << "\n";
210
OS << "namespace llvm {\n";
211
OS << "class StringRef;\n";
212
213
// Open namespaces defined in the directive language
214
llvm::SmallVector<StringRef, 2> Namespaces;
215
llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::");
216
for (auto Ns : Namespaces)
217
OS << "namespace " << Ns << " {\n";
218
219
if (DirLang.hasEnableBitmaskEnumInNamespace())
220
OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n";
221
222
// Emit Directive associations
223
std::vector<Record *> associations;
224
llvm::copy_if(
225
DirLang.getAssociations(), std::back_inserter(associations),
226
// Skip the "special" value
227
[](const Record *Def) { return Def->getName() != "AS_FromLeaves"; });
228
GenerateEnumClass(associations, OS, "Association",
229
/*Prefix=*/"", DirLang, /*ExportEnums=*/false);
230
231
GenerateEnumClass(DirLang.getCategories(), OS, "Category", /*Prefix=*/"",
232
DirLang, /*ExportEnums=*/false);
233
234
// Emit Directive enumeration
235
GenerateEnumClass(DirLang.getDirectives(), OS, "Directive",
236
DirLang.getDirectivePrefix(), DirLang,
237
DirLang.hasMakeEnumAvailableInNamespace());
238
239
// Emit Clause enumeration
240
GenerateEnumClass(DirLang.getClauses(), OS, "Clause",
241
DirLang.getClausePrefix(), DirLang,
242
DirLang.hasMakeEnumAvailableInNamespace());
243
244
// Emit ClauseVal enumeration
245
std::string EnumHelperFuncs;
246
GenerateEnumClauseVal(DirLang.getClauses(), OS, DirLang, EnumHelperFuncs);
247
248
// Generic function signatures
249
OS << "\n";
250
OS << "// Enumeration helper functions\n";
251
OS << "Directive get" << DirLang.getName()
252
<< "DirectiveKind(llvm::StringRef Str);\n";
253
OS << "\n";
254
OS << "llvm::StringRef get" << DirLang.getName()
255
<< "DirectiveName(Directive D);\n";
256
OS << "\n";
257
OS << "Clause get" << DirLang.getName()
258
<< "ClauseKind(llvm::StringRef Str);\n";
259
OS << "\n";
260
OS << "llvm::StringRef get" << DirLang.getName() << "ClauseName(Clause C);\n";
261
OS << "\n";
262
OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p "
263
<< "Version.\n";
264
OS << "bool isAllowedClauseForDirective(Directive D, "
265
<< "Clause C, unsigned Version);\n";
266
OS << "\n";
267
OS << "constexpr std::size_t getMaxLeafCount() { return "
268
<< GetMaxLeafCount(DirLang) << "; }\n";
269
OS << "Association getDirectiveAssociation(Directive D);\n";
270
OS << "Category getDirectiveCategory(Directive D);\n";
271
if (EnumHelperFuncs.length() > 0) {
272
OS << EnumHelperFuncs;
273
OS << "\n";
274
}
275
276
// Closing namespaces
277
for (auto Ns : llvm::reverse(Namespaces))
278
OS << "} // namespace " << Ns << "\n";
279
280
OS << "} // namespace llvm\n";
281
282
OS << "#endif // LLVM_" << DirLang.getName() << "_INC\n";
283
}
284
285
// Generate function implementation for get<Enum>Name(StringRef Str)
286
static void GenerateGetName(const std::vector<Record *> &Records,
287
raw_ostream &OS, StringRef Enum,
288
const DirectiveLanguage &DirLang,
289
StringRef Prefix) {
290
OS << "\n";
291
OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get"
292
<< DirLang.getName() << Enum << "Name(" << Enum << " Kind) {\n";
293
OS << " switch (Kind) {\n";
294
for (const auto &R : Records) {
295
BaseRecord Rec{R};
296
OS << " case " << Prefix << Rec.getFormattedName() << ":\n";
297
OS << " return \"";
298
if (Rec.getAlternativeName().empty())
299
OS << Rec.getName();
300
else
301
OS << Rec.getAlternativeName();
302
OS << "\";\n";
303
}
304
OS << " }\n"; // switch
305
OS << " llvm_unreachable(\"Invalid " << DirLang.getName() << " " << Enum
306
<< " kind\");\n";
307
OS << "}\n";
308
}
309
310
// Generate function implementation for get<Enum>Kind(StringRef Str)
311
static void GenerateGetKind(const std::vector<Record *> &Records,
312
raw_ostream &OS, StringRef Enum,
313
const DirectiveLanguage &DirLang, StringRef Prefix,
314
bool ImplicitAsUnknown) {
315
316
auto DefaultIt = llvm::find_if(
317
Records, [](Record *R) { return R->getValueAsBit("isDefault") == true; });
318
319
if (DefaultIt == Records.end()) {
320
PrintError("At least one " + Enum + " must be defined as default.");
321
return;
322
}
323
324
BaseRecord DefaultRec{(*DefaultIt)};
325
326
OS << "\n";
327
OS << Enum << " llvm::" << DirLang.getCppNamespace() << "::get"
328
<< DirLang.getName() << Enum << "Kind(llvm::StringRef Str) {\n";
329
OS << " return llvm::StringSwitch<" << Enum << ">(Str)\n";
330
331
for (const auto &R : Records) {
332
BaseRecord Rec{R};
333
if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) {
334
OS << " .Case(\"" << Rec.getName() << "\"," << Prefix
335
<< DefaultRec.getFormattedName() << ")\n";
336
} else {
337
OS << " .Case(\"" << Rec.getName() << "\"," << Prefix
338
<< Rec.getFormattedName() << ")\n";
339
}
340
}
341
OS << " .Default(" << Prefix << DefaultRec.getFormattedName() << ");\n";
342
OS << "}\n";
343
}
344
345
// Generate function implementation for get<ClauseVal>Kind(StringRef Str)
346
static void GenerateGetKindClauseVal(const DirectiveLanguage &DirLang,
347
raw_ostream &OS) {
348
for (const auto &R : DirLang.getClauses()) {
349
Clause C{R};
350
const auto &ClauseVals = C.getClauseVals();
351
if (ClauseVals.size() <= 0)
352
continue;
353
354
auto DefaultIt = llvm::find_if(ClauseVals, [](Record *CV) {
355
return CV->getValueAsBit("isDefault") == true;
356
});
357
358
if (DefaultIt == ClauseVals.end()) {
359
PrintError("At least one val in Clause " + C.getFormattedName() +
360
" must be defined as default.");
361
return;
362
}
363
const auto DefaultName = (*DefaultIt)->getName();
364
365
const auto &EnumName = C.getEnumName();
366
if (EnumName.size() == 0) {
367
PrintError("enumClauseValue field not set in Clause" +
368
C.getFormattedName() + ".");
369
return;
370
}
371
372
OS << "\n";
373
OS << EnumName << " llvm::" << DirLang.getCppNamespace() << "::get"
374
<< EnumName << "(llvm::StringRef Str) {\n";
375
OS << " return llvm::StringSwitch<" << EnumName << ">(Str)\n";
376
for (const auto &CV : ClauseVals) {
377
ClauseVal CVal{CV};
378
OS << " .Case(\"" << CVal.getFormattedName() << "\"," << CV->getName()
379
<< ")\n";
380
}
381
OS << " .Default(" << DefaultName << ");\n";
382
OS << "}\n";
383
384
OS << "\n";
385
OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get"
386
<< DirLang.getName() << EnumName
387
<< "Name(llvm::" << DirLang.getCppNamespace() << "::" << EnumName
388
<< " x) {\n";
389
OS << " switch (x) {\n";
390
for (const auto &CV : ClauseVals) {
391
ClauseVal CVal{CV};
392
OS << " case " << CV->getName() << ":\n";
393
OS << " return \"" << CVal.getFormattedName() << "\";\n";
394
}
395
OS << " }\n"; // switch
396
OS << " llvm_unreachable(\"Invalid " << DirLang.getName() << " "
397
<< EnumName << " kind\");\n";
398
OS << "}\n";
399
}
400
}
401
402
static void
403
GenerateCaseForVersionedClauses(const std::vector<Record *> &Clauses,
404
raw_ostream &OS, StringRef DirectiveName,
405
const DirectiveLanguage &DirLang,
406
llvm::StringSet<> &Cases) {
407
for (const auto &C : Clauses) {
408
VersionedClause VerClause{C};
409
410
const auto ClauseFormattedName = VerClause.getClause().getFormattedName();
411
412
if (Cases.insert(ClauseFormattedName).second) {
413
OS << " case " << DirLang.getClausePrefix() << ClauseFormattedName
414
<< ":\n";
415
OS << " return " << VerClause.getMinVersion()
416
<< " <= Version && " << VerClause.getMaxVersion() << " >= Version;\n";
417
}
418
}
419
}
420
421
static std::string GetDirectiveName(const DirectiveLanguage &DirLang,
422
const Record *Rec) {
423
Directive Dir{Rec};
424
return (llvm::Twine("llvm::") + DirLang.getCppNamespace() +
425
"::" + DirLang.getDirectivePrefix() + Dir.getFormattedName())
426
.str();
427
}
428
429
static std::string GetDirectiveType(const DirectiveLanguage &DirLang) {
430
return (llvm::Twine("llvm::") + DirLang.getCppNamespace() + "::Directive")
431
.str();
432
}
433
434
// Generate the isAllowedClauseForDirective function implementation.
435
static void GenerateIsAllowedClause(const DirectiveLanguage &DirLang,
436
raw_ostream &OS) {
437
OS << "\n";
438
OS << "bool llvm::" << DirLang.getCppNamespace()
439
<< "::isAllowedClauseForDirective("
440
<< "Directive D, Clause C, unsigned Version) {\n";
441
OS << " assert(unsigned(D) <= llvm::" << DirLang.getCppNamespace()
442
<< "::Directive_enumSize);\n";
443
OS << " assert(unsigned(C) <= llvm::" << DirLang.getCppNamespace()
444
<< "::Clause_enumSize);\n";
445
446
OS << " switch (D) {\n";
447
448
for (const auto &D : DirLang.getDirectives()) {
449
Directive Dir{D};
450
451
OS << " case " << DirLang.getDirectivePrefix() << Dir.getFormattedName()
452
<< ":\n";
453
if (Dir.getAllowedClauses().size() == 0 &&
454
Dir.getAllowedOnceClauses().size() == 0 &&
455
Dir.getAllowedExclusiveClauses().size() == 0 &&
456
Dir.getRequiredClauses().size() == 0) {
457
OS << " return false;\n";
458
} else {
459
OS << " switch (C) {\n";
460
461
llvm::StringSet<> Cases;
462
463
GenerateCaseForVersionedClauses(Dir.getAllowedClauses(), OS,
464
Dir.getName(), DirLang, Cases);
465
466
GenerateCaseForVersionedClauses(Dir.getAllowedOnceClauses(), OS,
467
Dir.getName(), DirLang, Cases);
468
469
GenerateCaseForVersionedClauses(Dir.getAllowedExclusiveClauses(), OS,
470
Dir.getName(), DirLang, Cases);
471
472
GenerateCaseForVersionedClauses(Dir.getRequiredClauses(), OS,
473
Dir.getName(), DirLang, Cases);
474
475
OS << " default:\n";
476
OS << " return false;\n";
477
OS << " }\n"; // End of clauses switch
478
}
479
OS << " break;\n";
480
}
481
482
OS << " }\n"; // End of directives switch
483
OS << " llvm_unreachable(\"Invalid " << DirLang.getName()
484
<< " Directive kind\");\n";
485
OS << "}\n"; // End of function isAllowedClauseForDirective
486
}
487
488
static void EmitLeafTable(const DirectiveLanguage &DirLang, raw_ostream &OS,
489
StringRef TableName) {
490
// The leaf constructs are emitted in a form of a 2D table, where each
491
// row corresponds to a directive (and there is a row for each directive).
492
//
493
// Each row consists of
494
// - the id of the directive itself,
495
// - number of leaf constructs that will follow (0 for leafs),
496
// - ids of the leaf constructs (none if the directive is itself a leaf).
497
// The total number of these entries is at most MaxLeafCount+2. If this
498
// number is less than that, it is padded to occupy exactly MaxLeafCount+2
499
// entries in memory.
500
//
501
// The rows are stored in the table in the lexicographical order. This
502
// is intended to enable binary search when mapping a sequence of leafs
503
// back to the compound directive.
504
// The consequence of that is that in order to find a row corresponding
505
// to the given directive, we'd need to scan the first element of each
506
// row. To avoid this, an auxiliary ordering table is created, such that
507
// row for Dir_A = table[auxiliary[Dir_A]].
508
509
std::vector<Record *> Directives = DirLang.getDirectives();
510
DenseMap<Record *, int> DirId; // Record * -> llvm::omp::Directive
511
512
for (auto [Idx, Rec] : llvm::enumerate(Directives))
513
DirId.insert(std::make_pair(Rec, Idx));
514
515
using LeafList = std::vector<int>;
516
int MaxLeafCount = GetMaxLeafCount(DirLang);
517
518
// The initial leaf table, rows order is same as directive order.
519
std::vector<LeafList> LeafTable(Directives.size());
520
for (auto [Idx, Rec] : llvm::enumerate(Directives)) {
521
Directive Dir{Rec};
522
std::vector<Record *> Leaves = Dir.getLeafConstructs();
523
524
auto &List = LeafTable[Idx];
525
List.resize(MaxLeafCount + 2);
526
List[0] = Idx; // The id of the directive itself.
527
List[1] = Leaves.size(); // The number of leaves to follow.
528
529
for (int I = 0; I != MaxLeafCount; ++I)
530
List[I + 2] =
531
static_cast<size_t>(I) < Leaves.size() ? DirId.at(Leaves[I]) : -1;
532
}
533
534
// Some Fortran directives are delimited, i.e. they have the form of
535
// "directive"---"end directive". If "directive" is a compound construct,
536
// then the set of leaf constituents will be nonempty and the same for
537
// both directives. Given this set of leafs, looking up the corresponding
538
// compound directive should return "directive", and not "end directive".
539
// To avoid this problem, gather all "end directives" at the end of the
540
// leaf table, and only do the search on the initial segment of the table
541
// that excludes the "end directives".
542
// It's safe to find all directives whose names begin with "end ". The
543
// problem only exists for compound directives, like "end do simd".
544
// All existing directives with names starting with "end " are either
545
// "end directives" for an existing "directive", or leaf directives
546
// (such as "end declare target").
547
DenseSet<int> EndDirectives;
548
for (auto [Rec, Id] : DirId) {
549
if (Directive{Rec}.getName().starts_with_insensitive("end "))
550
EndDirectives.insert(Id);
551
}
552
553
// Avoid sorting the vector<vector> array, instead sort an index array.
554
// It will also be useful later to create the auxiliary indexing array.
555
std::vector<int> Ordering(Directives.size());
556
std::iota(Ordering.begin(), Ordering.end(), 0);
557
558
llvm::sort(Ordering, [&](int A, int B) {
559
auto &LeavesA = LeafTable[A];
560
auto &LeavesB = LeafTable[B];
561
int DirA = LeavesA[0], DirB = LeavesB[0];
562
// First of all, end directives compare greater than non-end directives.
563
int IsEndA = EndDirectives.count(DirA), IsEndB = EndDirectives.count(DirB);
564
if (IsEndA != IsEndB)
565
return IsEndA < IsEndB;
566
if (LeavesA[1] == 0 && LeavesB[1] == 0)
567
return DirA < DirB;
568
return std::lexicographical_compare(&LeavesA[2], &LeavesA[2] + LeavesA[1],
569
&LeavesB[2], &LeavesB[2] + LeavesB[1]);
570
});
571
572
// Emit the table
573
574
// The directives are emitted into a scoped enum, for which the underlying
575
// type is `int` (by default). The code above uses `int` to store directive
576
// ids, so make sure that we catch it when something changes in the
577
// underlying type.
578
std::string DirectiveType = GetDirectiveType(DirLang);
579
OS << "\nstatic_assert(sizeof(" << DirectiveType << ") == sizeof(int));\n";
580
581
OS << "[[maybe_unused]] static const " << DirectiveType << ' ' << TableName
582
<< "[][" << MaxLeafCount + 2 << "] = {\n";
583
for (size_t I = 0, E = Directives.size(); I != E; ++I) {
584
auto &Leaves = LeafTable[Ordering[I]];
585
OS << " {" << GetDirectiveName(DirLang, Directives[Leaves[0]]);
586
OS << ", static_cast<" << DirectiveType << ">(" << Leaves[1] << "),";
587
for (size_t I = 2, E = Leaves.size(); I != E; ++I) {
588
int Idx = Leaves[I];
589
if (Idx >= 0)
590
OS << ' ' << GetDirectiveName(DirLang, Directives[Leaves[I]]) << ',';
591
else
592
OS << " static_cast<" << DirectiveType << ">(-1),";
593
}
594
OS << "},\n";
595
}
596
OS << "};\n\n";
597
598
// Emit a marker where the first "end directive" is.
599
auto FirstE = llvm::find_if(Ordering, [&](int RowIdx) {
600
return EndDirectives.count(LeafTable[RowIdx][0]);
601
});
602
OS << "[[maybe_unused]] static auto " << TableName
603
<< "EndDirective = " << TableName << " + "
604
<< std::distance(Ordering.begin(), FirstE) << ";\n\n";
605
606
// Emit the auxiliary index table: it's the inverse of the `Ordering`
607
// table above.
608
OS << "[[maybe_unused]] static const int " << TableName << "Ordering[] = {\n";
609
OS << " ";
610
std::vector<int> Reverse(Ordering.size());
611
for (int I = 0, E = Ordering.size(); I != E; ++I)
612
Reverse[Ordering[I]] = I;
613
for (int Idx : Reverse)
614
OS << ' ' << Idx << ',';
615
OS << "\n};\n";
616
}
617
618
static void GenerateGetDirectiveAssociation(const DirectiveLanguage &DirLang,
619
raw_ostream &OS) {
620
enum struct Association {
621
None = 0, // None should be the smallest value.
622
Block, // The values of the rest don't matter.
623
Declaration,
624
Delimited,
625
Loop,
626
Separating,
627
FromLeaves,
628
Invalid,
629
};
630
631
std::vector<Record *> associations = DirLang.getAssociations();
632
633
auto getAssocValue = [](StringRef name) -> Association {
634
return StringSwitch<Association>(name)
635
.Case("AS_Block", Association::Block)
636
.Case("AS_Declaration", Association::Declaration)
637
.Case("AS_Delimited", Association::Delimited)
638
.Case("AS_Loop", Association::Loop)
639
.Case("AS_None", Association::None)
640
.Case("AS_Separating", Association::Separating)
641
.Case("AS_FromLeaves", Association::FromLeaves)
642
.Default(Association::Invalid);
643
};
644
645
auto getAssocName = [&](Association A) -> StringRef {
646
if (A != Association::Invalid && A != Association::FromLeaves) {
647
auto F = llvm::find_if(associations, [&](const Record *R) {
648
return getAssocValue(R->getName()) == A;
649
});
650
if (F != associations.end())
651
return (*F)->getValueAsString("name"); // enum name
652
}
653
llvm_unreachable("Unexpected association value");
654
};
655
656
auto errorPrefixFor = [&](Directive D) -> std::string {
657
return (Twine("Directive '") + D.getName() + "' in namespace '" +
658
DirLang.getCppNamespace() + "' ")
659
.str();
660
};
661
662
auto reduce = [&](Association A, Association B) -> Association {
663
if (A > B)
664
std::swap(A, B);
665
666
// Calculate the result using the following rules:
667
// x + x = x
668
// AS_None + x = x
669
// AS_Block + AS_Loop = AS_Loop
670
if (A == Association::None || A == B)
671
return B;
672
if (A == Association::Block && B == Association::Loop)
673
return B;
674
if (A == Association::Loop && B == Association::Block)
675
return A;
676
return Association::Invalid;
677
};
678
679
llvm::DenseMap<const Record *, Association> AsMap;
680
681
auto compAssocImpl = [&](const Record *R, auto &&Self) -> Association {
682
if (auto F = AsMap.find(R); F != AsMap.end())
683
return F->second;
684
685
Directive D{R};
686
Association AS = getAssocValue(D.getAssociation()->getName());
687
if (AS == Association::Invalid) {
688
PrintFatalError(errorPrefixFor(D) +
689
"has an unrecognized value for association: '" +
690
D.getAssociation()->getName() + "'");
691
}
692
if (AS != Association::FromLeaves) {
693
AsMap.insert(std::make_pair(R, AS));
694
return AS;
695
}
696
// Compute the association from leaf constructs.
697
std::vector<Record *> leaves = D.getLeafConstructs();
698
if (leaves.empty()) {
699
llvm::errs() << D.getName() << '\n';
700
PrintFatalError(errorPrefixFor(D) +
701
"requests association to be computed from leaves, "
702
"but it has no leaves");
703
}
704
705
Association Result = Self(leaves[0], Self);
706
for (int I = 1, E = leaves.size(); I < E; ++I) {
707
Association A = Self(leaves[I], Self);
708
Association R = reduce(Result, A);
709
if (R == Association::Invalid) {
710
PrintFatalError(errorPrefixFor(D) +
711
"has leaves with incompatible association values: " +
712
getAssocName(A) + " and " + getAssocName(R));
713
}
714
Result = R;
715
}
716
717
assert(Result != Association::Invalid);
718
assert(Result != Association::FromLeaves);
719
AsMap.insert(std::make_pair(R, Result));
720
return Result;
721
};
722
723
for (Record *R : DirLang.getDirectives())
724
compAssocImpl(R, compAssocImpl); // Updates AsMap.
725
726
OS << '\n';
727
728
auto getQualifiedName = [&](StringRef Formatted) -> std::string {
729
return (llvm::Twine("llvm::") + DirLang.getCppNamespace() +
730
"::Directive::" + DirLang.getDirectivePrefix() + Formatted)
731
.str();
732
};
733
734
std::string DirectiveTypeName =
735
std::string("llvm::") + DirLang.getCppNamespace().str() + "::Directive";
736
std::string AssociationTypeName =
737
std::string("llvm::") + DirLang.getCppNamespace().str() + "::Association";
738
739
OS << AssociationTypeName << " llvm::" << DirLang.getCppNamespace()
740
<< "::getDirectiveAssociation(" << DirectiveTypeName << " Dir) {\n";
741
OS << " switch (Dir) {\n";
742
for (Record *R : DirLang.getDirectives()) {
743
if (auto F = AsMap.find(R); F != AsMap.end()) {
744
Directive Dir{R};
745
OS << " case " << getQualifiedName(Dir.getFormattedName()) << ":\n";
746
OS << " return " << AssociationTypeName
747
<< "::" << getAssocName(F->second) << ";\n";
748
}
749
}
750
OS << " } // switch (Dir)\n";
751
OS << " llvm_unreachable(\"Unexpected directive\");\n";
752
OS << "}\n";
753
}
754
755
static void GenerateGetDirectiveCategory(const DirectiveLanguage &DirLang,
756
raw_ostream &OS) {
757
std::string LangNamespace = "llvm::" + DirLang.getCppNamespace().str();
758
std::string CategoryTypeName = LangNamespace + "::Category";
759
std::string CategoryNamespace = CategoryTypeName + "::";
760
761
OS << '\n';
762
OS << CategoryTypeName << ' ' << LangNamespace << "::getDirectiveCategory("
763
<< GetDirectiveType(DirLang) << " Dir) {\n";
764
OS << " switch (Dir) {\n";
765
766
for (Record *R : DirLang.getDirectives()) {
767
Directive D{R};
768
OS << " case " << GetDirectiveName(DirLang, R) << ":\n";
769
OS << " return " << CategoryNamespace
770
<< D.getCategory()->getValueAsString("name") << ";\n";
771
}
772
OS << " } // switch (Dir)\n";
773
OS << " llvm_unreachable(\"Unexpected directive\");\n";
774
OS << "}\n";
775
}
776
777
// Generate a simple enum set with the give clauses.
778
static void GenerateClauseSet(const std::vector<Record *> &Clauses,
779
raw_ostream &OS, StringRef ClauseSetPrefix,
780
Directive &Dir,
781
const DirectiveLanguage &DirLang) {
782
783
OS << "\n";
784
OS << " static " << DirLang.getClauseEnumSetClass() << " " << ClauseSetPrefix
785
<< DirLang.getDirectivePrefix() << Dir.getFormattedName() << " {\n";
786
787
for (const auto &C : Clauses) {
788
VersionedClause VerClause{C};
789
OS << " llvm::" << DirLang.getCppNamespace()
790
<< "::Clause::" << DirLang.getClausePrefix()
791
<< VerClause.getClause().getFormattedName() << ",\n";
792
}
793
OS << " };\n";
794
}
795
796
// Generate an enum set for the 4 kinds of clauses linked to a directive.
797
static void GenerateDirectiveClauseSets(const DirectiveLanguage &DirLang,
798
raw_ostream &OS) {
799
800
IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_SETS", OS);
801
802
OS << "\n";
803
OS << "namespace llvm {\n";
804
805
// Open namespaces defined in the directive language.
806
llvm::SmallVector<StringRef, 2> Namespaces;
807
llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::");
808
for (auto Ns : Namespaces)
809
OS << "namespace " << Ns << " {\n";
810
811
for (const auto &D : DirLang.getDirectives()) {
812
Directive Dir{D};
813
814
OS << "\n";
815
OS << " // Sets for " << Dir.getName() << "\n";
816
817
GenerateClauseSet(Dir.getAllowedClauses(), OS, "allowedClauses_", Dir,
818
DirLang);
819
GenerateClauseSet(Dir.getAllowedOnceClauses(), OS, "allowedOnceClauses_",
820
Dir, DirLang);
821
GenerateClauseSet(Dir.getAllowedExclusiveClauses(), OS,
822
"allowedExclusiveClauses_", Dir, DirLang);
823
GenerateClauseSet(Dir.getRequiredClauses(), OS, "requiredClauses_", Dir,
824
DirLang);
825
}
826
827
// Closing namespaces
828
for (auto Ns : llvm::reverse(Namespaces))
829
OS << "} // namespace " << Ns << "\n";
830
831
OS << "} // namespace llvm\n";
832
}
833
834
// Generate a map of directive (key) with DirectiveClauses struct as values.
835
// The struct holds the 4 sets of enumeration for the 4 kinds of clauses
836
// allowances (allowed, allowed once, allowed exclusive and required).
837
static void GenerateDirectiveClauseMap(const DirectiveLanguage &DirLang,
838
raw_ostream &OS) {
839
840
IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_MAP", OS);
841
842
OS << "\n";
843
OS << "{\n";
844
845
for (const auto &D : DirLang.getDirectives()) {
846
Directive Dir{D};
847
OS << " {llvm::" << DirLang.getCppNamespace()
848
<< "::Directive::" << DirLang.getDirectivePrefix()
849
<< Dir.getFormattedName() << ",\n";
850
OS << " {\n";
851
OS << " llvm::" << DirLang.getCppNamespace() << "::allowedClauses_"
852
<< DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n";
853
OS << " llvm::" << DirLang.getCppNamespace() << "::allowedOnceClauses_"
854
<< DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n";
855
OS << " llvm::" << DirLang.getCppNamespace()
856
<< "::allowedExclusiveClauses_" << DirLang.getDirectivePrefix()
857
<< Dir.getFormattedName() << ",\n";
858
OS << " llvm::" << DirLang.getCppNamespace() << "::requiredClauses_"
859
<< DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n";
860
OS << " }\n";
861
OS << " },\n";
862
}
863
864
OS << "}\n";
865
}
866
867
// Generate classes entry for Flang clauses in the Flang parse-tree
868
// If the clause as a non-generic class, no entry is generated.
869
// If the clause does not hold a value, an EMPTY_CLASS is used.
870
// If the clause class is generic then a WRAPPER_CLASS is used. When the value
871
// is optional, the value class is wrapped into a std::optional.
872
static void GenerateFlangClauseParserClass(const DirectiveLanguage &DirLang,
873
raw_ostream &OS) {
874
875
IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES", OS);
876
877
OS << "\n";
878
879
for (const auto &C : DirLang.getClauses()) {
880
Clause Clause{C};
881
if (!Clause.getFlangClass().empty()) {
882
OS << "WRAPPER_CLASS(" << Clause.getFormattedParserClassName() << ", ";
883
if (Clause.isValueOptional() && Clause.isValueList()) {
884
OS << "std::optional<std::list<" << Clause.getFlangClass() << ">>";
885
} else if (Clause.isValueOptional()) {
886
OS << "std::optional<" << Clause.getFlangClass() << ">";
887
} else if (Clause.isValueList()) {
888
OS << "std::list<" << Clause.getFlangClass() << ">";
889
} else {
890
OS << Clause.getFlangClass();
891
}
892
} else {
893
OS << "EMPTY_CLASS(" << Clause.getFormattedParserClassName();
894
}
895
OS << ");\n";
896
}
897
}
898
899
// Generate a list of the different clause classes for Flang.
900
static void GenerateFlangClauseParserClassList(const DirectiveLanguage &DirLang,
901
raw_ostream &OS) {
902
903
IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST", OS);
904
905
OS << "\n";
906
llvm::interleaveComma(DirLang.getClauses(), OS, [&](Record *C) {
907
Clause Clause{C};
908
OS << Clause.getFormattedParserClassName() << "\n";
909
});
910
}
911
912
// Generate dump node list for the clauses holding a generic class name.
913
static void GenerateFlangClauseDump(const DirectiveLanguage &DirLang,
914
raw_ostream &OS) {
915
916
IfDefScope Scope("GEN_FLANG_DUMP_PARSE_TREE_CLAUSES", OS);
917
918
OS << "\n";
919
for (const auto &C : DirLang.getClauses()) {
920
Clause Clause{C};
921
OS << "NODE(" << DirLang.getFlangClauseBaseClass() << ", "
922
<< Clause.getFormattedParserClassName() << ")\n";
923
}
924
}
925
926
// Generate Unparse functions for clauses classes in the Flang parse-tree
927
// If the clause is a non-generic class, no entry is generated.
928
static void GenerateFlangClauseUnparse(const DirectiveLanguage &DirLang,
929
raw_ostream &OS) {
930
931
IfDefScope Scope("GEN_FLANG_CLAUSE_UNPARSE", OS);
932
933
OS << "\n";
934
935
for (const auto &C : DirLang.getClauses()) {
936
Clause Clause{C};
937
if (!Clause.getFlangClass().empty()) {
938
if (Clause.isValueOptional() && Clause.getDefaultValue().empty()) {
939
OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass()
940
<< "::" << Clause.getFormattedParserClassName() << " &x) {\n";
941
OS << " Word(\"" << Clause.getName().upper() << "\");\n";
942
943
OS << " Walk(\"(\", x.v, \")\");\n";
944
OS << "}\n";
945
} else if (Clause.isValueOptional()) {
946
OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass()
947
<< "::" << Clause.getFormattedParserClassName() << " &x) {\n";
948
OS << " Word(\"" << Clause.getName().upper() << "\");\n";
949
OS << " Put(\"(\");\n";
950
OS << " if (x.v.has_value())\n";
951
if (Clause.isValueList())
952
OS << " Walk(x.v, \",\");\n";
953
else
954
OS << " Walk(x.v);\n";
955
OS << " else\n";
956
OS << " Put(\"" << Clause.getDefaultValue() << "\");\n";
957
OS << " Put(\")\");\n";
958
OS << "}\n";
959
} else {
960
OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass()
961
<< "::" << Clause.getFormattedParserClassName() << " &x) {\n";
962
OS << " Word(\"" << Clause.getName().upper() << "\");\n";
963
OS << " Put(\"(\");\n";
964
if (Clause.isValueList())
965
OS << " Walk(x.v, \",\");\n";
966
else
967
OS << " Walk(x.v);\n";
968
OS << " Put(\")\");\n";
969
OS << "}\n";
970
}
971
} else {
972
OS << "void Before(const " << DirLang.getFlangClauseBaseClass()
973
<< "::" << Clause.getFormattedParserClassName() << " &) { Word(\""
974
<< Clause.getName().upper() << "\"); }\n";
975
}
976
}
977
}
978
979
// Generate check in the Enter functions for clauses classes.
980
static void GenerateFlangClauseCheckPrototypes(const DirectiveLanguage &DirLang,
981
raw_ostream &OS) {
982
983
IfDefScope Scope("GEN_FLANG_CLAUSE_CHECK_ENTER", OS);
984
985
OS << "\n";
986
for (const auto &C : DirLang.getClauses()) {
987
Clause Clause{C};
988
OS << "void Enter(const parser::" << DirLang.getFlangClauseBaseClass()
989
<< "::" << Clause.getFormattedParserClassName() << " &);\n";
990
}
991
}
992
993
// Generate the mapping for clauses between the parser class and the
994
// corresponding clause Kind
995
static void GenerateFlangClauseParserKindMap(const DirectiveLanguage &DirLang,
996
raw_ostream &OS) {
997
998
IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_KIND_MAP", OS);
999
1000
OS << "\n";
1001
for (const auto &C : DirLang.getClauses()) {
1002
Clause Clause{C};
1003
OS << "if constexpr (std::is_same_v<A, parser::"
1004
<< DirLang.getFlangClauseBaseClass()
1005
<< "::" << Clause.getFormattedParserClassName();
1006
OS << ">)\n";
1007
OS << " return llvm::" << DirLang.getCppNamespace()
1008
<< "::Clause::" << DirLang.getClausePrefix() << Clause.getFormattedName()
1009
<< ";\n";
1010
}
1011
1012
OS << "llvm_unreachable(\"Invalid " << DirLang.getName()
1013
<< " Parser clause\");\n";
1014
}
1015
1016
static bool compareClauseName(Record *R1, Record *R2) {
1017
Clause C1{R1};
1018
Clause C2{R2};
1019
return (C1.getName() > C2.getName());
1020
}
1021
1022
// Generate the parser for the clauses.
1023
static void GenerateFlangClausesParser(const DirectiveLanguage &DirLang,
1024
raw_ostream &OS) {
1025
std::vector<Record *> Clauses = DirLang.getClauses();
1026
// Sort clauses in reverse alphabetical order so with clauses with same
1027
// beginning, the longer option is tried before.
1028
llvm::sort(Clauses, compareClauseName);
1029
IfDefScope Scope("GEN_FLANG_CLAUSES_PARSER", OS);
1030
OS << "\n";
1031
unsigned index = 0;
1032
unsigned lastClauseIndex = DirLang.getClauses().size() - 1;
1033
OS << "TYPE_PARSER(\n";
1034
for (const auto &C : Clauses) {
1035
Clause Clause{C};
1036
if (Clause.getAliases().empty()) {
1037
OS << " \"" << Clause.getName() << "\"";
1038
} else {
1039
OS << " ("
1040
<< "\"" << Clause.getName() << "\"_tok";
1041
for (StringRef alias : Clause.getAliases()) {
1042
OS << " || \"" << alias << "\"_tok";
1043
}
1044
OS << ")";
1045
}
1046
1047
OS << " >> construct<" << DirLang.getFlangClauseBaseClass()
1048
<< ">(construct<" << DirLang.getFlangClauseBaseClass()
1049
<< "::" << Clause.getFormattedParserClassName() << ">(";
1050
if (Clause.getFlangClass().empty()) {
1051
OS << "))";
1052
if (index != lastClauseIndex)
1053
OS << " ||";
1054
OS << "\n";
1055
++index;
1056
continue;
1057
}
1058
1059
if (Clause.isValueOptional())
1060
OS << "maybe(";
1061
OS << "parenthesized(";
1062
if (Clause.isValueList())
1063
OS << "nonemptyList(";
1064
1065
if (!Clause.getPrefix().empty())
1066
OS << "\"" << Clause.getPrefix() << ":\" >> ";
1067
1068
// The common Flang parser are used directly. Their name is identical to
1069
// the Flang class with first letter as lowercase. If the Flang class is
1070
// not a common class, we assume there is a specific Parser<>{} with the
1071
// Flang class name provided.
1072
llvm::SmallString<128> Scratch;
1073
StringRef Parser =
1074
llvm::StringSwitch<StringRef>(Clause.getFlangClass())
1075
.Case("Name", "name")
1076
.Case("ScalarIntConstantExpr", "scalarIntConstantExpr")
1077
.Case("ScalarIntExpr", "scalarIntExpr")
1078
.Case("ScalarExpr", "scalarExpr")
1079
.Case("ScalarLogicalExpr", "scalarLogicalExpr")
1080
.Default(("Parser<" + Clause.getFlangClass() + ">{}")
1081
.toStringRef(Scratch));
1082
OS << Parser;
1083
if (!Clause.getPrefix().empty() && Clause.isPrefixOptional())
1084
OS << " || " << Parser;
1085
if (Clause.isValueList()) // close nonemptyList(.
1086
OS << ")";
1087
OS << ")"; // close parenthesized(.
1088
1089
if (Clause.isValueOptional()) // close maybe(.
1090
OS << ")";
1091
OS << "))";
1092
if (index != lastClauseIndex)
1093
OS << " ||";
1094
OS << "\n";
1095
++index;
1096
}
1097
OS << ")\n";
1098
}
1099
1100
// Generate the implementation section for the enumeration in the directive
1101
// language
1102
static void EmitDirectivesFlangImpl(const DirectiveLanguage &DirLang,
1103
raw_ostream &OS) {
1104
1105
GenerateDirectiveClauseSets(DirLang, OS);
1106
1107
GenerateDirectiveClauseMap(DirLang, OS);
1108
1109
GenerateFlangClauseParserClass(DirLang, OS);
1110
1111
GenerateFlangClauseParserClassList(DirLang, OS);
1112
1113
GenerateFlangClauseDump(DirLang, OS);
1114
1115
GenerateFlangClauseUnparse(DirLang, OS);
1116
1117
GenerateFlangClauseCheckPrototypes(DirLang, OS);
1118
1119
GenerateFlangClauseParserKindMap(DirLang, OS);
1120
1121
GenerateFlangClausesParser(DirLang, OS);
1122
}
1123
1124
static void GenerateClauseClassMacro(const DirectiveLanguage &DirLang,
1125
raw_ostream &OS) {
1126
// Generate macros style information for legacy code in clang
1127
IfDefScope Scope("GEN_CLANG_CLAUSE_CLASS", OS);
1128
1129
OS << "\n";
1130
1131
OS << "#ifndef CLAUSE\n";
1132
OS << "#define CLAUSE(Enum, Str, Implicit)\n";
1133
OS << "#endif\n";
1134
OS << "#ifndef CLAUSE_CLASS\n";
1135
OS << "#define CLAUSE_CLASS(Enum, Str, Class)\n";
1136
OS << "#endif\n";
1137
OS << "#ifndef CLAUSE_NO_CLASS\n";
1138
OS << "#define CLAUSE_NO_CLASS(Enum, Str)\n";
1139
OS << "#endif\n";
1140
OS << "\n";
1141
OS << "#define __CLAUSE(Name, Class) \\\n";
1142
OS << " CLAUSE(" << DirLang.getClausePrefix()
1143
<< "##Name, #Name, /* Implicit */ false) \\\n";
1144
OS << " CLAUSE_CLASS(" << DirLang.getClausePrefix()
1145
<< "##Name, #Name, Class)\n";
1146
OS << "#define __CLAUSE_NO_CLASS(Name) \\\n";
1147
OS << " CLAUSE(" << DirLang.getClausePrefix()
1148
<< "##Name, #Name, /* Implicit */ false) \\\n";
1149
OS << " CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, #Name)\n";
1150
OS << "#define __IMPLICIT_CLAUSE_CLASS(Name, Str, Class) \\\n";
1151
OS << " CLAUSE(" << DirLang.getClausePrefix()
1152
<< "##Name, Str, /* Implicit */ true) \\\n";
1153
OS << " CLAUSE_CLASS(" << DirLang.getClausePrefix()
1154
<< "##Name, Str, Class)\n";
1155
OS << "#define __IMPLICIT_CLAUSE_NO_CLASS(Name, Str) \\\n";
1156
OS << " CLAUSE(" << DirLang.getClausePrefix()
1157
<< "##Name, Str, /* Implicit */ true) \\\n";
1158
OS << " CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, Str)\n";
1159
OS << "\n";
1160
1161
for (const auto &R : DirLang.getClauses()) {
1162
Clause C{R};
1163
if (C.getClangClass().empty()) { // NO_CLASS
1164
if (C.isImplicit()) {
1165
OS << "__IMPLICIT_CLAUSE_NO_CLASS(" << C.getFormattedName() << ", \""
1166
<< C.getFormattedName() << "\")\n";
1167
} else {
1168
OS << "__CLAUSE_NO_CLASS(" << C.getFormattedName() << ")\n";
1169
}
1170
} else { // CLASS
1171
if (C.isImplicit()) {
1172
OS << "__IMPLICIT_CLAUSE_CLASS(" << C.getFormattedName() << ", \""
1173
<< C.getFormattedName() << "\", " << C.getClangClass() << ")\n";
1174
} else {
1175
OS << "__CLAUSE(" << C.getFormattedName() << ", " << C.getClangClass()
1176
<< ")\n";
1177
}
1178
}
1179
}
1180
1181
OS << "\n";
1182
OS << "#undef __IMPLICIT_CLAUSE_NO_CLASS\n";
1183
OS << "#undef __IMPLICIT_CLAUSE_CLASS\n";
1184
OS << "#undef __CLAUSE_NO_CLASS\n";
1185
OS << "#undef __CLAUSE\n";
1186
OS << "#undef CLAUSE_NO_CLASS\n";
1187
OS << "#undef CLAUSE_CLASS\n";
1188
OS << "#undef CLAUSE\n";
1189
}
1190
1191
// Generate the implemenation for the enumeration in the directive
1192
// language. This code can be included in library.
1193
void EmitDirectivesBasicImpl(const DirectiveLanguage &DirLang,
1194
raw_ostream &OS) {
1195
IfDefScope Scope("GEN_DIRECTIVES_IMPL", OS);
1196
1197
OS << "\n#include \"llvm/Support/ErrorHandling.h\"\n";
1198
1199
// getDirectiveKind(StringRef Str)
1200
GenerateGetKind(DirLang.getDirectives(), OS, "Directive", DirLang,
1201
DirLang.getDirectivePrefix(), /*ImplicitAsUnknown=*/false);
1202
1203
// getDirectiveName(Directive Kind)
1204
GenerateGetName(DirLang.getDirectives(), OS, "Directive", DirLang,
1205
DirLang.getDirectivePrefix());
1206
1207
// getClauseKind(StringRef Str)
1208
GenerateGetKind(DirLang.getClauses(), OS, "Clause", DirLang,
1209
DirLang.getClausePrefix(),
1210
/*ImplicitAsUnknown=*/true);
1211
1212
// getClauseName(Clause Kind)
1213
GenerateGetName(DirLang.getClauses(), OS, "Clause", DirLang,
1214
DirLang.getClausePrefix());
1215
1216
// get<ClauseVal>Kind(StringRef Str)
1217
GenerateGetKindClauseVal(DirLang, OS);
1218
1219
// isAllowedClauseForDirective(Directive D, Clause C, unsigned Version)
1220
GenerateIsAllowedClause(DirLang, OS);
1221
1222
// getDirectiveAssociation(Directive D)
1223
GenerateGetDirectiveAssociation(DirLang, OS);
1224
1225
// getDirectiveCategory(Directive D)
1226
GenerateGetDirectiveCategory(DirLang, OS);
1227
1228
// Leaf table for getLeafConstructs, etc.
1229
EmitLeafTable(DirLang, OS, "LeafConstructTable");
1230
}
1231
1232
// Generate the implemenation section for the enumeration in the directive
1233
// language.
1234
static void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) {
1235
const auto DirLang = DirectiveLanguage{Records};
1236
if (DirLang.HasValidityErrors())
1237
return;
1238
1239
EmitDirectivesFlangImpl(DirLang, OS);
1240
1241
GenerateClauseClassMacro(DirLang, OS);
1242
1243
EmitDirectivesBasicImpl(DirLang, OS);
1244
}
1245
1246
static TableGen::Emitter::Opt
1247
X("gen-directive-decl", EmitDirectivesDecl,
1248
"Generate directive related declaration code (header file)");
1249
1250
static TableGen::Emitter::Opt
1251
Y("gen-directive-impl", EmitDirectivesImpl,
1252
"Generate directive related implementation code");
1253
1254