mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 08:16:06 +00:00
[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.
This commit is contained in:
parent
09fb01a5e5
commit
15d1560ea4
@ -67,6 +67,7 @@ public:
|
||||
IgnoredAttribute,
|
||||
UnknownAttribute,
|
||||
};
|
||||
enum class Scope { NONE, CLANG, GNU, MSVC, OMP, HLSL, GSL, RISCV };
|
||||
|
||||
private:
|
||||
const IdentifierInfo *AttrName = nullptr;
|
||||
|
@ -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"
|
||||
}
|
||||
|
@ -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 differing 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
|
||||
|
Loading…
x
Reference in New Issue
Block a user