Skip to content

Commit

Permalink
DeadFunctionElimination: remove externally available witness tables a…
Browse files Browse the repository at this point in the history
…t 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.
  • Loading branch information
eeckstein committed Jan 27, 2020
1 parent d6b9d84 commit 03b0a6c
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 10 deletions.
2 changes: 2 additions & 0 deletions include/swift/SILOptimizer/PassManager/Passes.def
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
33 changes: 27 additions & 6 deletions lib/SILOptimizer/IPO/DeadFunctionElimination.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ class FunctionLivenessComputation {

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

bool keepExternalWitnessTablesAlive;

/// Checks is a function is alive, e.g. because it is visible externally.
bool isAnchorFunction(SILFunction *F) {

Expand Down Expand Up @@ -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');

Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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");

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

DeadFunctionElimination deadFunctionElimination(getModule());
DeadFunctionElimination deadFunctionElimination(getModule(),
/*keepExternalWitnessTablesAlive*/ !isLateDFE);
deadFunctionElimination.eliminateFunctions(this);
}
};

} // 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) {
Expand Down
4 changes: 3 additions & 1 deletion lib/SILOptimizer/PassManager/PassPipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
@@ -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 {

Expand Down
2 changes: 1 addition & 1 deletion test/SILOptimizer/devirt_opaque_witness.swift
Original file line number Diff line number Diff line change
@@ -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

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
// 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

// Make sure the specializer produces an external witness table.
//
// 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 : P>(_ t : T) -> Y {
return t.doSomething()
}
Expand Down

0 comments on commit 03b0a6c

Please sign in to comment.