Skip to content

Create fewer GenericSignatureBuilders, part 2 #19601

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Sep 28, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions include/swift/AST/GenericSignature.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,10 @@ class alignas(1 << TypeAlignInBits) GenericSignature final
Optional<ProtocolConformanceRef>
lookupConformance(CanType depTy, ProtocolDecl *proto) const;

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

/// Check if the generic signature makes all generic parameters
/// concrete.
Expand Down
2 changes: 0 additions & 2 deletions include/swift/AST/ProtocolConformance.h
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,6 @@ class NormalProtocolConformance : public ProtocolConformance,
{
assert(!conformingType->hasArchetype() &&
"ProtocolConformances should store interface types");
differenceAndStoreConditionalRequirements();
}

NormalProtocolConformance(Type conformingType,
Expand All @@ -428,7 +427,6 @@ class NormalProtocolConformance : public ProtocolConformance,
{
assert(!conformingType->hasArchetype() &&
"ProtocolConformances should store interface types");
differenceAndStoreConditionalRequirements();
}

void resolveLazyInfo() const;
Expand Down
9 changes: 9 additions & 0 deletions include/swift/AST/Witness.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,15 @@ class Witness {
return Witness(requirement);
}

/// Create a witness for the given requirement.
///
/// Deserialized witnesses do not have a synthetic environment.
static Witness forDeserialized(ValueDecl *decl,
SubstitutionMap substitutions) {
// TODO: It's probably a good idea to have a separate 'deserialized' bit.
return Witness(decl, substitutions, nullptr, SubstitutionMap());
}

/// Create a witness that requires substitutions.
///
/// \param decl The declaration for the witness.
Expand Down
11 changes: 7 additions & 4 deletions include/swift/SIL/TypeSubstCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -297,12 +297,15 @@ class TypeSubstCloner : public SILClonerWithScopes<ImplClass> {
if (SubsMap.empty())
return false;

for (auto ParamType : Sig->getSubstitutableParams()) {
bool Result = false;
Sig->forEachParam([&](GenericTypeParamType *ParamType, bool Canonical) {
if (!Canonical)
return;
if (!Type(ParamType).subst(SubsMap)->isEqual(ParamType))
return true;
}
Result = true;
});

return false;
return Result;
}

enum { ForInlining = true };
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const uint16_t VERSION_MAJOR = 0;
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
/// Don't worry about adhering to the 80-column limit for this line.
const uint16_t VERSION_MINOR = 449; // Last change: serialize @_implements names
const uint16_t VERSION_MINOR = 450; // Last change: don't serialize requirement environment

using DeclIDField = BCFixed<31>;

Expand Down
11 changes: 6 additions & 5 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4384,14 +4384,15 @@ void SubstitutionMap::Storage::Profile(
// Profile those replacement types that corresponding to canonical generic
// parameters within the generic signature.
id.AddInteger(replacementTypes.size());
auto genericParams = genericSig->getGenericParams();
for (unsigned i : indices(genericParams)) {
auto gp = genericParams[i];
if (genericSig->isCanonicalTypeInContext(gp->getCanonicalType()))

unsigned i = 0;
genericSig->forEachParam([&](GenericTypeParamType *gp, bool canonical) {
if (canonical)
id.AddPointer(replacementTypes[i].getPointer());
else
id.AddPointer(nullptr);
}
i++;
});

// Conformances.
id.AddInteger(conformances.size());
Expand Down
43 changes: 20 additions & 23 deletions lib/AST/GenericSignature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,45 +97,42 @@ GenericSignature::getInnermostGenericParams() const {
return params;
}


SmallVector<GenericTypeParamType *, 2>
GenericSignature::getSubstitutableParams() const {
void GenericSignature::forEachParam(
llvm::function_ref<void(GenericTypeParamType *, bool)> callback) const {
// Figure out which generic parameters are concrete or same-typed to another
// generic parameter.
// type parameter.
auto genericParams = getGenericParams();
auto genericParamsAreNotSubstitutable =
SmallVector<bool, 4>(genericParams.size(), false);
auto genericParamsAreCanonical =
SmallVector<bool, 4>(genericParams.size(), true);

for (auto req : getRequirements()) {
if (req.getKind() != RequirementKind::SameType) continue;

GenericTypeParamType *gp;
if (auto secondGP = req.getSecondType()->getAs<GenericTypeParamType>()) {
// If two generic parameters are same-typed, then the left-hand one
// is canonical.
// If two generic parameters are same-typed, then the right-hand one
// is non-canonical.
assert(req.getFirstType()->is<GenericTypeParamType>());
gp = secondGP;
} else {
// If an associated type is same-typed, it doesn't constrain the generic
// parameter itself.
if (req.getSecondType()->isTypeParameter()) continue;

// Otherwise, the generic parameter is concrete.
// Otherwise, the right-hand side is an associated type or concrete type,
// and the left-hand one is non-canonical.
gp = req.getFirstType()->getAs<GenericTypeParamType>();
if (!gp) continue;

// If an associated type is same-typed, it doesn't constrain the generic
// parameter itself. That is, if T == U.Foo, then T is canonical, whereas
// U.Foo is not.
if (req.getSecondType()->isTypeParameter()) continue;
}

unsigned index = GenericParamKey(gp).findIndexIn(genericParams);
genericParamsAreNotSubstitutable[index] = true;
genericParamsAreCanonical[index] = false;
}

// Collect the generic parameters that are substitutable.
SmallVector<GenericTypeParamType *, 2> result;
for (auto index : indices(genericParams)) {
auto gp = genericParams[index];
if (!genericParamsAreNotSubstitutable[index])
result.push_back(gp);
}

return result;
// Call the callback with each parameter and the result of the above analysis.
for (auto index : indices(genericParams))
callback(genericParams[index], genericParamsAreCanonical[index]);
}

bool GenericSignature::areAllParamsConcrete() const {
Expand Down
1 change: 0 additions & 1 deletion lib/AST/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -886,7 +886,6 @@ SpecializedProtocolConformance::SpecializedProtocolConformance(
GenericSubstitutions(substitutions)
{
assert(genericConformance->getKind() != ProtocolConformanceKind::Specialized);
computeConditionalRequirements();
}

void SpecializedProtocolConformance::computeConditionalRequirements() const {
Expand Down
25 changes: 19 additions & 6 deletions lib/AST/SubstitutionMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,18 +200,19 @@ SubstitutionMap SubstitutionMap::get(GenericSignature *genericSig,
// Form the replacement types.
SmallVector<Type, 4> replacementTypes;
replacementTypes.reserve(genericSig->getGenericParams().size());
for (auto gp : genericSig->getGenericParams()) {

genericSig->forEachParam([&](GenericTypeParamType *gp, bool canonical) {
// Don't eagerly form replacements for non-canonical generic parameters.
if (!genericSig->isCanonicalTypeInContext(gp->getCanonicalType())) {
if (!canonical) {
replacementTypes.push_back(Type());
continue;
return;
}

// Record the replacement.
Type replacement = Type(gp).subst(subs, lookupConformance,
SubstFlags::UseErrorType);
replacementTypes.push_back(replacement);
}
});

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

auto genericSig = getGenericSignature();

// Fast path
unsigned index = 0;
for (auto reqt : genericSig->getRequirements()) {
if (reqt.getKind() == RequirementKind::Conformance) {
if (reqt.getFirstType()->isEqual(type) &&
reqt.getSecondType()->isEqual(proto->getDeclaredType()))
return getConformances()[index];

index++;
}
}

// Retrieve the starting conformance from the conformance map.
auto getInitialConformance =
[&](Type type, ProtocolDecl *proto) -> Optional<ProtocolConformanceRef> {
Expand All @@ -338,8 +353,6 @@ SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const {
return None;
};

auto genericSig = getGenericSignature();

// If the type doesn't conform to this protocol, the result isn't formed
// from these requirements.
if (!genericSig->conformsToProtocol(type, proto)) {
Expand Down
12 changes: 6 additions & 6 deletions lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,15 +313,15 @@ namespace {
GenericSignature *sig = asImpl().getGenericSignature();
assert(sig);
auto canSig = sig->getCanonicalSignature();
for (auto param : canSig->getGenericParams()) {

canSig->forEachParam([&](GenericTypeParamType *param, bool canonical) {
// Currently, there are only type parameters. The parameter is a key
// argument if it's canonical in its generic context.
asImpl().addGenericParameter(GenericParamKind::Type,
/*key argument*/ canSig->isCanonicalTypeInContext(param),
/*extra argument*/ false);
}
/*key argument*/ canonical,
/*extra argument*/ false);
});

// Pad the structure up to four bytes for the following requirements.
unsigned padding = (unsigned) -canSig->getGenericParams().size() & 3;
for (unsigned i = 0; i < padding; ++i)
Expand Down
7 changes: 4 additions & 3 deletions lib/IRGen/GenProto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,10 @@ irgen::enumerateGenericSignatureRequirements(CanGenericSignature signature,
if (!signature) return;

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

// Get the protocol conformances.
for (auto &reqt : signature->getRequirements()) {
Expand Down
7 changes: 6 additions & 1 deletion lib/RemoteAST/RemoteAST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,12 @@ class RemoteASTTypeBuilder {

// Build a SubstitutionMap.
auto *genericSig = decl->getGenericSignature();
auto genericParams = genericSig->getSubstitutableParams();

SmallVector<GenericTypeParamType *, 4> genericParams;
genericSig->forEachParam([&](GenericTypeParamType *gp, bool canonical) {
if (canonical)
genericParams.push_back(gp);
});
if (genericParams.size() != args.size())
return Type();

Expand Down
9 changes: 7 additions & 2 deletions lib/SILOptimizer/IPO/EagerSpecializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,11 @@ void EagerDispatch::emitDispatchTo(SILFunction *NewFunc) {
auto GenericSig =
GenericFunc->getLoweredFunctionType()->getGenericSignature();
auto SubMap = ReInfo.getClonerParamSubstitutionMap();
for (auto ParamTy : GenericSig->getSubstitutableParams()) {

GenericSig->forEachParam([&](GenericTypeParamType *ParamTy, bool Canonical) {
if (!Canonical)
return;

auto Replacement = Type(ParamTy).subst(SubMap);
assert(!Replacement->hasTypeParameter());

Expand All @@ -368,7 +372,8 @@ void EagerDispatch::emitDispatchTo(SILFunction *NewFunc) {
Replacement, LayoutInfo);
}
}
}
});

static_cast<void>(FailedTypeCheckBB);

if (OldReturnBB == &EntryBB) {
Expand Down
21 changes: 13 additions & 8 deletions lib/SILOptimizer/Utils/Generics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,11 @@ bool ReabstractionInfo::prepareAndCheck(ApplySite Apply, SILFunction *Callee,
bool HasConcreteGenericParams = false;
bool HasNonArchetypeGenericParams = false;
HasUnboundGenericParams = false;
for (auto GP : CalleeGenericSig->getSubstitutableParams()) {

CalleeGenericSig->forEachParam([&](GenericTypeParamType *GP, bool Canonical) {
if (!Canonical)
return;

// Check only the substitutions for the generic parameters.
// Ignore any dependent types, etc.
auto Replacement = Type(GP).subst(CalleeParamSubMap);
Expand All @@ -458,11 +462,10 @@ bool ReabstractionInfo::prepareAndCheck(ApplySite Apply, SILFunction *Callee,
HasNonArchetypeGenericParams = true;
}
}
continue;
} else {
HasConcreteGenericParams = true;
}

HasConcreteGenericParams = true;
}
});

if (HasUnboundGenericParams) {
// Bail if we cannot specialize generic substitutions, but all substitutions
Expand Down Expand Up @@ -1561,14 +1564,16 @@ void FunctionSignaturePartialSpecializer::
// Simply create a set of same-type requirements based on concrete
// substitutions.
SmallVector<Requirement, 4> Requirements;
for (auto GP : CalleeGenericSig->getSubstitutableParams()) {
CalleeGenericSig->forEachParam([&](GenericTypeParamType *GP, bool Canonical) {
if (!Canonical)
return;
auto Replacement = Type(GP).subst(CalleeInterfaceToCallerArchetypeMap);
if (Replacement->hasArchetype())
continue;
return;
// Replacement is concrete. Add a same type requirement.
Requirement Req(RequirementKind::SameType, GP, Replacement);
Requirements.push_back(Req);
}
});

// Create a new generic signature by taking the existing one
// and adding new requirements to it. No need to introduce
Expand Down
11 changes: 8 additions & 3 deletions lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -625,10 +625,15 @@ static bool shouldSkipApplyDuringEarlyInlining(FullApplySite AI) {
static bool isCallerAndCalleeLayoutConstraintsCompatible(FullApplySite AI) {
SILFunction *Callee = AI.getReferencedFunction();
auto CalleeSig = Callee->getLoweredFunctionType()->getGenericSignature();
auto SubstParams = CalleeSig->getSubstitutableParams();
auto AISubs = AI.getSubstitutionMap();
for (auto idx : indices(SubstParams)) {
auto Param = SubstParams[idx];

SmallVector<GenericTypeParamType *, 4> SubstParams;
CalleeSig->forEachParam([&](GenericTypeParamType *Param, bool Canonical) {
if (Canonical)
SubstParams.push_back(Param);
});

for (auto Param : SubstParams) {
// Map the parameter into context
auto ContextTy = Callee->mapTypeIntoContext(Param->getCanonicalType());
auto Archetype = ContextTy->getAs<ArchetypeType>();
Expand Down
10 changes: 6 additions & 4 deletions lib/SILOptimizer/Utils/SpecializationMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,12 @@ std::string GenericSpecializationMangler::mangle(GenericSignature *Sig) {
}

bool First = true;
for (auto ParamType : Sig->getSubstitutableParams()) {
appendType(Type(ParamType).subst(SubMap)->getCanonicalType());
appendListSeparator(First);
}
Sig->forEachParam([&](GenericTypeParamType *ParamType, bool Canonical) {
if (Canonical) {
appendType(Type(ParamType).subst(SubMap)->getCanonicalType());
appendListSeparator(First);
}
});
assert(!First && "no generic substitutions");

if (isInlined)
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/CSBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint(
// should be allowed to escape. As a result we allow anything
// passed in to escape.
if (auto *fnTy = type->getAs<AnyFunctionType>())
if (typeVar->getImpl().getArchetype() && !shouldAttemptFixes())
if (typeVar->getImpl().getGenericParameter() && !shouldAttemptFixes())
type = fnTy->withExtInfo(fnTy->getExtInfo().withNoEscape(false));

// Check whether we can perform this binding.
Expand Down
Loading