| //===--- PruneVTables.cpp - Prune unnecessary vtable entries --------------===// |
| // |
| // 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 |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Mark sil_vtable entries as [nonoverridden] when possible, so that we know |
| // at IRGen time they can be elided from runtime vtables. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #define DEBUG_TYPE "prune-vtables" |
| |
| #include "swift/SILOptimizer/PassManager/Transforms.h" |
| #include "swift/SILOptimizer/Utils/InstOptUtils.h" |
| |
| STATISTIC(NumNonoverriddenVTableEntries, |
| "# of vtable entries marked non-overridden"); |
| |
| using namespace swift; |
| |
| namespace { |
| class PruneVTables : public SILModuleTransform { |
| void runOnVTable(SILModule *M, SILVTable *vtable) { |
| LLVM_DEBUG(llvm::dbgs() << "PruneVTables inspecting table:\n"; |
| vtable->print(llvm::dbgs())); |
| if (!M->isWholeModule() && |
| vtable->getClass()->getEffectiveAccess() >= AccessLevel::FilePrivate) { |
| LLVM_DEBUG(llvm::dbgs() << "Ignoring visible table: "; |
| vtable->print(llvm::dbgs())); |
| return; |
| } |
| |
| for (auto &entry : vtable->getMutableEntries()) { |
| |
| // We don't need to worry about entries that are overridden, |
| // or have already been found to have no overrides. |
| if (entry.isNonOverridden()) { |
| LLVM_DEBUG(llvm::dbgs() << "-- entry for "; |
| entry.getMethod().print(llvm::dbgs()); |
| llvm::dbgs() << " is already nonoverridden\n"); |
| continue; |
| } |
| |
| switch (entry.getKind()) { |
| case SILVTable::Entry::Normal: |
| case SILVTable::Entry::Inherited: |
| break; |
| |
| case SILVTable::Entry::Override: |
| LLVM_DEBUG(llvm::dbgs() << "-- entry for "; |
| entry.getMethod().print(llvm::dbgs()); |
| llvm::dbgs() << " is an override\n"); |
| continue; |
| } |
| |
| // The destructor entry must remain. |
| if (entry.getMethod().kind == SILDeclRef::Kind::Deallocator) { |
| LLVM_DEBUG(llvm::dbgs() << "-- entry for "; |
| entry.getMethod().print(llvm::dbgs()); |
| llvm::dbgs() << " is a destructor\n"); |
| continue; |
| } |
| |
| auto methodDecl = entry.getMethod().getAbstractFunctionDecl(); |
| if (!methodDecl) { |
| LLVM_DEBUG(llvm::dbgs() << "-- entry for "; |
| entry.getMethod().print(llvm::dbgs()); |
| llvm::dbgs() << " is not a function decl\n"); |
| continue; |
| } |
| |
| // Is the method declared final? |
| if (!methodDecl->isFinal()) { |
| // Are callees of this entry statically knowable? |
| if (!calleesAreStaticallyKnowable(*M, entry.getMethod())) { |
| LLVM_DEBUG(llvm::dbgs() << "-- entry for "; |
| entry.getMethod().print(llvm::dbgs()); |
| llvm::dbgs() << " does not have statically-knowable callees\n"); |
| continue; |
| } |
| |
| // Does the method have any overrides in this module? |
| if (methodDecl->isOverridden()) { |
| LLVM_DEBUG(llvm::dbgs() << "-- entry for "; |
| entry.getMethod().print(llvm::dbgs()); |
| llvm::dbgs() << " has overrides\n"); |
| continue; |
| } |
| } |
| LLVM_DEBUG(llvm::dbgs() << "++ entry for "; |
| entry.getMethod().print(llvm::dbgs()); |
| llvm::dbgs() << " can be marked non-overridden!\n"); |
| ++NumNonoverriddenVTableEntries; |
| entry.setNonOverridden(true); |
| vtable->updateVTableCache(entry); |
| } |
| } |
| |
| void run() override { |
| // SWIFT_ENABLE_TENSORFLOW |
| return; |
| // SWIFT_ENABLE_TENSORFLOW END |
| |
| SILModule *M = getModule(); |
| |
| for (auto &vtable : M->getVTables()) { |
| runOnVTable(M, vtable); |
| } |
| } |
| }; |
| } |
| |
| SILTransform *swift::createPruneVTables() { |
| return new PruneVTables(); |
| } |