Skip to content

Commit 849a5e9

Browse files
committed
MandatoryPerformanceOptimizations: don't de-virtualize a generic class method call to specialized method
This results in wrong argument/return calling conventions. First, the method call must be specialized. Only then the call can be de-virtualized. Usually, it's done in this order anyway, because the `class_method` instruction is located before the `apply`. But when inlining functions, the order (in the worklist) can be the other way round. Fixes a compiler crash. rdar://154631438
1 parent 2e0b9d7 commit 849a5e9

File tree

4 files changed

+32
-5
lines changed

4 files changed

+32
-5
lines changed

include/swift/SILOptimizer/Utils/Devirtualize.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ bool canDevirtualizeClassMethod(FullApplySite AI, ClassDecl *CD,
7676
CanType ClassType,
7777
OptRemark::Emitter *ORE = nullptr,
7878
bool isEffectivelyFinalMethod = false);
79-
SILFunction *getTargetClassMethod(SILModule &M, ClassDecl *CD,
79+
SILFunction *getTargetClassMethod(SILModule &M, FullApplySite as, ClassDecl *CD,
8080
CanType ClassType, MethodInst *MI);
8181
CanType getSelfInstanceType(CanType ClassOrMetatypeType);
8282

lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ static bool tryToSpeculateTarget(SILPassManager *pm, FullApplySite AI, ClassHier
446446

447447
// Try to devirtualize the static class of instance
448448
// if it is possible.
449-
if (auto F = getTargetClassMethod(M, CD, ClassType, CMI)) {
449+
if (auto F = getTargetClassMethod(M, AI, CD, ClassType, CMI)) {
450450
// Do not devirtualize if a method in the base class is marked
451451
// as non-optimizable. This way it is easy to disable the
452452
// devirtualization of this method in the base class and

lib/SILOptimizer/Utils/Devirtualize.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -718,7 +718,7 @@ void swift::deleteDevirtualizedApply(ApplySite old) {
718718
recursivelyDeleteTriviallyDeadInstructions(oldApply, true);
719719
}
720720

721-
SILFunction *swift::getTargetClassMethod(SILModule &module, ClassDecl *cd,
721+
SILFunction *swift::getTargetClassMethod(SILModule &module, FullApplySite as, ClassDecl *cd,
722722
CanType classType, MethodInst *mi) {
723723
assert((isa<ClassMethodInst>(mi) || isa<SuperMethodInst>(mi)) &&
724724
"Only class_method and super_method instructions are supported");
@@ -727,6 +727,11 @@ SILFunction *swift::getTargetClassMethod(SILModule &module, ClassDecl *cd,
727727

728728
SILType silType = SILType::getPrimitiveObjectType(classType);
729729
if (auto *vtable = module.lookUpSpecializedVTable(silType)) {
730+
// We cannot de-virtualize a generic method call to a specialized method.
731+
// This would result in wrong argument/return calling conventions.
732+
if (as.getSubstitutionMap().hasAnySubstitutableParams())
733+
return nullptr;
734+
730735
return vtable->getEntry(module, member)->getImplementation();
731736
}
732737

@@ -763,7 +768,7 @@ bool swift::canDevirtualizeClassMethod(FullApplySite applySite, ClassDecl *cd,
763768
auto *mi = cast<MethodInst>(applySite.getCallee());
764769

765770
// Find the implementation of the member which should be invoked.
766-
auto *f = getTargetClassMethod(module, cd, classType, mi);
771+
auto *f = getTargetClassMethod(module, applySite, cd, classType, mi);
767772

768773
// If we do not find any such function, we have no function to devirtualize
769774
// to... so bail.
@@ -849,7 +854,7 @@ swift::devirtualizeClassMethod(SILPassManager *pm, FullApplySite applySite,
849854
SILModule &module = applySite.getModule();
850855
auto *mi = cast<MethodInst>(applySite.getCallee());
851856

852-
auto *f = getTargetClassMethod(module, cd, classType, mi);
857+
auto *f = getTargetClassMethod(module, applySite, cd, classType, mi);
853858

854859
CanSILFunctionType genCalleeType = f->getLoweredFunctionTypeInContext(
855860
TypeExpansionContext(*applySite.getFunction()));
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %target-swift-frontend %s -parse-as-library -enable-experimental-feature Embedded -Xllvm -sil-disable-pass=mandatory-inlining -emit-ir -o /dev/null
2+
3+
// REQUIRES: swift_feature_Embedded
4+
5+
6+
// Check that the compiler doesn't crash
7+
8+
public class Base<T> {
9+
func foo(_ t: T) -> T {
10+
return t
11+
}
12+
}
13+
14+
@_transparent
15+
func callee(_ i: Int, _ c: Base<Int>) -> Int {
16+
return c.foo(i)
17+
}
18+
19+
public func testit(_ i : Int) -> Int {
20+
return callee(i, Base<Int>())
21+
}
22+

0 commit comments

Comments
 (0)