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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits