[clang] 15d1560 - [Clang] Improve EmitClangAttrSpellingListIndex (#114899)

via cfe-commits cfe-commits at lists.llvm.org
Thu Nov 7 13:02:01 PST 2024


Author: Chinmay Deshpande
Date: 2024-11-07T13:01:58-08:00
New Revision: 15d1560ea4047a2b4b14c826767089f538ddda70

URL: https://github.com/llvm/llvm-project/commit/15d1560ea4047a2b4b14c826767089f538ddda70
DIFF: https://github.com/llvm/llvm-project/commit/15d1560ea4047a2b4b14c826767089f538ddda70.diff

LOG: [Clang] Improve EmitClangAttrSpellingListIndex (#114899)

`EmitClangAttrSpellingListIndex()` performs a lot of unnecessary string
comparisons which is wasteful in time and stack space. This commit
attempts to refactor this method to be more performant.

Added: 
    

Modified: 
    clang/include/clang/Basic/AttributeCommonInfo.h
    clang/lib/Basic/Attributes.cpp
    clang/utils/TableGen/ClangAttrEmitter.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/AttributeCommonInfo.h b/clang/include/clang/Basic/AttributeCommonInfo.h
index 5f024b4b5fd782..11c64547721739 100644
--- a/clang/include/clang/Basic/AttributeCommonInfo.h
+++ b/clang/include/clang/Basic/AttributeCommonInfo.h
@@ -67,6 +67,7 @@ class AttributeCommonInfo {
     IgnoredAttribute,
     UnknownAttribute,
   };
+  enum class Scope { NONE, CLANG, GNU, MSVC, OMP, HLSL, GSL, RISCV };
 
 private:
   const IdentifierInfo *AttrName = nullptr;

diff  --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp
index 867d241a2cf847..2d18fb3f9d5bb2 100644
--- a/clang/lib/Basic/Attributes.cpp
+++ b/clang/lib/Basic/Attributes.cpp
@@ -17,6 +17,8 @@
 #include "clang/Basic/ParsedAttrInfo.h"
 #include "clang/Basic/TargetInfo.h"
 
+#include "llvm/ADT/StringMap.h"
+
 using namespace clang;
 
 static int hasAttributeImpl(AttributeCommonInfo::Syntax Syntax, StringRef Name,
@@ -153,12 +155,37 @@ std::string AttributeCommonInfo::getNormalizedFullName() const {
       normalizeName(getAttrName(), getScopeName(), getSyntax()));
 }
 
+// Sorted list of attribute scope names
+static constexpr std::pair<StringRef, AttributeCommonInfo::Scope> ScopeList[] =
+    {{"", AttributeCommonInfo::Scope::NONE},
+     {"clang", AttributeCommonInfo::Scope::CLANG},
+     {"gnu", AttributeCommonInfo::Scope::GNU},
+     {"gsl", AttributeCommonInfo::Scope::GSL},
+     {"hlsl", AttributeCommonInfo::Scope::HLSL},
+     {"msvc", AttributeCommonInfo::Scope::MSVC},
+     {"omp", AttributeCommonInfo::Scope::OMP},
+     {"riscv", AttributeCommonInfo::Scope::RISCV}};
+
+AttributeCommonInfo::Scope
+getScopeFromNormalizedScopeName(StringRef ScopeName) {
+  auto It = std::lower_bound(
+      std::begin(ScopeList), std::end(ScopeList), ScopeName,
+      [](const std::pair<StringRef, AttributeCommonInfo::Scope> &Element,
+         StringRef Value) { return Element.first < Value; });
+  assert(It != std::end(ScopeList) && It->first == ScopeName);
+
+  return It->second;
+}
+
 unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const {
   // Both variables will be used in tablegen generated
   // attribute spell list index matching code.
   auto Syntax = static_cast<AttributeCommonInfo::Syntax>(getSyntax());
-  StringRef Scope = normalizeAttrScopeName(getScopeName(), Syntax);
-  StringRef Name = normalizeAttrName(getAttrName(), Scope, Syntax);
+  StringRef ScopeName = normalizeAttrScopeName(getScopeName(), Syntax);
+  StringRef Name = normalizeAttrName(getAttrName(), ScopeName, Syntax);
+
+  AttributeCommonInfo::Scope ComputedScope =
+      getScopeFromNormalizedScopeName(ScopeName);
 
 #include "clang/Sema/AttrSpellingListIndex.inc"
 }

diff  --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp
index 5a80c8c0b7ad36..932cf25f6a7c26 100644
--- a/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -20,6 +20,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/ADT/StringSwitch.h"
@@ -3843,19 +3844,59 @@ void EmitClangAttrSpellingListIndex(const RecordKeeper &Records,
     const Record &R = *I.second;
     std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R);
     OS << "  case AT_" << I.first << ": {\n";
-    for (unsigned I = 0; I < Spellings.size(); ++ I) {
-      OS << "    if (Name == \"" << Spellings[I].name() << "\" && "
-         << "getSyntax() == AttributeCommonInfo::AS_" << Spellings[I].variety()
-         << " && Scope == \"" << Spellings[I].nameSpace() << "\")\n"
-         << "        return " << I << ";\n";
+
+    // If there are none or one spelling to check, resort to the default
+    // behavior of returning index as 0.
+    if (Spellings.size() <= 1) {
+      OS << "    return 0;\n"
+         << "    break;\n"
+         << "  }\n";
+      continue;
     }
 
-    OS << "    break;\n";
-    OS << "  }\n";
+    std::vector<StringRef> Names;
+    llvm::transform(Spellings, std::back_inserter(Names),
+                    [](const FlattenedSpelling &FS) { return FS.name(); });
+    llvm::sort(Names);
+    Names.erase(llvm::unique(Names), Names.end());
+
+    for (const auto &[Idx, FS] : enumerate(Spellings)) {
+      OS << "    if (";
+      if (Names.size() > 1) {
+        SmallVector<StringRef, 6> SameLenNames;
+        llvm::copy_if(
+            Names, std::back_inserter(SameLenNames),
+            [&](StringRef N) { return N.size() == FS.name().size(); });
+
+        if (SameLenNames.size() == 1) {
+          OS << "Name.size() == " << FS.name().size() << " && ";
+        } else {
+          // FIXME: We currently fall back to comparing entire strings if there
+          // are 2 or more spelling names with the same length. This can be
+          // optimized to check only for the the first 
diff ering character
+          // between them instead.
+          OS << "Name == \"" << FS.name() << "\""
+             << " && ";
+        }
+      }
+
+      OS << "getSyntax() == AttributeCommonInfo::AS_" << FS.variety()
+         << " && ComputedScope == ";
+      if (FS.nameSpace() == "")
+        OS << "AttributeCommonInfo::Scope::NONE";
+      else
+        OS << "AttributeCommonInfo::Scope::" + FS.nameSpace().upper();
+
+      OS << ")\n"
+         << "      return " << Idx << ";\n";
+    }
+
+    OS << "    break;\n"
+       << "  }\n";
   }
 
-  OS << "  }\n";
-  OS << "  return 0;\n";
+  OS << "  }\n"
+     << "  return 0;\n";
 }
 
 // Emits code used by RecursiveASTVisitor to visit attributes


        


More information about the cfe-commits mailing list