20
20
#include " llvm/TableGen/Record.h"
21
21
#include " llvm/TableGen/TableGenBackend.h"
22
22
23
+ #include < numeric>
24
+ #include < vector>
25
+
23
26
using namespace llvm ;
24
27
25
28
namespace {
@@ -39,7 +42,8 @@ class IfDefScope {
39
42
};
40
43
} // namespace
41
44
42
- // Generate enum class
45
+ // Generate enum class. Entries are emitted in the order in which they appear
46
+ // in the `Records` vector.
43
47
static void GenerateEnumClass (const std::vector<Record *> &Records,
44
48
raw_ostream &OS, StringRef Enum, StringRef Prefix,
45
49
const DirectiveLanguage &DirLang,
@@ -175,6 +179,16 @@ bool DirectiveLanguage::HasValidityErrors() const {
175
179
return HasDuplicateClausesInDirectives (getDirectives ());
176
180
}
177
181
182
+ // Count the maximum number of leaf constituents per construct.
183
+ static size_t GetMaxLeafCount (const DirectiveLanguage &DirLang) {
184
+ size_t MaxCount = 0 ;
185
+ for (Record *R : DirLang.getDirectives ()) {
186
+ size_t Count = Directive{R}.getLeafConstructs ().size ();
187
+ MaxCount = std::max (MaxCount, Count);
188
+ }
189
+ return MaxCount;
190
+ }
191
+
178
192
// Generate the declaration section for the enumeration in the directive
179
193
// language
180
194
static void EmitDirectivesDecl (RecordKeeper &Records, raw_ostream &OS) {
@@ -189,6 +203,7 @@ static void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) {
189
203
if (DirLang.hasEnableBitmaskEnumInNamespace ())
190
204
OS << " #include \" llvm/ADT/BitmaskEnum.h\"\n " ;
191
205
206
+ OS << " #include <cstddef>\n " ; // for size_t
192
207
OS << " \n " ;
193
208
OS << " namespace llvm {\n " ;
194
209
OS << " class StringRef;\n " ;
@@ -244,7 +259,8 @@ static void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) {
244
259
OS << " bool isAllowedClauseForDirective(Directive D, "
245
260
<< " Clause C, unsigned Version);\n " ;
246
261
OS << " \n " ;
247
- OS << " llvm::ArrayRef<Directive> getLeafConstructs(Directive D);\n " ;
262
+ OS << " constexpr std::size_t getMaxLeafCount() { return "
263
+ << GetMaxLeafCount (DirLang) << " ; }\n " ;
248
264
OS << " Association getDirectiveAssociation(Directive D);\n " ;
249
265
if (EnumHelperFuncs.length () > 0 ) {
250
266
OS << EnumHelperFuncs;
@@ -396,6 +412,19 @@ GenerateCaseForVersionedClauses(const std::vector<Record *> &Clauses,
396
412
}
397
413
}
398
414
415
+ static std::string GetDirectiveName (const DirectiveLanguage &DirLang,
416
+ const Record *Rec) {
417
+ Directive Dir{Rec};
418
+ return (llvm::Twine (" llvm::" ) + DirLang.getCppNamespace () + " ::" +
419
+ DirLang.getDirectivePrefix () + Dir.getFormattedName ())
420
+ .str ();
421
+ }
422
+
423
+ static std::string GetDirectiveType (const DirectiveLanguage &DirLang) {
424
+ return (llvm::Twine (" llvm::" ) + DirLang.getCppNamespace () + " ::Directive" )
425
+ .str ();
426
+ }
427
+
399
428
// Generate the isAllowedClauseForDirective function implementation.
400
429
static void GenerateIsAllowedClause (const DirectiveLanguage &DirLang,
401
430
raw_ostream &OS) {
@@ -450,77 +479,102 @@ static void GenerateIsAllowedClause(const DirectiveLanguage &DirLang,
450
479
OS << " }\n " ; // End of function isAllowedClauseForDirective
451
480
}
452
481
453
- // Generate the getLeafConstructs function implementation.
454
- static void GenerateGetLeafConstructs (const DirectiveLanguage &DirLang,
455
- raw_ostream &OS) {
456
- auto getQualifiedName = [&](StringRef Formatted) -> std::string {
457
- return (llvm::Twine (" llvm::" ) + DirLang.getCppNamespace () +
458
- " ::Directive::" + DirLang.getDirectivePrefix () + Formatted)
459
- .str ();
460
- };
461
-
462
- // For each list of leaves, generate a static local object, then
463
- // return a reference to that object for a given directive, e.g.
482
+ static void EmitLeafTable (const DirectiveLanguage &DirLang, raw_ostream &OS,
483
+ StringRef TableName) {
484
+ // The leaf constructs are emitted in a form of a 2D table, where each
485
+ // row corresponds to a directive (and there is a row for each directive).
464
486
//
465
- // static ListTy leafConstructs_A_B = { A, B };
466
- // static ListTy leafConstructs_C_D_E = { C, D, E };
467
- // switch (Dir) {
468
- // case A_B:
469
- // return leafConstructs_A_B;
470
- // case C_D_E:
471
- // return leafConstructs_C_D_E;
472
- // }
473
-
474
- // Map from a record that defines a directive to the name of the
475
- // local object with the list of its leaves.
476
- DenseMap<Record *, std::string> ListNames;
477
-
478
- std::string DirectiveTypeName =
479
- std::string (" llvm::" ) + DirLang.getCppNamespace ().str () + " ::Directive" ;
480
-
481
- OS << ' \n ' ;
482
-
483
- // ArrayRef<...> llvm::<ns>::GetLeafConstructs(llvm::<ns>::Directive Dir)
484
- OS << " llvm::ArrayRef<" << DirectiveTypeName
485
- << " > llvm::" << DirLang.getCppNamespace () << " ::getLeafConstructs("
486
- << DirectiveTypeName << " Dir) " ;
487
- OS << " {\n " ;
488
-
489
- // Generate the locals.
490
- for (Record *R : DirLang.getDirectives ()) {
491
- Directive Dir{R};
487
+ // Each row consists of
488
+ // - the id of the directive itself,
489
+ // - number of leaf constructs that will follow (0 for leafs),
490
+ // - ids of the leaf constructs (none if the directive is itself a leaf).
491
+ // The total number of these entries is at most MaxLeafCount+2. If this
492
+ // number is less than that, it is padded to occupy exactly MaxLeafCount+2
493
+ // entries in memory.
494
+ //
495
+ // The rows are stored in the table in the lexicographical order. This
496
+ // is intended to enable binary search when mapping a sequence of leafs
497
+ // back to the compound directive.
498
+ // The consequence of that is that in order to find a row corresponding
499
+ // to the given directive, we'd need to scan the first element of each
500
+ // row. To avoid this, an auxiliary ordering table is created, such that
501
+ // row for Dir_A = table[auxiliary[Dir_A]].
502
+
503
+ std::vector<Record *> Directives = DirLang.getDirectives ();
504
+ DenseMap<Record *, size_t > DirId; // Record * -> llvm::omp::Directive
505
+
506
+ for (auto [Idx, Rec] : llvm::enumerate (Directives))
507
+ DirId.insert (std::make_pair (Rec, Idx));
508
+
509
+ using LeafList = std::vector<int >;
510
+ int MaxLeafCount = GetMaxLeafCount (DirLang);
511
+
512
+ // The initial leaf table, rows order is same as directive order.
513
+ std::vector<LeafList> LeafTable (Directives.size ());
514
+ for (auto [Idx, Rec] : llvm::enumerate (Directives)) {
515
+ Directive Dir{Rec};
516
+ std::vector<Record *> Leaves = Dir.getLeafConstructs ();
517
+
518
+ auto &List = LeafTable[Idx];
519
+ List.resize (MaxLeafCount + 2 );
520
+ List[0 ] = Idx; // The id of the directive itself.
521
+ List[1 ] = Leaves.size (); // The number of leaves to follow.
522
+
523
+ for (int I = 0 ; I != MaxLeafCount; ++I)
524
+ List[I + 2 ] =
525
+ static_cast <size_t >(I) < Leaves.size () ? DirId.at (Leaves[I]) : -1 ;
526
+ }
492
527
493
- std::vector<Record *> LeafConstructs = Dir.getLeafConstructs ();
494
- if (LeafConstructs.empty ())
495
- continue ;
528
+ // Avoid sorting the vector<vector> array, instead sort an index array.
529
+ // It will also be useful later to create the auxiliary indexing array.
530
+ std::vector<int > Ordering (Directives.size ());
531
+ std::iota (Ordering.begin (), Ordering.end (), 0 );
532
+
533
+ llvm::sort (Ordering, [&](int A, int B) {
534
+ auto &LeavesA = LeafTable[A];
535
+ auto &LeavesB = LeafTable[B];
536
+ if (LeavesA[1 ] == 0 && LeavesB[1 ] == 0 )
537
+ return LeavesA[0 ] < LeavesB[0 ];
538
+ return std::lexicographical_compare (&LeavesA[2 ], &LeavesA[2 ] + LeavesA[1 ],
539
+ &LeavesB[2 ], &LeavesB[2 ] + LeavesB[1 ]);
540
+ });
496
541
497
- std::string ListName = " leafConstructs_" + Dir.getFormattedName ();
498
- OS << " static const " << DirectiveTypeName << ' ' << ListName
499
- << " [] = {\n " ;
500
- for (Record *L : LeafConstructs) {
501
- Directive LeafDir{L};
502
- OS << " " << getQualifiedName (LeafDir.getFormattedName ()) << " ,\n " ;
542
+ // Emit the table
543
+
544
+ // The directives are emitted into a scoped enum, for which the underlying
545
+ // type is `int` (by default). The code above uses `int` to store directive
546
+ // ids, so make sure that we catch it when something changes in the
547
+ // underlying type.
548
+ std::string DirectiveType = GetDirectiveType (DirLang);
549
+ OS << " static_assert(sizeof(" << DirectiveType << " ) == sizeof(int));\n " ;
550
+
551
+ OS << " [[maybe_unused]] static const " << DirectiveType << ' ' << TableName
552
+ << " [][" << MaxLeafCount + 2 << " ] = {\n " ;
553
+ for (size_t I = 0 , E = Directives.size (); I != E; ++I) {
554
+ auto &Leaves = LeafTable[Ordering[I]];
555
+ OS << " " << GetDirectiveName (DirLang, Directives[Leaves[0 ]]);
556
+ OS << " , static_cast<" << DirectiveType << " >(" << Leaves[1 ] << " )," ;
557
+ for (size_t I = 2 , E = Leaves.size (); I != E; ++I) {
558
+ int Idx = Leaves[I];
559
+ if (Idx >= 0 )
560
+ OS << ' ' << GetDirectiveName (DirLang, Directives[Leaves[I]]) << ' ,' ;
561
+ else
562
+ OS << " static_cast<" << DirectiveType << " >(-1)," ;
503
563
}
504
- OS << " };\n " ;
505
- ListNames.insert (std::make_pair (R, std::move (ListName)));
506
- }
507
-
508
- if (!ListNames.empty ())
509
564
OS << ' \n ' ;
510
- OS << " switch (Dir) {\n " ;
511
- for (Record *R : DirLang.getDirectives ()) {
512
- auto F = ListNames.find (R);
513
- if (F == ListNames.end ())
514
- continue ;
515
-
516
- Directive Dir{R};
517
- OS << " case " << getQualifiedName (Dir.getFormattedName ()) << " :\n " ;
518
- OS << " return " << F->second << " ;\n " ;
519
565
}
520
- OS << " default:\n " ;
521
- OS << " return ArrayRef<" << DirectiveTypeName << " >{};\n " ;
522
- OS << " } // switch (Dir)\n " ;
523
- OS << " }\n " ;
566
+ OS << " };\n\n " ;
567
+
568
+ // Emit the auxiliary index table: it's the inverse of the `Ordering`
569
+ // table above.
570
+ OS << " [[maybe_unused]] static const int " << TableName << " Ordering[] = {\n " ;
571
+ OS << " " ;
572
+ std::vector<int > Reverse (Ordering.size ());
573
+ for (int I = 0 , E = Ordering.size (); I != E; ++I)
574
+ Reverse[Ordering[I]] = I;
575
+ for (int Idx : Reverse)
576
+ OS << ' ' << Idx << ' ,' ;
577
+ OS << " \n };\n " ;
524
578
}
525
579
526
580
static void GenerateGetDirectiveAssociation (const DirectiveLanguage &DirLang,
@@ -1105,11 +1159,11 @@ void EmitDirectivesBasicImpl(const DirectiveLanguage &DirLang,
1105
1159
// isAllowedClauseForDirective(Directive D, Clause C, unsigned Version)
1106
1160
GenerateIsAllowedClause (DirLang, OS);
1107
1161
1108
- // getLeafConstructs(Directive D)
1109
- GenerateGetLeafConstructs (DirLang, OS);
1110
-
1111
1162
// getDirectiveAssociation(Directive D)
1112
1163
GenerateGetDirectiveAssociation (DirLang, OS);
1164
+
1165
+ // Leaf table for getLeafConstructs, etc.
1166
+ EmitLeafTable (DirLang, OS, " LeafConstructTable" );
1113
1167
}
1114
1168
1115
1169
// Generate the implemenation section for the enumeration in the directive
0 commit comments