diff --git a/include/swift/SILOptimizer/PassManager/Passes.def b/include/swift/SILOptimizer/PassManager/Passes.def index 5b8005e807db6..b879b3a666795 100644 --- a/include/swift/SILOptimizer/PassManager/Passes.def +++ b/include/swift/SILOptimizer/PassManager/Passes.def @@ -200,6 +200,8 @@ PASS(LICM, "licm", "Loop Invariant Code Motion") PASS(LateCodeMotion, "late-codemotion", "Late Code Motion with Release Hoisting") +PASS(LateDeadFunctionElimination, "late-deadfuncelim", + "Late Dead Function Elimination") PASS(LateInliner, "late-inline", "Late Function Inlining") PASS(LoopCanonicalizer, "loop-canonicalizer", diff --git a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp index 4607210e2f4ee..82fd149ddbdb5 100644 --- a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp +++ b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp @@ -90,6 +90,8 @@ class FunctionLivenessComputation { llvm::SmallPtrSet AliveFunctionsAndTables; + bool keepExternalWitnessTablesAlive; + /// Checks is a function is alive, e.g. because it is visible externally. bool isAnchorFunction(SILFunction *F) { @@ -148,6 +150,11 @@ class FunctionLivenessComputation { /// Marks all contained functions and witness tables of a witness table as /// alive. void makeAlive(SILWitnessTable *WT) { + if (isAvailableExternally(WT->getLinkage()) && + !keepExternalWitnessTablesAlive) { + return; + } + LLVM_DEBUG(llvm::dbgs() << " scan witness table " << WT->getName() << '\n'); @@ -393,8 +400,10 @@ class FunctionLivenessComputation { } public: - FunctionLivenessComputation(SILModule *module) : - Module(module) {} + FunctionLivenessComputation(SILModule *module, + bool keepExternalWitnessTablesAlive) : + Module(module), + keepExternalWitnessTablesAlive(keepExternalWitnessTablesAlive) {} /// The main entry point of the optimization. bool findAliveFunctions() { @@ -635,8 +644,8 @@ class DeadFunctionElimination : FunctionLivenessComputation { } public: - DeadFunctionElimination(SILModule *module) - : FunctionLivenessComputation(module) {} + DeadFunctionElimination(SILModule *module, bool keepExternalWitnessTablesAlive) + : FunctionLivenessComputation(module, keepExternalWitnessTablesAlive) {} /// The main entry point of the optimization. void eliminateFunctions(SILModuleTransform *DFEPass) { @@ -693,6 +702,13 @@ class DeadFunctionElimination : FunctionLivenessComputation { namespace { class SILDeadFuncElimination : public SILModuleTransform { + +private: + bool isLateDFE; + +public: + SILDeadFuncElimination(bool isLateDFE) : isLateDFE(isLateDFE) { } + void run() override { LLVM_DEBUG(llvm::dbgs() << "Running DeadFuncElimination\n"); @@ -703,7 +719,8 @@ class SILDeadFuncElimination : public SILModuleTransform { // can eliminate such functions. getModule()->invalidateSILLoaderCaches(); - DeadFunctionElimination deadFunctionElimination(getModule()); + DeadFunctionElimination deadFunctionElimination(getModule(), + /*keepExternalWitnessTablesAlive*/ !isLateDFE); deadFunctionElimination.eliminateFunctions(this); } }; @@ -711,7 +728,11 @@ class SILDeadFuncElimination : public SILModuleTransform { } // end anonymous namespace SILTransform *swift::createDeadFunctionElimination() { - return new SILDeadFuncElimination(); + return new SILDeadFuncElimination(/*isLateDFE*/ false); +} + +SILTransform *swift::createLateDeadFunctionElimination() { + return new SILDeadFuncElimination(/*isLateDFE*/ true); } void swift::performSILDeadFunctionElimination(SILModule *M) { diff --git a/lib/SILOptimizer/PassManager/PassPipeline.cpp b/lib/SILOptimizer/PassManager/PassPipeline.cpp index 5868d453a4653..cf9775bed4ed2 100644 --- a/lib/SILOptimizer/PassManager/PassPipeline.cpp +++ b/lib/SILOptimizer/PassManager/PassPipeline.cpp @@ -522,7 +522,9 @@ static void addLateLoopOptPassPipeline(SILPassPipelinePlan &P) { P.startPipeline("LateLoopOpt"); // Delete dead code and drop the bodies of shared functions. - P.addDeadFunctionElimination(); + // Also, remove externally available witness tables. They are not needed + // anymore after the last devirtualizer run. + P.addLateDeadFunctionElimination(); // Perform the final lowering transformations. P.addCodeSinking(); diff --git a/test/SIL/Serialization/init_existential_inst_deserializes_witness_tables.swift b/test/SIL/Serialization/init_existential_inst_deserializes_witness_tables.swift index 9273c467d3c44..c58bc913cf01f 100644 --- a/test/SIL/Serialization/init_existential_inst_deserializes_witness_tables.swift +++ b/test/SIL/Serialization/init_existential_inst_deserializes_witness_tables.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -sil-inline-threshold 0 %S/Inputs/init_existential_inst_deserializes_witness_tables_input.swift -o %t/Swift.swiftmodule -emit-module -parse-as-library -parse-stdlib -module-link-name swiftCore -module-name Swift -O -// RUN: %target-swift-frontend -I %t -O %s -emit-sil -o - | %FileCheck %s +// RUN: %target-swift-frontend -I %t -O %s -Xllvm -sil-disable-pass=late-deadfuncelim -emit-sil -o - | %FileCheck %s // CHECK: sil_witness_table public_external X: P module Swift { diff --git a/test/SILOptimizer/devirt_opaque_witness.swift b/test/SILOptimizer/devirt_opaque_witness.swift index 5f8b992882b85..debd3c80b9e9e 100644 --- a/test/SILOptimizer/devirt_opaque_witness.swift +++ b/test/SILOptimizer/devirt_opaque_witness.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -emit-module -emit-module-path %t/opaque_conformance.swiftmodule -primary-file %S/Inputs/opaque_conformance.swift -// RUN: %target-swift-frontend -O -emit-sil -primary-file %s -I %t | %FileCheck %s +// RUN: %target-swift-frontend -O -emit-sil -primary-file %s -I %t -Xllvm -sil-disable-pass=late-deadfuncelim | %FileCheck %s import opaque_conformance diff --git a/test/SILOptimizer/sil_witness_tables_external_witnesstable.swift b/test/SILOptimizer/sil_witness_tables_external_witnesstable.swift index 3cde3796ed8db..97831516e1bd1 100644 --- a/test/SILOptimizer/sil_witness_tables_external_witnesstable.swift +++ b/test/SILOptimizer/sil_witness_tables_external_witnesstable.swift @@ -1,6 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -emit-module %S/Inputs/sil_witness_tables_external_input.swift -o %t/Swift.swiftmodule -parse-stdlib -parse-as-library -module-name Swift -module-link-name swiftCore -// RUN: %target-swift-frontend -O -I %t %s -emit-sil | %FileCheck %s +// RUN: %target-swift-frontend -O -I %t %s -Xllvm -sil-disable-pass=late-deadfuncelim -emit-sil | %FileCheck %s +// RUN: %target-swift-frontend -O -I %t %s -emit-sil | %FileCheck -check-prefix=CHECK-DFE %s import Swift @@ -8,6 +9,11 @@ import Swift // // CHECK: sil_witness_table public_external X: P module Swift { +// Also check that late dead-function-elimination is removing externally +// available witness tables. +// +// CHECK-DFE-NOT: sil_witness_table public_external + func doSomething(_ t : T) -> Y { return t.doSomething() }