69
69
using namespace llvm ;
70
70
71
71
namespace {
72
+
73
+ // A list of signatures that are shared by one or more builtin functions.
74
+ struct BuiltinTableEntries {
75
+ SmallVector<StringRef, 4 > Names;
76
+ std::vector<std::pair<const Record *, unsigned >> Signatures;
77
+ };
78
+
72
79
class BuiltinNameEmitter {
73
80
public:
74
81
BuiltinNameEmitter (RecordKeeper &Records, raw_ostream &OS)
@@ -79,6 +86,9 @@ class BuiltinNameEmitter {
79
86
void Emit ();
80
87
81
88
private:
89
+ // A list of indices into the builtin function table.
90
+ using BuiltinIndexListTy = SmallVector<unsigned , 11 >;
91
+
82
92
// Contains OpenCL builtin functions and related information, stored as
83
93
// Record instances. They are coming from the associated TableGen file.
84
94
RecordKeeper &Records;
@@ -106,6 +116,23 @@ class BuiltinNameEmitter {
106
116
// FctOverloadMap and TypeMap.
107
117
void GetOverloads ();
108
118
119
+ // Compare two lists of signatures and check that e.g. the OpenCL version,
120
+ // function attributes, and extension are equal for each signature.
121
+ // \param Candidate (in) Entry in the SignatureListMap to check.
122
+ // \param SignatureList (in) List of signatures of the considered function.
123
+ // \returns true if the two lists of signatures are identical.
124
+ bool CanReuseSignature (
125
+ BuiltinIndexListTy *Candidate,
126
+ std::vector<std::pair<const Record *, unsigned >> &SignatureList);
127
+
128
+ // Group functions with the same list of signatures by populating the
129
+ // SignatureListMap.
130
+ // Some builtin functions have the same list of signatures, for example the
131
+ // "sin" and "cos" functions. To save space in the BuiltinTable, the
132
+ // "isOpenCLBuiltin" function will have the same output for these two
133
+ // function names.
134
+ void GroupBySignature ();
135
+
109
136
// Emit the TypeTable containing all types used by OpenCL builtins.
110
137
void EmitTypeTable ();
111
138
@@ -170,6 +197,24 @@ class BuiltinNameEmitter {
170
197
171
198
// Same as TypeList, but for generic types only.
172
199
std::vector<const Record *> GenTypeList;
200
+
201
+ // Map an ordered vector of signatures to their original Record instances,
202
+ // and to a list of function names that share these signatures.
203
+ //
204
+ // For example, suppose the "cos" and "sin" functions have only three
205
+ // signatures, and these signatures are at index Ix in the SignatureTable:
206
+ // cos | sin | Signature | Index
207
+ // float cos(float) | float sin(float) | Signature1 | I1
208
+ // double cos(double) | double sin(double) | Signature2 | I2
209
+ // half cos(half) | half sin(half) | Signature3 | I3
210
+ //
211
+ // Then we will create a mapping of the vector of signatures:
212
+ // SignatureListMap[<I1, I2, I3>] = <
213
+ // <"cos", "sin">,
214
+ // <Signature1, Signature2, Signature3>>
215
+ // The function "tan", having the same signatures, would be mapped to the
216
+ // same entry (<I1, I2, I3>).
217
+ MapVector<BuiltinIndexListTy *, BuiltinTableEntries> SignatureListMap;
173
218
};
174
219
} // namespace
175
220
@@ -183,6 +228,7 @@ void BuiltinNameEmitter::Emit() {
183
228
EmitDeclarations ();
184
229
185
230
GetOverloads ();
231
+ GroupBySignature ();
186
232
187
233
// Emit tables.
188
234
EmitTypeTable ();
@@ -408,11 +454,15 @@ void BuiltinNameEmitter::EmitBuiltinTable() {
408
454
unsigned Index = 0 ;
409
455
410
456
OS << " static const OpenCLBuiltinStruct BuiltinTable[] = {\n " ;
411
- for (const auto &FOM : FctOverloadMap ) {
457
+ for (const auto &SLM : SignatureListMap ) {
412
458
413
- OS << " // " << (Index + 1 ) << " : " << FOM.first << " \n " ;
459
+ OS << " // " << (Index + 1 ) << " : " ;
460
+ for (const auto &Name : SLM.second .Names ) {
461
+ OS << Name << " , " ;
462
+ }
463
+ OS << " \n " ;
414
464
415
- for (const auto &Overload : FOM .second ) {
465
+ for (const auto &Overload : SLM .second . Signatures ) {
416
466
OS << " { " << Overload.second << " , "
417
467
<< Overload.first ->getValueAsListOfDefs (" Signature" ).size () << " , "
418
468
<< (Overload.first ->getValueAsBit (" IsPure" )) << " , "
@@ -428,19 +478,92 @@ void BuiltinNameEmitter::EmitBuiltinTable() {
428
478
OS << " };\n\n " ;
429
479
}
430
480
481
+ bool BuiltinNameEmitter::CanReuseSignature (
482
+ BuiltinIndexListTy *Candidate,
483
+ std::vector<std::pair<const Record *, unsigned >> &SignatureList) {
484
+ assert (Candidate->size () == SignatureList.size () &&
485
+ " signature lists should have the same size" );
486
+
487
+ auto &CandidateSigs =
488
+ SignatureListMap.find (Candidate)->second .Signatures ;
489
+ for (unsigned Index = 0 ; Index < Candidate->size (); Index++) {
490
+ const Record *Rec = SignatureList[Index].first ;
491
+ const Record *Rec2 = CandidateSigs[Index].first ;
492
+ if (Rec->getValueAsBit (" IsPure" ) == Rec2->getValueAsBit (" IsPure" ) &&
493
+ Rec->getValueAsBit (" IsConst" ) == Rec2->getValueAsBit (" IsConst" ) &&
494
+ Rec->getValueAsBit (" IsConv" ) == Rec2->getValueAsBit (" IsConv" ) &&
495
+ Rec->getValueAsDef (" MinVersion" )->getValueAsInt (" ID" ) ==
496
+ Rec2->getValueAsDef (" MinVersion" )->getValueAsInt (" ID" ) &&
497
+ Rec->getValueAsDef (" MaxVersion" )->getValueAsInt (" ID" ) ==
498
+ Rec2->getValueAsDef (" MaxVersion" )->getValueAsInt (" ID" ) &&
499
+ Rec->getValueAsString (" Extension" ) ==
500
+ Rec2->getValueAsString (" Extension" )) {
501
+ return true ;
502
+ }
503
+ }
504
+ return false ;
505
+ }
506
+
507
+ void BuiltinNameEmitter::GroupBySignature () {
508
+ // List of signatures known to be emitted.
509
+ std::vector<BuiltinIndexListTy *> KnownSignatures;
510
+
511
+ for (auto &Fct : FctOverloadMap) {
512
+ bool FoundReusableSig = false ;
513
+
514
+ // Gather all signatures for the current function.
515
+ auto *CurSignatureList = new BuiltinIndexListTy ();
516
+ for (const auto &Signature : Fct.second ) {
517
+ CurSignatureList->push_back (Signature.second );
518
+ }
519
+ // Sort the list to facilitate future comparisons.
520
+ std::sort (CurSignatureList->begin (), CurSignatureList->end ());
521
+
522
+ // Check if we have already seen another function with the same list of
523
+ // signatures. If so, just add the name of the function.
524
+ for (auto *Candidate : KnownSignatures) {
525
+ if (Candidate->size () == CurSignatureList->size () &&
526
+ *Candidate == *CurSignatureList) {
527
+ if (CanReuseSignature (Candidate, Fct.second )) {
528
+ SignatureListMap.find (Candidate)->second .Names .push_back (Fct.first );
529
+ FoundReusableSig = true ;
530
+ }
531
+ }
532
+ }
533
+
534
+ if (FoundReusableSig) {
535
+ delete CurSignatureList;
536
+ } else {
537
+ // Add a new entry.
538
+ SignatureListMap[CurSignatureList] = {
539
+ SmallVector<StringRef, 4 >(1 , Fct.first ), Fct.second };
540
+ KnownSignatures.push_back (CurSignatureList);
541
+ }
542
+ }
543
+
544
+ for (auto *I : KnownSignatures) {
545
+ delete I;
546
+ }
547
+ }
548
+
431
549
void BuiltinNameEmitter::EmitStringMatcher () {
432
550
std::vector<StringMatcher::StringPair> ValidBuiltins;
433
551
unsigned CumulativeIndex = 1 ;
434
- for (auto &i : FctOverloadMap) {
435
- auto &Ov = i.second ;
436
- std::string RetStmt;
437
- raw_string_ostream SS (RetStmt);
438
- SS << " return std::make_pair(" << CumulativeIndex << " , " << Ov.size ()
439
- << " );" ;
440
- SS.flush ();
441
- CumulativeIndex += Ov.size ();
442
-
443
- ValidBuiltins.push_back (StringMatcher::StringPair (i.first , RetStmt));
552
+
553
+ for (const auto &SLM : SignatureListMap) {
554
+ const auto &Ovl = SLM.second .Signatures ;
555
+
556
+ // A single signature list may be used by different builtins. Return the
557
+ // same <index, length> pair for each of those builtins.
558
+ for (const auto &FctName : SLM.second .Names ) {
559
+ std::string RetStmt;
560
+ raw_string_ostream SS (RetStmt);
561
+ SS << " return std::make_pair(" << CumulativeIndex << " , " << Ovl.size ()
562
+ << " );" ;
563
+ SS.flush ();
564
+ ValidBuiltins.push_back (StringMatcher::StringPair (FctName, RetStmt));
565
+ }
566
+ CumulativeIndex += Ovl.size ();
444
567
}
445
568
446
569
OS << R"(
0 commit comments