forked from OSchip/llvm-project
[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
This commit is contained in:
parent
9a8d477a0e
commit
0e56b0f94b
|
@ -69,6 +69,13 @@
|
|||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
// A list of signatures that are shared by one or more builtin functions.
|
||||
struct BuiltinTableEntries {
|
||||
SmallVector<StringRef, 4> Names;
|
||||
std::vector<std::pair<const Record *, unsigned>> Signatures;
|
||||
};
|
||||
|
||||
class BuiltinNameEmitter {
|
||||
public:
|
||||
BuiltinNameEmitter(RecordKeeper &Records, raw_ostream &OS)
|
||||
|
@ -79,6 +86,9 @@ public:
|
|||
void Emit();
|
||||
|
||||
private:
|
||||
// A list of indices into the builtin function table.
|
||||
using BuiltinIndexListTy = SmallVector<unsigned, 11>;
|
||||
|
||||
// Contains OpenCL builtin functions and related information, stored as
|
||||
// Record instances. They are coming from the associated TableGen file.
|
||||
RecordKeeper &Records;
|
||||
|
@ -106,6 +116,23 @@ private:
|
|||
// FctOverloadMap and TypeMap.
|
||||
void GetOverloads();
|
||||
|
||||
// Compare two lists of signatures and check that e.g. the OpenCL version,
|
||||
// function attributes, and extension are equal for each signature.
|
||||
// \param Candidate (in) Entry in the SignatureListMap to check.
|
||||
// \param SignatureList (in) List of signatures of the considered function.
|
||||
// \returns true if the two lists of signatures are identical.
|
||||
bool CanReuseSignature(
|
||||
BuiltinIndexListTy *Candidate,
|
||||
std::vector<std::pair<const Record *, unsigned>> &SignatureList);
|
||||
|
||||
// Group functions with the same list of signatures by populating the
|
||||
// SignatureListMap.
|
||||
// Some builtin functions have the same list of signatures, for example the
|
||||
// "sin" and "cos" functions. To save space in the BuiltinTable, the
|
||||
// "isOpenCLBuiltin" function will have the same output for these two
|
||||
// function names.
|
||||
void GroupBySignature();
|
||||
|
||||
// Emit the TypeTable containing all types used by OpenCL builtins.
|
||||
void EmitTypeTable();
|
||||
|
||||
|
@ -170,6 +197,24 @@ private:
|
|||
|
||||
// Same as TypeList, but for generic types only.
|
||||
std::vector<const Record *> GenTypeList;
|
||||
|
||||
// Map an ordered vector of signatures to their original Record instances,
|
||||
// and to a list of function names that share these signatures.
|
||||
//
|
||||
// For example, suppose the "cos" and "sin" functions have only three
|
||||
// signatures, and these signatures are at index Ix in the SignatureTable:
|
||||
// cos | sin | Signature | Index
|
||||
// float cos(float) | float sin(float) | Signature1 | I1
|
||||
// double cos(double) | double sin(double) | Signature2 | I2
|
||||
// half cos(half) | half sin(half) | Signature3 | I3
|
||||
//
|
||||
// Then we will create a mapping of the vector of signatures:
|
||||
// SignatureListMap[<I1, I2, I3>] = <
|
||||
// <"cos", "sin">,
|
||||
// <Signature1, Signature2, Signature3>>
|
||||
// The function "tan", having the same signatures, would be mapped to the
|
||||
// same entry (<I1, I2, I3>).
|
||||
MapVector<BuiltinIndexListTy *, BuiltinTableEntries> SignatureListMap;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
@ -183,6 +228,7 @@ void BuiltinNameEmitter::Emit() {
|
|||
EmitDeclarations();
|
||||
|
||||
GetOverloads();
|
||||
GroupBySignature();
|
||||
|
||||
// Emit tables.
|
||||
EmitTypeTable();
|
||||
|
@ -408,11 +454,15 @@ void BuiltinNameEmitter::EmitBuiltinTable() {
|
|||
unsigned Index = 0;
|
||||
|
||||
OS << "static const OpenCLBuiltinStruct BuiltinTable[] = {\n";
|
||||
for (const auto &FOM : FctOverloadMap) {
|
||||
for (const auto &SLM : SignatureListMap) {
|
||||
|
||||
OS << " // " << (Index + 1) << ": " << FOM.first << "\n";
|
||||
OS << " // " << (Index + 1) << ": ";
|
||||
for (const auto &Name : SLM.second.Names) {
|
||||
OS << Name << ", ";
|
||||
}
|
||||
OS << "\n";
|
||||
|
||||
for (const auto &Overload : FOM.second) {
|
||||
for (const auto &Overload : SLM.second.Signatures) {
|
||||
OS << " { " << Overload.second << ", "
|
||||
<< Overload.first->getValueAsListOfDefs("Signature").size() << ", "
|
||||
<< (Overload.first->getValueAsBit("IsPure")) << ", "
|
||||
|
@ -428,19 +478,92 @@ void BuiltinNameEmitter::EmitBuiltinTable() {
|
|||
OS << "};\n\n";
|
||||
}
|
||||
|
||||
bool BuiltinNameEmitter::CanReuseSignature(
|
||||
BuiltinIndexListTy *Candidate,
|
||||
std::vector<std::pair<const Record *, unsigned>> &SignatureList) {
|
||||
assert(Candidate->size() == SignatureList.size() &&
|
||||
"signature lists should have the same size");
|
||||
|
||||
auto &CandidateSigs =
|
||||
SignatureListMap.find(Candidate)->second.Signatures;
|
||||
for (unsigned Index = 0; Index < Candidate->size(); Index++) {
|
||||
const Record *Rec = SignatureList[Index].first;
|
||||
const Record *Rec2 = CandidateSigs[Index].first;
|
||||
if (Rec->getValueAsBit("IsPure") == Rec2->getValueAsBit("IsPure") &&
|
||||
Rec->getValueAsBit("IsConst") == Rec2->getValueAsBit("IsConst") &&
|
||||
Rec->getValueAsBit("IsConv") == Rec2->getValueAsBit("IsConv") &&
|
||||
Rec->getValueAsDef("MinVersion")->getValueAsInt("ID") ==
|
||||
Rec2->getValueAsDef("MinVersion")->getValueAsInt("ID") &&
|
||||
Rec->getValueAsDef("MaxVersion")->getValueAsInt("ID") ==
|
||||
Rec2->getValueAsDef("MaxVersion")->getValueAsInt("ID") &&
|
||||
Rec->getValueAsString("Extension") ==
|
||||
Rec2->getValueAsString("Extension")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BuiltinNameEmitter::GroupBySignature() {
|
||||
// List of signatures known to be emitted.
|
||||
std::vector<BuiltinIndexListTy *> KnownSignatures;
|
||||
|
||||
for (auto &Fct : FctOverloadMap) {
|
||||
bool FoundReusableSig = false;
|
||||
|
||||
// Gather all signatures for the current function.
|
||||
auto *CurSignatureList = new BuiltinIndexListTy();
|
||||
for (const auto &Signature : Fct.second) {
|
||||
CurSignatureList->push_back(Signature.second);
|
||||
}
|
||||
// Sort the list to facilitate future comparisons.
|
||||
std::sort(CurSignatureList->begin(), CurSignatureList->end());
|
||||
|
||||
// Check if we have already seen another function with the same list of
|
||||
// signatures. If so, just add the name of the function.
|
||||
for (auto *Candidate : KnownSignatures) {
|
||||
if (Candidate->size() == CurSignatureList->size() &&
|
||||
*Candidate == *CurSignatureList) {
|
||||
if (CanReuseSignature(Candidate, Fct.second)) {
|
||||
SignatureListMap.find(Candidate)->second.Names.push_back(Fct.first);
|
||||
FoundReusableSig = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (FoundReusableSig) {
|
||||
delete CurSignatureList;
|
||||
} else {
|
||||
// Add a new entry.
|
||||
SignatureListMap[CurSignatureList] = {
|
||||
SmallVector<StringRef, 4>(1, Fct.first), Fct.second};
|
||||
KnownSignatures.push_back(CurSignatureList);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto *I : KnownSignatures) {
|
||||
delete I;
|
||||
}
|
||||
}
|
||||
|
||||
void BuiltinNameEmitter::EmitStringMatcher() {
|
||||
std::vector<StringMatcher::StringPair> ValidBuiltins;
|
||||
unsigned CumulativeIndex = 1;
|
||||
for (auto &i : FctOverloadMap) {
|
||||
auto &Ov = i.second;
|
||||
std::string RetStmt;
|
||||
raw_string_ostream SS(RetStmt);
|
||||
SS << "return std::make_pair(" << CumulativeIndex << ", " << Ov.size()
|
||||
<< ");";
|
||||
SS.flush();
|
||||
CumulativeIndex += Ov.size();
|
||||
|
||||
ValidBuiltins.push_back(StringMatcher::StringPair(i.first, RetStmt));
|
||||
for (const auto &SLM : SignatureListMap) {
|
||||
const auto &Ovl = SLM.second.Signatures;
|
||||
|
||||
// A single signature list may be used by different builtins. Return the
|
||||
// same <index, length> pair for each of those builtins.
|
||||
for (const auto &FctName : SLM.second.Names) {
|
||||
std::string RetStmt;
|
||||
raw_string_ostream SS(RetStmt);
|
||||
SS << "return std::make_pair(" << CumulativeIndex << ", " << Ovl.size()
|
||||
<< ");";
|
||||
SS.flush();
|
||||
ValidBuiltins.push_back(StringMatcher::StringPair(FctName, RetStmt));
|
||||
}
|
||||
CumulativeIndex += Ovl.size();
|
||||
}
|
||||
|
||||
OS << R"(
|
||||
|
|
Loading…
Reference in New Issue