Skip to content

Commit a46885d

Browse files
committed
[Clang] Add __type_list_dedup builtin to deduplicate types in template arguments
This allows to deduplicate the type lists efficiently in C++. It is possible to achieve the same effect via template metaprogramming, but performance of the resulting code is much lower than in the compiler. We have observed that this code is quite common in our internal codebase and this builtin allows to have significant savings (up to 25% of compile time on targets that already take 3 minutes to compile). The same builtin is also used widely enough in the codebase that we expect a savings from a long tail of uses, too, although it is hard to put an estimate on this number in advance. The implementation aims to be as simple as possible and relies on the exsisting machinery for builtin templates.
1 parent 2a9f93b commit a46885d

File tree

16 files changed

+185
-5
lines changed

16 files changed

+185
-5
lines changed

clang-tools-extra/clangd/unittests/FindTargetTests.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,12 @@ TEST_F(TargetDeclTest, BuiltinTemplates) {
731731
using type_pack_element = [[__type_pack_element]]<N, Pack...>;
732732
)cpp";
733733
EXPECT_DECLS("TemplateSpecializationTypeLoc", );
734+
735+
Code = R"cpp(
736+
template <template <class...> Templ, class... Types>
737+
using type_list_dedup = [[__type_list_dedup]]<Templ, Types...>;
738+
)cpp";
739+
EXPECT_DECLS("TemplateSpecializationTypeLoc", );
734740
}
735741

736742
TEST_F(TargetDeclTest, MemberOfTemplate) {

clang/include/clang/AST/ASTContext.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
401401
/// The identifier '__type_pack_element'.
402402
mutable IdentifierInfo *TypePackElementName = nullptr;
403403

404+
/// The identifier '__type_list_dedup'.
405+
mutable IdentifierInfo *TypeListDedupName = nullptr;
406+
404407
QualType ObjCConstantStringType;
405408
mutable RecordDecl *CFConstantStringTagDecl = nullptr;
406409
mutable TypedefDecl *CFConstantStringTypeDecl = nullptr;
@@ -608,6 +611,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
608611
mutable ExternCContextDecl *ExternCContext = nullptr;
609612
mutable BuiltinTemplateDecl *MakeIntegerSeqDecl = nullptr;
610613
mutable BuiltinTemplateDecl *TypePackElementDecl = nullptr;
614+
mutable BuiltinTemplateDecl *TypeListDedupDecl = nullptr;
611615

612616
/// The associated SourceManager object.
613617
SourceManager &SourceMgr;
@@ -1115,6 +1119,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
11151119
ExternCContextDecl *getExternCContextDecl() const;
11161120
BuiltinTemplateDecl *getMakeIntegerSeqDecl() const;
11171121
BuiltinTemplateDecl *getTypePackElementDecl() const;
1122+
BuiltinTemplateDecl *getTypeListDedupDecl() const;
11181123

11191124
// Builtin Types.
11201125
CanQualType VoidTy;
@@ -2006,6 +2011,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
20062011
return TypePackElementName;
20072012
}
20082013

2014+
IdentifierInfo *getTypeListDedupName() const {
2015+
if (!TypeListDedupName)
2016+
TypeListDedupName = &Idents.get("__type_list_dedup");
2017+
return TypeListDedupName;
2018+
}
2019+
20092020
/// Retrieve the Objective-C "instancetype" type, if already known;
20102021
/// otherwise, returns a NULL type;
20112022
QualType getObjCInstanceType() {

clang/include/clang/AST/DeclID.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ enum PredefinedDeclIDs {
8383
/// The internal '__type_pack_element' template.
8484
PREDEF_DECL_TYPE_PACK_ELEMENT_ID,
8585

86+
/// The internal '__type_list_dedup' template.
87+
PREDEF_DECL_TYPE_LIST_DEDUP_ID,
88+
8689
/// The number of declaration IDs that are predefined.
8790
NUM_PREDEF_DECL_IDS
8891
};

clang/include/clang/Basic/Builtins.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,10 @@ enum BuiltinTemplateKind : int {
309309
BTK__make_integer_seq,
310310

311311
/// This names the __type_pack_element BuiltinTemplateDecl.
312-
BTK__type_pack_element
312+
BTK__type_pack_element,
313+
314+
/// This names the __type_list_dedup BuiltinTemplateDecl.
315+
BTK__type_list_dedup,
313316
};
314317

315318
} // end namespace clang

clang/lib/AST/ASTContext.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,6 +1170,14 @@ ASTContext::getTypePackElementDecl() const {
11701170
return TypePackElementDecl;
11711171
}
11721172

1173+
BuiltinTemplateDecl *
1174+
ASTContext::getTypeListDedupDecl() const {
1175+
if (!TypeListDedupDecl)
1176+
TypeListDedupDecl =
1177+
buildBuiltinTemplateDecl(BTK__type_list_dedup, getTypeListDedupName());
1178+
return TypeListDedupDecl;
1179+
}
1180+
11731181
RecordDecl *ASTContext::buildImplicitRecord(StringRef Name,
11741182
RecordDecl::TagKind TK) const {
11751183
SourceLocation Loc;

clang/lib/AST/ASTImporter.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5476,6 +5476,9 @@ ExpectedDecl ASTNodeImporter::VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D) {
54765476
case BuiltinTemplateKind::BTK__type_pack_element:
54775477
ToD = Importer.getToContext().getTypePackElementDecl();
54785478
break;
5479+
case BuiltinTemplateKind::BTK__type_list_dedup:
5480+
ToD = Importer.getToContext().getTypeListDedupDecl();
5481+
break;
54795482
}
54805483
assert(ToD && "BuiltinTemplateDecl of unsupported kind!");
54815484
Importer.MapImported(D, ToD);

clang/lib/AST/DeclTemplate.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,13 +1608,44 @@ createTypePackElementParameterList(const ASTContext &C, DeclContext *DC) {
16081608
nullptr);
16091609
}
16101610

1611+
static TemplateParameterList *
1612+
createTypeListDedupParameterList(const ASTContext &C, DeclContext *DC) {
1613+
// template <typename ...> typename Templ
1614+
auto *InnerTs = TemplateTypeParmDecl::Create(
1615+
C, DC, SourceLocation(), SourceLocation(), /*Depth=*/1, /*Position=*/0,
1616+
/*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/true,
1617+
/*HasTypeConstraint=*/false);
1618+
InnerTs->setImplicit(true);
1619+
auto *TemplateParamList = TemplateParameterList::Create(
1620+
C, SourceLocation(), SourceLocation(), {InnerTs}, SourceLocation(),
1621+
/*RequiresClause=*/nullptr);
1622+
auto *Template = TemplateTemplateParmDecl::Create(
1623+
C, DC, SourceLocation(), /*Depth=*/0,
1624+
/*Position=*/0, /*ParameterPack=*/false, /*Id=*/nullptr,
1625+
/*Typename=*/true, TemplateParamList);
1626+
Template->setImplicit(true);
1627+
1628+
// typename ...Ts
1629+
auto *Ts = TemplateTypeParmDecl::Create(
1630+
C, DC, SourceLocation(), SourceLocation(), /*Depth=*/0, /*Position=*/1,
1631+
/*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/true,
1632+
/*HasTypeConstraint=*/false);
1633+
Ts->setImplicit(true);
1634+
return TemplateParameterList::Create(
1635+
C, SourceLocation(), SourceLocation(),
1636+
llvm::ArrayRef<NamedDecl *>({Template, Ts}), SourceLocation(),
1637+
/*RequiresClause=*/nullptr);
1638+
}
1639+
16111640
static TemplateParameterList *createBuiltinTemplateParameterList(
16121641
const ASTContext &C, DeclContext *DC, BuiltinTemplateKind BTK) {
16131642
switch (BTK) {
16141643
case BTK__make_integer_seq:
16151644
return createMakeIntegerSeqParameterList(C, DC);
16161645
case BTK__type_pack_element:
16171646
return createTypePackElementParameterList(C, DC);
1647+
case BTK__type_list_dedup:
1648+
return createTypeListDedupParameterList(C, DC);
16181649
}
16191650

16201651
llvm_unreachable("unhandled BuiltinTemplateKind!");

clang/lib/Lex/PPMacroExpansion.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1836,6 +1836,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
18361836
// Report builtin templates as being builtins.
18371837
.Case("__make_integer_seq", getLangOpts().CPlusPlus)
18381838
.Case("__type_pack_element", getLangOpts().CPlusPlus)
1839+
.Case("__type_list_dedup", getLangOpts().CPlusPlus)
18391840
// Likewise for some builtin preprocessor macros.
18401841
// FIXME: This is inconsistent; we usually suggest detecting
18411842
// builtin macros via #ifdef. Don't add more cases here.

clang/lib/Sema/SemaLookup.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -928,10 +928,15 @@ bool Sema::LookupBuiltin(LookupResult &R) {
928928
if (II == getASTContext().getMakeIntegerSeqName()) {
929929
R.addDecl(getASTContext().getMakeIntegerSeqDecl());
930930
return true;
931-
} else if (II == getASTContext().getTypePackElementName()) {
931+
}
932+
if (II == getASTContext().getTypePackElementName()) {
932933
R.addDecl(getASTContext().getTypePackElementDecl());
933934
return true;
934935
}
936+
if (II == getASTContext().getTypeListDedupName()) {
937+
R.addDecl(getASTContext().getTypeListDedupDecl());
938+
return true;
939+
}
935940
}
936941

937942
// Check if this is an OpenCL Builtin, and if so, insert its overloads.

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
#include "clang/AST/Expr.h"
1818
#include "clang/AST/ExprCXX.h"
1919
#include "clang/AST/RecursiveASTVisitor.h"
20+
#include "clang/AST/TemplateBase.h"
2021
#include "clang/AST/TemplateName.h"
22+
#include "clang/AST/TypeOrdering.h"
2123
#include "clang/AST/TypeVisitor.h"
2224
#include "clang/Basic/Builtins.h"
2325
#include "clang/Basic/DiagnosticSema.h"
@@ -38,9 +40,11 @@
3840
#include "clang/Sema/Template.h"
3941
#include "clang/Sema/TemplateDeduction.h"
4042
#include "llvm/ADT/BitVector.h"
43+
#include "llvm/ADT/DenseSet.h"
4144
#include "llvm/ADT/SmallBitVector.h"
4245
#include "llvm/ADT/SmallString.h"
4346
#include "llvm/ADT/StringExtras.h"
47+
#include "llvm/Support/raw_ostream.h"
4448

4549
#include <iterator>
4650
#include <optional>
@@ -3132,12 +3136,12 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
31323136
TemplateLoc, SyntheticTemplateArgs);
31333137
}
31343138

3135-
case BTK__type_pack_element:
3139+
case BTK__type_pack_element: {
31363140
// Specializations of
31373141
// __type_pack_element<Index, T_1, ..., T_N>
31383142
// are treated like T_Index.
31393143
assert(Converted.size() == 2 &&
3140-
"__type_pack_element should be given an index and a parameter pack");
3144+
"__type_pack_element should be given an index and a parameter pack");
31413145

31423146
TemplateArgument IndexArg = Converted[0], Ts = Converted[1];
31433147
if (IndexArg.isDependent() || Ts.isDependent())
@@ -3158,6 +3162,34 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
31583162
int64_t N = Index.getExtValue();
31593163
return Ts.getPackAsArray()[N].getAsType();
31603164
}
3165+
case BTK__type_list_dedup: {
3166+
assert(Converted.size() == 2 &&
3167+
"__type_list_dedup should be given a template and a parameter pack");
3168+
TemplateArgument Template = Converted[0];
3169+
TemplateArgument Ts = Converted[1];
3170+
if (Template.isDependent() || Ts.isDependent())
3171+
return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD),
3172+
Converted);
3173+
3174+
assert(Template.getKind() == clang::TemplateArgument::Template);
3175+
assert(Ts.getKind() == clang::TemplateArgument::Pack);
3176+
TemplateArgumentListInfo SyntheticTemplateArgs;
3177+
llvm::DenseSet<QualType> Seen;
3178+
// Synthesize a new template argument list, removing duplicates.
3179+
for (auto T : Ts.getPackAsArray()) {
3180+
assert(T.getKind() == clang::TemplateArgument::Type);
3181+
if (!Seen.insert(T.getAsType().getCanonicalType()).second)
3182+
continue;
3183+
SyntheticTemplateArgs.addArgument(TemplateArgumentLoc(
3184+
TemplateArgument(T),
3185+
SemaRef.Context.getTrivialTypeSourceInfo(
3186+
T.getAsType(),
3187+
/*FIXME: add location*/ SourceLocation())));
3188+
}
3189+
return SemaRef.CheckTemplateIdType(Template.getAsTemplate(), TemplateLoc,
3190+
SyntheticTemplateArgs);
3191+
}
3192+
}
31613193
llvm_unreachable("unexpected BuiltinTemplateDecl!");
31623194
}
31633195

0 commit comments

Comments
 (0)