Skip to content

Commit b4e78b9

Browse files
authored
Merge pull request swiftlang#12384 from swiftix/sil-serialization-before-optimizations3
IRGen should not emit bodies of public_external functions
2 parents 2431103 + 6f3b326 commit b4e78b9

File tree

12 files changed

+19
-357
lines changed

12 files changed

+19
-357
lines changed

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,6 @@ PASS(EmitDFDiagnostics, "dataflow-diagnostics",
134134
"Emit SIL Diagnostics")
135135
PASS(EscapeAnalysisDumper, "escapes-dump",
136136
"Dump Escape Analysis Results")
137-
PASS(ExternalDefsToDecls, "external-defs-to-decls",
138-
"External Definition To Declaration Conversion")
139-
PASS(ExternalFunctionDefinitionsElimination, "external-func-definition-elim",
140-
"External Function Definition Elimination")
141137
PASS(FunctionOrderPrinter, "function-order-printer",
142138
"Print Function Order for Testing")
143139
PASS(FunctionSignatureOpts, "function-signature-opts",

lib/IRGen/IRGenSIL.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1461,6 +1461,11 @@ static void emitLocalSelfMetadata(IRGenSILFunction &IGF) {
14611461
void IRGenModule::emitSILFunction(SILFunction *f) {
14621462
if (f->isExternalDeclaration())
14631463
return;
1464+
// Do not emit bodies of public_external functions.
1465+
// The only exception is transparent functions.
1466+
if (hasPublicVisibility(f->getLinkage()) && f->isAvailableExternally() &&
1467+
!f->isTransparent())
1468+
return;
14641469

14651470
PrettyStackTraceSILFunction stackTrace("emitting IR", f);
14661471
IRGenSILFunction(*this, f).emitSILFunction();

lib/SILOptimizer/IPO/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ set(IPO_SOURCES
44
IPO/ClosureSpecializer.cpp
55
IPO/DeadFunctionElimination.cpp
66
IPO/EagerSpecializer.cpp
7-
IPO/ExternalDefsToDecls.cpp
87
IPO/GlobalOpt.cpp
98
IPO/GlobalPropertyOpt.cpp
109
IPO/LetPropertiesOpts.cpp

lib/SILOptimizer/IPO/DeadFunctionElimination.cpp

Lines changed: 8 additions & 197 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
using namespace swift;
2828

2929
STATISTIC(NumDeadFunc, "Number of dead functions eliminated");
30-
STATISTIC(NumEliminatedExternalDefs, "Number of external function definitions eliminated");
3130

3231
namespace {
3332

@@ -98,7 +97,7 @@ class FunctionLivenessComputation {
9897
/// Checks is a function is alive, e.g. because it is visible externally.
9998
bool isAnchorFunction(SILFunction *F) {
10099

101-
// Remove internal functions that are not referenced by anything.
100+
// Functions that may be used externally cannot be removed.
102101
if (isPossiblyUsedExternally(F->getLinkage(), Module->isWholeModule()))
103102
return true;
104103

@@ -191,7 +190,7 @@ class FunctionLivenessComputation {
191190
}
192191

193192
}
194-
193+
195194
/// Marks the declarations referenced by a key path pattern as alive if they
196195
/// aren't yet.
197196
void ensureKeyPathComponentsAreAlive(KeyPathPattern *KP) {
@@ -223,7 +222,7 @@ class FunctionLivenessComputation {
223222
case KeyPathPatternComponent::ComputedPropertyId::Property:
224223
break;
225224
}
226-
225+
227226
if (auto equals = component.getComputedPropertyIndexEquals())
228227
ensureAlive(equals);
229228
if (auto hash = component.getComputedPropertyIndexHash())
@@ -234,12 +233,12 @@ class FunctionLivenessComputation {
234233
case KeyPathPatternComponent::Kind::StoredProperty:
235234
case KeyPathPatternComponent::Kind::OptionalChain:
236235
case KeyPathPatternComponent::Kind::OptionalForce:
237-
case KeyPathPatternComponent::Kind::OptionalWrap:
236+
case KeyPathPatternComponent::Kind::OptionalWrap:
238237
continue;
239238
}
240239
}
241240
}
242-
241+
243242
/// Marks a function as alive if it is not alive yet.
244243
void ensureAlive(SILFunction *F) {
245244
if (!isAlive(F))
@@ -279,14 +278,14 @@ class FunctionLivenessComputation {
279278
// All implementations of derived classes may be called.
280279
if (isDerivedOrEqual(ImplCl, MethodCl))
281280
return true;
282-
281+
283282
// Check if the method implementation is the same in a super class, i.e.
284283
// it is not overridden in the derived class.
285284
auto *Impl1 = MethodCl->findImplementingMethod(FD);
286285
assert(Impl1);
287286
auto *Impl2 = ImplCl->findImplementingMethod(FD);
288287
assert(Impl2);
289-
288+
290289
return Impl1 == Impl2;
291290
}
292291

@@ -505,7 +504,7 @@ class DeadFunctionElimination : FunctionLivenessComputation {
505504
mi->addWitnessFunction(F, nullptr);
506505
}
507506
}
508-
507+
509508

510509
}
511510

@@ -701,172 +700,6 @@ class DeadFunctionElimination : FunctionLivenessComputation {
701700

702701
} // end anonymous namespace
703702

704-
//===----------------------------------------------------------------------===//
705-
// ExternalFunctionDefinitionsElimination
706-
//===----------------------------------------------------------------------===//
707-
708-
namespace {
709-
710-
/// This pass performs removal of external function definitions for a sake of
711-
/// reducing the amount of code to run through IRGen. It is supposed to run very
712-
/// late in the pipeline, after devirtualization, inlining and specialization
713-
/// passes.
714-
///
715-
/// NOTE:
716-
/// Overall, this pass does not try to remove any information which can be
717-
/// useful for LLVM code generation, e.g. for analysis of function's
718-
/// side-effects. Therefore it does not remove bodies of any external functions
719-
/// that are alive, because LLVM may analyze their bodies to determine their
720-
/// side-effects and use it to achieve a better optimization.
721-
///
722-
/// Current implementation does not consider functions which are reachable only
723-
/// via vtables or witness_tables as alive and removes their bodies, because
724-
/// even if they would be kept around, LLVM does not know how to look at
725-
/// function definitions through Swift's vtables and witness_tables.
726-
///
727-
/// TODO:
728-
/// Once there is a proper support for IPO in Swift compiler and/or there is
729-
/// a way to communicate function's side-effects without providing its body
730-
/// (e.g. by means of SILFunction flags, attributes, etc), it should be
731-
/// safe to remove bodies of all external definitions.
732-
733-
class ExternalFunctionDefinitionsElimination : FunctionLivenessComputation {
734-
735-
/// ExternalFunctionDefinitionsElimination pass does not take functions
736-
/// reachable via vtables and witness_tables into account when computing
737-
/// a function liveness information. The only exceptions are external
738-
/// transparent functions, because bodies of external transparent functions
739-
/// should never be removed.
740-
void findAnchorsInTables() override {
741-
// Check vtable methods.
742-
for (SILVTable &vTable : Module->getVTableList()) {
743-
for (auto &entry : vTable.getEntries()) {
744-
SILFunction *F = entry.Implementation;
745-
if (F->isTransparent() && isAvailableExternally(F->getLinkage()))
746-
ensureAlive(F);
747-
}
748-
}
749-
750-
// Check witness methods.
751-
for (SILWitnessTable &WT : Module->getWitnessTableList()) {
752-
isVisibleExternally(WT.getConformance()->getProtocol());
753-
for (const SILWitnessTable::Entry &entry : WT.getEntries()) {
754-
if (entry.getKind() != SILWitnessTable::Method)
755-
continue;
756-
757-
auto methodWitness = entry.getMethodWitness();
758-
SILFunction *F = methodWitness.Witness;
759-
if (!F)
760-
continue;
761-
if (F->isTransparent() && isAvailableExternally(F->getLinkage()))
762-
ensureAlive(F);
763-
}
764-
}
765-
766-
// Check default witness methods.
767-
for (SILDefaultWitnessTable &WT : Module->getDefaultWitnessTableList()) {
768-
for (const SILDefaultWitnessTable::Entry &entry : WT.getEntries()) {
769-
if (!entry.isValid())
770-
continue;
771-
772-
SILFunction *F = entry.getWitness();
773-
if (F->isTransparent() && isAvailableExternally(F->getLinkage()))
774-
ensureAlive(F);
775-
}
776-
}
777-
778-
}
779-
780-
bool findAliveFunctions() {
781-
/// TODO: Once there is a proper support for IPO,
782-
/// bodies of all external functions can be removed.
783-
/// Therefore there is no need for a liveness computation.
784-
/// The next line can be just replaced by:
785-
/// return false;
786-
787-
// Keep all transparent functions alive. This is important because we have
788-
// to generate code for transparent functions.
789-
// Here we handle the special case if a transparent function is referenced
790-
// from a non-externally-available function (i.e. a function for which we
791-
// generate code). And those function is only reachable through a
792-
// vtable/witness-table. In such a case we would not visit the transparent
793-
// function in findAliveFunctions() because we don't consider vtables/
794-
// witness-tables as anchors.
795-
for (SILFunction &F : *Module) {
796-
if (isAvailableExternally(F.getLinkage()))
797-
continue;
798-
799-
for (SILBasicBlock &BB : F) {
800-
for (SILInstruction &I : BB) {
801-
if (auto *FRI = dyn_cast<FunctionRefInst>(&I)) {
802-
SILFunction *RefF = FRI->getReferencedFunction();
803-
// FIXME: Bad usage of transparent
804-
if (RefF->isTransparent() && RefF->isSerialized())
805-
ensureAlive(RefF);
806-
}
807-
}
808-
}
809-
}
810-
811-
return FunctionLivenessComputation::findAliveFunctions();
812-
}
813-
814-
/// Try to convert definition into declaration.
815-
/// Returns true if function was erased from the module.
816-
bool tryToConvertExternalDefinitionIntoDeclaration(SILFunction *F) {
817-
// Bail if it is a declaration already
818-
if (!F->isDefinition())
819-
return false;
820-
// Bail if there is no external implementation of this function.
821-
if (!F->isAvailableExternally())
822-
return false;
823-
// Bail if has a shared visibility, as there are no guarantees
824-
// that an implementation is available elsewhere.
825-
if (hasSharedVisibility(F->getLinkage()))
826-
return false;
827-
// Make this definition a declaration by removing the body of a function.
828-
829-
DEBUG(llvm::dbgs() << " removed external function " << F->getName()
830-
<< "\n");
831-
F->dropAllReferences();
832-
auto &Blocks = F->getBlocks();
833-
Blocks.clear();
834-
assert(F->isExternalDeclaration() &&
835-
"Function should be an external declaration");
836-
NumEliminatedExternalDefs++;
837-
return true;
838-
}
839-
840-
public:
841-
ExternalFunctionDefinitionsElimination(SILModule *module)
842-
: FunctionLivenessComputation(module) {}
843-
844-
/// Eliminate bodies of external functions which are not alive.
845-
///
846-
/// Bodies of alive functions should not be removed, as LLVM may
847-
/// still need them for analyzing their side-effects.
848-
void eliminateFunctions(SILModuleTransform *DFEPass) {
849-
850-
findAliveFunctions();
851-
// Get rid of definitions for all global functions that are not marked as
852-
// alive.
853-
for (auto FI = Module->begin(), EI = Module->end(); FI != EI;) {
854-
SILFunction *F = &*FI;
855-
++FI;
856-
// Do not remove bodies of any functions that are alive.
857-
if (!isAlive(F)) {
858-
if (tryToConvertExternalDefinitionIntoDeclaration(F)) {
859-
DFEPass->notifyDeleteFunction(F);
860-
if (F->getRefCount() == 0)
861-
F->getModule().eraseFunction(F);
862-
}
863-
}
864-
}
865-
}
866-
};
867-
868-
} // end anonymous namespace
869-
870703
//===----------------------------------------------------------------------===//
871704
// Pass Definition and Entry Points
872705
//===----------------------------------------------------------------------===//
@@ -887,24 +720,6 @@ class SILDeadFuncElimination : public SILModuleTransform {
887720
DeadFunctionElimination deadFunctionElimination(getModule());
888721
deadFunctionElimination.eliminateFunctions(this);
889722
}
890-
891-
};
892-
893-
class SILExternalFuncDefinitionsElimination : public SILModuleTransform {
894-
void run() override {
895-
DEBUG(llvm::dbgs() << "Running ExternalFunctionDefinitionsElimination\n");
896-
897-
// The deserializer caches functions that it deserializes so that if it is
898-
// asked to deserialize that function again, it does not do extra work. This
899-
// causes the function's reference count to be incremented causing it to be
900-
// alive unnecessarily. We invalidate the SILLoaderCaches here so that we
901-
// can eliminate the definitions of such functions.
902-
getModule()->invalidateSILLoaderCaches();
903-
904-
ExternalFunctionDefinitionsElimination EFDFE(getModule());
905-
EFDFE.eliminateFunctions(this);
906-
}
907-
908723
};
909724

910725
} // end anonymous namespace
@@ -913,10 +728,6 @@ SILTransform *swift::createDeadFunctionElimination() {
913728
return new SILDeadFuncElimination();
914729
}
915730

916-
SILTransform *swift::createExternalFunctionDefinitionsElimination() {
917-
return new SILExternalFuncDefinitionsElimination();
918-
}
919-
920731
void swift::performSILDeadFunctionElimination(SILModule *M) {
921732
SILPassManager PM(M);
922733
llvm::SmallVector<PassKind, 1> Pass = {PassKind::DeadFunctionElimination};

lib/SILOptimizer/IPO/ExternalDefsToDecls.cpp

Lines changed: 0 additions & 43 deletions
This file was deleted.

lib/SILOptimizer/PassManager/PassPipeline.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,6 @@ static void addLateLoopOptPassPipeline(SILPassPipelinePlan &P) {
408408
P.startPipeline("LateLoopOpt");
409409

410410
// Delete dead code and drop the bodies of shared functions.
411-
P.addExternalFunctionDefinitionsElimination();
412411
P.addDeadFunctionElimination();
413412

414413
// Perform the final lowering transformations.
@@ -531,12 +530,6 @@ SILPassPipelinePlan SILPassPipelinePlan::getOnonePassPipeline() {
531530
P.addUsePrespecialized();
532531

533532
P.startPipeline("Rest of Onone");
534-
// Don't keep external functions from stdlib and other modules.
535-
// We don't want that our unoptimized version will be linked instead
536-
// of the optimized version from the stdlib.
537-
// Here we just convert external definitions to declarations. LLVM will
538-
// eventually remove unused declarations.
539-
P.addExternalDefsToDecls();
540533

541534
// Has only an effect if the -assume-single-thread option is specified.
542535
P.addAssumeSingleThreaded();

0 commit comments

Comments
 (0)