Skip to content

Commit 0e56b0f

Browse files
committed
[OpenCL] Group builtin functions by prototype
The TableGen-generated file containing the function definitions can be reorganized to save some memory in the Clang binary. Functions having the same prototype(s) will point to a shared list of prototype(s). Patch by Pierre Gondois and Sven van Haastregt. Differential Revision: https://reviews.llvm.org/D63557
1 parent 9a8d477 commit 0e56b0f

File tree

1 file changed

+136
-13
lines changed

1 file changed

+136
-13
lines changed

clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp

Lines changed: 136 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,13 @@
6969
using namespace llvm;
7070

7171
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+
7279
class BuiltinNameEmitter {
7380
public:
7481
BuiltinNameEmitter(RecordKeeper &Records, raw_ostream &OS)
@@ -79,6 +86,9 @@ class BuiltinNameEmitter {
7986
void Emit();
8087

8188
private:
89+
// A list of indices into the builtin function table.
90+
using BuiltinIndexListTy = SmallVector<unsigned, 11>;
91+
8292
// Contains OpenCL builtin functions and related information, stored as
8393
// Record instances. They are coming from the associated TableGen file.
8494
RecordKeeper &Records;
@@ -106,6 +116,23 @@ class BuiltinNameEmitter {
106116
// FctOverloadMap and TypeMap.
107117
void GetOverloads();
108118

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+
109136
// Emit the TypeTable containing all types used by OpenCL builtins.
110137
void EmitTypeTable();
111138

@@ -170,6 +197,24 @@ class BuiltinNameEmitter {
170197

171198
// Same as TypeList, but for generic types only.
172199
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;
173218
};
174219
} // namespace
175220

@@ -183,6 +228,7 @@ void BuiltinNameEmitter::Emit() {
183228
EmitDeclarations();
184229

185230
GetOverloads();
231+
GroupBySignature();
186232

187233
// Emit tables.
188234
EmitTypeTable();
@@ -408,11 +454,15 @@ void BuiltinNameEmitter::EmitBuiltinTable() {
408454
unsigned Index = 0;
409455

410456
OS << "static const OpenCLBuiltinStruct BuiltinTable[] = {\n";
411-
for (const auto &FOM : FctOverloadMap) {
457+
for (const auto &SLM : SignatureListMap) {
412458

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";
414464

415-
for (const auto &Overload : FOM.second) {
465+
for (const auto &Overload : SLM.second.Signatures) {
416466
OS << " { " << Overload.second << ", "
417467
<< Overload.first->getValueAsListOfDefs("Signature").size() << ", "
418468
<< (Overload.first->getValueAsBit("IsPure")) << ", "
@@ -428,19 +478,92 @@ void BuiltinNameEmitter::EmitBuiltinTable() {
428478
OS << "};\n\n";
429479
}
430480

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+
431549
void BuiltinNameEmitter::EmitStringMatcher() {
432550
std::vector<StringMatcher::StringPair> ValidBuiltins;
433551
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();
444567
}
445568

446569
OS << R"(

0 commit comments

Comments
 (0)