Skip to content

Commit 0997438

Browse files
committed
[AST] NFC: Improve non-generic nominal type memory efficiency
The non-generic nominal type nodes do not actually need to use LLVM's FoldingSetNode, and on my workstation the release build of the standard library completes about 1/3 of a second faster after switching to LLVM DenseMap. This is perhaps not surprising, because Decl to Type mappings are only needed during early compiler stages, but the intrusive FoldingSetNode data decreases CPU cache efficiency during all compiler stages. As a bonus, the resulting code is simpler.
1 parent 9e5d8ee commit 0997438

File tree

2 files changed

+32
-97
lines changed

2 files changed

+32
-97
lines changed

include/swift/AST/Types.h

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2241,7 +2241,7 @@ class NominalType : public NominalOrBoundGenericNominalType {
22412241
DEFINE_EMPTY_CAN_TYPE_WRAPPER(NominalType, NominalOrBoundGenericNominalType)
22422242

22432243
/// EnumType - This represents the type declared by an EnumDecl.
2244-
class EnumType : public NominalType, public llvm::FoldingSetNode {
2244+
class EnumType : public NominalType {
22452245
public:
22462246
/// getDecl() - Returns the decl which declares this type.
22472247
EnumDecl *getDecl() const {
@@ -2252,11 +2252,6 @@ class EnumType : public NominalType, public llvm::FoldingSetNode {
22522252
/// declaration in the parent type \c Parent.
22532253
static EnumType *get(EnumDecl *D, Type Parent, const ASTContext &C);
22542254

2255-
void Profile(llvm::FoldingSetNodeID &ID) {
2256-
Profile(ID, getDecl(), getParent());
2257-
}
2258-
static void Profile(llvm::FoldingSetNodeID &ID, EnumDecl *D, Type Parent);
2259-
22602255
// Implement isa/cast/dyncast/etc.
22612256
static bool classof(const TypeBase *T) {
22622257
return T->getKind() == TypeKind::Enum;
@@ -2269,7 +2264,7 @@ class EnumType : public NominalType, public llvm::FoldingSetNode {
22692264
DEFINE_EMPTY_CAN_TYPE_WRAPPER(EnumType, NominalType)
22702265

22712266
/// StructType - This represents the type declared by a StructDecl.
2272-
class StructType : public NominalType, public llvm::FoldingSetNode {
2267+
class StructType : public NominalType {
22732268
public:
22742269
/// getDecl() - Returns the decl which declares this type.
22752270
StructDecl *getDecl() const {
@@ -2280,11 +2275,6 @@ class StructType : public NominalType, public llvm::FoldingSetNode {
22802275
/// declaration in the parent type \c Parent.
22812276
static StructType *get(StructDecl *D, Type Parent, const ASTContext &C);
22822277

2283-
void Profile(llvm::FoldingSetNodeID &ID) {
2284-
Profile(ID, getDecl(), getParent());
2285-
}
2286-
static void Profile(llvm::FoldingSetNodeID &ID, StructDecl *D, Type Parent);
2287-
22882278
// Implement isa/cast/dyncast/etc.
22892279
static bool classof(const TypeBase *T) {
22902280
return T->getKind() == TypeKind::Struct;
@@ -2297,7 +2287,7 @@ class StructType : public NominalType, public llvm::FoldingSetNode {
22972287
DEFINE_EMPTY_CAN_TYPE_WRAPPER(StructType, NominalType)
22982288

22992289
/// ClassType - This represents the type declared by a ClassDecl.
2300-
class ClassType : public NominalType, public llvm::FoldingSetNode {
2290+
class ClassType : public NominalType {
23012291
public:
23022292
/// getDecl() - Returns the decl which declares this type.
23032293
ClassDecl *getDecl() const {
@@ -2308,11 +2298,6 @@ class ClassType : public NominalType, public llvm::FoldingSetNode {
23082298
/// declaration in the parent type \c Parent.
23092299
static ClassType *get(ClassDecl *D, Type Parent, const ASTContext &C);
23102300

2311-
void Profile(llvm::FoldingSetNodeID &ID) {
2312-
Profile(ID, getDecl(), getParent());
2313-
}
2314-
static void Profile(llvm::FoldingSetNodeID &ID, ClassDecl *D, Type Parent);
2315-
23162301
// Implement isa/cast/dyncast/etc.
23172302
static bool classof(const TypeBase *T) {
23182303
return T->getKind() == TypeKind::Class;
@@ -4343,7 +4328,7 @@ class DictionaryType : public SyntaxSugarType {
43434328

43444329
/// ProtocolType - A protocol type describes an abstract interface implemented
43454330
/// by another type.
4346-
class ProtocolType : public NominalType, public llvm::FoldingSetNode {
4331+
class ProtocolType : public NominalType {
43474332
public:
43484333
/// Retrieve the type when we're referencing the given protocol.
43494334
/// declaration.
@@ -4376,11 +4361,6 @@ class ProtocolType : public NominalType, public llvm::FoldingSetNode {
43764361
static bool visitAllProtocols(ArrayRef<ProtocolDecl *> protocols,
43774362
llvm::function_ref<bool(ProtocolDecl *)> fn);
43784363

4379-
void Profile(llvm::FoldingSetNodeID &ID) {
4380-
Profile(ID, getDecl(), getParent());
4381-
}
4382-
static void Profile(llvm::FoldingSetNodeID &ID, ProtocolDecl *D, Type Parent);
4383-
43844364
private:
43854365
friend class NominalTypeDecl;
43864366
ProtocolType(ProtocolDecl *TheDecl, Type Parent, const ASTContext &Ctx,

lib/AST/ASTContext.cpp

Lines changed: 28 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -317,12 +317,12 @@ FOR_KNOWN_FOUNDATION_TYPES(CACHE_FOUNDATION_DECL)
317317
llvm::DenseMap<std::pair<Type, void*>, DependentMemberType *>
318318
DependentMemberTypes;
319319
llvm::DenseMap<Type, DynamicSelfType *> DynamicSelfTypes;
320-
llvm::FoldingSet<EnumType> EnumTypes;
321-
llvm::FoldingSet<StructType> StructTypes;
322-
llvm::FoldingSet<ClassType> ClassTypes;
320+
llvm::DenseMap<std::pair<EnumDecl*, Type>, EnumType*> EnumTypes;
321+
llvm::DenseMap<std::pair<StructDecl*, Type>, StructType*> StructTypes;
322+
llvm::DenseMap<std::pair<ClassDecl*, Type>, ClassType*> ClassTypes;
323+
llvm::DenseMap<std::pair<ProtocolDecl*, Type>, ProtocolType*> ProtocolTypes;
323324
llvm::FoldingSet<UnboundGenericType> UnboundGenericTypes;
324325
llvm::FoldingSet<BoundGenericType> BoundGenericTypes;
325-
llvm::FoldingSet<ProtocolType> ProtocolTypes;
326326
llvm::FoldingSet<ProtocolCompositionType> ProtocolCompositionTypes;
327327
llvm::FoldingSet<LayoutConstraintInfo> LayoutConstraints;
328328

@@ -2093,11 +2093,12 @@ size_t ASTContext::Implementation::Arena::getTotalMemory() const {
20932093
llvm::capacity_in_bytes(LValueTypes) +
20942094
llvm::capacity_in_bytes(InOutTypes) +
20952095
llvm::capacity_in_bytes(DependentMemberTypes) +
2096+
llvm::capacity_in_bytes(EnumTypes) +
2097+
llvm::capacity_in_bytes(StructTypes) +
2098+
llvm::capacity_in_bytes(ClassTypes) +
2099+
llvm::capacity_in_bytes(ProtocolTypes) +
20962100
llvm::capacity_in_bytes(DynamicSelfTypes);
20972101
// FunctionTypes ?
2098-
// EnumTypes ?
2099-
// StructTypes ?
2100-
// ClassTypes ?
21012102
// UnboundGenericTypes ?
21022103
// BoundGenericTypes ?
21032104
// NormalConformances ?
@@ -3362,80 +3363,47 @@ EnumType::EnumType(EnumDecl *TheDecl, Type Parent, const ASTContext &C,
33623363
: NominalType(TypeKind::Enum, &C, TheDecl, Parent, properties) { }
33633364

33643365
EnumType *EnumType::get(EnumDecl *D, Type Parent, const ASTContext &C) {
3365-
llvm::FoldingSetNodeID id;
3366-
EnumType::Profile(id, D, Parent);
3367-
33683366
RecursiveTypeProperties properties;
33693367
if (Parent) properties |= Parent->getRecursiveProperties();
33703368
auto arena = getArena(properties);
33713369

3372-
void *insertPos = nullptr;
3373-
if (auto enumTy
3374-
= C.getImpl().getArena(arena).EnumTypes.FindNodeOrInsertPos(id, insertPos))
3375-
return enumTy;
3376-
3377-
auto enumTy = new (C, arena) EnumType(D, Parent, C, properties);
3378-
C.getImpl().getArena(arena).EnumTypes.InsertNode(enumTy, insertPos);
3379-
return enumTy;
3380-
}
3381-
3382-
void EnumType::Profile(llvm::FoldingSetNodeID &ID, EnumDecl *D, Type Parent) {
3383-
ID.AddPointer(D);
3384-
ID.AddPointer(Parent.getPointer());
3370+
auto *&known = C.getImpl().getArena(arena).EnumTypes[{D, Parent}];
3371+
if (!known) {
3372+
known = new (C, arena) EnumType(D, Parent, C, properties);
3373+
}
3374+
return known;
33853375
}
33863376

33873377
StructType::StructType(StructDecl *TheDecl, Type Parent, const ASTContext &C,
33883378
RecursiveTypeProperties properties)
33893379
: NominalType(TypeKind::Struct, &C, TheDecl, Parent, properties) { }
33903380

33913381
StructType *StructType::get(StructDecl *D, Type Parent, const ASTContext &C) {
3392-
llvm::FoldingSetNodeID id;
3393-
StructType::Profile(id, D, Parent);
3394-
33953382
RecursiveTypeProperties properties;
33963383
if (Parent) properties |= Parent->getRecursiveProperties();
33973384
auto arena = getArena(properties);
33983385

3399-
void *insertPos = nullptr;
3400-
if (auto structTy
3401-
= C.getImpl().getArena(arena).StructTypes.FindNodeOrInsertPos(id, insertPos))
3402-
return structTy;
3403-
3404-
auto structTy = new (C, arena) StructType(D, Parent, C, properties);
3405-
C.getImpl().getArena(arena).StructTypes.InsertNode(structTy, insertPos);
3406-
return structTy;
3407-
}
3408-
3409-
void StructType::Profile(llvm::FoldingSetNodeID &ID, StructDecl *D, Type Parent) {
3410-
ID.AddPointer(D);
3411-
ID.AddPointer(Parent.getPointer());
3386+
auto *&known = C.getImpl().getArena(arena).StructTypes[{D, Parent}];
3387+
if (!known) {
3388+
known = new (C, arena) StructType(D, Parent, C, properties);
3389+
}
3390+
return known;
34123391
}
34133392

34143393
ClassType::ClassType(ClassDecl *TheDecl, Type Parent, const ASTContext &C,
34153394
RecursiveTypeProperties properties)
34163395
: NominalType(TypeKind::Class, &C, TheDecl, Parent, properties) { }
34173396

34183397
ClassType *ClassType::get(ClassDecl *D, Type Parent, const ASTContext &C) {
3419-
llvm::FoldingSetNodeID id;
3420-
ClassType::Profile(id, D, Parent);
3421-
34223398
RecursiveTypeProperties properties;
34233399
if (Parent) properties |= Parent->getRecursiveProperties();
34243400
auto arena = getArena(properties);
34253401

3426-
void *insertPos = nullptr;
3427-
if (auto classTy
3428-
= C.getImpl().getArena(arena).ClassTypes.FindNodeOrInsertPos(id, insertPos))
3429-
return classTy;
3430-
3431-
auto classTy = new (C, arena) ClassType(D, Parent, C, properties);
3432-
C.getImpl().getArena(arena).ClassTypes.InsertNode(classTy, insertPos);
3433-
return classTy;
3434-
}
3435-
3436-
void ClassType::Profile(llvm::FoldingSetNodeID &ID, ClassDecl *D, Type Parent) {
3437-
ID.AddPointer(D);
3438-
ID.AddPointer(Parent.getPointer());
3402+
auto *&known = C.getImpl().getArena(arena).ClassTypes[{D, Parent}];
3403+
if (!known) {
3404+
known = new (C, arena) ClassType(D, Parent, C, properties);
3405+
}
3406+
return known;
34393407
}
34403408

34413409
ProtocolCompositionType *
@@ -4171,35 +4139,22 @@ OptionalType *OptionalType::get(Type base) {
41714139

41724140
ProtocolType *ProtocolType::get(ProtocolDecl *D, Type Parent,
41734141
const ASTContext &C) {
4174-
llvm::FoldingSetNodeID id;
4175-
ProtocolType::Profile(id, D, Parent);
4176-
41774142
RecursiveTypeProperties properties;
41784143
if (Parent) properties |= Parent->getRecursiveProperties();
41794144
auto arena = getArena(properties);
41804145

4181-
void *insertPos = nullptr;
4182-
if (auto protoTy
4183-
= C.getImpl().getArena(arena).ProtocolTypes.FindNodeOrInsertPos(id, insertPos))
4184-
return protoTy;
4185-
4186-
auto protoTy = new (C, arena) ProtocolType(D, Parent, C, properties);
4187-
C.getImpl().getArena(arena).ProtocolTypes.InsertNode(protoTy, insertPos);
4188-
4189-
return protoTy;
4146+
auto *&known = C.getImpl().getArena(arena).ProtocolTypes[{D, Parent}];
4147+
if (!known) {
4148+
known = new (C, arena) ProtocolType(D, Parent, C, properties);
4149+
}
4150+
return known;
41904151
}
41914152

41924153
ProtocolType::ProtocolType(ProtocolDecl *TheDecl, Type Parent,
41934154
const ASTContext &Ctx,
41944155
RecursiveTypeProperties properties)
41954156
: NominalType(TypeKind::Protocol, &Ctx, TheDecl, Parent, properties) { }
41964157

4197-
void ProtocolType::Profile(llvm::FoldingSetNodeID &ID, ProtocolDecl *D,
4198-
Type Parent) {
4199-
ID.AddPointer(D);
4200-
ID.AddPointer(Parent.getPointer());
4201-
}
4202-
42034158
LValueType *LValueType::get(Type objectTy) {
42044159
assert(!objectTy->hasError() &&
42054160
"cannot have ErrorType wrapped inside LValueType");

0 commit comments

Comments
 (0)