mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
223 lines
8.3 KiB
C++
223 lines
8.3 KiB
C++
//===--- VTableSpecializer.cpp - Specialization of vtables ----------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Specialize vtables of generic classes for embedded Swift.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "sil-vtable-specializer"
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "swift/AST/DiagnosticsSIL.h"
|
|
#include "swift/AST/ProtocolConformance.h"
|
|
#include "swift/SIL/OptimizationRemark.h"
|
|
#include "swift/SIL/SILFunction.h"
|
|
#include "swift/SIL/SILInstruction.h"
|
|
#include "swift/SILOptimizer/PassManager/Transforms.h"
|
|
#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h"
|
|
#include "swift/SILOptimizer/Utils/ConstantFolding.h"
|
|
#include "swift/SILOptimizer/Utils/Devirtualize.h"
|
|
#include "swift/SILOptimizer/Utils/Generics.h"
|
|
#include "swift/SILOptimizer/Utils/InstructionDeleter.h"
|
|
#include "swift/SILOptimizer/Utils/SILInliner.h"
|
|
#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h"
|
|
#include "swift/SILOptimizer/Utils/StackNesting.h"
|
|
|
|
using namespace swift;
|
|
|
|
namespace {
|
|
|
|
class VTableSpecializer : public SILModuleTransform {
|
|
bool specializeVTables(SILModule &module);
|
|
bool specializeVTableFor(AllocRefInst *allocRef, SILModule &module);
|
|
SILFunction *specializeVTableMethod(SILFunction *origMethod,
|
|
SubstitutionMap subs, SILModule &module);
|
|
bool specializeClassMethodInst(ClassMethodInst *cm);
|
|
|
|
/// The entry point to the transformation.
|
|
void run() override {
|
|
SILModule &module = *getModule();
|
|
|
|
if (!module.getASTContext().LangOpts.hasFeature(Feature::Embedded)) return;
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << "***** VTableSpecializer\n");
|
|
|
|
if (specializeVTables(module)) invalidateFunctionTables();
|
|
}
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
bool VTableSpecializer::specializeVTables(SILModule &module) {
|
|
bool changed = false;
|
|
for (SILFunction &func : module) {
|
|
if (func.getLoweredFunctionType()->isPolymorphic()) continue;
|
|
|
|
for (SILBasicBlock &block : func) {
|
|
for (SILInstruction &inst : block) {
|
|
if (auto *allocRef = dyn_cast<AllocRefInst>(&inst)) {
|
|
changed |= specializeVTableFor(allocRef, module);
|
|
continue;
|
|
}
|
|
if (auto *cm = dyn_cast<ClassMethodInst>(&inst)) {
|
|
changed |= specializeClassMethodInst(cm);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (SILVTable *vtable : module.getVTables()) {
|
|
if (vtable->getClass()->isGenericContext()) continue;
|
|
|
|
for (SILVTableEntry &entry : vtable->getMutableEntries()) {
|
|
SILFunction *method = entry.getImplementation();
|
|
if (!method->getLoweredFunctionType()->isPolymorphic()) continue;
|
|
|
|
ValueDecl *decl = entry.getMethod().getDecl();
|
|
module.getASTContext().Diags.diagnose(
|
|
decl->getLoc(), diag::non_final_generic_class_function);
|
|
}
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
|
|
bool VTableSpecializer::specializeVTableFor(AllocRefInst *allocRef,
|
|
SILModule &module) {
|
|
SILType classTy = allocRef->getType();
|
|
CanType astType = classTy.getASTType();
|
|
BoundGenericClassType *genClassTy = dyn_cast<BoundGenericClassType>(astType);
|
|
if (!genClassTy) return false;
|
|
|
|
if (module.lookUpSpecializedVTable(classTy)) return false;
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << "specializeVTableFor "
|
|
<< genClassTy->getDecl()->getName() << '\n');
|
|
|
|
ClassDecl *classDecl = genClassTy->getDecl();
|
|
SILVTable *origVtable = module.lookUpVTable(classDecl);
|
|
if (!origVtable) {
|
|
llvm::errs() << "No vtable available for "
|
|
<< genClassTy->getDecl()->getName() << '\n';
|
|
llvm::report_fatal_error("no vtable");
|
|
}
|
|
|
|
SubstitutionMap subs = astType->getContextSubstitutionMap(
|
|
classDecl->getParentModule(), classDecl);
|
|
|
|
llvm::SmallVector<SILVTableEntry, 8> newEntries;
|
|
|
|
for (const SILVTableEntry &entry : origVtable->getEntries()) {
|
|
SILFunction *origMethod = entry.getImplementation();
|
|
SILFunction *specializedMethod =
|
|
specializeVTableMethod(origMethod, subs, module);
|
|
newEntries.push_back(SILVTableEntry(entry.getMethod(), specializedMethod,
|
|
entry.getKind(),
|
|
entry.isNonOverridden()));
|
|
}
|
|
|
|
SILVTable::create(module, classDecl, classTy, IsNotSerialized, newEntries);
|
|
return true;
|
|
}
|
|
|
|
SILFunction *VTableSpecializer::specializeVTableMethod(SILFunction *origMethod,
|
|
SubstitutionMap subs,
|
|
SILModule &module) {
|
|
LLVM_DEBUG(llvm::dbgs() << "specializeVTableMethod " << origMethod->getName()
|
|
<< '\n');
|
|
|
|
if (!origMethod->getLoweredFunctionType()->isPolymorphic()) return origMethod;
|
|
|
|
ReabstractionInfo ReInfo(module.getSwiftModule(), module.isWholeModule(),
|
|
ApplySite(), origMethod, subs, IsNotSerialized,
|
|
/*ConvertIndirectToDirect=*/true,
|
|
/*dropMetatypeArgs=*/false);
|
|
|
|
if (!ReInfo.canBeSpecialized()) {
|
|
llvm::errs() << "Cannot specialize vtable method " << origMethod->getName()
|
|
<< '\n';
|
|
llvm::report_fatal_error("cannot specialize vtable method");
|
|
}
|
|
|
|
SILOptFunctionBuilder FunctionBuilder(*this);
|
|
|
|
GenericFuncSpecializer FuncSpecializer(FunctionBuilder, origMethod, subs,
|
|
ReInfo, /*isMandatory=*/true);
|
|
SILFunction *SpecializedF = FuncSpecializer.lookupSpecialization();
|
|
if (!SpecializedF) SpecializedF = FuncSpecializer.tryCreateSpecialization();
|
|
if (!SpecializedF || SpecializedF->getLoweredFunctionType()->hasError()) {
|
|
llvm::errs()
|
|
<< "Cannot specialize vtable method " << origMethod->getName() << '\n'
|
|
<< "Generic class methods are not supported in embedded mode\n";
|
|
llvm::report_fatal_error("cannot specialize vtable method");
|
|
}
|
|
|
|
// Link after specializing to pull in everything referenced from another
|
|
// module in case some referenced functions have non-public linkage.
|
|
module.linkFunction(SpecializedF, SILModule::LinkingMode::LinkAll);
|
|
|
|
SpecializedF->setLinkage(SILLinkage::Public);
|
|
SpecializedF->setSerialized(IsNotSerialized);
|
|
|
|
return SpecializedF;
|
|
}
|
|
|
|
bool VTableSpecializer::specializeClassMethodInst(ClassMethodInst *cm) {
|
|
SILValue instance = cm->getOperand();
|
|
SILType classTy = instance->getType();
|
|
CanType astType = classTy.getASTType();
|
|
BoundGenericClassType *genClassTy = dyn_cast<BoundGenericClassType>(astType);
|
|
if (!genClassTy) return false;
|
|
|
|
ClassDecl *classDecl = genClassTy->getDecl();
|
|
SubstitutionMap subs = astType->getContextSubstitutionMap(
|
|
classDecl->getParentModule(), classDecl);
|
|
|
|
SILType funcTy = cm->getType();
|
|
|
|
SILFunction *f = cm->getFunction();
|
|
SILModule &m = f->getModule();
|
|
SILType substitutedType =
|
|
funcTy.substGenericArgs(m, subs, TypeExpansionContext::minimal());
|
|
|
|
ReabstractionInfo reInfo(substitutedType.getAs<SILFunctionType>(), m);
|
|
reInfo.createSubstitutedAndSpecializedTypes();
|
|
CanSILFunctionType finalFuncTy = reInfo.getSpecializedType();
|
|
SILType finalSILTy = SILType::getPrimitiveObjectType(finalFuncTy);
|
|
|
|
SILBuilder builder(cm);
|
|
auto *newCM = builder.createClassMethod(cm->getLoc(), cm->getOperand(),
|
|
cm->getMember(), finalSILTy);
|
|
|
|
while (!cm->use_empty()) {
|
|
Operand *use = *cm->use_begin();
|
|
SILInstruction *user = use->getUser();
|
|
ApplySite AI = ApplySite::isa(user);
|
|
if (AI && AI.getCalleeOperand() == use) {
|
|
replaceWithSpecializedCallee(AI, newCM, reInfo);
|
|
AI.getInstruction()->eraseFromParent();
|
|
continue;
|
|
}
|
|
llvm::errs() << "unsupported use of class method "
|
|
<< newCM->getMember().getDecl()->getName() << " in function "
|
|
<< newCM->getFunction()->getName() << '\n';
|
|
llvm::report_fatal_error("unsupported class method");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
SILTransform *swift::createVTableSpecializer() {
|
|
return new VTableSpecializer();
|
|
}
|