Skip to content

Commit 71612e6

Browse files
authored
Merge pull request #69678 from kubamracek/embedded-devirt
[embedded] Fix class_method devirtualizer to consider specialized VTables
2 parents 5533886 + afced31 commit 71612e6

File tree

5 files changed

+52
-36
lines changed

5 files changed

+52
-36
lines changed

include/swift/SILOptimizer/Utils/Devirtualize.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,21 +73,21 @@ tryDevirtualizeApply(ApplySite AI, ClassHierarchyAnalysis *CHA,
7373
bool isMandatory = false);
7474
bool canDevirtualizeApply(FullApplySite AI, ClassHierarchyAnalysis *CHA);
7575
bool canDevirtualizeClassMethod(FullApplySite AI, ClassDecl *CD,
76+
CanType ClassType,
7677
OptRemark::Emitter *ORE = nullptr,
7778
bool isEffectivelyFinalMethod = false);
7879
SILFunction *getTargetClassMethod(SILModule &M, ClassDecl *CD,
79-
MethodInst *MI);
80+
CanType ClassType, MethodInst *MI);
8081
CanType getSelfInstanceType(CanType ClassOrMetatypeType);
8182

8283
/// Devirtualize the given apply site, which is known to be devirtualizable.
8384
///
8485
/// The caller must call deleteDevirtualizedApply on the original apply site.
8586
///
8687
/// Return the new apply and true if the CFG was also modified.
87-
std::pair<FullApplySite, bool> devirtualizeClassMethod(FullApplySite AI,
88-
SILValue ClassInstance,
89-
ClassDecl *CD,
90-
OptRemark::Emitter *ORE);
88+
std::pair<FullApplySite, bool>
89+
devirtualizeClassMethod(FullApplySite AI, SILValue ClassInstance, ClassDecl *CD,
90+
CanType classType, OptRemark::Emitter *ORE);
9191

9292
/// Attempt to devirtualize the given apply site, which is known to be
9393
/// of a class method. If this fails, the returned FullApplySite will be null.
@@ -98,7 +98,8 @@ std::pair<FullApplySite, bool> devirtualizeClassMethod(FullApplySite AI,
9898
/// Return the new apply and true if the CFG was also modified.
9999
std::pair<FullApplySite, bool>
100100
tryDevirtualizeClassMethod(FullApplySite AI, SILValue ClassInstance,
101-
ClassDecl *CD, OptRemark::Emitter *ORE,
101+
ClassDecl *CD, CanType ClassType,
102+
OptRemark::Emitter *ORE,
102103
bool isEffectivelyFinalMethod = false);
103104

104105
/// Attempt to devirtualize the given apply site, which is known to be

lib/SILOptimizer/Mandatory/DiagnoseInfiniteRecursion.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ static bool isRecursiveCall(FullApplySite applySite) {
9090
if (classDecl && classDecl->getModuleContext() != module.getSwiftModule())
9191
return false;
9292

93-
SILFunction *method = getTargetClassMethod(module, classDecl, CMI);
93+
SILFunction *method = getTargetClassMethod(module, classDecl, classType, CMI);
9494
if (method != parentFunc)
9595
return false;
9696

lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -123,15 +123,15 @@ static FullApplySite CloneApply(FullApplySite AI, SILValue SelfArg,
123123
/// Insert monomorphic inline caches for a specific class or metatype
124124
/// type \p SubClassTy.
125125
static FullApplySite speculateMonomorphicTarget(FullApplySite AI,
126-
CanType SubType,
127-
ClassDecl *CD,
126+
CanType SubType, ClassDecl *CD,
127+
CanType ClassType,
128128
CheckedCastBranchInst *&CCBI) {
129129
if (SubType->hasDynamicSelfType())
130130
return FullApplySite();
131131

132132
CCBI = nullptr;
133133
// Bail if this class_method cannot be devirtualized.
134-
if (!canDevirtualizeClassMethod(AI, CD))
134+
if (!canDevirtualizeClassMethod(AI, CD, ClassType))
135135
return FullApplySite();
136136

137137
// Can't speculate begin_apply yet.
@@ -228,9 +228,9 @@ static FullApplySite speculateMonomorphicTarget(FullApplySite AI,
228228
++NumTargetsPredicted;
229229

230230
// Devirtualize the apply instruction on the identical path.
231-
auto NewInst =
232-
devirtualizeClassMethod(IdenAI, DownCastedClassInstance, CD, nullptr)
233-
.first;
231+
auto NewInst = devirtualizeClassMethod(IdenAI, DownCastedClassInstance, CD,
232+
ClassType, nullptr)
233+
.first;
234234
assert(NewInst && "Expected to be able to devirtualize apply!");
235235
(void)NewInst;
236236

@@ -401,15 +401,16 @@ static bool tryToSpeculateTarget(FullApplySite AI, ClassHierarchyAnalysis *CHA,
401401
ClassHierarchyAnalysis::ClassList Subs;
402402
if (isDefaultCaseKnown(CHA, AI, CD, Subs)) {
403403
auto NewInst =
404-
tryDevirtualizeClassMethod(AI, SubTypeValue, CD, &ORE).first;
404+
tryDevirtualizeClassMethod(AI, SubTypeValue, CD, ClassType, &ORE)
405+
.first;
405406
if (NewInst)
406407
deleteDevirtualizedApply(AI);
407408
return bool(NewInst);
408409
}
409410

410411
LLVM_DEBUG(llvm::dbgs() << "Inserting monomorphic speculative call for "
411412
"class " << CD->getName() << "\n");
412-
return !!speculateMonomorphicTarget(AI, SubType, CD, LastCCBI);
413+
return !!speculateMonomorphicTarget(AI, SubType, CD, ClassType, LastCCBI);
413414
}
414415

415416
// True if any instructions were changed or generated.
@@ -435,7 +436,7 @@ static bool tryToSpeculateTarget(FullApplySite AI, ClassHierarchyAnalysis *CHA,
435436

436437
// Try to devirtualize the static class of instance
437438
// if it is possible.
438-
if (auto F = getTargetClassMethod(M, CD, CMI)) {
439+
if (auto F = getTargetClassMethod(M, CD, ClassType, CMI)) {
439440
// Do not devirtualize if a method in the base class is marked
440441
// as non-optimizable. This way it is easy to disable the
441442
// devirtualization of this method in the base class and
@@ -444,7 +445,8 @@ static bool tryToSpeculateTarget(FullApplySite AI, ClassHierarchyAnalysis *CHA,
444445
return false;
445446
}
446447

447-
auto FirstAI = speculateMonomorphicTarget(AI, SubType, CD, LastCCBI);
448+
auto FirstAI =
449+
speculateMonomorphicTarget(AI, SubType, CD, ClassType, LastCCBI);
448450
if (FirstAI) {
449451
Changed = true;
450452
AI = FirstAI;
@@ -506,7 +508,8 @@ static bool tryToSpeculateTarget(FullApplySite AI, ClassHierarchyAnalysis *CHA,
506508
}
507509

508510
// Pass the metatype of the subclass.
509-
auto NewAI = speculateMonomorphicTarget(AI, ClassOrMetatypeType, S, LastCCBI);
511+
auto NewAI = speculateMonomorphicTarget(AI, ClassOrMetatypeType, S,
512+
CanClassType, LastCCBI);
510513
if (!NewAI) {
511514
++NotHandledSubsNum;
512515
continue;
@@ -562,7 +565,8 @@ static bool tryToSpeculateTarget(FullApplySite AI, ClassHierarchyAnalysis *CHA,
562565
return true;
563566
}
564567
auto NewInst =
565-
tryDevirtualizeClassMethod(AI, SubTypeValue, CD, nullptr).first;
568+
tryDevirtualizeClassMethod(AI, SubTypeValue, CD, ClassType, nullptr)
569+
.first;
566570
if (NewInst) {
567571
ORE.emit(RB);
568572
deleteDevirtualizedApply(AI);

lib/SILOptimizer/Utils/Devirtualize.cpp

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -646,11 +646,17 @@ void swift::deleteDevirtualizedApply(ApplySite old) {
646646
}
647647

648648
SILFunction *swift::getTargetClassMethod(SILModule &module, ClassDecl *cd,
649-
MethodInst *mi) {
650-
assert((isa<ClassMethodInst>(mi) || isa<SuperMethodInst>(mi))
651-
&& "Only class_method and super_method instructions are supported");
649+
CanType classType, MethodInst *mi) {
650+
assert((isa<ClassMethodInst>(mi) || isa<SuperMethodInst>(mi)) &&
651+
"Only class_method and super_method instructions are supported");
652652

653653
SILDeclRef member = mi->getMember();
654+
655+
SILType silType = SILType::getPrimitiveObjectType(classType);
656+
if (auto *vtable = module.lookUpSpecializedVTable(silType)) {
657+
return vtable->getEntry(module, member)->getImplementation();
658+
}
659+
654660
return module.lookUpFunctionInVTable(cd, member);
655661
}
656662

@@ -672,6 +678,7 @@ CanType swift::getSelfInstanceType(CanType classOrMetatypeType) {
672678
/// \p cd is the class declaration we are devirtualizing for.
673679
/// return true if it is possible to devirtualize, false - otherwise.
674680
bool swift::canDevirtualizeClassMethod(FullApplySite applySite, ClassDecl *cd,
681+
CanType classType,
675682
OptRemark::Emitter *ore,
676683
bool isEffectivelyFinalMethod) {
677684

@@ -683,7 +690,7 @@ bool swift::canDevirtualizeClassMethod(FullApplySite applySite, ClassDecl *cd,
683690
auto *mi = cast<MethodInst>(applySite.getCallee());
684691

685692
// Find the implementation of the member which should be invoked.
686-
auto *f = getTargetClassMethod(module, cd, mi);
693+
auto *f = getTargetClassMethod(module, cd, classType, mi);
687694

688695
// If we do not find any such function, we have no function to devirtualize
689696
// to... so bail.
@@ -742,15 +749,15 @@ bool swift::canDevirtualizeClassMethod(FullApplySite applySite, ClassDecl *cd,
742749
std::pair<FullApplySite, bool /* changedCFG */>
743750
swift::devirtualizeClassMethod(FullApplySite applySite,
744751
SILValue classOrMetatype, ClassDecl *cd,
745-
OptRemark::Emitter *ore) {
752+
CanType classType, OptRemark::Emitter *ore) {
746753
bool changedCFG = false;
747754
LLVM_DEBUG(llvm::dbgs() << " Trying to devirtualize : "
748755
<< *applySite.getInstruction());
749756

750757
SILModule &module = applySite.getModule();
751758
auto *mi = cast<MethodInst>(applySite.getCallee());
752759

753-
auto *f = getTargetClassMethod(module, cd, mi);
760+
auto *f = getTargetClassMethod(module, cd, classType, mi);
754761

755762
CanSILFunctionType genCalleeType = f->getLoweredFunctionTypeInContext(
756763
TypeExpansionContext(*applySite.getFunction()));
@@ -835,10 +842,11 @@ swift::devirtualizeClassMethod(FullApplySite applySite,
835842

836843
std::pair<FullApplySite, bool> swift::tryDevirtualizeClassMethod(
837844
FullApplySite applySite, SILValue classInstance, ClassDecl *cd,
838-
OptRemark::Emitter *ore, bool isEffectivelyFinalMethod) {
839-
if (!canDevirtualizeClassMethod(applySite, cd, ore, isEffectivelyFinalMethod))
845+
CanType classType, OptRemark::Emitter *ore, bool isEffectivelyFinalMethod) {
846+
if (!canDevirtualizeClassMethod(applySite, cd, classType, ore,
847+
isEffectivelyFinalMethod))
840848
return {FullApplySite(), false};
841-
return devirtualizeClassMethod(applySite, classInstance, cd, ore);
849+
return devirtualizeClassMethod(applySite, classInstance, cd, classType, ore);
842850
}
843851

844852
//===----------------------------------------------------------------------===//
@@ -1322,7 +1330,7 @@ swift::tryDevirtualizeApply(ApplySite applySite, ClassHierarchyAnalysis *cha,
13221330
auto *cd = classType.getClassOrBoundGenericClass();
13231331

13241332
if (isEffectivelyFinalMethod(fas, classType, cd, cha))
1325-
return tryDevirtualizeClassMethod(fas, instance, cd, ore,
1333+
return tryDevirtualizeClassMethod(fas, instance, cd, classType, ore,
13261334
true /*isEffectivelyFinalMethod*/);
13271335

13281336
// Try to check if the exact dynamic type of the instance is statically
@@ -1333,13 +1341,14 @@ swift::tryDevirtualizeApply(ApplySite applySite, ClassHierarchyAnalysis *cha,
13331341
CanType classType = getSelfInstanceType(instance->getType().getASTType());
13341342
// This should never be null - make the check just to be on the safe side.
13351343
if (ClassDecl *cd = classType.getClassOrBoundGenericClass())
1336-
return tryDevirtualizeClassMethod(fas, instance, cd, ore);
1344+
return tryDevirtualizeClassMethod(fas, instance, cd, classType, ore);
13371345
return {ApplySite(), false};
13381346
}
13391347

13401348
if (auto exactTy = getExactDynamicType(cmi->getOperand(), cha)) {
13411349
if (exactTy == cmi->getOperand()->getType())
1342-
return tryDevirtualizeClassMethod(fas, cmi->getOperand(), cd, ore);
1350+
return tryDevirtualizeClassMethod(fas, cmi->getOperand(), cd, classType,
1351+
ore);
13431352
}
13441353
}
13451354

@@ -1348,7 +1357,7 @@ swift::tryDevirtualizeApply(ApplySite applySite, ClassHierarchyAnalysis *cha,
13481357
auto classType = getSelfInstanceType(instance->getType().getASTType());
13491358
auto *cd = classType.getClassOrBoundGenericClass();
13501359

1351-
return tryDevirtualizeClassMethod(fas, instance, cd, ore);
1360+
return tryDevirtualizeClassMethod(fas, instance, cd, classType, ore);
13521361
}
13531362

13541363
return {ApplySite(), false};
@@ -1389,20 +1398,21 @@ bool swift::canDevirtualizeApply(FullApplySite applySite,
13891398
auto *cd = classType.getClassOrBoundGenericClass();
13901399

13911400
if (isEffectivelyFinalMethod(applySite, classType, cd, cha))
1392-
return canDevirtualizeClassMethod(applySite, cd, nullptr /*ore*/,
1401+
return canDevirtualizeClassMethod(applySite, cd, classType,
1402+
nullptr /*ore*/,
13931403
true /*isEffectivelyFinalMethod*/);
13941404

13951405
// Try to check if the exact dynamic type of the instance is statically
13961406
// known.
13971407
if (auto instance = getInstanceWithExactDynamicType(cmi->getOperand(), cha)) {
13981408
CanType classType = getSelfInstanceType(instance->getType().getASTType());
13991409
ClassDecl *cd = classType.getClassOrBoundGenericClass();
1400-
return cd && canDevirtualizeClassMethod(applySite, cd);
1410+
return cd && canDevirtualizeClassMethod(applySite, cd, classType);
14011411
}
14021412

14031413
if (auto exactTy = getExactDynamicType(cmi->getOperand(), cha)) {
14041414
if (exactTy == cmi->getOperand()->getType())
1405-
return canDevirtualizeClassMethod(applySite, cd);
1415+
return canDevirtualizeClassMethod(applySite, cd, classType);
14061416
}
14071417
}
14081418

@@ -1411,7 +1421,7 @@ bool swift::canDevirtualizeApply(FullApplySite applySite,
14111421
auto classType = getSelfInstanceType(instance->getType().getASTType());
14121422
auto *cd = classType.getClassOrBoundGenericClass();
14131423

1414-
return canDevirtualizeClassMethod(applySite, cd);
1424+
return canDevirtualizeClassMethod(applySite, cd, classType);
14151425
}
14161426

14171427
return false;

test/embedded/generic-classes.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// 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+
// RUN: %target-run-simple-swift(-Osize %S/Inputs/print.swift -enable-experimental-feature Embedded -parse-as-library -runtime-compatibility-version none -wmo -Xfrontend -disable-objc-interop) | %FileCheck %s
23

34
// REQUIRES: executable_test
45
// REQUIRES: optimized_stdlib

0 commit comments

Comments
 (0)