Skip to content

Commit 8876c9e

Browse files
committed
[GSB] NFC: Precompute or cache DependentMemberType when possible
Calling DependentMemberType::get() repeatedly pollutes the processor caches because the global hash table can be quite large. With this change, we either precompute DependentMemberTypes or cache them on demand. This change makes the release/no-assert build of Swift.swiftmodule 4.1% faster.
1 parent b76ac41 commit 8876c9e

File tree

2 files changed

+49
-15
lines changed

2 files changed

+49
-15
lines changed

include/swift/AST/GenericSignatureBuilder.h

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,11 @@ class GenericSignatureBuilder::RequirementSource final
935935
AssociatedTypeDecl,
936936
};
937937

938+
/// Cache DependentMemberType results instead of calling
939+
/// DependentMemberType::get(). The much smaller hash table is more
940+
/// processor cache efficient.
941+
mutable llvm::DenseMap<Type, Type> ReplacedSelfCache;
942+
938943
/// The kind of storage we have.
939944
const StorageKind storageKind;
940945

@@ -954,8 +959,9 @@ class GenericSignatureBuilder::RequirementSource final
954959
/// A protocol conformance used to satisfy the requirement.
955960
void *conformance;
956961

957-
/// An associated type to which a requirement is being applied.
958-
AssociatedTypeDecl *assocType;
962+
/// A precomputed dependent member of an associated type to which a
963+
/// requirement is being applied.
964+
DependentMemberType *dependentMember;
959965
} storage;
960966

961967
friend TrailingObjects;
@@ -1093,7 +1099,8 @@ class GenericSignatureBuilder::RequirementSource final
10931099
assert(isAcceptableStorageKind(kind, storageKind) &&
10941100
"RequirementSource kind/storageKind mismatch");
10951101

1096-
storage.assocType = assocType;
1102+
auto ty = assocType->getDeclaredInterfaceType();
1103+
storage.dependentMember = cast<DependentMemberType>(ty.getPointer());
10971104
}
10981105

10991106
RequirementSource(Kind kind, const RequirementSource *parent)
@@ -1315,11 +1322,18 @@ class GenericSignatureBuilder::RequirementSource final
13151322
return ProtocolConformanceRef::getFromOpaqueValue(storage.conformance);
13161323
}
13171324

1325+
/// Retrieve the precomputed dependent member for the associated type
1326+
/// declaration for this requirement, if there is one.
1327+
DependentMemberType *getDependentMember() const {
1328+
if (storageKind != StorageKind::AssociatedTypeDecl) return nullptr;
1329+
return storage.dependentMember;
1330+
}
1331+
13181332
/// Retrieve the associated type declaration for this requirement, if there
13191333
/// is one.
13201334
AssociatedTypeDecl *getAssociatedType() const {
13211335
if (storageKind != StorageKind::AssociatedTypeDecl) return nullptr;
1322-
return storage.assocType;
1336+
return storage.dependentMember->getAssocType();
13231337
}
13241338

13251339
/// Profiling support for \c FoldingSet.
@@ -1558,6 +1572,11 @@ class GenericSignatureBuilder::PotentialArchetype {
15581572
/// that share a name.
15591573
llvm::MapVector<Identifier, StoredNestedType> NestedTypes;
15601574

1575+
/// Cache DependentMemberType results instead of calling
1576+
/// DependentMemberType::get(). The much smaller hash table is more
1577+
/// processor cache efficient.
1578+
mutable llvm::DenseMap<Type, DependentMemberType*> CachedDMTs;
1579+
15611580
/// Construct a new potential archetype for a concrete declaration.
15621581
PotentialArchetype(PotentialArchetype *parent, AssociatedTypeDecl *assocType)
15631582
: parentOrContext(parent), identifier(assocType) {
@@ -1597,6 +1616,14 @@ class GenericSignatureBuilder::PotentialArchetype {
15971616
return identifier.assocType;
15981617
}
15991618

1619+
/// Retrieve the type declaration to which this nested type was resolved.
1620+
DependentMemberType *getResolvedDependentMemberType(Type Parent) const {
1621+
auto *&known = CachedDMTs[Parent];
1622+
if (!known)
1623+
known = DependentMemberType::get(Parent, getResolvedType());
1624+
return known;
1625+
}
1626+
16001627
/// Determine whether this is a generic parameter.
16011628
bool isGenericParam() const {
16021629
return parentOrContext.is<ASTContext *>();

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -818,7 +818,7 @@ const void *RequirementSource::getOpaqueStorage1() const {
818818
return storage.type;
819819

820820
case StorageKind::AssociatedTypeDecl:
821-
return storage.assocType;
821+
return storage.dependentMember;
822822
}
823823

824824
llvm_unreachable("Unhandled StorageKind in switch.");
@@ -918,11 +918,16 @@ bool RequirementSource::isSelfDerivedSource(GenericSignatureBuilder &builder,
918918
/// the nested type. This limited operation makes sure that it does not
919919
/// create any new potential archetypes along the way, so it should only be
920920
/// used in cases where we're reconstructing something that we know exists.
921-
static Type replaceSelfWithType(Type selfType, Type depTy) {
921+
static Type replaceSelfWithType(llvm::DenseMap<Type, Type> &cache,
922+
Type selfType, Type depTy) {
922923
if (auto depMemTy = depTy->getAs<DependentMemberType>()) {
923-
Type baseType = replaceSelfWithType(selfType, depMemTy->getBase());
924+
Type baseType = replaceSelfWithType(cache, selfType, depMemTy->getBase());
924925
assert(depMemTy->getAssocType() && "Missing associated type");
925-
return DependentMemberType::get(baseType, depMemTy->getAssocType());
926+
auto &known = cache[baseType];
927+
if (!known) {
928+
known = DependentMemberType::get(baseType, depMemTy->getAssocType());
929+
}
930+
return known;
926931
}
927932

928933
assert(depTy->is<GenericTypeParamType>() && "missing Self?");
@@ -1366,8 +1371,8 @@ RequirementSource::visitPotentialArchetypesAlongPath(
13661371

13671372
if (visitor(parentType, this)) return nullptr;
13681373

1369-
return replaceSelfWithType(parentType,
1370-
getAssociatedType()->getDeclaredInterfaceType());
1374+
return replaceSelfWithType(ReplacedSelfCache,
1375+
parentType, getDependentMember());
13711376
}
13721377

13731378
case RequirementSource::NestedTypeNameMatch:
@@ -1402,7 +1407,8 @@ RequirementSource::visitPotentialArchetypesAlongPath(
14021407

14031408
if (visitor(parentType, this)) return nullptr;
14041409

1405-
return replaceSelfWithType(parentType, getStoredType());
1410+
return replaceSelfWithType(ReplacedSelfCache,
1411+
parentType, getStoredType());
14061412
}
14071413
}
14081414
llvm_unreachable("unhandled kind");
@@ -1436,7 +1442,7 @@ ProtocolDecl *RequirementSource::getProtocolDecl() const {
14361442
return getProtocolConformance().getRequirement();
14371443

14381444
case StorageKind::AssociatedTypeDecl:
1439-
return storage.assocType->getProtocol();
1445+
return storage.dependentMember->getAssocType()->getProtocol();
14401446
}
14411447

14421448
llvm_unreachable("Unhandled StorageKind in switch.");
@@ -1607,8 +1613,9 @@ void RequirementSource::print(llvm::raw_ostream &out,
16071613
}
16081614

16091615
case StorageKind::AssociatedTypeDecl:
1610-
out << " (" << storage.assocType->getProtocol()->getName()
1611-
<< "::" << storage.assocType->getName() << ")";
1616+
auto assocType = storage.dependentMember->getAssocType();
1617+
out << " (" << assocType->getProtocol()->getName()
1618+
<< "::" << assocType->getName() << ")";
16121619
break;
16131620
}
16141621

@@ -2935,7 +2942,7 @@ Type GenericSignatureBuilder::PotentialArchetype::getDependentType(
29352942

29362943
// If we've resolved to an associated type, use it.
29372944
if (auto assocType = getResolvedType())
2938-
return DependentMemberType::get(parentType, assocType);
2945+
return getResolvedDependentMemberType(parentType);
29392946

29402947
return DependentMemberType::get(parentType, getNestedName());
29412948
}

0 commit comments

Comments
 (0)