Skip to content

Commit 2882e16

Browse files
committed
[AST] Perf: Make generic decl types share field offsets and fast casting logic
1 parent b11d544 commit 2882e16

File tree

4 files changed

+109
-116
lines changed

4 files changed

+109
-116
lines changed

include/swift/AST/TypeNodes.def

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,22 @@ ABSTRACT_TYPE(ReferenceStorage, Type)
107107
ARTIFICIAL_TYPE(UnmanagedStorage, ReferenceStorageType)
108108
ARTIFICIAL_TYPE(WeakStorage, ReferenceStorageType)
109109
TYPE_RANGE(ReferenceStorage, UnownedStorage, WeakStorage)
110-
ABSTRACT_TYPE(Nominal, Type)
111-
TYPE(Enum, NominalType)
112-
TYPE(Struct, NominalType)
113-
TYPE(Class, NominalType)
114-
TYPE(Protocol, NominalType)
115-
TYPE_RANGE(Nominal, Enum, Protocol)
110+
ABSTRACT_TYPE(AnyGeneric, Type)
111+
ABSTRACT_TYPE(NominalOrBoundGenericNominal, Type)
112+
ABSTRACT_TYPE(Nominal, Type)
113+
TYPE(Enum, NominalType)
114+
TYPE(Struct, NominalType)
115+
TYPE(Class, NominalType)
116+
TYPE(Protocol, NominalType)
117+
TYPE_RANGE(Nominal, Enum, Protocol)
118+
ABSTRACT_TYPE(BoundGeneric, Type)
119+
TYPE(BoundGenericClass, BoundGenericType)
120+
TYPE(BoundGenericEnum, BoundGenericType)
121+
TYPE(BoundGenericStruct, BoundGenericType)
122+
TYPE_RANGE(BoundGeneric, BoundGenericClass, BoundGenericStruct)
123+
TYPE_RANGE(NominalOrBoundGenericNominal, Enum, BoundGenericStruct)
124+
UNCHECKED_TYPE(UnboundGeneric, Type)
125+
TYPE_RANGE(AnyGeneric, Enum, UnboundGeneric)
116126
ABSTRACT_TYPE(AnyMetatype, Type)
117127
TYPE(Metatype, AnyMetatypeType)
118128
TYPE(ExistentialMetatype, AnyMetatypeType)
@@ -140,12 +150,6 @@ SUGARED_TYPE(Dictionary, Type)
140150
TYPE(ProtocolComposition, Type)
141151
TYPE(LValue, Type)
142152
TYPE(InOut, Type)
143-
UNCHECKED_TYPE(UnboundGeneric, Type)
144-
ABSTRACT_TYPE(BoundGeneric, Type)
145-
TYPE(BoundGenericClass, BoundGenericType)
146-
TYPE(BoundGenericEnum, BoundGenericType)
147-
TYPE(BoundGenericStruct, BoundGenericType)
148-
TYPE_RANGE(BoundGeneric, BoundGenericClass, BoundGenericStruct)
149153
UNCHECKED_TYPE(TypeVariable, Type)
150154
LAST_TYPE(TypeVariable)
151155

include/swift/AST/Types.h

Lines changed: 89 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,76 @@ class alignas(1 << TypeAlignInBits) TypeBase {
10251025
void *operator new(size_t Bytes, void *Mem) throw() { return Mem; }
10261026
};
10271027

1028+
/// AnyGenericType - This abstract class helps types ensure that fields
1029+
/// exist at the same offset in memory to improve code generation of the
1030+
/// compiler itself.
1031+
class AnyGenericType : public TypeBase {
1032+
friend class NominalOrBoundGenericNominalType;
1033+
1034+
/// TheDecl - This is the TypeDecl which declares the given type. It
1035+
/// specifies the name and other useful information about this type.
1036+
union {
1037+
GenericTypeDecl *GenDecl;
1038+
NominalTypeDecl *NomDecl;
1039+
};
1040+
1041+
/// \brief The type of the parent, in which this type is nested.
1042+
Type Parent;
1043+
1044+
template <typename... Args>
1045+
AnyGenericType(NominalTypeDecl *TheDecl, Type Parent, Args &&...args)
1046+
: TypeBase(std::forward<Args>(args)...), NomDecl(TheDecl), Parent(Parent) {}
1047+
1048+
protected:
1049+
template <typename... Args>
1050+
AnyGenericType(GenericTypeDecl *TheDecl, Type Parent, Args &&...args)
1051+
: TypeBase(std::forward<Args>(args)...), GenDecl(TheDecl), Parent(Parent) {}
1052+
1053+
public:
1054+
1055+
/// \brief Returns the declaration that declares this type.
1056+
GenericTypeDecl *getDecl() const { return GenDecl; }
1057+
1058+
/// \brief Returns the type of the parent of this type. This will
1059+
/// be null for top-level types or local types, and for non-generic types
1060+
/// will simply be the same as the declared type of the declaration context
1061+
/// of TheDecl. For types nested within generic types, however, this will
1062+
/// involve \c BoundGenericType nodes that provide context for the nested
1063+
/// type, e.g., the type Dictionary<String, Int>.ItemRange would be
1064+
/// represented as a NominalType with Dictionary<String, Int> as its parent
1065+
/// type.
1066+
Type getParent() const { return Parent; }
1067+
1068+
// Implement isa/cast/dyncast/etc.
1069+
static bool classof(const TypeBase *T) {
1070+
return T->getKind() >= TypeKind::First_AnyGenericType &&
1071+
T->getKind() <= TypeKind::Last_AnyGenericType;
1072+
}
1073+
};
1074+
BEGIN_CAN_TYPE_WRAPPER(AnyGenericType, Type)
1075+
PROXY_CAN_TYPE_SIMPLE_GETTER(getParent)
1076+
END_CAN_TYPE_WRAPPER(AnyGenericType, Type)
1077+
1078+
/// NominalOrBoundGenericNominal - This abstract class helps types ensure that
1079+
/// fields exist at the same offset in memory to improve code generation of the
1080+
/// compiler itself.
1081+
class NominalOrBoundGenericNominalType : public AnyGenericType {
1082+
public:
1083+
template <typename... Args>
1084+
NominalOrBoundGenericNominalType(Args &&...args)
1085+
: AnyGenericType(std::forward<Args>(args)...) {}
1086+
1087+
/// \brief Returns the declaration that declares this type.
1088+
NominalTypeDecl *getDecl() const { return NomDecl; }
1089+
1090+
// Implement isa/cast/dyncast/etc.
1091+
static bool classof(const TypeBase *T) {
1092+
return T->getKind() >= TypeKind::First_NominalOrBoundGenericNominalType &&
1093+
T->getKind() <= TypeKind::Last_NominalOrBoundGenericNominalType;
1094+
}
1095+
};
1096+
DEFINE_EMPTY_CAN_TYPE_WRAPPER(NominalOrBoundGenericNominalType, AnyGenericType)
1097+
10281098
/// ErrorType - This represents a type that was erroneously constructed. This
10291099
/// is produced when parsing types and when name binding type aliases, and is
10301100
/// installed in declaration that use these erroneous types. All uses of a
@@ -1679,37 +1749,19 @@ END_CAN_TYPE_WRAPPER(TupleType, Type)
16791749

16801750
/// UnboundGenericType - Represents a generic type where the type arguments have
16811751
/// not yet been resolved.
1682-
class UnboundGenericType : public TypeBase, public llvm::FoldingSetNode {
1683-
GenericTypeDecl *TheDecl;
1684-
1685-
/// \brief The type of the parent, in which this type is nested.
1686-
Type Parent;
1687-
1752+
class UnboundGenericType : public AnyGenericType,
1753+
public llvm::FoldingSetNode {
16881754
private:
16891755
UnboundGenericType(GenericTypeDecl *TheDecl, Type Parent, const ASTContext &C,
16901756
RecursiveTypeProperties properties)
1691-
: TypeBase(TypeKind::UnboundGeneric,
1692-
(!Parent || Parent->isCanonical())? &C : nullptr,
1693-
properties | RecursiveTypeProperties::HasUnboundGeneric),
1694-
TheDecl(TheDecl), Parent(Parent) { }
1757+
: AnyGenericType(TheDecl, Parent, TypeKind::UnboundGeneric,
1758+
(!Parent || Parent->isCanonical()) ? &C : nullptr,
1759+
properties | RecursiveTypeProperties::HasUnboundGeneric) {}
16951760

16961761
public:
16971762
static UnboundGenericType* get(GenericTypeDecl *TheDecl, Type Parent,
16981763
const ASTContext &C);
16991764

1700-
/// \brief Returns the declaration that declares this type.
1701-
GenericTypeDecl *getDecl() const { return TheDecl; }
1702-
1703-
/// \brief Returns the type of the parent of this type. This will
1704-
/// be null for top-level types or local types, and for non-generic types
1705-
/// will simply be the same as the declared type of the declaration context
1706-
/// of TheDecl. For types nested within generic types, however, this will
1707-
/// involve \c BoundGenericType nodes that provide context for the nested
1708-
/// type, e.g., the bound type Dictionary<String, Int>.Inner would be
1709-
/// represented as an UnboundGenericType with Dictionary<String, Int> as its
1710-
/// parent type.
1711-
Type getParent() const { return Parent; }
1712-
17131765
void Profile(llvm::FoldingSetNodeID &ID) {
17141766
Profile(ID, getDecl(), getParent());
17151767
}
@@ -1721,20 +1773,15 @@ class UnboundGenericType : public TypeBase, public llvm::FoldingSetNode {
17211773
return T->getKind() == TypeKind::UnboundGeneric;
17221774
}
17231775
};
1724-
BEGIN_CAN_TYPE_WRAPPER(UnboundGenericType, Type)
1725-
PROXY_CAN_TYPE_SIMPLE_GETTER(getParent)
1726-
END_CAN_TYPE_WRAPPER(UnboundGenericType, Type)
1776+
DEFINE_EMPTY_CAN_TYPE_WRAPPER(UnboundGenericType, AnyGenericType)
17271777

17281778
inline CanType getAsCanType(const Type &type) { return CanType(type); }
17291779
typedef ArrayRefView<Type,CanType,getAsCanType> CanTypeArrayRef;
17301780

17311781
/// BoundGenericType - An abstract class for applying a generic type to the
17321782
/// given type arguments.
1733-
class BoundGenericType : public TypeBase, public llvm::FoldingSetNode {
1734-
NominalTypeDecl *TheDecl;
1735-
1736-
/// \brief The type of the parent, in which this type is nested.
1737-
Type Parent;
1783+
class BoundGenericType : public NominalOrBoundGenericNominalType,
1784+
public llvm::FoldingSetNode {
17381785

17391786
/// Retrieve the intrusive pointer storage from the subtype
17401787
const Type *getTrailingObjectsPointer() const;
@@ -1752,26 +1799,13 @@ class BoundGenericType : public TypeBase, public llvm::FoldingSetNode {
17521799
static BoundGenericType* get(NominalTypeDecl *TheDecl, Type Parent,
17531800
ArrayRef<Type> GenericArgs);
17541801

1755-
/// \brief Returns the declaration that declares this type.
1756-
NominalTypeDecl *getDecl() const { return TheDecl; }
1757-
1758-
/// \brief Returns the type of the parent of this type. This will
1759-
/// be null for top-level types or local types, and for non-generic types
1760-
/// will simply be the same as the declared type of the declaration context
1761-
/// of TheDecl. For types nested within generic types, however, this will
1762-
/// involve \c BoundGenericType nodes that provide context for the nested
1763-
/// type, e.g., the bound type Dictionary<String, Int>.Inner<Int> would be
1764-
/// represented as a BoundGenericType with Dictionary<String, Int> as its
1765-
/// parent type.
1766-
Type getParent() const { return Parent; }
1767-
17681802
/// Retrieve the set of generic arguments provided at this level.
17691803
ArrayRef<Type> getGenericArgs() const {
17701804
return {getTrailingObjectsPointer(), Bits.BoundGenericType.GenericArgCount};
17711805
}
17721806

17731807
void Profile(llvm::FoldingSetNodeID &ID) {
1774-
Profile(ID, TheDecl, Parent, getGenericArgs());
1808+
Profile(ID, getDecl(), getParent(), getGenericArgs());
17751809
}
17761810
static void Profile(llvm::FoldingSetNodeID &ID, NominalTypeDecl *TheDecl,
17771811
Type Parent, ArrayRef<Type> GenericArgs);
@@ -1782,12 +1816,11 @@ class BoundGenericType : public TypeBase, public llvm::FoldingSetNode {
17821816
T->getKind() <= TypeKind::Last_BoundGenericType;
17831817
}
17841818
};
1785-
BEGIN_CAN_TYPE_WRAPPER(BoundGenericType, Type)
1786-
PROXY_CAN_TYPE_SIMPLE_GETTER(getParent)
1819+
BEGIN_CAN_TYPE_WRAPPER(BoundGenericType, NominalOrBoundGenericNominalType)
17871820
CanTypeArrayRef getGenericArgs() const {
17881821
return CanTypeArrayRef(getPointer()->getGenericArgs());
17891822
}
1790-
END_CAN_TYPE_WRAPPER(BoundGenericType, Type)
1823+
END_CAN_TYPE_WRAPPER(BoundGenericType, NominalOrBoundGenericNominalType)
17911824

17921825

17931826
/// BoundGenericClassType - A subclass of BoundGenericType for the case
@@ -1895,46 +1928,24 @@ DEFINE_EMPTY_CAN_TYPE_WRAPPER(BoundGenericStructType, BoundGenericType)
18951928
/// NominalType - Represents a type with a name that is significant, such that
18961929
/// the name distinguishes it from other structurally-similar types that have
18971930
/// different names. Nominal types are always canonical.
1898-
class NominalType : public TypeBase {
1899-
/// TheDecl - This is the TypeDecl which declares the given type. It
1900-
/// specifies the name and other useful information about this type.
1901-
NominalTypeDecl * const TheDecl;
1902-
1903-
/// \brief The type of the parent, in which this type is nested.
1904-
Type Parent;
1931+
class NominalType : public NominalOrBoundGenericNominalType {
19051932

19061933
protected:
19071934
NominalType(TypeKind K, const ASTContext *C, NominalTypeDecl *TheDecl,
19081935
Type Parent, RecursiveTypeProperties properties)
1909-
: TypeBase(K, (!Parent || Parent->isCanonical())? C : nullptr,
1910-
properties),
1911-
TheDecl(TheDecl), Parent(Parent) { }
1936+
: NominalOrBoundGenericNominalType(TheDecl, Parent, K,
1937+
(!Parent || Parent->isCanonical())? C : nullptr, properties) {}
19121938

19131939
public:
19141940
static NominalType *get(NominalTypeDecl *D, Type Parent, const ASTContext &C);
19151941

1916-
/// \brief Returns the declaration that declares this type.
1917-
NominalTypeDecl *getDecl() const { return TheDecl; }
1918-
1919-
/// \brief Returns the type of the parent of this type. This will
1920-
/// be null for top-level types or local types, and for non-generic types
1921-
/// will simply be the same as the declared type of the declaration context
1922-
/// of TheDecl. For types nested within generic types, however, this will
1923-
/// involve \c BoundGenericType nodes that provide context for the nested
1924-
/// type, e.g., the type Dictionary<String, Int>.ItemRange would be
1925-
/// represented as a NominalType with Dictionary<String, Int> as its parent
1926-
/// type.
1927-
Type getParent() const { return Parent; }
1928-
19291942
// Implement isa/cast/dyncast/etc.
19301943
static bool classof(const TypeBase *T) {
19311944
return T->getKind() >= TypeKind::First_NominalType &&
19321945
T->getKind() <= TypeKind::Last_NominalType;
19331946
}
19341947
};
1935-
BEGIN_CAN_TYPE_WRAPPER(NominalType, Type)
1936-
PROXY_CAN_TYPE_SIMPLE_GETTER(getParent)
1937-
END_CAN_TYPE_WRAPPER(NominalType, Type)
1948+
DEFINE_EMPTY_CAN_TYPE_WRAPPER(NominalType, NominalOrBoundGenericNominalType)
19381949

19391950
/// EnumType - This represents the type declared by an EnumDecl.
19401951
class EnumType : public NominalType, public llvm::FoldingSetNode {
@@ -4964,12 +4975,8 @@ inline NominalTypeDecl *TypeBase::getNominalOrBoundGenericNominal() {
49644975
}
49654976

49664977
inline NominalTypeDecl *CanType::getNominalOrBoundGenericNominal() const {
4967-
if (auto nomTy = dyn_cast<NominalType>(*this))
4968-
return nomTy->getDecl();
4969-
4970-
if (auto boundTy = dyn_cast<BoundGenericType>(*this))
4971-
return boundTy->getDecl();
4972-
4978+
if (auto Ty = dyn_cast<NominalOrBoundGenericNominalType>(*this))
4979+
return Ty->getDecl();
49734980
return nullptr;
49744981
}
49754982

@@ -4978,13 +4985,7 @@ inline NominalTypeDecl *TypeBase::getAnyNominal() {
49784985
}
49794986

49804987
inline Type TypeBase::getNominalParent() {
4981-
if (auto classType = getAs<NominalType>()) {
4982-
return classType->getParent();
4983-
} else if (auto unboundType = getAs<UnboundGenericType>()) {
4984-
return unboundType->getParent();
4985-
} else {
4986-
return castTo<BoundGenericType>()->getParent();
4987-
}
4988+
return castTo<AnyGenericType>()->getParent();
49884989
}
49894990

49904991
inline GenericTypeDecl *TypeBase::getAnyGeneric() {
@@ -5053,11 +5054,7 @@ inline CanType CanType::getWithoutSpecifierTypeImpl(CanType type) {
50535054
}
50545055

50555056
inline CanType CanType::getNominalParent() const {
5056-
if (auto classType = dyn_cast<NominalType>(*this)) {
5057-
return classType.getParent();
5058-
} else {
5059-
return cast<BoundGenericType>(*this).getParent();
5060-
}
5057+
return cast<NominalOrBoundGenericNominalType>(*this).getParent();
50615058
}
50625059

50635060
inline Type TupleTypeElt::getVarargBaseTy() const {

lib/AST/ASTContext.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3243,9 +3243,8 @@ BoundGenericType::BoundGenericType(TypeKind theKind,
32433243
ArrayRef<Type> genericArgs,
32443244
const ASTContext *context,
32453245
RecursiveTypeProperties properties)
3246-
: TypeBase(theKind, context, properties),
3247-
TheDecl(theDecl), Parent(parent)
3248-
{
3246+
: NominalOrBoundGenericNominalType(theDecl, parent, theKind, context,
3247+
properties) {
32493248
Bits.BoundGenericType.GenericArgCount = genericArgs.size();
32503249
// Subtypes are required to provide storage for the generic arguments
32513250
std::uninitialized_copy(genericArgs.begin(), genericArgs.end(),

lib/AST/Type.cpp

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,18 +108,11 @@ NominalTypeDecl *CanType::getAnyNominal() const {
108108
}
109109

110110
GenericTypeDecl *CanType::getAnyGeneric() const {
111-
if (auto nominalTy = dyn_cast<NominalType>(*this))
112-
return (GenericTypeDecl*)nominalTy->getDecl();
113-
114-
if (auto boundTy = dyn_cast<BoundGenericType>(*this))
115-
return (GenericTypeDecl*)boundTy->getDecl();
116-
117-
if (auto unboundTy = dyn_cast<UnboundGenericType>(*this))
118-
return unboundTy->getDecl();
111+
if (auto Ty = dyn_cast<AnyGenericType>(*this))
112+
return Ty->getDecl();
119113
return nullptr;
120114
}
121115

122-
123116
//===----------------------------------------------------------------------===//
124117
// Various Type Methods.
125118
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)