Skip to content

Commit 43c7310

Browse files
committed
SILOptimizer: Move combineSubstitutionMaps() to Devirtualize.cpp
1 parent 7648a31 commit 43c7310

File tree

3 files changed

+93
-117
lines changed

3 files changed

+93
-117
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;

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/SILOptimizer/Utils/Devirtualize.cpp

Lines changed: 93 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#define DEBUG_TYPE "sil-devirtualize-utility"
1414
#include "swift/SILOptimizer/Utils/Devirtualize.h"
15+
#include "swift/AST/ConformanceLookup.h"
1516
#include "swift/AST/Decl.h"
1617
#include "swift/AST/GenericSignature.h"
1718
#include "swift/AST/ProtocolConformance.h"
@@ -386,6 +387,93 @@ swift::getExactDynamicTypeOfUnderlyingObject(SILValue instance,
386387
return getExactDynamicType(instance, cha, /* forUnderlyingObject */ true);
387388
}
388389

390+
/// Combine two substitution maps as follows.
391+
///
392+
/// The result is written in terms of the generic parameters of 'genericSig'.
393+
///
394+
/// Generic parameters with a depth less than 'firstDepth'
395+
/// come from 'firstSubMap'.
396+
///
397+
/// Generic parameters with a depth greater than 'firstDepth' come from
398+
/// 'secondSubMap', but are looked up starting with a depth or index of
399+
/// 'secondDepth'.
400+
///
401+
/// The 'how' parameter determines if we're looking at the depth or index.
402+
static SubstitutionMap
403+
combineSubstitutionMaps(SubstitutionMap firstSubMap,
404+
SubstitutionMap secondSubMap,
405+
unsigned firstDepth,
406+
unsigned secondDepth,
407+
GenericSignature genericSig) {
408+
auto &ctx = genericSig->getASTContext();
409+
410+
auto replaceGenericParameter = [&](Type type) -> std::optional<Type> {
411+
if (auto gp = type->getAs<GenericTypeParamType>()) {
412+
if (gp->getDepth() < firstDepth)
413+
return Type();
414+
return Type(GenericTypeParamType::get(gp->isParameterPack(),
415+
gp->getDepth() + secondDepth -
416+
firstDepth,
417+
gp->getIndex(), ctx));
418+
}
419+
420+
return std::nullopt;
421+
};
422+
423+
return SubstitutionMap::get(
424+
genericSig,
425+
[&](SubstitutableType *type) {
426+
if (auto replacement = replaceGenericParameter(type))
427+
if (*replacement)
428+
return replacement->subst(secondSubMap);
429+
return Type(type).subst(firstSubMap);
430+
},
431+
[&](CanType type, Type substType, ProtocolDecl *proto) {
432+
if (auto replacement = type.transformRec(replaceGenericParameter))
433+
return secondSubMap.lookupConformance(replacement->getCanonicalType(),
434+
proto);
435+
if (auto conformance = firstSubMap.lookupConformance(type, proto))
436+
return conformance;
437+
438+
// We might not have enough information in the substitution maps alone.
439+
//
440+
// Eg,
441+
//
442+
// class Base<T1> {
443+
// func foo<U1>(_: U1) where T1 : P {}
444+
// }
445+
//
446+
// class Derived<T2> : Base<Foo<T2>> {
447+
// override func foo<U2>(_: U2) where T2 : Q {}
448+
// }
449+
//
450+
// Suppose we're devirtualizing a call to Base.foo() on a value whose
451+
// type is known to be Derived<Bar>. We start with substitutions written
452+
// in terms of Base.foo()'s generic signature:
453+
//
454+
// <T1, U1 where T1 : P>
455+
// T1 := Foo<Bar>
456+
// T1 : P := Foo<Bar> : P
457+
//
458+
// We want to build substitutions in terms of Derived.foo()'s
459+
// generic signature:
460+
//
461+
// <T2, U2 where T2 : Q>
462+
// T2 := Bar
463+
// T2 : Q := Bar : Q
464+
//
465+
// The conformance Bar : Q is difficult to recover in the general case.
466+
//
467+
// Some combination of storing substitution maps in BoundGenericTypes
468+
// as well as for method overrides would solve this, but for now, just
469+
// punt to module lookup.
470+
if (substType->isTypeParameter())
471+
return ProtocolConformanceRef(proto);
472+
473+
return swift::lookupConformance(substType, proto);
474+
});
475+
}
476+
389477
// Start with the substitutions from the apply.
390478
// Try to propagate them to find out the real substitutions required
391479
// to invoke the method.
@@ -440,13 +528,11 @@ getSubstitutionsForCallee(SILModule &module, CanSILFunctionType baseCalleeType,
440528

441529
auto baseCalleeSig = baseCalleeType->getInvocationGenericSignature();
442530

443-
return
444-
SubstitutionMap::combineSubstitutionMaps(baseSubMap,
445-
origSubMap,
446-
CombineSubstitutionMaps::AtDepth,
447-
baseDepth,
448-
origDepth,
449-
baseCalleeSig);
531+
return combineSubstitutionMaps(baseSubMap,
532+
origSubMap,
533+
baseDepth,
534+
origDepth,
535+
baseCalleeSig);
450536
}
451537

452538
// Return the new apply and true if a cast required CFG modification.

0 commit comments

Comments
 (0)