Skip to content

Commit d36dcea

Browse files
authored
Merge pull request swiftlang#76154 from slavapestov/combine-substitution-maps
Move combineSubstitutionMaps() to SILOptimizer and fix an assertion
2 parents a9120c3 + df1b4bc commit d36dcea

File tree

15 files changed

+174
-224
lines changed

15 files changed

+174
-224
lines changed

include/swift/AST/SubstitutionMap.h

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,6 @@ typedef CanTypeWrapper<GenericTypeParamType> CanGenericTypeParamType;
4141
template<class Type> class CanTypeWrapper;
4242
typedef CanTypeWrapper<SubstitutableType> CanSubstitutableType;
4343

44-
enum class CombineSubstitutionMaps {
45-
AtDepth,
46-
AtIndex
47-
};
48-
4944
/// SubstitutionMap is a data structure type that describes the mapping of
5045
/// abstract types to replacement types, together with associated conformances
5146
/// to use for deriving nested types and conformances.
@@ -205,26 +200,6 @@ class SubstitutionMap {
205200
GenericSignature baseSig,
206201
const GenericParamList *derivedParams);
207202

208-
/// Combine two substitution maps as follows.
209-
///
210-
/// The result is written in terms of the generic parameters of 'genericSig'.
211-
///
212-
/// Generic parameters with a depth or index less than 'firstDepthOrIndex'
213-
/// come from 'firstSubMap'.
214-
///
215-
/// Generic parameters with a depth greater than 'firstDepthOrIndex' come
216-
/// from 'secondSubMap', but are looked up starting with a depth or index of
217-
/// 'secondDepthOrIndex'.
218-
///
219-
/// The 'how' parameter determines if we're looking at the depth or index.
220-
static SubstitutionMap
221-
combineSubstitutionMaps(SubstitutionMap firstSubMap,
222-
SubstitutionMap secondSubMap,
223-
CombineSubstitutionMaps how,
224-
unsigned baseDepthOrIndex,
225-
unsigned origDepthOrIndex,
226-
GenericSignature genericSig);
227-
228203
/// Swap archetypes in the substitution map's replacement types with their
229204
/// interface types.
230205
SubstitutionMap mapReplacementTypesOutOfContext() const;

include/swift/SIL/SILInstruction.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -722,8 +722,8 @@ class SILInstruction : public llvm::ilist_node<SILInstruction> {
722722
/// Run the given function for each local archetype this instruction
723723
/// defines, passing the value that should be used to record the
724724
/// dependency.
725-
void forEachDefinedLocalArchetype(
726-
llvm::function_ref<void(CanLocalArchetypeType archetype,
725+
void forEachDefinedLocalEnvironment(
726+
llvm::function_ref<void(GenericEnvironment *genericEnv,
727727
SILValue typeDependency)> function) const;
728728
bool definesLocalArchetypes() const;
729729

@@ -8194,8 +8194,8 @@ class OpenPackElementInst final
81948194
public:
81958195
/// Call the given function for each element archetype that this
81968196
/// instruction opens.
8197-
void forEachDefinedLocalArchetype(
8198-
llvm::function_ref<void(CanLocalArchetypeType, SILValue)> fn) const;
8197+
void forEachDefinedLocalEnvironment(
8198+
llvm::function_ref<void(GenericEnvironment *, SILValue)> fn) const;
81998199

82008200
GenericEnvironment *getOpenedGenericEnvironment() const {
82018201
return Env;

include/swift/SIL/SILModule.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -343,18 +343,18 @@ class SILModule {
343343
/// projections, shared between all functions in the module.
344344
std::unique_ptr<IndexTrieNode> indexTrieRoot;
345345

346-
/// A mapping from root local archetypes to the instructions which define
346+
/// A mapping from local generic environments to the instructions which define
347347
/// them.
348348
///
349349
/// The value is either a SingleValueInstruction or a PlaceholderValue,
350350
/// in case a local archetype definition is looked up during parsing or
351351
/// deserializing SIL, where local archetypes can be forward referenced.
352352
///
353353
/// In theory we wouldn't need to have the SILFunction in the key, because
354-
/// local archetypes \em should be unique across the module. But currently
354+
/// local environments should be unique across the module. But currently
355355
/// in some rare cases SILGen re-uses the same local archetype for multiple
356356
/// functions.
357-
using LocalArchetypeKey = std::pair<LocalArchetypeType *, SILFunction *>;
357+
using LocalArchetypeKey = std::pair<GenericEnvironment *, SILFunction *>;
358358
llvm::DenseMap<LocalArchetypeKey, SILValue> RootLocalArchetypeDefs;
359359

360360
/// The number of PlaceholderValues in RootLocalArchetypeDefs.
@@ -451,6 +451,15 @@ class SILModule {
451451
hasAccessMarkerHandler = true;
452452
}
453453

454+
/// Returns the instruction which defines the given local generic environment,
455+
/// e.g. an open_existential_addr.
456+
///
457+
/// In case the generic environment is not defined yet (e.g. during parsing or
458+
/// deserialization), a PlaceholderValue is returned. This should not be the
459+
/// case outside of parsing or deserialization.
460+
SILValue getLocalGenericEnvironmentDef(GenericEnvironment *genericEnv,
461+
SILFunction *inFunction);
462+
454463
/// Returns the instruction which defines the given root local archetype,
455464
/// e.g. an open_existential_addr.
456465
///

lib/AST/SubstitutionMap.cpp

Lines changed: 0 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -541,91 +541,6 @@ SubstitutionMap::getOverrideSubstitutions(const NominalTypeDecl *baseNominal,
541541
LookUpConformanceInOverrideSubs(info));
542542
}
543543

544-
SubstitutionMap
545-
SubstitutionMap::combineSubstitutionMaps(SubstitutionMap firstSubMap,
546-
SubstitutionMap secondSubMap,
547-
CombineSubstitutionMaps how,
548-
unsigned firstDepthOrIndex,
549-
unsigned secondDepthOrIndex,
550-
GenericSignature genericSig) {
551-
auto &ctx = genericSig->getASTContext();
552-
553-
auto replaceGenericParameter = [&](Type type) -> std::optional<Type> {
554-
if (auto gp = type->getAs<GenericTypeParamType>()) {
555-
if (how == CombineSubstitutionMaps::AtDepth) {
556-
if (gp->getDepth() < firstDepthOrIndex)
557-
return Type();
558-
return Type(GenericTypeParamType::get(gp->isParameterPack(),
559-
gp->getDepth() + secondDepthOrIndex -
560-
firstDepthOrIndex,
561-
gp->getIndex(), ctx));
562-
}
563-
564-
assert(how == CombineSubstitutionMaps::AtIndex);
565-
if (gp->getIndex() < firstDepthOrIndex)
566-
return Type();
567-
return Type(GenericTypeParamType::get(
568-
gp->isParameterPack(), gp->getDepth(),
569-
gp->getIndex() + secondDepthOrIndex - firstDepthOrIndex, ctx));
570-
}
571-
572-
return std::nullopt;
573-
};
574-
575-
return get(
576-
genericSig,
577-
[&](SubstitutableType *type) {
578-
if (auto replacement = replaceGenericParameter(type))
579-
if (*replacement)
580-
return replacement->subst(secondSubMap);
581-
return Type(type).subst(firstSubMap);
582-
},
583-
[&](CanType type, Type substType, ProtocolDecl *proto) {
584-
if (auto replacement = type.transformRec(replaceGenericParameter))
585-
return secondSubMap.lookupConformance(replacement->getCanonicalType(),
586-
proto);
587-
if (auto conformance = firstSubMap.lookupConformance(type, proto))
588-
return conformance;
589-
590-
// We might not have enough information in the substitution maps alone.
591-
//
592-
// Eg,
593-
//
594-
// class Base<T1> {
595-
// func foo<U1>(_: U1) where T1 : P {}
596-
// }
597-
//
598-
// class Derived<T2> : Base<Foo<T2>> {
599-
// override func foo<U2>(_: U2) where T2 : Q {}
600-
// }
601-
//
602-
// Suppose we're devirtualizing a call to Base.foo() on a value whose
603-
// type is known to be Derived<Bar>. We start with substitutions written
604-
// in terms of Base.foo()'s generic signature:
605-
//
606-
// <T1, U1 where T1 : P>
607-
// T1 := Foo<Bar>
608-
// T1 : P := Foo<Bar> : P
609-
//
610-
// We want to build substitutions in terms of Derived.foo()'s
611-
// generic signature:
612-
//
613-
// <T2, U2 where T2 : Q>
614-
// T2 := Bar
615-
// T2 : Q := Bar : Q
616-
//
617-
// The conformance Bar : Q is difficult to recover in the general case.
618-
//
619-
// Some combination of storing substitution maps in BoundGenericTypes
620-
// as well as for method overrides would solve this, but for now, just
621-
// punt to module lookup.
622-
if (substType->isTypeParameter())
623-
return ProtocolConformanceRef(proto);
624-
625-
return swift::lookupConformance(substType, proto);
626-
});
627-
}
628-
629544
void SubstitutionMap::verify() const {
630545
#ifndef NDEBUG
631546
if (empty())

lib/SIL/IR/SILInstruction.cpp

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1676,22 +1676,21 @@ const ValueBase *SILInstructionResultArray::back() const {
16761676

16771677
bool SILInstruction::definesLocalArchetypes() const {
16781678
bool definesAny = false;
1679-
forEachDefinedLocalArchetype([&](CanLocalArchetypeType type,
1680-
SILValue dependency) {
1679+
forEachDefinedLocalEnvironment([&](GenericEnvironment *genericEnv,
1680+
SILValue dependency) {
16811681
definesAny = true;
16821682
});
16831683
return definesAny;
16841684
}
16851685

1686-
void SILInstruction::forEachDefinedLocalArchetype(
1687-
llvm::function_ref<void(CanLocalArchetypeType, SILValue)> fn) const {
1686+
void SILInstruction::forEachDefinedLocalEnvironment(
1687+
llvm::function_ref<void(GenericEnvironment *, SILValue)> fn) const {
16881688
switch (getKind()) {
16891689
#define SINGLE_VALUE_SINGLE_OPEN(TYPE) \
16901690
case SILInstructionKind::TYPE: { \
16911691
auto I = cast<TYPE>(this); \
16921692
auto archetype = I->getDefinedOpenedArchetype(); \
1693-
assert(archetype); \
1694-
return fn(archetype, I); \
1693+
return fn(archetype->getGenericEnvironment(), I); \
16951694
}
16961695
SINGLE_VALUE_SINGLE_OPEN(OpenExistentialAddrInst)
16971696
SINGLE_VALUE_SINGLE_OPEN(OpenExistentialRefInst)
@@ -1700,22 +1699,15 @@ void SILInstruction::forEachDefinedLocalArchetype(
17001699
SINGLE_VALUE_SINGLE_OPEN(OpenExistentialMetatypeInst)
17011700
SINGLE_VALUE_SINGLE_OPEN(OpenExistentialValueInst)
17021701
#undef SINGLE_VALUE_SINGLE_OPEN
1703-
case SILInstructionKind::OpenPackElementInst:
1704-
return cast<OpenPackElementInst>(this)->forEachDefinedLocalArchetype(fn);
1702+
case SILInstructionKind::OpenPackElementInst: {
1703+
auto I = cast<OpenPackElementInst>(this);
1704+
return fn(I->getOpenedGenericEnvironment(), I);
1705+
}
17051706
default:
17061707
return;
17071708
}
17081709
}
17091710

1710-
void OpenPackElementInst::forEachDefinedLocalArchetype(
1711-
llvm::function_ref<void(CanLocalArchetypeType, SILValue)> fn) const {
1712-
getOpenedGenericEnvironment()->forEachPackElementBinding(
1713-
[&](ElementArchetypeType *elementType,
1714-
PackType *packSubstitution) {
1715-
fn(CanElementArchetypeType(elementType), this);
1716-
});
1717-
}
1718-
17191711
//===----------------------------------------------------------------------===//
17201712
// Multiple Value Instruction
17211713
//===----------------------------------------------------------------------===//

lib/SIL/IR/SILInstructions.cpp

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ static void *allocateTrailingInst(SILFunction &F, CountTypes... counts) {
4747

4848
namespace {
4949
class TypeDependentOperandCollector {
50-
SmallVector<CanLocalArchetypeType, 4> rootLocalArchetypes;
50+
SmallVector<GenericEnvironment *, 4> genericEnvs;
5151
bool hasDynamicSelf = false;
5252
public:
5353
void collect(CanType type);
@@ -86,15 +86,15 @@ void TypeDependentOperandCollector::collect(CanType type) {
8686
return;
8787
type.visit([&](CanType t) {
8888
if (const auto local = dyn_cast<LocalArchetypeType>(t)) {
89-
const auto root = local.getRoot();
89+
auto *genericEnv = local->getGenericEnvironment();
9090

91-
// Add this root local archetype if it was not seen yet.
91+
// Add this local archetype's environment if it was not seen yet.
9292
// We don't use a set here, because the number of open archetypes
9393
// is usually very small and using a real set may introduce too
9494
// much overhead.
95-
if (std::find(rootLocalArchetypes.begin(), rootLocalArchetypes.end(),
96-
root) == rootLocalArchetypes.end())
97-
rootLocalArchetypes.push_back(root);
95+
if (std::find(genericEnvs.begin(), genericEnvs.end(),
96+
genericEnv) == genericEnvs.end())
97+
genericEnvs.push_back(genericEnv);
9898
}
9999
});
100100
}
@@ -113,20 +113,11 @@ void TypeDependentOperandCollector::collect(SubstitutionMap subs) {
113113
/// for those dependencies to the given vector.
114114
void TypeDependentOperandCollector::addTo(SmallVectorImpl<SILValue> &operands,
115115
SILFunction &F) {
116-
size_t firstArchetypeOperand = operands.size();
117-
for (CanLocalArchetypeType archetype : rootLocalArchetypes) {
118-
SILValue def = F.getModule().getRootLocalArchetypeDef(archetype, &F);
116+
for (GenericEnvironment *genericEnv : genericEnvs) {
117+
SILValue def = F.getModule().getLocalGenericEnvironmentDef(genericEnv, &F);
119118
assert(def->getFunction() == &F &&
120-
"def of root local archetype is in wrong function");
121-
122-
// The archetypes in rootLocalArchetypes have already been uniqued,
123-
// but a single instruction can open multiple archetypes (e.g.
124-
// open_pack_element), so we also unique the actual operand values.
125-
// As above, we assume there are very few values in practice and so
126-
// a linear scan is better than maintaining a set.
127-
if (std::find(operands.begin() + firstArchetypeOperand, operands.end(),
128-
def) == operands.end())
129-
operands.push_back(def);
119+
"def of local environment is in wrong function");
120+
operands.push_back(def);
130121
}
131122
if (hasDynamicSelf)
132123
operands.push_back(F.getDynamicSelfMetadata());

lib/SIL/IR/SILModule.cpp

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,9 @@ void *SILModule::allocateInst(unsigned Size, unsigned Align) const {
208208

209209
void SILModule::willDeleteInstruction(SILInstruction *I) {
210210
// Update RootLocalArchetypeDefs.
211-
I->forEachDefinedLocalArchetype([&](CanLocalArchetypeType archeTy,
212-
SILValue dependency) {
213-
LocalArchetypeKey key = {archeTy, I->getFunction()};
211+
I->forEachDefinedLocalEnvironment([&](GenericEnvironment *genericEnv,
212+
SILValue dependency) {
213+
LocalArchetypeKey key = {genericEnv, I->getFunction()};
214214
// In case `willDeleteInstruction` is called twice for the
215215
// same instruction, we need to check if the archetype is really
216216
// still in the map for this instruction.
@@ -674,20 +674,25 @@ void SILModule::registerDeserializationNotificationHandler(
674674
deserializationNotificationHandlers.add(std::move(handler));
675675
}
676676

677-
SILValue SILModule::getRootLocalArchetypeDef(CanLocalArchetypeType archetype,
678-
SILFunction *inFunction) {
679-
assert(archetype->isRoot());
680-
681-
SILValue &def = RootLocalArchetypeDefs[{archetype, inFunction}];
677+
SILValue SILModule::getLocalGenericEnvironmentDef(GenericEnvironment *genericEnv,
678+
SILFunction *inFunction) {
679+
SILValue &def = RootLocalArchetypeDefs[{genericEnv, inFunction}];
682680
if (!def) {
683681
numUnresolvedLocalArchetypes++;
684682
def = ::new PlaceholderValue(inFunction,
685-
SILType::getPrimitiveAddressType(archetype));
683+
SILType::getPrimitiveAddressType(
684+
inFunction->getASTContext().TheEmptyTupleType));
686685
}
687686

688687
return def;
689688
}
690689

690+
SILValue SILModule::getRootLocalArchetypeDef(CanLocalArchetypeType archetype,
691+
SILFunction *inFunction) {
692+
return getLocalGenericEnvironmentDef(archetype->getGenericEnvironment(),
693+
inFunction);
694+
}
695+
691696
void SILModule::reclaimUnresolvedLocalArchetypeDefinitions() {
692697
llvm::DenseMap<LocalArchetypeKey, SILValue> newLocalArchetypeDefs;
693698

@@ -757,21 +762,21 @@ unsigned SILModule::getCaseIndex(EnumElementDecl *enumElement) {
757762
}
758763

759764
void SILModule::notifyAddedInstruction(SILInstruction *inst) {
760-
inst->forEachDefinedLocalArchetype([&](CanLocalArchetypeType archeTy,
761-
SILValue dependency) {
762-
SILValue &val = RootLocalArchetypeDefs[{archeTy, inst->getFunction()}];
765+
inst->forEachDefinedLocalEnvironment([&](GenericEnvironment *genericEnv,
766+
SILValue dependency) {
767+
SILValue &val = RootLocalArchetypeDefs[{genericEnv, inst->getFunction()}];
763768
if (val) {
764769
if (!isa<PlaceholderValue>(val)) {
765770
// Print a useful error message (and not just abort with an assert).
766-
llvm::errs() << "re-definition of root local archetype in function "
771+
llvm::errs() << "re-definition of local environment in function "
767772
<< inst->getFunction()->getName() << ":\n";
768773
inst->print(llvm::errs());
769774
llvm::errs() << "previously defined in function "
770775
<< val->getFunction()->getName() << ":\n";
771776
val->print(llvm::errs());
772777
abort();
773778
}
774-
// The local archetype was unresolved so far. Replace the placeholder
779+
// The local environment was unresolved so far. Replace the placeholder
775780
// by inst.
776781
auto *placeholder = cast<PlaceholderValue>(val);
777782
placeholder->replaceAllUsesWith(dependency);
@@ -792,13 +797,13 @@ void SILModule::notifyMovedInstruction(SILInstruction *inst,
792797
}
793798
}
794799

795-
inst->forEachDefinedLocalArchetype([&](CanLocalArchetypeType archeTy,
796-
SILValue dependency) {
797-
LocalArchetypeKey key = {archeTy, fromFunction};
800+
inst->forEachDefinedLocalEnvironment([&](GenericEnvironment *genericEnv,
801+
SILValue dependency) {
802+
LocalArchetypeKey key = {genericEnv, fromFunction};
798803
assert(RootLocalArchetypeDefs.lookup(key) == dependency &&
799804
"archetype def was not registered");
800805
RootLocalArchetypeDefs.erase(key);
801-
RootLocalArchetypeDefs[{archeTy, inst->getFunction()}] = dependency;
806+
RootLocalArchetypeDefs[{genericEnv, inst->getFunction()}] = dependency;
802807
});
803808
}
804809

0 commit comments

Comments
 (0)