Skip to content

Commit 606f769

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 7651db7 commit 606f769

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
@@ -712,7 +712,7 @@ void swift::deleteDevirtualizedApply(ApplySite old) {
712712
recursivelyDeleteTriviallyDeadInstructions(oldApply, true);
713713
}
714714

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

722722
SILType silType = SILType::getPrimitiveObjectType(classType);
723723
if (auto *vtable = module.lookUpSpecializedVTable(silType)) {
724+
// We cannot de-virtualize a generic method call to a specialized method.
725+
// This would result in wrong argument/return calling conventions.
726+
if (as.getSubstitutionMap().hasAnySubstitutableParams())
727+
return nullptr;
728+
724729
return vtable->getEntry(module, member)->getImplementation();
725730
}
726731

@@ -757,7 +762,7 @@ bool swift::canDevirtualizeClassMethod(FullApplySite applySite, ClassDecl *cd,
757762
auto *mi = cast<MethodInst>(applySite.getCallee());
758763

759764
// Find the implementation of the member which should be invoked.
760-
auto *f = getTargetClassMethod(module, cd, classType, mi);
765+
auto *f = getTargetClassMethod(module, applySite, cd, classType, mi);
761766

762767
// If we do not find any such function, we have no function to devirtualize
763768
// to... so bail.
@@ -843,7 +848,7 @@ swift::devirtualizeClassMethod(SILPassManager *pm, FullApplySite applySite,
843848
SILModule &module = applySite.getModule();
844849
auto *mi = cast<MethodInst>(applySite.getCallee());
845850

846-
auto *f = getTargetClassMethod(module, cd, classType, mi);
851+
auto *f = getTargetClassMethod(module, applySite, cd, classType, mi);
847852

848853
CanSILFunctionType genCalleeType = f->getLoweredFunctionTypeInContext(
849854
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)