Skip to content

Commit 03b0a6c

Browse files
committed
DeadFunctionElimination: remove externally available witness tables at the end of the pipeline
... including all SIL functions with are transitively referenced from such witness tables. After the last devirtualizer run witness tables are not needed in the optimizer anymore. We can delete witness tables with an available-externally linkage. IRGen does not emit such witness tables anyway. This can save a little bit of compile time, because it reduces the amount of SIL at the end of the optimizer pipeline. It also reduces the size of the SIL output after the optimizer, which makes debugging the SIL output easier.
1 parent d6b9d84 commit 03b0a6c

File tree

6 files changed

+41
-10
lines changed

6 files changed

+41
-10
lines changed

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ PASS(LICM, "licm",
200200
"Loop Invariant Code Motion")
201201
PASS(LateCodeMotion, "late-codemotion",
202202
"Late Code Motion with Release Hoisting")
203+
PASS(LateDeadFunctionElimination, "late-deadfuncelim",
204+
"Late Dead Function Elimination")
203205
PASS(LateInliner, "late-inline",
204206
"Late Function Inlining")
205207
PASS(LoopCanonicalizer, "loop-canonicalizer",

lib/SILOptimizer/IPO/DeadFunctionElimination.cpp

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ class FunctionLivenessComputation {
9090

9191
llvm::SmallPtrSet<void *, 32> AliveFunctionsAndTables;
9292

93+
bool keepExternalWitnessTablesAlive;
94+
9395
/// Checks is a function is alive, e.g. because it is visible externally.
9496
bool isAnchorFunction(SILFunction *F) {
9597

@@ -148,6 +150,11 @@ class FunctionLivenessComputation {
148150
/// Marks all contained functions and witness tables of a witness table as
149151
/// alive.
150152
void makeAlive(SILWitnessTable *WT) {
153+
if (isAvailableExternally(WT->getLinkage()) &&
154+
!keepExternalWitnessTablesAlive) {
155+
return;
156+
}
157+
151158
LLVM_DEBUG(llvm::dbgs() << " scan witness table " << WT->getName()
152159
<< '\n');
153160

@@ -393,8 +400,10 @@ class FunctionLivenessComputation {
393400
}
394401

395402
public:
396-
FunctionLivenessComputation(SILModule *module) :
397-
Module(module) {}
403+
FunctionLivenessComputation(SILModule *module,
404+
bool keepExternalWitnessTablesAlive) :
405+
Module(module),
406+
keepExternalWitnessTablesAlive(keepExternalWitnessTablesAlive) {}
398407

399408
/// The main entry point of the optimization.
400409
bool findAliveFunctions() {
@@ -635,8 +644,8 @@ class DeadFunctionElimination : FunctionLivenessComputation {
635644
}
636645

637646
public:
638-
DeadFunctionElimination(SILModule *module)
639-
: FunctionLivenessComputation(module) {}
647+
DeadFunctionElimination(SILModule *module, bool keepExternalWitnessTablesAlive)
648+
: FunctionLivenessComputation(module, keepExternalWitnessTablesAlive) {}
640649

641650
/// The main entry point of the optimization.
642651
void eliminateFunctions(SILModuleTransform *DFEPass) {
@@ -693,6 +702,13 @@ class DeadFunctionElimination : FunctionLivenessComputation {
693702
namespace {
694703

695704
class SILDeadFuncElimination : public SILModuleTransform {
705+
706+
private:
707+
bool isLateDFE;
708+
709+
public:
710+
SILDeadFuncElimination(bool isLateDFE) : isLateDFE(isLateDFE) { }
711+
696712
void run() override {
697713
LLVM_DEBUG(llvm::dbgs() << "Running DeadFuncElimination\n");
698714

@@ -703,15 +719,20 @@ class SILDeadFuncElimination : public SILModuleTransform {
703719
// can eliminate such functions.
704720
getModule()->invalidateSILLoaderCaches();
705721

706-
DeadFunctionElimination deadFunctionElimination(getModule());
722+
DeadFunctionElimination deadFunctionElimination(getModule(),
723+
/*keepExternalWitnessTablesAlive*/ !isLateDFE);
707724
deadFunctionElimination.eliminateFunctions(this);
708725
}
709726
};
710727

711728
} // end anonymous namespace
712729

713730
SILTransform *swift::createDeadFunctionElimination() {
714-
return new SILDeadFuncElimination();
731+
return new SILDeadFuncElimination(/*isLateDFE*/ false);
732+
}
733+
734+
SILTransform *swift::createLateDeadFunctionElimination() {
735+
return new SILDeadFuncElimination(/*isLateDFE*/ true);
715736
}
716737

717738
void swift::performSILDeadFunctionElimination(SILModule *M) {

lib/SILOptimizer/PassManager/PassPipeline.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,9 @@ static void addLateLoopOptPassPipeline(SILPassPipelinePlan &P) {
522522
P.startPipeline("LateLoopOpt");
523523

524524
// Delete dead code and drop the bodies of shared functions.
525-
P.addDeadFunctionElimination();
525+
// Also, remove externally available witness tables. They are not needed
526+
// anymore after the last devirtualizer run.
527+
P.addLateDeadFunctionElimination();
526528

527529
// Perform the final lowering transformations.
528530
P.addCodeSinking();

test/SIL/Serialization/init_existential_inst_deserializes_witness_tables.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %empty-directory(%t)
22
// 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
3-
// RUN: %target-swift-frontend -I %t -O %s -emit-sil -o - | %FileCheck %s
3+
// RUN: %target-swift-frontend -I %t -O %s -Xllvm -sil-disable-pass=late-deadfuncelim -emit-sil -o - | %FileCheck %s
44

55
// CHECK: sil_witness_table public_external X: P module Swift {
66

test/SILOptimizer/devirt_opaque_witness.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %empty-directory(%t)
22
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/opaque_conformance.swiftmodule -primary-file %S/Inputs/opaque_conformance.swift
3-
// RUN: %target-swift-frontend -O -emit-sil -primary-file %s -I %t | %FileCheck %s
3+
// RUN: %target-swift-frontend -O -emit-sil -primary-file %s -I %t -Xllvm -sil-disable-pass=late-deadfuncelim | %FileCheck %s
44

55
import opaque_conformance
66

test/SILOptimizer/sil_witness_tables_external_witnesstable.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
// RUN: %empty-directory(%t)
22
// 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
3-
// RUN: %target-swift-frontend -O -I %t %s -emit-sil | %FileCheck %s
3+
// RUN: %target-swift-frontend -O -I %t %s -Xllvm -sil-disable-pass=late-deadfuncelim -emit-sil | %FileCheck %s
4+
// RUN: %target-swift-frontend -O -I %t %s -emit-sil | %FileCheck -check-prefix=CHECK-DFE %s
45

56
import Swift
67

78
// Make sure the specializer produces an external witness table.
89
//
910
// CHECK: sil_witness_table public_external X: P module Swift {
1011

12+
// Also check that late dead-function-elimination is removing externally
13+
// available witness tables.
14+
//
15+
// CHECK-DFE-NOT: sil_witness_table public_external
16+
1117
func doSomething<T : P>(_ t : T) -> Y {
1218
return t.doSomething()
1319
}

0 commit comments

Comments
 (0)