[clang] 0e56b0f - [OpenCL] Group builtin functions by prototype

Sven van Haastregt via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 5 02:45:14 PST 2019


Author: Sven van Haastregt
Date: 2019-11-05T10:26:47Z
New Revision: 0e56b0f94bfc683c5a95e96784cfc9229a730bc8

URL: https://github.com/llvm/llvm-project/commit/0e56b0f94bfc683c5a95e96784cfc9229a730bc8
DIFF: https://github.com/llvm/llvm-project/commit/0e56b0f94bfc683c5a95e96784cfc9229a730bc8.diff

LOG: [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

Added: 
    

Modified: 
    clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp

Removed: 
    


################################################################################
diff  --git a/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp b/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp
index 983e267ce9ac..4042c17c5296 100644
--- 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<StringRef, 4> Names;
+  std::vector<std::pair<const Record *, unsigned>> Signatures;
+};
+
 class BuiltinNameEmitter {
 public:
   BuiltinNameEmitter(RecordKeeper &Records, raw_ostream &OS)
@@ -79,6 +86,9 @@ class BuiltinNameEmitter {
   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 @@ class BuiltinNameEmitter {
   // 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 @@ class BuiltinNameEmitter {
 
   // 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 
diff erent 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"(


        


More information about the cfe-commits mailing list