Skip to content

Commit 9b48b50

Browse files
committed
[AST] Perf: Unite DictionaryType with SyntaxSugarType
1) Move existing SyntaxSugarTypes under a new subclass called UnarySyntaxSugarType. 2) Make DictionaryType subclass SyntaxSugarType. This helps improve getDesugaredType() performance by ensuring that ImplOrContext is stored at the same field offset in memory. This also de-boilerplates some AST walking.
1 parent 07f5029 commit 9b48b50

File tree

8 files changed

+90
-81
lines changed

8 files changed

+90
-81
lines changed

include/swift/AST/TypeNodes.def

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,13 @@ ARTIFICIAL_TYPE(SILBlockStorage, Type)
142142
ARTIFICIAL_TYPE(SILBox, Type)
143143
ARTIFICIAL_TYPE(SILToken, Type)
144144
ABSTRACT_SUGARED_TYPE(SyntaxSugar, Type)
145-
SUGARED_TYPE(ArraySlice, SyntaxSugarType)
146-
SUGARED_TYPE(Optional, SyntaxSugarType)
147-
SUGARED_TYPE(ImplicitlyUnwrappedOptional, SyntaxSugarType)
148-
TYPE_RANGE(SyntaxSugar, ArraySlice, ImplicitlyUnwrappedOptional)
149-
SUGARED_TYPE(Dictionary, Type)
145+
ABSTRACT_SUGARED_TYPE(UnarySyntaxSugar, SyntaxSugarType)
146+
SUGARED_TYPE(ArraySlice, UnarySyntaxSugarType)
147+
SUGARED_TYPE(Optional, UnarySyntaxSugarType)
148+
SUGARED_TYPE(ImplicitlyUnwrappedOptional, UnarySyntaxSugarType)
149+
TYPE_RANGE(UnarySyntaxSugar, ArraySlice, ImplicitlyUnwrappedOptional)
150+
SUGARED_TYPE(Dictionary, SyntaxSugarType)
151+
TYPE_RANGE(SyntaxSugar, ArraySlice, Dictionary)
150152
TYPE(ProtocolComposition, Type)
151153
TYPE(LValue, Type)
152154
TYPE(InOut, Type)

include/swift/AST/Types.h

Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3943,40 +3943,69 @@ class SILTokenType final : public TypeBase {
39433943
};
39443944
DEFINE_EMPTY_CAN_TYPE_WRAPPER(SILTokenType, Type)
39453945

3946-
/// A type with a special syntax that is always sugar for a library type.
3946+
/// A type with a special syntax that is always sugar for a library type. The
3947+
/// library type may have multiple base types. For unary syntax sugar, see
3948+
/// UnarySyntaxSugarType.
39473949
///
3948-
/// The prime examples are arrays ([T] -> Array<T>) and
3949-
/// optionals (T? -> Optional<T>).
3950+
/// The prime examples are:
3951+
/// Arrays: [T] -> Array<T>
3952+
/// Optionals: T? -> Optional<T>
3953+
/// Dictionaries: [K : V] -> Dictionary<K, V>
39503954
class SyntaxSugarType : public TypeBase {
3951-
Type Base;
39523955
llvm::PointerUnion<Type, const ASTContext *> ImplOrContext;
39533956

3957+
Type getImplementationTypeSlow();
3958+
39543959
protected:
39553960
// Syntax sugar types are never canonical.
3956-
SyntaxSugarType(TypeKind K, const ASTContext &ctx, Type base,
3957-
RecursiveTypeProperties properties)
3958-
: TypeBase(K, nullptr, properties), Base(base), ImplOrContext(&ctx) {}
3961+
SyntaxSugarType(TypeKind K, const ASTContext &ctx,
3962+
RecursiveTypeProperties properties)
3963+
: TypeBase(K, nullptr, properties), ImplOrContext(&ctx) {}
39593964

39603965
public:
3961-
Type getBaseType() const {
3962-
return Base;
3963-
}
3964-
39653966
TypeBase *getSinglyDesugaredType();
39663967

3967-
Type getImplementationType();
3968+
Type getImplementationType() {
3969+
if (ImplOrContext.is<Type>())
3970+
return ImplOrContext.get<Type>();
3971+
return getImplementationTypeSlow();
3972+
}
39683973

39693974
static bool classof(const TypeBase *T) {
39703975
return T->getKind() >= TypeKind::First_SyntaxSugarType &&
39713976
T->getKind() <= TypeKind::Last_SyntaxSugarType;
39723977
}
39733978
};
3979+
3980+
/// A type with a special syntax that is always sugar for a library type that
3981+
/// wraps a single other type.
3982+
///
3983+
/// The prime examples are arrays ([T] -> Array<T>) and
3984+
/// optionals (T? -> Optional<T>).
3985+
class UnarySyntaxSugarType : public SyntaxSugarType {
3986+
Type Base;
3987+
3988+
protected:
3989+
UnarySyntaxSugarType(TypeKind K, const ASTContext &ctx, Type base,
3990+
RecursiveTypeProperties properties)
3991+
: SyntaxSugarType(K, ctx, properties), Base(base) {}
3992+
3993+
public:
3994+
Type getBaseType() const {
3995+
return Base;
3996+
}
3997+
3998+
static bool classof(const TypeBase *T) {
3999+
return T->getKind() >= TypeKind::First_UnarySyntaxSugarType &&
4000+
T->getKind() <= TypeKind::Last_UnarySyntaxSugarType;
4001+
}
4002+
};
39744003

39754004
/// The type [T], which is always sugar for a library type.
3976-
class ArraySliceType : public SyntaxSugarType {
4005+
class ArraySliceType : public UnarySyntaxSugarType {
39774006
ArraySliceType(const ASTContext &ctx, Type base,
39784007
RecursiveTypeProperties properties)
3979-
: SyntaxSugarType(TypeKind::ArraySlice, ctx, base, properties) {}
4008+
: UnarySyntaxSugarType(TypeKind::ArraySlice, ctx, base, properties) {}
39804009

39814010
public:
39824011
/// Return a uniqued array slice type with the specified base type.
@@ -3988,10 +4017,10 @@ class ArraySliceType : public SyntaxSugarType {
39884017
};
39894018

39904019
/// The type T?, which is always sugar for a library type.
3991-
class OptionalType : public SyntaxSugarType {
4020+
class OptionalType : public UnarySyntaxSugarType {
39924021
OptionalType(const ASTContext &ctx,Type base,
39934022
RecursiveTypeProperties properties)
3994-
: SyntaxSugarType(TypeKind::Optional, ctx, base, properties) {}
4023+
: UnarySyntaxSugarType(TypeKind::Optional, ctx, base, properties) {}
39954024

39964025
public:
39974026
/// Return a uniqued optional type with the specified base type.
@@ -4014,10 +4043,11 @@ class OptionalType : public SyntaxSugarType {
40144043
};
40154044

40164045
/// The type T!, which is always sugar for a library type.
4017-
class ImplicitlyUnwrappedOptionalType : public SyntaxSugarType {
4046+
class ImplicitlyUnwrappedOptionalType : public UnarySyntaxSugarType {
40184047
ImplicitlyUnwrappedOptionalType(const ASTContext &ctx, Type base,
40194048
RecursiveTypeProperties properties)
4020-
: SyntaxSugarType(TypeKind::ImplicitlyUnwrappedOptional, ctx, base, properties) {}
4049+
: UnarySyntaxSugarType(TypeKind::ImplicitlyUnwrappedOptional, ctx, base,
4050+
properties) {}
40214051

40224052
public:
40234053
/// Return a uniqued optional type with the specified base type.
@@ -4035,17 +4065,16 @@ class ImplicitlyUnwrappedOptionalType : public SyntaxSugarType {
40354065
/// \code
40364066
/// var dict: [String : Int] = ["hello" : 0, "world" : 1]
40374067
/// \endcode
4038-
class DictionaryType : public TypeBase {
4068+
class DictionaryType : public SyntaxSugarType {
40394069
Type Key;
40404070
Type Value;
4041-
llvm::PointerUnion<Type, const ASTContext *> ImplOrContext;
40424071

40434072
protected:
40444073
// Syntax sugar types are never canonical.
40454074
DictionaryType(const ASTContext &ctx, Type key, Type value,
40464075
RecursiveTypeProperties properties)
4047-
: TypeBase(TypeKind::Dictionary, nullptr, properties),
4048-
Key(key), Value(value), ImplOrContext(&ctx) {}
4076+
: SyntaxSugarType(TypeKind::Dictionary, ctx, properties),
4077+
Key(key), Value(value) {}
40494078

40504079
public:
40514080
/// Return a uniqued dictionary type with the specified key and value types.
@@ -4054,10 +4083,6 @@ class DictionaryType : public TypeBase {
40544083
Type getKeyType() const { return Key; }
40554084
Type getValueType() const { return Value; }
40564085

4057-
TypeBase *getSinglyDesugaredType();
4058-
4059-
Type getImplementationType();
4060-
40614086
static bool classof(const TypeBase *T) {
40624087
return T->getKind() == TypeKind::Dictionary;
40634088
}

lib/AST/ASTMangler.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -734,9 +734,8 @@ void ASTMangler::appendType(Type type) {
734734
return appendSugaredType<ParenType>(type);
735735
case TypeKind::ArraySlice: /* fallthrough */
736736
case TypeKind::Optional:
737-
return appendSugaredType<SyntaxSugarType>(type);
738737
case TypeKind::Dictionary:
739-
return appendSugaredType<DictionaryType>(type);
738+
return appendSugaredType<SyntaxSugarType>(type);
740739

741740
case TypeKind::ImplicitlyUnwrappedOptional: {
742741
assert(DWARFMangling && "sugared types are only legal for the debugger");

lib/AST/ASTPrinter.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3381,8 +3381,6 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
33813381

33823382
if (auto sugarType = dyn_cast<SyntaxSugarType>(T.getPointer()))
33833383
T = sugarType->getImplementationType();
3384-
else if (auto dictType = dyn_cast<DictionaryType>(T.getPointer()))
3385-
T = dictType->getImplementationType();
33863384

33873385
TypePrinter(Printer, innerOptions).visit(T);
33883386
}

lib/AST/Type.cpp

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,47 +1319,46 @@ TypeBase *SyntaxSugarType::getSinglyDesugaredType() {
13191319
return getImplementationType().getPointer();
13201320
}
13211321

1322-
Type SyntaxSugarType::getImplementationType() {
1323-
if (ImplOrContext.is<Type>())
1324-
return ImplOrContext.get<Type>();
1325-
1322+
Type SyntaxSugarType::getImplementationTypeSlow() {
13261323
// Find the generic type that implements this syntactic sugar type.
13271324
auto &ctx = *ImplOrContext.get<const ASTContext *>();
13281325
NominalTypeDecl *implDecl;
13291326

1330-
if (isa<ArraySliceType>(this)) {
1327+
// XXX -- If the Decl and Type class hierarchies agreed on spelling, then
1328+
// we could handle the entire switch statement via macros.
1329+
switch (getKind()) {
1330+
#define TYPE(Id, Parent) \
1331+
case TypeKind::Id: llvm_unreachable("non-sugared type?");
1332+
#define SUGARED_TYPE(Id, Parent)
1333+
#include "swift/AST/TypeNodes.def"
1334+
case TypeKind::NameAlias:
1335+
case TypeKind::Paren:
1336+
llvm_unreachable("typealiases and parens are sugar, but not syntax sugar");
1337+
case TypeKind::ArraySlice:
13311338
implDecl = ctx.getArrayDecl();
1332-
assert(implDecl && "Array type has not been set yet");
1333-
} else if (isa<OptionalType>(this)) {
1339+
break;
1340+
case TypeKind::Optional:
13341341
implDecl = ctx.getOptionalDecl();
1335-
assert(implDecl && "Optional type has not been set yet");
1336-
} else if (isa<ImplicitlyUnwrappedOptionalType>(this)) {
1342+
break;
1343+
case TypeKind::ImplicitlyUnwrappedOptional:
13371344
implDecl = ctx.getImplicitlyUnwrappedOptionalDecl();
1338-
assert(implDecl && "Optional type has not been set yet");
1339-
} else {
1340-
llvm_unreachable("Unhandled syntax sugar type");
1345+
break;
1346+
case TypeKind::Dictionary:
1347+
implDecl = ctx.getDictionaryDecl();
1348+
break;
13411349
}
1350+
assert(implDecl && "Type has not been set yet");
13421351

1343-
// Record the implementation type.
1344-
ImplOrContext = BoundGenericType::get(implDecl, Type(), Base);
1345-
return ImplOrContext.get<Type>();
1346-
}
1347-
1348-
TypeBase *DictionaryType::getSinglyDesugaredType() {
1349-
return getImplementationType().getPointer();
1350-
}
1351-
1352-
Type DictionaryType::getImplementationType() {
1353-
if (ImplOrContext.is<Type>())
1354-
return ImplOrContext.get<Type>();
1355-
1356-
// Find the generic type that implements this syntactic sugar type.
1357-
auto &ctx = *ImplOrContext.get<const ASTContext *>();
1358-
NominalTypeDecl *implDecl = ctx.getDictionaryDecl();
1359-
assert(implDecl && "Dictionary type has not been set yet");
1352+
if (auto Ty = dyn_cast<UnarySyntaxSugarType>(this)) {
1353+
ImplOrContext = BoundGenericType::get(implDecl, Type(), Ty->getBaseType());
1354+
} else if (auto Ty = dyn_cast<DictionaryType>(this)) {
1355+
ImplOrContext = BoundGenericType::get(implDecl, Type(),
1356+
{ Ty->getKeyType(), Ty->getValueType() });
1357+
} else {
1358+
llvm_unreachable("Not UnarySyntaxSugarType or DictionaryType?");
1359+
}
13601360

13611361
// Record the implementation type.
1362-
ImplOrContext = BoundGenericType::get(implDecl, Type(), { Key, Value });
13631362
return ImplOrContext.get<Type>();
13641363
}
13651364

lib/AST/TypeWalker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ class Traversal : public TypeVisitor<Traversal, bool>
119119
return false;
120120
}
121121

122-
bool visitSyntaxSugarType(SyntaxSugarType *ty) {
122+
bool visitUnarySyntaxSugarType(UnarySyntaxSugarType *ty) {
123123
return doIt(ty->getBaseType());
124124
}
125125

lib/IRGen/IRGenDebugInfo.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,6 +1298,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
12981298
}
12991299

13001300
// SyntaxSugarType derivations.
1301+
case TypeKind::Dictionary:
13011302
case TypeKind::ArraySlice:
13021303
case TypeKind::Optional:
13031304
case TypeKind::ImplicitlyUnwrappedOptional: {
@@ -1306,12 +1307,6 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
13061307
return getOrCreateDesugaredType(CanTy, DbgTy);
13071308
}
13081309

1309-
case TypeKind::Dictionary: {
1310-
auto *DictionaryTy = cast<DictionaryType>(BaseTy);
1311-
auto *CanTy = DictionaryTy->getDesugaredType();
1312-
return getOrCreateDesugaredType(CanTy, DbgTy);
1313-
}
1314-
13151310
case TypeKind::GenericTypeParam: {
13161311
auto *ParamTy = cast<GenericTypeParamType>(BaseTy);
13171312
// FIXME: Provide a more meaningful debug type.

lib/PrintAsObjC/PrintAsObjC.cpp

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1824,11 +1824,6 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
18241824
visitPart(SST->getSinglyDesugaredType(), optionalKind);
18251825
}
18261826

1827-
void visitDictionaryType(DictionaryType *DT,
1828-
Optional<OptionalTypeKind> optionalKind) {
1829-
visitPart(DT->getSinglyDesugaredType(), optionalKind);
1830-
}
1831-
18321827
void visitDynamicSelfType(DynamicSelfType *DST,
18331828
Optional<OptionalTypeKind> optionalKind) {
18341829
printNullability(optionalKind, NullabilityPrintKind::ContextSensitive);
@@ -1961,10 +1956,6 @@ class ReferencedTypeFinder : public TypeVisitor<ReferencedTypeFinder> {
19611956
visit(sugar->getSinglyDesugaredType());
19621957
}
19631958

1964-
void visitDictionaryType(DictionaryType *DT) {
1965-
visit(DT->getSinglyDesugaredType());
1966-
}
1967-
19681959
void visitProtocolCompositionType(ProtocolCompositionType *composition) {
19691960
auto layout = composition->getExistentialLayout();
19701961
if (layout.superclass)

0 commit comments

Comments
 (0)