Skip to content

Commit cf4d70c

Browse files
committed
[Clang] Improve EmitClangAttrSpellingListIndex
EmitClangAttrSpellingListIndex() performs a lot of unnecessary string comparisons which is wasteful in time and space. This commit attempts to refactor this method to be more performant.
1 parent 6d7e51d commit cf4d70c

File tree

3 files changed

+126
-7
lines changed

3 files changed

+126
-7
lines changed

clang/include/clang/Basic/AttributeCommonInfo.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,16 @@ class AttributeCommonInfo {
6767
IgnoredAttribute,
6868
UnknownAttribute,
6969
};
70+
enum Scope {
71+
SC_NONE,
72+
SC_CLANG,
73+
SC_GNU,
74+
SC_MSVC,
75+
SC_OMP,
76+
SC_HLSL,
77+
SC_GSL,
78+
SC_RISCV
79+
};
7080

7181
private:
7282
const IdentifierInfo *AttrName = nullptr;

clang/lib/Basic/Attributes.cpp

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "clang/Basic/LangOptions.h"
1717
#include "clang/Basic/ParsedAttrInfo.h"
1818
#include "clang/Basic/TargetInfo.h"
19+
#include "llvm/ADT/StringMap.h"
1920

2021
using namespace clang;
2122

@@ -153,12 +154,35 @@ std::string AttributeCommonInfo::getNormalizedFullName() const {
153154
normalizeName(getAttrName(), getScopeName(), getSyntax()));
154155
}
155156

157+
static const llvm::StringMap<AttributeCommonInfo::Scope> ScopeMap = {
158+
{"", AttributeCommonInfo::SC_NONE},
159+
{"clang", AttributeCommonInfo::SC_CLANG},
160+
{"gnu", AttributeCommonInfo::SC_GNU},
161+
{"msvc", AttributeCommonInfo::SC_MSVC},
162+
{"omp", AttributeCommonInfo::SC_OMP},
163+
{"hlsl", AttributeCommonInfo::SC_HLSL},
164+
{"gsl", AttributeCommonInfo::SC_GSL},
165+
{"riscv", AttributeCommonInfo::SC_RISCV}};
166+
167+
AttributeCommonInfo::Scope
168+
getScopeFromNormalizedScopeName(const StringRef ScopeName) {
169+
auto It = ScopeMap.find(ScopeName);
170+
if (It == ScopeMap.end()) {
171+
llvm_unreachable("Unknown normalized scope name. Shouldn't get here");
172+
}
173+
174+
return It->second;
175+
}
176+
156177
unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const {
157178
// Both variables will be used in tablegen generated
158179
// attribute spell list index matching code.
159180
auto Syntax = static_cast<AttributeCommonInfo::Syntax>(getSyntax());
160-
StringRef Scope = normalizeAttrScopeName(getScopeName(), Syntax);
161-
StringRef Name = normalizeAttrName(getAttrName(), Scope, Syntax);
181+
StringRef ScopeName = normalizeAttrScopeName(getScopeName(), Syntax);
182+
StringRef Name = normalizeAttrName(getAttrName(), ScopeName, Syntax);
183+
184+
AttributeCommonInfo::Scope ComputedScope =
185+
getScopeFromNormalizedScopeName(ScopeName);
162186

163187
#include "clang/Sema/AttrSpellingListIndex.inc"
164188
}

clang/utils/TableGen/ClangAttrEmitter.cpp

Lines changed: 90 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "llvm/ADT/STLExtras.h"
2121
#include "llvm/ADT/SmallString.h"
2222
#include "llvm/ADT/StringExtras.h"
23+
#include "llvm/ADT/StringMap.h"
2324
#include "llvm/ADT/StringRef.h"
2425
#include "llvm/ADT/StringSet.h"
2526
#include "llvm/ADT/StringSwitch.h"
@@ -3843,11 +3844,95 @@ void EmitClangAttrSpellingListIndex(const RecordKeeper &Records,
38433844
const Record &R = *I.second;
38443845
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R);
38453846
OS << " case AT_" << I.first << ": {\n";
3846-
for (unsigned I = 0; I < Spellings.size(); ++ I) {
3847-
OS << " if (Name == \"" << Spellings[I].name() << "\" && "
3848-
<< "getSyntax() == AttributeCommonInfo::AS_" << Spellings[I].variety()
3849-
<< " && Scope == \"" << Spellings[I].nameSpace() << "\")\n"
3850-
<< " return " << I << ";\n";
3847+
3848+
// If there are none or one spelling to check, resort to the default
3849+
// behavior of returning index as 0.
3850+
if (Spellings.size() <= 1) {
3851+
OS << " return 0;\n";
3852+
OS << " break;\n";
3853+
OS << " }\n";
3854+
continue;
3855+
}
3856+
3857+
bool HasSingleUniqueSpellingName = true;
3858+
StringMap<std::vector<const FlattenedSpelling *>> SpellingMap;
3859+
3860+
StringRef FirstName = Spellings.front().name();
3861+
for (const auto &S : Spellings) {
3862+
StringRef Name = S.name();
3863+
if (Name != FirstName)
3864+
HasSingleUniqueSpellingName = false;
3865+
SpellingMap[Name].push_back(&S);
3866+
}
3867+
3868+
// If parsed attribute has only one possible spelling name, only compare
3869+
// syntax and scope.
3870+
if (HasSingleUniqueSpellingName) {
3871+
for (const auto &[Idx, S] : enumerate(SpellingMap[FirstName])) {
3872+
OS << " if (getSyntax() == AttributeCommonInfo::AS_" << S->variety();
3873+
3874+
std::string ScopeStr = "AttributeCommonInfo::SC_";
3875+
if (S->nameSpace() == "")
3876+
ScopeStr += "NONE";
3877+
else
3878+
ScopeStr += S->nameSpace().upper();
3879+
3880+
OS << " && ComputedScope == " << ScopeStr << ")\n"
3881+
<< " return " << Idx << ";\n";
3882+
}
3883+
} else {
3884+
size_t Idx = 0;
3885+
for (const auto &MapEntry : SpellingMap) {
3886+
StringRef Name = MapEntry.first();
3887+
const std::vector<const FlattenedSpelling *> &Cases = SpellingMap[Name];
3888+
3889+
if (Cases.size() > 1) {
3890+
// For names with multiple possible cases, emit an enclosing if such
3891+
// that the name is compared against only once. Eg:
3892+
//
3893+
// if (Name == "always_inline") {
3894+
// if (getSyntax() == AttributeCommonInfo::AS_GNU &&
3895+
// ComputedScope == AttributeCommonInfo::SC_None)
3896+
// return 0;
3897+
// ...
3898+
// }
3899+
OS << " if (Name == \"" << Name << "\") {\n";
3900+
for (const auto &S : SpellingMap[Name]) {
3901+
OS << " if (getSyntax() == AttributeCommonInfo::AS_"
3902+
<< S->variety();
3903+
std::string ScopeStr = "AttributeCommonInfo::SC_";
3904+
if (S->nameSpace() == "")
3905+
ScopeStr += "NONE";
3906+
else
3907+
ScopeStr += S->nameSpace().upper();
3908+
3909+
OS << " && ComputedScope == " << ScopeStr << ")\n"
3910+
<< " return " << Idx << ";\n";
3911+
Idx++;
3912+
}
3913+
OS << " }\n";
3914+
} else {
3915+
// If there is only possible case for the spelling name, no need of
3916+
// enclosing if. Eg.
3917+
//
3918+
// if (Name == "__forceinline" &&
3919+
// getSyntax() == AttributeCommonInfo::AS_Keyword
3920+
// && ComputedScope == AttributeCommonInfo::SC_NONE)
3921+
// return 5;
3922+
const FlattenedSpelling *S = Cases.front();
3923+
OS << " if (Name == \"" << Name << "\"";
3924+
OS << " && getSyntax() == AttributeCommonInfo::AS_" << S->variety();
3925+
std::string ScopeStr = "AttributeCommonInfo::SC_";
3926+
if (S->nameSpace() == "")
3927+
ScopeStr += "NONE";
3928+
else
3929+
ScopeStr += S->nameSpace().upper();
3930+
3931+
OS << " && ComputedScope == " << ScopeStr << ")\n"
3932+
<< " return " << Idx << ";\n";
3933+
Idx++;
3934+
}
3935+
}
38513936
}
38523937

38533938
OS << " break;\n";

0 commit comments

Comments
 (0)