27
27
using namespace swift ;
28
28
29
29
STATISTIC (NumDeadFunc, " Number of dead functions eliminated" );
30
- STATISTIC (NumEliminatedExternalDefs, " Number of external function definitions eliminated" );
31
30
32
31
namespace {
33
32
@@ -98,7 +97,7 @@ class FunctionLivenessComputation {
98
97
// / Checks is a function is alive, e.g. because it is visible externally.
99
98
bool isAnchorFunction (SILFunction *F) {
100
99
101
- // Remove internal functions that are not referenced by anything .
100
+ // Functions that may be used externally cannot be removed .
102
101
if (isPossiblyUsedExternally (F->getLinkage (), Module->isWholeModule ()))
103
102
return true ;
104
103
@@ -191,7 +190,7 @@ class FunctionLivenessComputation {
191
190
}
192
191
193
192
}
194
-
193
+
195
194
// / Marks the declarations referenced by a key path pattern as alive if they
196
195
// / aren't yet.
197
196
void ensureKeyPathComponentsAreAlive (KeyPathPattern *KP) {
@@ -223,7 +222,7 @@ class FunctionLivenessComputation {
223
222
case KeyPathPatternComponent::ComputedPropertyId::Property:
224
223
break ;
225
224
}
226
-
225
+
227
226
if (auto equals = component.getComputedPropertyIndexEquals ())
228
227
ensureAlive (equals);
229
228
if (auto hash = component.getComputedPropertyIndexHash ())
@@ -234,12 +233,12 @@ class FunctionLivenessComputation {
234
233
case KeyPathPatternComponent::Kind::StoredProperty:
235
234
case KeyPathPatternComponent::Kind::OptionalChain:
236
235
case KeyPathPatternComponent::Kind::OptionalForce:
237
- case KeyPathPatternComponent::Kind::OptionalWrap:
236
+ case KeyPathPatternComponent::Kind::OptionalWrap:
238
237
continue ;
239
238
}
240
239
}
241
240
}
242
-
241
+
243
242
// / Marks a function as alive if it is not alive yet.
244
243
void ensureAlive (SILFunction *F) {
245
244
if (!isAlive (F))
@@ -279,14 +278,14 @@ class FunctionLivenessComputation {
279
278
// All implementations of derived classes may be called.
280
279
if (isDerivedOrEqual (ImplCl, MethodCl))
281
280
return true ;
282
-
281
+
283
282
// Check if the method implementation is the same in a super class, i.e.
284
283
// it is not overridden in the derived class.
285
284
auto *Impl1 = MethodCl->findImplementingMethod (FD);
286
285
assert (Impl1);
287
286
auto *Impl2 = ImplCl->findImplementingMethod (FD);
288
287
assert (Impl2);
289
-
288
+
290
289
return Impl1 == Impl2;
291
290
}
292
291
@@ -505,7 +504,7 @@ class DeadFunctionElimination : FunctionLivenessComputation {
505
504
mi->addWitnessFunction (F, nullptr );
506
505
}
507
506
}
508
-
507
+
509
508
510
509
}
511
510
@@ -701,172 +700,6 @@ class DeadFunctionElimination : FunctionLivenessComputation {
701
700
702
701
} // end anonymous namespace
703
702
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
-
870
703
// ===----------------------------------------------------------------------===//
871
704
// Pass Definition and Entry Points
872
705
// ===----------------------------------------------------------------------===//
@@ -887,24 +720,6 @@ class SILDeadFuncElimination : public SILModuleTransform {
887
720
DeadFunctionElimination deadFunctionElimination (getModule ());
888
721
deadFunctionElimination.eliminateFunctions (this );
889
722
}
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
-
908
723
};
909
724
910
725
} // end anonymous namespace
@@ -913,10 +728,6 @@ SILTransform *swift::createDeadFunctionElimination() {
913
728
return new SILDeadFuncElimination ();
914
729
}
915
730
916
- SILTransform *swift::createExternalFunctionDefinitionsElimination () {
917
- return new SILExternalFuncDefinitionsElimination ();
918
- }
919
-
920
731
void swift::performSILDeadFunctionElimination (SILModule *M) {
921
732
SILPassManager PM (M);
922
733
llvm::SmallVector<PassKind, 1 > Pass = {PassKind::DeadFunctionElimination};
0 commit comments