Skip to content

Commit 2b67b0c

Browse files
authored
Merge pull request #19601 from slavapestov/fewer-gsbs-2
Create fewer GenericSignatureBuilders, part 2
2 parents 3268b9d + 3b203a5 commit 2b67b0c

31 files changed

+241
-197
lines changed

include/swift/AST/GenericSignature.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,10 @@ class alignas(1 << TypeAlignInBits) GenericSignature final
190190
Optional<ProtocolConformanceRef>
191191
lookupConformance(CanType depTy, ProtocolDecl *proto) const;
192192

193-
/// Return a vector of all generic parameters that are not subject to
194-
/// a concrete same-type constraint.
195-
SmallVector<GenericTypeParamType *, 2> getSubstitutableParams() const;
193+
/// Iterate over all generic parameters, passing a flag to the callback
194+
/// indicating if the generic parameter is canonical or not.
195+
void forEachParam(
196+
llvm::function_ref<void(GenericTypeParamType *, bool)> callback) const;
196197

197198
/// Check if the generic signature makes all generic parameters
198199
/// concrete.

include/swift/AST/ProtocolConformance.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,6 @@ class NormalProtocolConformance : public ProtocolConformance,
415415
{
416416
assert(!conformingType->hasArchetype() &&
417417
"ProtocolConformances should store interface types");
418-
differenceAndStoreConditionalRequirements();
419418
}
420419

421420
NormalProtocolConformance(Type conformingType,
@@ -428,7 +427,6 @@ class NormalProtocolConformance : public ProtocolConformance,
428427
{
429428
assert(!conformingType->hasArchetype() &&
430429
"ProtocolConformances should store interface types");
431-
differenceAndStoreConditionalRequirements();
432430
}
433431

434432
void resolveLazyInfo() const;

include/swift/AST/Witness.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,15 @@ class Witness {
117117
return Witness(requirement);
118118
}
119119

120+
/// Create a witness for the given requirement.
121+
///
122+
/// Deserialized witnesses do not have a synthetic environment.
123+
static Witness forDeserialized(ValueDecl *decl,
124+
SubstitutionMap substitutions) {
125+
// TODO: It's probably a good idea to have a separate 'deserialized' bit.
126+
return Witness(decl, substitutions, nullptr, SubstitutionMap());
127+
}
128+
120129
/// Create a witness that requires substitutions.
121130
///
122131
/// \param decl The declaration for the witness.

include/swift/SIL/TypeSubstCloner.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -297,12 +297,15 @@ class TypeSubstCloner : public SILClonerWithScopes<ImplClass> {
297297
if (SubsMap.empty())
298298
return false;
299299

300-
for (auto ParamType : Sig->getSubstitutableParams()) {
300+
bool Result = false;
301+
Sig->forEachParam([&](GenericTypeParamType *ParamType, bool Canonical) {
302+
if (!Canonical)
303+
return;
301304
if (!Type(ParamType).subst(SubsMap)->isEqual(ParamType))
302-
return true;
303-
}
305+
Result = true;
306+
});
304307

305-
return false;
308+
return Result;
306309
}
307310

308311
enum { ForInlining = true };

include/swift/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const uint16_t VERSION_MAJOR = 0;
5555
/// describe what change you made. The content of this comment isn't important;
5656
/// it just ensures a conflict if two people change the module format.
5757
/// Don't worry about adhering to the 80-column limit for this line.
58-
const uint16_t VERSION_MINOR = 449; // Last change: serialize @_implements names
58+
const uint16_t VERSION_MINOR = 450; // Last change: don't serialize requirement environment
5959

6060
using DeclIDField = BCFixed<31>;
6161

lib/AST/ASTContext.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4384,14 +4384,15 @@ void SubstitutionMap::Storage::Profile(
43844384
// Profile those replacement types that corresponding to canonical generic
43854385
// parameters within the generic signature.
43864386
id.AddInteger(replacementTypes.size());
4387-
auto genericParams = genericSig->getGenericParams();
4388-
for (unsigned i : indices(genericParams)) {
4389-
auto gp = genericParams[i];
4390-
if (genericSig->isCanonicalTypeInContext(gp->getCanonicalType()))
4387+
4388+
unsigned i = 0;
4389+
genericSig->forEachParam([&](GenericTypeParamType *gp, bool canonical) {
4390+
if (canonical)
43914391
id.AddPointer(replacementTypes[i].getPointer());
43924392
else
43934393
id.AddPointer(nullptr);
4394-
}
4394+
i++;
4395+
});
43954396

43964397
// Conformances.
43974398
id.AddInteger(conformances.size());

lib/AST/GenericSignature.cpp

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -97,45 +97,42 @@ GenericSignature::getInnermostGenericParams() const {
9797
return params;
9898
}
9999

100-
101-
SmallVector<GenericTypeParamType *, 2>
102-
GenericSignature::getSubstitutableParams() const {
100+
void GenericSignature::forEachParam(
101+
llvm::function_ref<void(GenericTypeParamType *, bool)> callback) const {
103102
// Figure out which generic parameters are concrete or same-typed to another
104-
// generic parameter.
103+
// type parameter.
105104
auto genericParams = getGenericParams();
106-
auto genericParamsAreNotSubstitutable =
107-
SmallVector<bool, 4>(genericParams.size(), false);
105+
auto genericParamsAreCanonical =
106+
SmallVector<bool, 4>(genericParams.size(), true);
107+
108108
for (auto req : getRequirements()) {
109109
if (req.getKind() != RequirementKind::SameType) continue;
110110

111111
GenericTypeParamType *gp;
112112
if (auto secondGP = req.getSecondType()->getAs<GenericTypeParamType>()) {
113-
// If two generic parameters are same-typed, then the left-hand one
114-
// is canonical.
113+
// If two generic parameters are same-typed, then the right-hand one
114+
// is non-canonical.
115+
assert(req.getFirstType()->is<GenericTypeParamType>());
115116
gp = secondGP;
116117
} else {
117-
// If an associated type is same-typed, it doesn't constrain the generic
118-
// parameter itself.
119-
if (req.getSecondType()->isTypeParameter()) continue;
120-
121-
// Otherwise, the generic parameter is concrete.
118+
// Otherwise, the right-hand side is an associated type or concrete type,
119+
// and the left-hand one is non-canonical.
122120
gp = req.getFirstType()->getAs<GenericTypeParamType>();
123121
if (!gp) continue;
122+
123+
// If an associated type is same-typed, it doesn't constrain the generic
124+
// parameter itself. That is, if T == U.Foo, then T is canonical, whereas
125+
// U.Foo is not.
126+
if (req.getSecondType()->isTypeParameter()) continue;
124127
}
125128

126129
unsigned index = GenericParamKey(gp).findIndexIn(genericParams);
127-
genericParamsAreNotSubstitutable[index] = true;
130+
genericParamsAreCanonical[index] = false;
128131
}
129132

130-
// Collect the generic parameters that are substitutable.
131-
SmallVector<GenericTypeParamType *, 2> result;
132-
for (auto index : indices(genericParams)) {
133-
auto gp = genericParams[index];
134-
if (!genericParamsAreNotSubstitutable[index])
135-
result.push_back(gp);
136-
}
137-
138-
return result;
133+
// Call the callback with each parameter and the result of the above analysis.
134+
for (auto index : indices(genericParams))
135+
callback(genericParams[index], genericParamsAreCanonical[index]);
139136
}
140137

141138
bool GenericSignature::areAllParamsConcrete() const {

lib/AST/ProtocolConformance.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -886,7 +886,6 @@ SpecializedProtocolConformance::SpecializedProtocolConformance(
886886
GenericSubstitutions(substitutions)
887887
{
888888
assert(genericConformance->getKind() != ProtocolConformanceKind::Specialized);
889-
computeConditionalRequirements();
890889
}
891890

892891
void SpecializedProtocolConformance::computeConditionalRequirements() const {

lib/AST/SubstitutionMap.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -200,18 +200,19 @@ SubstitutionMap SubstitutionMap::get(GenericSignature *genericSig,
200200
// Form the replacement types.
201201
SmallVector<Type, 4> replacementTypes;
202202
replacementTypes.reserve(genericSig->getGenericParams().size());
203-
for (auto gp : genericSig->getGenericParams()) {
203+
204+
genericSig->forEachParam([&](GenericTypeParamType *gp, bool canonical) {
204205
// Don't eagerly form replacements for non-canonical generic parameters.
205-
if (!genericSig->isCanonicalTypeInContext(gp->getCanonicalType())) {
206+
if (!canonical) {
206207
replacementTypes.push_back(Type());
207-
continue;
208+
return;
208209
}
209210

210211
// Record the replacement.
211212
Type replacement = Type(gp).subst(subs, lookupConformance,
212213
SubstFlags::UseErrorType);
213214
replacementTypes.push_back(replacement);
214-
}
215+
});
215216

216217
// Form the stored conformances.
217218
SmallVector<ProtocolConformanceRef, 4> conformances;
@@ -318,6 +319,20 @@ SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const {
318319
if (!type->isTypeParameter())
319320
return None;
320321

322+
auto genericSig = getGenericSignature();
323+
324+
// Fast path
325+
unsigned index = 0;
326+
for (auto reqt : genericSig->getRequirements()) {
327+
if (reqt.getKind() == RequirementKind::Conformance) {
328+
if (reqt.getFirstType()->isEqual(type) &&
329+
reqt.getSecondType()->isEqual(proto->getDeclaredType()))
330+
return getConformances()[index];
331+
332+
index++;
333+
}
334+
}
335+
321336
// Retrieve the starting conformance from the conformance map.
322337
auto getInitialConformance =
323338
[&](Type type, ProtocolDecl *proto) -> Optional<ProtocolConformanceRef> {
@@ -338,8 +353,6 @@ SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const {
338353
return None;
339354
};
340355

341-
auto genericSig = getGenericSignature();
342-
343356
// If the type doesn't conform to this protocol, the result isn't formed
344357
// from these requirements.
345358
if (!genericSig->conformsToProtocol(type, proto)) {

lib/IRGen/GenMeta.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -313,15 +313,15 @@ namespace {
313313
GenericSignature *sig = asImpl().getGenericSignature();
314314
assert(sig);
315315
auto canSig = sig->getCanonicalSignature();
316-
317-
for (auto param : canSig->getGenericParams()) {
316+
317+
canSig->forEachParam([&](GenericTypeParamType *param, bool canonical) {
318318
// Currently, there are only type parameters. The parameter is a key
319319
// argument if it's canonical in its generic context.
320320
asImpl().addGenericParameter(GenericParamKind::Type,
321-
/*key argument*/ canSig->isCanonicalTypeInContext(param),
322-
/*extra argument*/ false);
323-
}
324-
321+
/*key argument*/ canonical,
322+
/*extra argument*/ false);
323+
});
324+
325325
// Pad the structure up to four bytes for the following requirements.
326326
unsigned padding = (unsigned) -canSig->getGenericParams().size() & 3;
327327
for (unsigned i = 0; i < padding; ++i)

lib/IRGen/GenProto.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -238,9 +238,10 @@ irgen::enumerateGenericSignatureRequirements(CanGenericSignature signature,
238238
if (!signature) return;
239239

240240
// Get all of the type metadata.
241-
for (auto gp : signature->getSubstitutableParams()) {
242-
callback({CanType(gp), nullptr});
243-
}
241+
signature->forEachParam([&](GenericTypeParamType *gp, bool canonical) {
242+
if (canonical)
243+
callback({CanType(gp), nullptr});
244+
});
244245

245246
// Get the protocol conformances.
246247
for (auto &reqt : signature->getRequirements()) {

lib/RemoteAST/RemoteAST.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,12 @@ class RemoteASTTypeBuilder {
178178

179179
// Build a SubstitutionMap.
180180
auto *genericSig = decl->getGenericSignature();
181-
auto genericParams = genericSig->getSubstitutableParams();
181+
182+
SmallVector<GenericTypeParamType *, 4> genericParams;
183+
genericSig->forEachParam([&](GenericTypeParamType *gp, bool canonical) {
184+
if (canonical)
185+
genericParams.push_back(gp);
186+
});
182187
if (genericParams.size() != args.size())
183188
return Type();
184189

lib/SILOptimizer/IPO/EagerSpecializer.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,11 @@ void EagerDispatch::emitDispatchTo(SILFunction *NewFunc) {
347347
auto GenericSig =
348348
GenericFunc->getLoweredFunctionType()->getGenericSignature();
349349
auto SubMap = ReInfo.getClonerParamSubstitutionMap();
350-
for (auto ParamTy : GenericSig->getSubstitutableParams()) {
350+
351+
GenericSig->forEachParam([&](GenericTypeParamType *ParamTy, bool Canonical) {
352+
if (!Canonical)
353+
return;
354+
351355
auto Replacement = Type(ParamTy).subst(SubMap);
352356
assert(!Replacement->hasTypeParameter());
353357

@@ -368,7 +372,8 @@ void EagerDispatch::emitDispatchTo(SILFunction *NewFunc) {
368372
Replacement, LayoutInfo);
369373
}
370374
}
371-
}
375+
});
376+
372377
static_cast<void>(FailedTypeCheckBB);
373378

374379
if (OldReturnBB == &EntryBB) {

lib/SILOptimizer/Utils/Generics.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,11 @@ bool ReabstractionInfo::prepareAndCheck(ApplySite Apply, SILFunction *Callee,
434434
bool HasConcreteGenericParams = false;
435435
bool HasNonArchetypeGenericParams = false;
436436
HasUnboundGenericParams = false;
437-
for (auto GP : CalleeGenericSig->getSubstitutableParams()) {
437+
438+
CalleeGenericSig->forEachParam([&](GenericTypeParamType *GP, bool Canonical) {
439+
if (!Canonical)
440+
return;
441+
438442
// Check only the substitutions for the generic parameters.
439443
// Ignore any dependent types, etc.
440444
auto Replacement = Type(GP).subst(CalleeParamSubMap);
@@ -458,11 +462,10 @@ bool ReabstractionInfo::prepareAndCheck(ApplySite Apply, SILFunction *Callee,
458462
HasNonArchetypeGenericParams = true;
459463
}
460464
}
461-
continue;
465+
} else {
466+
HasConcreteGenericParams = true;
462467
}
463-
464-
HasConcreteGenericParams = true;
465-
}
468+
});
466469

467470
if (HasUnboundGenericParams) {
468471
// Bail if we cannot specialize generic substitutions, but all substitutions
@@ -1561,14 +1564,16 @@ void FunctionSignaturePartialSpecializer::
15611564
// Simply create a set of same-type requirements based on concrete
15621565
// substitutions.
15631566
SmallVector<Requirement, 4> Requirements;
1564-
for (auto GP : CalleeGenericSig->getSubstitutableParams()) {
1567+
CalleeGenericSig->forEachParam([&](GenericTypeParamType *GP, bool Canonical) {
1568+
if (!Canonical)
1569+
return;
15651570
auto Replacement = Type(GP).subst(CalleeInterfaceToCallerArchetypeMap);
15661571
if (Replacement->hasArchetype())
1567-
continue;
1572+
return;
15681573
// Replacement is concrete. Add a same type requirement.
15691574
Requirement Req(RequirementKind::SameType, GP, Replacement);
15701575
Requirements.push_back(Req);
1571-
}
1576+
});
15721577

15731578
// Create a new generic signature by taking the existing one
15741579
// and adding new requirements to it. No need to introduce

lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -625,10 +625,15 @@ static bool shouldSkipApplyDuringEarlyInlining(FullApplySite AI) {
625625
static bool isCallerAndCalleeLayoutConstraintsCompatible(FullApplySite AI) {
626626
SILFunction *Callee = AI.getReferencedFunction();
627627
auto CalleeSig = Callee->getLoweredFunctionType()->getGenericSignature();
628-
auto SubstParams = CalleeSig->getSubstitutableParams();
629628
auto AISubs = AI.getSubstitutionMap();
630-
for (auto idx : indices(SubstParams)) {
631-
auto Param = SubstParams[idx];
629+
630+
SmallVector<GenericTypeParamType *, 4> SubstParams;
631+
CalleeSig->forEachParam([&](GenericTypeParamType *Param, bool Canonical) {
632+
if (Canonical)
633+
SubstParams.push_back(Param);
634+
});
635+
636+
for (auto Param : SubstParams) {
632637
// Map the parameter into context
633638
auto ContextTy = Callee->mapTypeIntoContext(Param->getCanonicalType());
634639
auto Archetype = ContextTy->getAs<ArchetypeType>();

lib/SILOptimizer/Utils/SpecializationMangler.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,12 @@ std::string GenericSpecializationMangler::mangle(GenericSignature *Sig) {
8383
}
8484

8585
bool First = true;
86-
for (auto ParamType : Sig->getSubstitutableParams()) {
87-
appendType(Type(ParamType).subst(SubMap)->getCanonicalType());
88-
appendListSeparator(First);
89-
}
86+
Sig->forEachParam([&](GenericTypeParamType *ParamType, bool Canonical) {
87+
if (Canonical) {
88+
appendType(Type(ParamType).subst(SubMap)->getCanonicalType());
89+
appendListSeparator(First);
90+
}
91+
});
9092
assert(!First && "no generic substitutions");
9193

9294
if (isInlined)

lib/Sema/CSBindings.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint(
333333
// should be allowed to escape. As a result we allow anything
334334
// passed in to escape.
335335
if (auto *fnTy = type->getAs<AnyFunctionType>())
336-
if (typeVar->getImpl().getArchetype() && !shouldAttemptFixes())
336+
if (typeVar->getImpl().getGenericParameter() && !shouldAttemptFixes())
337337
type = fnTy->withExtInfo(fnTy->getExtInfo().withNoEscape(false));
338338

339339
// Check whether we can perform this binding.

0 commit comments

Comments
 (0)