mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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
This commit is contained in:
@@ -76,7 +76,7 @@ bool canDevirtualizeClassMethod(FullApplySite AI, ClassDecl *CD,
|
||||
CanType ClassType,
|
||||
OptRemark::Emitter *ORE = nullptr,
|
||||
bool isEffectivelyFinalMethod = false);
|
||||
SILFunction *getTargetClassMethod(SILModule &M, ClassDecl *CD,
|
||||
SILFunction *getTargetClassMethod(SILModule &M, FullApplySite as, ClassDecl *CD,
|
||||
CanType ClassType, MethodInst *MI);
|
||||
CanType getSelfInstanceType(CanType ClassOrMetatypeType);
|
||||
|
||||
|
||||
@@ -446,7 +446,7 @@ static bool tryToSpeculateTarget(SILPassManager *pm, FullApplySite AI, ClassHier
|
||||
|
||||
// Try to devirtualize the static class of instance
|
||||
// if it is possible.
|
||||
if (auto F = getTargetClassMethod(M, CD, ClassType, CMI)) {
|
||||
if (auto F = getTargetClassMethod(M, AI, CD, ClassType, CMI)) {
|
||||
// Do not devirtualize if a method in the base class is marked
|
||||
// as non-optimizable. This way it is easy to disable the
|
||||
// devirtualization of this method in the base class and
|
||||
|
||||
@@ -712,7 +712,7 @@ void swift::deleteDevirtualizedApply(ApplySite old) {
|
||||
recursivelyDeleteTriviallyDeadInstructions(oldApply, true);
|
||||
}
|
||||
|
||||
SILFunction *swift::getTargetClassMethod(SILModule &module, ClassDecl *cd,
|
||||
SILFunction *swift::getTargetClassMethod(SILModule &module, FullApplySite as, ClassDecl *cd,
|
||||
CanType classType, MethodInst *mi) {
|
||||
assert((isa<ClassMethodInst>(mi) || isa<SuperMethodInst>(mi)) &&
|
||||
"Only class_method and super_method instructions are supported");
|
||||
@@ -721,6 +721,11 @@ SILFunction *swift::getTargetClassMethod(SILModule &module, ClassDecl *cd,
|
||||
|
||||
SILType silType = SILType::getPrimitiveObjectType(classType);
|
||||
if (auto *vtable = module.lookUpSpecializedVTable(silType)) {
|
||||
// We cannot de-virtualize a generic method call to a specialized method.
|
||||
// This would result in wrong argument/return calling conventions.
|
||||
if (as.getSubstitutionMap().hasAnySubstitutableParams())
|
||||
return nullptr;
|
||||
|
||||
return vtable->getEntry(module, member)->getImplementation();
|
||||
}
|
||||
|
||||
@@ -757,7 +762,7 @@ bool swift::canDevirtualizeClassMethod(FullApplySite applySite, ClassDecl *cd,
|
||||
auto *mi = cast<MethodInst>(applySite.getCallee());
|
||||
|
||||
// Find the implementation of the member which should be invoked.
|
||||
auto *f = getTargetClassMethod(module, cd, classType, mi);
|
||||
auto *f = getTargetClassMethod(module, applySite, cd, classType, mi);
|
||||
|
||||
// If we do not find any such function, we have no function to devirtualize
|
||||
// to... so bail.
|
||||
@@ -843,7 +848,7 @@ swift::devirtualizeClassMethod(SILPassManager *pm, FullApplySite applySite,
|
||||
SILModule &module = applySite.getModule();
|
||||
auto *mi = cast<MethodInst>(applySite.getCallee());
|
||||
|
||||
auto *f = getTargetClassMethod(module, cd, classType, mi);
|
||||
auto *f = getTargetClassMethod(module, applySite, cd, classType, mi);
|
||||
|
||||
CanSILFunctionType genCalleeType = f->getLoweredFunctionTypeInContext(
|
||||
TypeExpansionContext(*applySite.getFunction()));
|
||||
|
||||
22
test/embedded/devirt_generic_class_methods.swift
Normal file
22
test/embedded/devirt_generic_class_methods.swift
Normal file
@@ -0,0 +1,22 @@
|
||||
// RUN: %target-swift-frontend %s -parse-as-library -enable-experimental-feature Embedded -Xllvm -sil-disable-pass=mandatory-inlining -emit-ir -o /dev/null
|
||||
|
||||
// REQUIRES: swift_feature_Embedded
|
||||
|
||||
|
||||
// Check that the compiler doesn't crash
|
||||
|
||||
public class Base<T> {
|
||||
func foo(_ t: T) -> T {
|
||||
return t
|
||||
}
|
||||
}
|
||||
|
||||
@_transparent
|
||||
func callee(_ i: Int, _ c: Base<Int>) -> Int {
|
||||
return c.foo(i)
|
||||
}
|
||||
|
||||
public func testit(_ i : Int) -> Int {
|
||||
return callee(i, Base<Int>())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user