Skip to content

Commit 1ebc8e9

Browse files
authored
Merge pull request #13691 from davezarzycki/nfc_perf_getDesugaredType2
[AST] Perf: Improve getDesugaredType() efficiency
2 parents 0632d87 + 77a29c9 commit 1ebc8e9

File tree

5 files changed

+110
-105
lines changed

5 files changed

+110
-105
lines changed

include/swift/AST/TypeNodes.def

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,6 @@ ABSTRACT_TYPE(Builtin, Type)
9999
BUILTIN_TYPE(BuiltinUnsafeValueBuffer, BuiltinType)
100100
BUILTIN_TYPE(BuiltinVector, BuiltinType)
101101
TYPE_RANGE(Builtin, BuiltinInteger, BuiltinVector)
102-
SUGARED_TYPE(NameAlias, Type)
103-
SUGARED_TYPE(Paren, Type)
104102
TYPE(Tuple, Type)
105103
ABSTRACT_TYPE(ReferenceStorage, Type)
106104
ARTIFICIAL_TYPE(UnownedStorage, ReferenceStorageType)
@@ -141,19 +139,23 @@ ARTIFICIAL_TYPE(SILFunction, Type)
141139
ARTIFICIAL_TYPE(SILBlockStorage, Type)
142140
ARTIFICIAL_TYPE(SILBox, Type)
143141
ARTIFICIAL_TYPE(SILToken, Type)
144-
ABSTRACT_SUGARED_TYPE(SyntaxSugar, 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)
152142
TYPE(ProtocolComposition, Type)
153143
TYPE(LValue, Type)
154144
TYPE(InOut, Type)
155145
UNCHECKED_TYPE(TypeVariable, Type)
156-
LAST_TYPE(TypeVariable)
146+
ABSTRACT_SUGARED_TYPE(Sugar, Type)
147+
SUGARED_TYPE(Paren, SugarType)
148+
SUGARED_TYPE(NameAlias, SugarType)
149+
ABSTRACT_SUGARED_TYPE(SyntaxSugar, SugarType)
150+
ABSTRACT_SUGARED_TYPE(UnarySyntaxSugar, SyntaxSugarType)
151+
SUGARED_TYPE(ArraySlice, UnarySyntaxSugarType)
152+
SUGARED_TYPE(Optional, UnarySyntaxSugarType)
153+
SUGARED_TYPE(ImplicitlyUnwrappedOptional, UnarySyntaxSugarType)
154+
TYPE_RANGE(UnarySyntaxSugar, ArraySlice, ImplicitlyUnwrappedOptional)
155+
SUGARED_TYPE(Dictionary, SyntaxSugarType)
156+
TYPE_RANGE(SyntaxSugar, ArraySlice, Dictionary)
157+
TYPE_RANGE(Sugar, Paren, Dictionary)
158+
LAST_TYPE(Dictionary) // Sugared types are last to make isa<SugarType>() fast.
157159

158160
#undef TYPE_RANGE
159161
#undef ABSTRACT_SUGARED_TYPE

include/swift/AST/Types.h

Lines changed: 68 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,12 @@ class alignas(1 << TypeAlignInBits) TypeBase {
286286
HasOriginalType : 1
287287
);
288288

289+
SWIFT_INLINE_BITFIELD(SugarType, TypeBase, 1,
290+
HasCachedType : 1
291+
);
292+
289293
enum { NumFlagBits = 5 };
290-
SWIFT_INLINE_BITFIELD(ParenType, TypeBase, NumFlagBits,
294+
SWIFT_INLINE_BITFIELD(ParenType, SugarType, NumFlagBits,
291295
/// Whether there is an original type.
292296
Flags : NumFlagBits
293297
);
@@ -1461,13 +1465,62 @@ class BuiltinFloatType : public BuiltinType {
14611465
};
14621466
DEFINE_EMPTY_CAN_TYPE_WRAPPER(BuiltinFloatType, BuiltinType)
14631467

1468+
/// An abstract type for all sugared types to make getDesugaredType() fast by
1469+
/// sharing field offsets and logic for the fast path.
1470+
class SugarType : public TypeBase {
1471+
// The state of this union is known via Bits.SugarType.HasCachedType so that
1472+
// we can avoid masking the pointer on the fast path.
1473+
union {
1474+
TypeBase *UnderlyingType;
1475+
const ASTContext *Context;
1476+
};
1477+
1478+
protected:
1479+
// Sugar types are never canonical.
1480+
SugarType(TypeKind K, const ASTContext *ctx,
1481+
RecursiveTypeProperties properties)
1482+
: TypeBase(K, nullptr, properties), Context(ctx) {
1483+
Bits.SugarType.HasCachedType = false;
1484+
}
1485+
1486+
// Sugar types are never canonical.
1487+
SugarType(TypeKind K, Type type, RecursiveTypeProperties properties)
1488+
: TypeBase(K, nullptr, properties), UnderlyingType(type.getPointer()) {
1489+
Bits.SugarType.HasCachedType = true;
1490+
}
1491+
1492+
void setUnderlyingType(Type type) {
1493+
assert(!Bits.SugarType.HasCachedType && "Cached type already set");
1494+
Bits.SugarType.HasCachedType = true;
1495+
UnderlyingType = type.getPointer();
1496+
}
1497+
1498+
public:
1499+
/// Remove one level of top-level sugar from this type.
1500+
Type getSinglyDesugaredTypeSlow();
1501+
TypeBase *getSinglyDesugaredType() const {
1502+
if (LLVM_LIKELY(Bits.SugarType.HasCachedType))
1503+
return UnderlyingType;
1504+
auto Ty = const_cast<SugarType*>(this);
1505+
return Ty->getSinglyDesugaredTypeSlow().getPointer();
1506+
}
1507+
1508+
static bool classof(const TypeBase *T) {
1509+
if (TypeKind::Last_Type == TypeKind::Last_SugarType)
1510+
return T->getKind() >= TypeKind::First_SugarType;
1511+
return T->getKind() >= TypeKind::First_SugarType &&
1512+
T->getKind() <= TypeKind::Last_SugarType;
1513+
}
1514+
};
1515+
14641516
/// NameAliasType - An alias type is a name for another type, just like a
14651517
/// typedef in C.
1466-
class NameAliasType : public TypeBase {
1518+
class NameAliasType : public SugarType {
14671519
friend class TypeAliasDecl;
14681520
// NameAliasType are never canonical.
14691521
NameAliasType(TypeAliasDecl *d)
1470-
: TypeBase(TypeKind::NameAlias, nullptr, RecursiveTypeProperties()),
1522+
: SugarType(TypeKind::NameAlias, (ASTContext*)nullptr,
1523+
RecursiveTypeProperties()),
14711524
TheDecl(d) {}
14721525
TypeAliasDecl *const TheDecl;
14731526

@@ -1476,9 +1529,6 @@ class NameAliasType : public TypeBase {
14761529

14771530
using TypeBase::setRecursiveProperties;
14781531

1479-
/// Remove one level of top-level sugar from this type.
1480-
TypeBase *getSinglyDesugaredType();
1481-
14821532
// Implement isa/cast/dyncast/etc.
14831533
static bool classof(const TypeBase *T) {
14841534
return T->getKind() == TypeKind::NameAlias;
@@ -1561,23 +1611,18 @@ class ParameterTypeFlags {
15611611
};
15621612

15631613
/// ParenType - A paren type is a type that's been written in parentheses.
1564-
class ParenType : public TypeBase {
1565-
Type UnderlyingType;
1566-
1614+
class ParenType : public SugarType {
15671615
friend class ASTContext;
15681616

15691617
ParenType(Type UnderlyingType, RecursiveTypeProperties properties,
15701618
ParameterTypeFlags flags);
15711619

15721620
public:
1573-
Type getUnderlyingType() const { return UnderlyingType; }
1621+
Type getUnderlyingType() const { return getSinglyDesugaredType(); }
15741622

15751623
static ParenType *get(const ASTContext &C, Type underlying,
15761624
ParameterTypeFlags flags = {});
15771625

1578-
/// Remove one level of top-level sugar from this type.
1579-
TypeBase *getSinglyDesugaredType();
1580-
15811626
/// Get the parameter flags
15821627
ParameterTypeFlags getParameterFlags() const {
15831628
return ParameterTypeFlags::fromRaw(Bits.ParenType.Flags);
@@ -3951,25 +3996,15 @@ DEFINE_EMPTY_CAN_TYPE_WRAPPER(SILTokenType, Type)
39513996
/// Arrays: [T] -> Array<T>
39523997
/// Optionals: T? -> Optional<T>
39533998
/// Dictionaries: [K : V] -> Dictionary<K, V>
3954-
class SyntaxSugarType : public TypeBase {
3955-
llvm::PointerUnion<Type, const ASTContext *> ImplOrContext;
3956-
3957-
Type getImplementationTypeSlow();
3958-
3999+
class SyntaxSugarType : public SugarType {
39594000
protected:
39604001
// Syntax sugar types are never canonical.
39614002
SyntaxSugarType(TypeKind K, const ASTContext &ctx,
3962-
RecursiveTypeProperties properties)
3963-
: TypeBase(K, nullptr, properties), ImplOrContext(&ctx) {}
4003+
RecursiveTypeProperties properties)
4004+
: SugarType(K, &ctx, properties) {}
39644005

39654006
public:
3966-
TypeBase *getSinglyDesugaredType();
3967-
3968-
Type getImplementationType() {
3969-
if (ImplOrContext.is<Type>())
3970-
return ImplOrContext.get<Type>();
3971-
return getImplementationTypeSlow();
3972-
}
4007+
Type getImplementationType() const { return getSinglyDesugaredType(); }
39734008

39744009
static bool classof(const TypeBase *T) {
39754010
return T->getKind() >= TypeKind::First_SyntaxSugarType &&
@@ -5169,6 +5204,12 @@ constexpr bool TypeBase::isSugaredType<id##Type>() { \
51695204
inline GenericParamKey::GenericParamKey(const GenericTypeParamType *p)
51705205
: Depth(p->getDepth()), Index(p->getIndex()) { }
51715206

5207+
inline TypeBase *TypeBase::getDesugaredType() {
5208+
if (!isa<SugarType>(this))
5209+
return this;
5210+
return cast<SugarType>(this)->getSinglyDesugaredType()->getDesugaredType();
5211+
}
5212+
51725213
} // end namespace swift
51735214

51745215
namespace llvm {

include/swift/Basic/InlineBitfield.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,22 +38,27 @@ namespace swift {
3838
class T##Bitfield { \
3939
friend class T; \
4040
uint64_t __VA_ARGS__; \
41+
uint64_t : 64 - (C); /* Better code gen */ \
4142
} T; \
4243
LLVM_PACKED_END \
4344
enum { Num##T##Bits = (C) }; \
4445
static_assert(sizeof(T##Bitfield) <= 8, "Bitfield overflow")
4546

4647
/// Define an bitfield for type 'T' with parent class 'U' and 'C' bits used.
47-
#define SWIFT_INLINE_BITFIELD(T, U, C, ...) \
48+
#define SWIFT_INLINE_BITFIELD_TEMPLATE(T, U, C, HC, ...) \
4849
LLVM_PACKED_START \
4950
class T##Bitfield { \
5051
friend class T; \
5152
uint64_t : Num##U##Bits, __VA_ARGS__; \
53+
uint64_t : 64 - (Num##U##Bits + (HC) + (C)); /* Better code gen */ \
5254
} T; \
5355
LLVM_PACKED_END \
5456
enum { Num##T##Bits = Num##U##Bits + (C) }; \
5557
static_assert(sizeof(T##Bitfield) <= 8, "Bitfield overflow")
5658

59+
#define SWIFT_INLINE_BITFIELD(T, U, C, ...) \
60+
SWIFT_INLINE_BITFIELD_TEMPLATE(T, U, C, 0, __VA_ARGS__)
61+
5762
/// Define a full bitfield for type 'T' that uses all of the remaining bits in
5863
/// the inline bitfield.
5964
///

include/swift/SIL/SILNode.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ class alignas(8) SILNode {
142142
);
143143

144144
#define IBWTO_BITFIELD(T, U, C, ...) \
145-
SWIFT_INLINE_BITFIELD(T, U, (C), __VA_ARGS__, : 32)
145+
SWIFT_INLINE_BITFIELD_TEMPLATE(T, U, (C), 32, __VA_ARGS__)
146146
#define IBWTO_BITFIELD_EMPTY(T, U) \
147147
SWIFT_INLINE_BITFIELD_EMPTY(T, U)
148148

lib/AST/Type.cpp

Lines changed: 22 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,56 +1249,16 @@ TypeBase *TypeBase::reconstituteSugar(bool Recursive) {
12491249
return Func(this).getPointer();
12501250
}
12511251

1252-
TypeBase *TypeBase::getDesugaredType() {
1253-
switch (getKind()) {
1254-
#define ALWAYS_CANONICAL_TYPE(id, parent) case TypeKind::id:
1255-
#define UNCHECKED_TYPE(id, parent) case TypeKind::id:
1256-
#define TYPE(id, parent)
1257-
#include "swift/AST/TypeNodes.def"
1258-
case TypeKind::Error:
1259-
case TypeKind::Tuple:
1260-
case TypeKind::Function:
1261-
case TypeKind::GenericFunction:
1262-
case TypeKind::SILBlockStorage:
1263-
case TypeKind::SILBox:
1264-
case TypeKind::SILFunction:
1265-
case TypeKind::SILToken:
1266-
case TypeKind::LValue:
1267-
case TypeKind::InOut:
1268-
case TypeKind::ProtocolComposition:
1269-
case TypeKind::ExistentialMetatype:
1270-
case TypeKind::Metatype:
1271-
case TypeKind::BoundGenericClass:
1272-
case TypeKind::BoundGenericEnum:
1273-
case TypeKind::BoundGenericStruct:
1274-
case TypeKind::Enum:
1275-
case TypeKind::Struct:
1276-
case TypeKind::Class:
1277-
case TypeKind::Protocol:
1278-
case TypeKind::GenericTypeParam:
1279-
case TypeKind::DependentMember:
1280-
case TypeKind::UnownedStorage:
1281-
case TypeKind::UnmanagedStorage:
1282-
case TypeKind::WeakStorage:
1283-
case TypeKind::DynamicSelf:
1284-
// None of these types have sugar at the outer level.
1285-
return this;
1286-
#define SUGARED_TYPE(ID, PARENT) \
1287-
case TypeKind::ID: \
1288-
return cast<ID##Type>(this)->getSinglyDesugaredType()->getDesugaredType();
1289-
#define TYPE(id, parent)
1252+
#define TYPE(Id, Parent)
1253+
#define SUGARED_TYPE(Id, Parent) \
1254+
static_assert(std::is_base_of<SugarType, Id##Type>::value, "Sugar mismatch");
12901255
#include "swift/AST/TypeNodes.def"
1291-
}
1292-
1293-
llvm_unreachable("Unknown type kind");
1294-
}
12951256

12961257
ParenType::ParenType(Type baseType, RecursiveTypeProperties properties,
12971258
ParameterTypeFlags flags)
1298-
: TypeBase(TypeKind::Paren, nullptr, properties),
1299-
UnderlyingType(flags.isInOut()
1300-
? InOutType::get(baseType)
1301-
: baseType) {
1259+
: SugarType(TypeKind::Paren,
1260+
flags.isInOut() ? InOutType::get(baseType) : baseType,
1261+
properties) {
13021262
Bits.ParenType.Flags = flags.toRaw();
13031263
if (flags.isInOut())
13041264
assert(!baseType->is<InOutType>() && "caller did not pass a base type");
@@ -1307,21 +1267,9 @@ ParenType::ParenType(Type baseType, RecursiveTypeProperties properties,
13071267
}
13081268

13091269

1310-
TypeBase *ParenType::getSinglyDesugaredType() {
1311-
return getUnderlyingType().getPointer();
1312-
}
1313-
1314-
TypeBase *NameAliasType::getSinglyDesugaredType() {
1315-
return getDecl()->getUnderlyingTypeLoc().getType().getPointer();
1316-
}
1317-
1318-
TypeBase *SyntaxSugarType::getSinglyDesugaredType() {
1319-
return getImplementationType().getPointer();
1320-
}
1321-
1322-
Type SyntaxSugarType::getImplementationTypeSlow() {
1270+
Type SugarType::getSinglyDesugaredTypeSlow() {
13231271
// Find the generic type that implements this syntactic sugar type.
1324-
auto &ctx = *ImplOrContext.get<const ASTContext *>();
1272+
auto &ctx = *Context;
13251273
NominalTypeDecl *implDecl;
13261274

13271275
// XXX -- If the Decl and Type class hierarchies agreed on spelling, then
@@ -1331,9 +1279,17 @@ Type SyntaxSugarType::getImplementationTypeSlow() {
13311279
case TypeKind::Id: llvm_unreachable("non-sugared type?");
13321280
#define SUGARED_TYPE(Id, Parent)
13331281
#include "swift/AST/TypeNodes.def"
1334-
case TypeKind::NameAlias:
13351282
case TypeKind::Paren:
1336-
llvm_unreachable("typealiases and parens are sugar, but not syntax sugar");
1283+
llvm_unreachable("parenthesis are sugar, but not syntax sugar");
1284+
case TypeKind::NameAlias: {
1285+
auto Ty = cast<NameAliasType>(this);
1286+
auto UTy = Ty->getDecl()->getUnderlyingTypeLoc().getType().getPointer();
1287+
if (isa<NominalOrBoundGenericNominalType>(UTy)) {
1288+
Bits.SugarType.HasCachedType = true;
1289+
UnderlyingType = UTy;
1290+
}
1291+
return UTy;
1292+
}
13371293
case TypeKind::ArraySlice:
13381294
implDecl = ctx.getArrayDecl();
13391295
break;
@@ -1349,17 +1305,18 @@ Type SyntaxSugarType::getImplementationTypeSlow() {
13491305
}
13501306
assert(implDecl && "Type has not been set yet");
13511307

1308+
Bits.SugarType.HasCachedType = true;
13521309
if (auto Ty = dyn_cast<UnarySyntaxSugarType>(this)) {
1353-
ImplOrContext = BoundGenericType::get(implDecl, Type(), Ty->getBaseType());
1310+
UnderlyingType = BoundGenericType::get(implDecl, Type(), Ty->getBaseType());
13541311
} else if (auto Ty = dyn_cast<DictionaryType>(this)) {
1355-
ImplOrContext = BoundGenericType::get(implDecl, Type(),
1312+
UnderlyingType = BoundGenericType::get(implDecl, Type(),
13561313
{ Ty->getKeyType(), Ty->getValueType() });
13571314
} else {
13581315
llvm_unreachable("Not UnarySyntaxSugarType or DictionaryType?");
13591316
}
13601317

13611318
// Record the implementation type.
1362-
return ImplOrContext.get<Type>();
1319+
return UnderlyingType;
13631320
}
13641321

13651322
unsigned GenericTypeParamType::getDepth() const {

0 commit comments

Comments
 (0)