Skip to content

Commit a68fcab

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 2e30f8d commit a68fcab

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
@@ -403,6 +403,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
403403
/// The identifier '__type_pack_element'.
404404
mutable IdentifierInfo *TypePackElementName = nullptr;
405405

406+
/// The identifier '__type_list_dedup'.
407+
mutable IdentifierInfo *TypeListDedupName = nullptr;
408+
406409
QualType ObjCConstantStringType;
407410
mutable RecordDecl *CFConstantStringTagDecl = nullptr;
408411
mutable TypedefDecl *CFConstantStringTypeDecl = nullptr;
@@ -610,6 +613,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
610613
mutable ExternCContextDecl *ExternCContext = nullptr;
611614
mutable BuiltinTemplateDecl *MakeIntegerSeqDecl = nullptr;
612615
mutable BuiltinTemplateDecl *TypePackElementDecl = nullptr;
616+
mutable BuiltinTemplateDecl *TypeListDedupDecl = nullptr;
613617

614618
/// The associated SourceManager object.
615619
SourceManager &SourceMgr;
@@ -1117,6 +1121,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
11171121
ExternCContextDecl *getExternCContextDecl() const;
11181122
BuiltinTemplateDecl *getMakeIntegerSeqDecl() const;
11191123
BuiltinTemplateDecl *getTypePackElementDecl() const;
1124+
BuiltinTemplateDecl *getTypeListDedupDecl() const;
11201125

11211126
// Builtin Types.
11221127
CanQualType VoidTy;
@@ -2008,6 +2013,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
20082013
return TypePackElementName;
20092014
}
20102015

2016+
IdentifierInfo *getTypeListDedupName() const {
2017+
if (!TypeListDedupName)
2018+
TypeListDedupName = &Idents.get("__type_list_dedup");
2019+
return TypeListDedupName;
2020+
}
2021+
20112022
/// Retrieve the Objective-C "instancetype" type, if already known;
20122023
/// otherwise, returns a NULL type;
20132024
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
@@ -5467,6 +5467,9 @@ ExpectedDecl ASTNodeImporter::VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D) {
54675467
case BuiltinTemplateKind::BTK__type_pack_element:
54685468
ToD = Importer.getToContext().getTypePackElementDecl();
54695469
break;
5470+
case BuiltinTemplateKind::BTK__type_list_dedup:
5471+
ToD = Importer.getToContext().getTypeListDedupDecl();
5472+
break;
54705473
}
54715474
assert(ToD && "BuiltinTemplateDecl of unsupported kind!");
54725475
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)