Skip to content

Commit 3b5cd06

Browse files
authored
Merge pull request #69674 from eeckstein/fix-generic-embedded-classes
Fix specialization of generic classes in embedded swift
2 parents 031f112 + b33bb38 commit 3b5cd06

File tree

8 files changed

+104
-38
lines changed

8 files changed

+104
-38
lines changed

include/swift/SILOptimizer/Utils/Generics.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,14 @@ class ReabstractionInfo {
124124
// callee.
125125
SubstitutionMap ClonerParamSubMap;
126126

127-
// Reference to the original generic non-specialized callee function.
127+
// Reference to the original generic non-specialized callee function, if available
128128
SILFunction *Callee = nullptr;
129129

130+
// The method to specialize. This must be not null if Callee is null.
131+
SILDeclRef methodDecl;
132+
133+
SILModule *M = nullptr;
134+
130135
// The module the specialization is created in.
131136
ModuleDecl *TargetModule = nullptr;
132137

@@ -186,7 +191,7 @@ class ReabstractionInfo {
186191
FunctionSignaturePartialSpecializer &FSPS);
187192

188193
public:
189-
ReabstractionInfo() {}
194+
ReabstractionInfo(SILModule &M) : M(&M) {}
190195

191196
/// Constructs the ReabstractionInfo for generic function \p Callee with
192197
/// substitutions \p ParamSubs.
@@ -208,9 +213,11 @@ class ReabstractionInfo {
208213
bool isPrespecialization = false);
209214

210215
ReabstractionInfo(CanSILFunctionType substitutedType,
216+
SILDeclRef methodDecl,
211217
SILModule &M) :
212218
SubstitutedType(substitutedType),
213-
isWholeModule(M.isWholeModule()) {}
219+
methodDecl(methodDecl),
220+
M(&M), isWholeModule(M.isWholeModule()) {}
214221

215222

216223
bool isPrespecialized() const { return isPrespecialization; }
@@ -326,13 +333,10 @@ class ReabstractionInfo {
326333

327334
SILFunction *getNonSpecializedFunction() const { return Callee; }
328335

329-
/// Map type into a context of the specialized function.
330-
Type mapTypeIntoContext(Type type) const;
331-
332336
/// Map SIL type into a context of the specialized function.
333337
SILType mapTypeIntoContext(SILType type) const;
334338

335-
SILModule &getModule() const { return Callee->getModule(); }
339+
SILModule &getModule() const { return *M; }
336340

337341
/// Returns true if generic specialization is possible.
338342
bool canBeSpecialized() const;

lib/IRGen/ClassMetadataVisitor.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,18 @@ template <class Impl> class ClassMetadataVisitor
6767
: super(IGM), Target(target), VTable(vtable) {}
6868

6969
public:
70+
71+
// Layout in embedded mode while considering the class type.
72+
// This is important for adding the right superclass pointer.
73+
// The regular `layout` method can be used for layout tasks for which the
74+
// actual superclass pointer is not relevant.
75+
void layoutEmbedded(CanType classTy) {
76+
asImpl().noteAddressPoint();
77+
asImpl().addEmbeddedSuperclass(classTy);
78+
asImpl().addDestructorFunction();
79+
addEmbeddedClassMembers(Target);
80+
}
81+
7082
void layout() {
7183
static_assert(MetadataAdjustmentIndex::Class == 3,
7284
"Adjustment index must be synchronized with this layout");

lib/IRGen/GenMeta.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3903,6 +3903,16 @@ namespace {
39033903
llvm_unreachable("covered switch");
39043904
}
39053905

3906+
void addEmbeddedSuperclass(CanType classTy) {
3907+
CanType superclass = asImpl().getSuperclassTypeForMetadata();
3908+
if (!superclass) {
3909+
B.addNullPointer(IGM.TypeMetadataPtrTy);
3910+
return;
3911+
}
3912+
CanType superTy = classTy->getSuperclass()->getCanonicalType();
3913+
B.add(IGM.getAddrOfTypeMetadata(superTy));
3914+
}
3915+
39063916
void addSuperclass() {
39073917
if (asImpl().shouldAddNullSuperclass()) {
39083918
B.addNullPointer(IGM.TypeMetadataPtrTy);
@@ -5025,7 +5035,7 @@ static void emitEmbeddedVTable(IRGenModule &IGM, CanType classTy,
50255035

50265036
FixedClassMetadataBuilder builder(IGM, classDecl, init, fragileLayout,
50275037
vtable);
5028-
builder.layout();
5038+
builder.layoutEmbedded(classTy);
50295039
bool canBeConstant = builder.canBeConstant();
50305040

50315041
StringRef section{};

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3857,7 +3857,11 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
38573857
auto member = CMI->getMember();
38583858
auto overrideTy =
38593859
TC.getConstantOverrideType(F.getTypeExpansionContext(), member);
3860-
if (CMI->getModule().getStage() != SILStage::Lowered) {
3860+
3861+
SILModule &mod = CMI->getModule();
3862+
bool embedded = mod.getASTContext().LangOpts.hasFeature(Feature::Embedded);
3863+
3864+
if (mod.getStage() != SILStage::Lowered && !embedded) {
38613865
requireSameType(
38623866
CMI->getType(), SILType::getPrimitiveObjectType(overrideTy),
38633867
"result type of class_method must match abstracted type of method");

lib/SILOptimizer/Transforms/EagerSpecializer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -857,7 +857,7 @@ void EagerSpecializerTransform::run() {
857857
// That means we are loading it from another module. In this case, we
858858
// don't want to create a pre-specialization.
859859
SpecializedFuncs.push_back(nullptr);
860-
ReInfoVec.emplace_back(ReabstractionInfo());
860+
ReInfoVec.emplace_back(ReabstractionInfo(F.getModule()));
861861
continue;
862862
}
863863
ReInfoVec.emplace_back(FuncBuilder.getModule().getSwiftModule(),

lib/SILOptimizer/Transforms/VTableSpecializer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ bool swift::specializeClassMethodInst(ClassMethodInst *cm) {
204204
SILType substitutedType =
205205
funcTy.substGenericArgs(m, subs, TypeExpansionContext::minimal());
206206

207-
ReabstractionInfo reInfo(substitutedType.getAs<SILFunctionType>(), m);
207+
ReabstractionInfo reInfo(substitutedType.getAs<SILFunctionType>(), cm->getMember(), m);
208208
reInfo.createSubstitutedAndSpecializedTypes();
209209
CanSILFunctionType finalFuncTy = reInfo.getSpecializedType();
210210
SILType finalSILTy = SILType::getPrimitiveObjectType(finalFuncTy);

lib/SILOptimizer/Utils/Generics.cpp

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ bool ReabstractionInfo::prepareAndCheck(ApplySite Apply, SILFunction *Callee,
649649

650650
bool ReabstractionInfo::canBeSpecialized(ApplySite Apply, SILFunction *Callee,
651651
SubstitutionMap ParamSubs) {
652-
ReabstractionInfo ReInfo;
652+
ReabstractionInfo ReInfo(Callee->getModule());
653653
return ReInfo.prepareAndCheck(Apply, Callee, ParamSubs);
654654
}
655655

@@ -659,6 +659,7 @@ ReabstractionInfo::ReabstractionInfo(
659659
bool ConvertIndirectToDirect, bool dropMetatypeArgs, OptRemark::Emitter *ORE)
660660
: ConvertIndirectToDirect(ConvertIndirectToDirect),
661661
dropMetatypeArgs(dropMetatypeArgs),
662+
M(&Callee->getModule()),
662663
TargetModule(targetModule), isWholeModule(isWholeModule),
663664
Serialized(Serialized) {
664665
if (!prepareAndCheck(Apply, Callee, ParamSubs, ORE))
@@ -772,8 +773,6 @@ bool ReabstractionInfo::isPartialSpecialization() const {
772773
}
773774

774775
void ReabstractionInfo::createSubstitutedAndSpecializedTypes() {
775-
auto &M = Callee->getModule();
776-
777776
// Find out how the function type looks like after applying the provided
778777
// substitutions.
779778
if (!SubstitutedType) {
@@ -792,7 +791,7 @@ void ReabstractionInfo::createSubstitutedAndSpecializedTypes() {
792791
TrivialArgs.resize(NumArgs);
793792
droppedMetatypeArgs.resize(NumArgs);
794793

795-
SILFunctionConventions substConv(SubstitutedType, M);
794+
SILFunctionConventions substConv(SubstitutedType, getModule());
796795
TypeExpansionContext resilienceExp = getResilienceExpansion();
797796
TypeExpansionContext minimalExp(ResilienceExpansion::Minimal,
798797
TargetModule, isWholeModule);
@@ -863,26 +862,25 @@ void ReabstractionInfo::createSubstitutedAndSpecializedTypes() {
863862
// Produce a specialized type, which is the substituted type with
864863
// the parameters/results passing conventions adjusted according
865864
// to the conversions selected above.
866-
SpecializedType = createSpecializedType(SubstitutedType, M);
865+
SpecializedType = createSpecializedType(SubstitutedType, getModule());
867866
}
868867

869868
ReabstractionInfo::TypeCategory ReabstractionInfo::
870869
getReturnTypeCategory(const SILResultInfo &RI,
871870
const SILFunctionConventions &substConv,
872871
TypeExpansionContext typeExpansion) {
873-
auto &M = Callee->getModule();
874872
auto ResultTy = substConv.getSILType(RI, typeExpansion);
875873
ResultTy = Callee->mapTypeIntoContext(ResultTy);
876-
auto &TL = M.Types.getTypeLowering(ResultTy, typeExpansion);
874+
auto &TL = getModule().Types.getTypeLowering(ResultTy, typeExpansion);
877875

878876
if (!TL.isLoadable())
879877
return NotLoadable;
880878

881-
if (RI.getReturnValueType(M, SubstitutedType, typeExpansion)
879+
if (RI.getReturnValueType(getModule(), SubstitutedType, typeExpansion)
882880
->isVoid())
883881
return NotLoadable;
884882

885-
if (!shouldExpand(M, ResultTy))
883+
if (!shouldExpand(getModule(), ResultTy))
886884
return NotLoadable;
887885

888886
return TL.isTrivial() ? LoadableAndTrivial : Loadable;
@@ -892,10 +890,9 @@ ReabstractionInfo::TypeCategory ReabstractionInfo::
892890
getParamTypeCategory(const SILParameterInfo &PI,
893891
const SILFunctionConventions &substConv,
894892
TypeExpansionContext typeExpansion) {
895-
auto &M = Callee->getModule();
896893
auto ParamTy = substConv.getSILType(PI, typeExpansion);
897-
ParamTy = Callee->mapTypeIntoContext(ParamTy);
898-
auto &TL = M.Types.getTypeLowering(ParamTy, typeExpansion);
894+
ParamTy = mapTypeIntoContext(ParamTy);
895+
auto &TL = getModule().Types.getTypeLowering(ParamTy, typeExpansion);
899896

900897
if (!TL.isLoadable())
901898
return NotLoadable;
@@ -908,7 +905,6 @@ CanSILFunctionType
908905
ReabstractionInfo::createSubstitutedType(SILFunction *OrigF,
909906
SubstitutionMap SubstMap,
910907
bool HasUnboundGenericParams) {
911-
auto &M = OrigF->getModule();
912908
if ((SpecializedGenericSig &&
913909
SpecializedGenericSig->areAllParamsConcrete()) ||
914910
!HasUnboundGenericParams) {
@@ -920,8 +916,8 @@ ReabstractionInfo::createSubstitutedType(SILFunction *OrigF,
920916

921917
auto lowered = OrigF->getLoweredFunctionType();
922918
auto genSub =
923-
lowered->substGenericArgs(M, SubstMap, getResilienceExpansion());
924-
auto unsub = genSub->getUnsubstitutedType(M);
919+
lowered->substGenericArgs(getModule(), SubstMap, getResilienceExpansion());
920+
auto unsub = genSub->getUnsubstitutedType(getModule());
925921
auto specialized = CanSpecializedGenericSig.getReducedType(unsub);
926922

927923
// First substitute concrete types into the existing function type.
@@ -935,7 +931,7 @@ ReabstractionInfo::createSubstitutedType(SILFunction *OrigF,
935931
CanSpecializedGenericSig, FnTy->getExtInfo(), FnTy->getCoroutineKind(),
936932
FnTy->getCalleeConvention(), FnTy->getParameters(), FnTy->getYields(),
937933
FnTy->getResults(), FnTy->getOptionalErrorResult(),
938-
FnTy->getPatternSubstitutions(), SubstitutionMap(), M.getASTContext(),
934+
FnTy->getPatternSubstitutions(), SubstitutionMap(), getModule().getASTContext(),
939935
FnTy->getWitnessMethodConformanceOrInvalid());
940936

941937
// This is an interface type. It should not have any archetypes.
@@ -972,6 +968,16 @@ CanSILFunctionType ReabstractionInfo::createThunkType(PartialApplyInst *forPAI)
972968
return newFnTy;
973969
}
974970

971+
SILType ReabstractionInfo::mapTypeIntoContext(SILType type) const {
972+
if (Callee) {
973+
return Callee->mapTypeIntoContext(type);
974+
}
975+
assert(!methodDecl.isNull());
976+
if (auto *genericEnv = M->Types.getConstantGenericEnvironment(methodDecl))
977+
return genericEnv->mapTypeIntoContext(getModule(), type);
978+
return type;
979+
}
980+
975981
/// Convert the substituted function type into a specialized function type based
976982
/// on the ReabstractionInfo.
977983
CanSILFunctionType ReabstractionInfo::
@@ -1081,15 +1087,13 @@ void ReabstractionInfo::performFullSpecializationPreparation(
10811087
assert((!EnablePartialSpecialization || !HasUnboundGenericParams) &&
10821088
"Only full specializations are handled here");
10831089

1084-
SILModule &M = Callee->getModule();
1085-
10861090
this->Callee = Callee;
10871091

10881092
// Get the original substitution map.
10891093
ClonerParamSubMap = ParamSubs;
10901094

10911095
SubstitutedType = Callee->getLoweredFunctionType()->substGenericArgs(
1092-
M, ClonerParamSubMap, getResilienceExpansion());
1096+
getModule(), ClonerParamSubMap, getResilienceExpansion());
10931097
CallerParamSubMap = {};
10941098
createSubstitutedAndSpecializedTypes();
10951099
}
@@ -1889,8 +1893,6 @@ void FunctionSignaturePartialSpecializer::createSpecializedGenericSignature(
18891893
void ReabstractionInfo::performPartialSpecializationPreparation(
18901894
SILFunction *Caller, SILFunction *Callee,
18911895
SubstitutionMap ParamSubs) {
1892-
SILModule &M = Callee->getModule();
1893-
18941896
// Caller is the SILFunction containing the apply instruction.
18951897
CanGenericSignature CallerGenericSig;
18961898
GenericEnvironment *CallerGenericEnv = nullptr;
@@ -1910,7 +1912,7 @@ void ReabstractionInfo::performPartialSpecializationPreparation(
19101912
llvm::dbgs() << "Callee generic signature is:\n";
19111913
CalleeGenericSig->print(llvm::dbgs()));
19121914

1913-
FunctionSignaturePartialSpecializer FSPS(M,
1915+
FunctionSignaturePartialSpecializer FSPS(getModule(),
19141916
CallerGenericSig, CallerGenericEnv,
19151917
CalleeGenericSig, CalleeGenericEnv,
19161918
ParamSubs);
@@ -1968,7 +1970,7 @@ ReabstractionInfo::ReabstractionInfo(ModuleDecl *targetModule,
19681970
bool isWholeModule, SILFunction *Callee,
19691971
GenericSignature SpecializedSig,
19701972
bool isPrespecialization)
1971-
: TargetModule(targetModule), isWholeModule(isWholeModule),
1973+
: M(&Callee->getModule()), TargetModule(targetModule), isWholeModule(isWholeModule),
19721974
isPrespecialization(isPrespecialization) {
19731975
Serialized =
19741976
this->isPrespecialization ? IsNotSerialized : Callee->isSerialized();
@@ -1979,13 +1981,11 @@ ReabstractionInfo::ReabstractionInfo(ModuleDecl *targetModule,
19791981
this->Callee = Callee;
19801982
ConvertIndirectToDirect = true;
19811983

1982-
SILModule &M = Callee->getModule();
1983-
19841984
auto CalleeGenericSig =
19851985
Callee->getLoweredFunctionType()->getInvocationGenericSignature();
19861986
auto *CalleeGenericEnv = Callee->getGenericEnvironment();
19871987

1988-
FunctionSignaturePartialSpecializer FSPS(M,
1988+
FunctionSignaturePartialSpecializer FSPS(getModule(),
19891989
CalleeGenericSig, CalleeGenericEnv,
19901990
SpecializedSig);
19911991

@@ -3091,7 +3091,7 @@ void swift::trySpecializeApplyOfGeneric(
30913091

30923092
// Check if there is a pre-specialization available in a library.
30933093
SpecializedFunction prespecializedF{};
3094-
ReabstractionInfo prespecializedReInfo;
3094+
ReabstractionInfo prespecializedReInfo(FuncBuilder.getModule());
30953095
bool replacePartialApplyWithoutReabstraction = false;
30963096

30973097
if (usePrespecialized(FuncBuilder, Apply, RefF, ReInfo, prespecializedReInfo,

test/embedded/generic-classes.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %target-run-simple-swift(%S/Inputs/print.swift -enable-experimental-feature Embedded -parse-as-library -runtime-compatibility-version none -wmo -Xfrontend -disable-objc-interop) | %FileCheck %s
2+
3+
// REQUIRES: executable_test
4+
// REQUIRES: optimized_stdlib
5+
// REQUIRES: VENDOR=apple
6+
// REQUIRES: OS=macosx
7+
8+
protocol Fooable {
9+
func foo()
10+
}
11+
12+
class GenericFooableClass<T>: Fooable {
13+
func foo() { print("GenericFooableClass<T>.foo") }
14+
}
15+
16+
class GenericFooableSubClass<T>: GenericFooableClass<T> {
17+
override func foo() { print("GenericFooableSubClass<T>.foo") }
18+
}
19+
20+
func makeItFoo<F: Fooable>(f: F) {
21+
f.foo()
22+
}
23+
24+
@main
25+
struct Main {
26+
static func main() {
27+
let f = GenericFooableClass<Int>()
28+
makeItFoo(f: f)
29+
let g: GenericFooableClass = GenericFooableSubClass<Int>()
30+
makeItFoo(f: g)
31+
}
32+
}
33+
34+
// CHECK: GenericFooableClass<T>.foo
35+
// CHECK: GenericFooableSubClass<T>.foo
36+

0 commit comments

Comments
 (0)