diff --git a/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp b/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp --- a/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp +++ b/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp @@ -69,6 +69,13 @@ using namespace llvm; namespace { + +// A list of signatures that are shared by one or more builtin functions. +struct BuiltinTableEntries { + SmallVector Names; + std::vector> Signatures; +}; + class BuiltinNameEmitter { public: BuiltinNameEmitter(RecordKeeper &Records, raw_ostream &OS) @@ -79,6 +86,9 @@ void Emit(); private: + // A list of indices into the builtin function table. + using BuiltinIndexListTy = SmallVector; + // 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 @@ // 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> &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 @@ // Same as TypeList, but for generic types only. std::vector 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[] = < + // <"cos", "sin">, + // > + // The function "tan", having the same signatures, would be mapped to the + // same entry (). + MapVector SignatureListMap; }; } // namespace @@ -183,6 +228,7 @@ EmitDeclarations(); GetOverloads(); + GroupBySignature(); // Emit tables. EmitTypeTable(); @@ -408,11 +454,15 @@ 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 @@ OS << "};\n\n"; } +bool BuiltinNameEmitter::CanReuseSignature( + BuiltinIndexListTy *Candidate, + std::vector> &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 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(1, Fct.first), Fct.second}; + KnownSignatures.push_back(CurSignatureList); + } + } + + for (auto *I : KnownSignatures) { + delete I; + } +} + void BuiltinNameEmitter::EmitStringMatcher() { std::vector 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 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"(