Skip to content

Commit 6def04d

Browse files
committed
Removes dead function cleanup from MandatoryInlining.
This will help reduce compile time in SourceKit (among others). Dead function elimination will handle the removal of dead functions (not in -Onone).
1 parent 276e1a2 commit 6def04d

File tree

3 files changed

+62
-46
lines changed

3 files changed

+62
-46
lines changed

lib/SILOptimizer/Mandatory/MandatoryInlining.cpp

Lines changed: 26 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -809,12 +809,12 @@ static SILInstruction *tryDevirtualizeApplyHelper(FullApplySite InnerAI,
809809
///
810810
/// \returns true if successful, false if failed due to circular inlining.
811811
static bool
812-
runOnFunctionRecursively(SILOptFunctionBuilder &FuncBuilder,
813-
SILFunction *F, FullApplySite AI,
814-
DenseFunctionSet &FullyInlinedSet,
812+
runOnFunctionRecursively(SILOptFunctionBuilder &FuncBuilder, SILFunction *F,
813+
FullApplySite AI, DenseFunctionSet &FullyInlinedSet,
815814
ImmutableFunctionSet::Factory &SetFactory,
816815
ImmutableFunctionSet CurrentInliningSet,
817-
ClassHierarchyAnalysis *CHA) {
816+
ClassHierarchyAnalysis *CHA,
817+
DenseFunctionSet &changedFunctions) {
818818
// Avoid reprocessing functions needlessly.
819819
if (FullyInlinedSet.count(F))
820820
return true;
@@ -861,6 +861,10 @@ runOnFunctionRecursively(SILOptFunctionBuilder &FuncBuilder,
861861
// but a casted result of InnerAI or even a block argument due to
862862
// abstraction changes when calling the witness or class method.
863863
auto *devirtInst = tryDevirtualizeApplyHelper(InnerAI, CHA);
864+
// If devirtualization succeeds, make sure we record that this function
865+
// changed.
866+
if (devirtInst != InnerAI.getInstruction())
867+
changedFunctions.insert(F);
864868
// Restore II to the current apply site.
865869
II = devirtInst->getReverseIterator();
866870
// If the devirtualized call result is no longer a invalid FullApplySite,
@@ -879,9 +883,9 @@ runOnFunctionRecursively(SILOptFunctionBuilder &FuncBuilder,
879883
continue;
880884

881885
// Then recursively process it first before trying to inline it.
882-
if (!runOnFunctionRecursively(FuncBuilder, CalleeFunction, InnerAI,
883-
FullyInlinedSet, SetFactory,
884-
CurrentInliningSet, CHA)) {
886+
if (!runOnFunctionRecursively(
887+
FuncBuilder, CalleeFunction, InnerAI, FullyInlinedSet, SetFactory,
888+
CurrentInliningSet, CHA, changedFunctions)) {
885889
// If we failed due to circular inlining, then emit some notes to
886890
// trace back the failure if we have more information.
887891
// FIXME: possibly it could be worth recovering and attempting other
@@ -971,6 +975,10 @@ runOnFunctionRecursively(SILOptFunctionBuilder &FuncBuilder,
971975
closureCleanup.cleanupDeadClosures(F);
972976
invalidatedStackNesting |= closureCleanup.invalidatedStackNesting;
973977

978+
// Record that we inlined into this function so that we can invalidate it
979+
// later.
980+
changedFunctions.insert(F);
981+
974982
// Resume inlining within nextBB, which contains only the inlined
975983
// instructions and possibly instructions in the original call block that
976984
// have not yet been visited.
@@ -980,6 +988,7 @@ runOnFunctionRecursively(SILOptFunctionBuilder &FuncBuilder,
980988

981989
if (invalidatedStackNesting) {
982990
StackNesting().correctStackNesting(F);
991+
changedFunctions.insert(F);
983992
}
984993

985994
// Keep track of full inlined functions so we don't waste time recursively
@@ -999,10 +1008,10 @@ class MandatoryInlining : public SILModuleTransform {
9991008
void run() override {
10001009
ClassHierarchyAnalysis *CHA = getAnalysis<ClassHierarchyAnalysis>();
10011010
SILModule *M = getModule();
1002-
bool ShouldCleanup = !getOptions().DebugSerialization;
10031011
bool SILVerifyAll = getOptions().VerifyAll;
10041012
DenseFunctionSet FullyInlinedSet;
10051013
ImmutableFunctionSet::Factory SetFactory;
1014+
DenseFunctionSet changedFunctions;
10061015

10071016
SILOptFunctionBuilder FuncBuilder(*this);
10081017
for (auto &F : *M) {
@@ -1014,13 +1023,15 @@ class MandatoryInlining : public SILModuleTransform {
10141023
if (F.wasDeserializedCanonical())
10151024
continue;
10161025

1017-
runOnFunctionRecursively(FuncBuilder, &F,
1018-
FullApplySite(), FullyInlinedSet, SetFactory,
1019-
SetFactory.getEmptySet(), CHA);
1026+
runOnFunctionRecursively(FuncBuilder, &F, FullApplySite(),
1027+
FullyInlinedSet, SetFactory,
1028+
SetFactory.getEmptySet(), CHA, changedFunctions);
10201029

10211030
// The inliner splits blocks at call sites. Re-merge trivial branches
10221031
// to reestablish a canonical CFG.
1023-
mergeBasicBlocks(&F);
1032+
if (mergeBasicBlocks(&F)) {
1033+
changedFunctions.insert(&F);
1034+
}
10241035

10251036
// If we are asked to perform SIL verify all, perform that now so that we
10261037
// can discover the immediate inlining trigger of the problematic
@@ -1030,38 +1041,10 @@ class MandatoryInlining : public SILModuleTransform {
10301041
}
10311042
}
10321043

1033-
if (!ShouldCleanup)
1044+
if (getOptions().DebugSerialization)
10341045
return;
1035-
1036-
// Now that we've inlined some functions, clean up. If there are any
1037-
// transparent functions that are deserialized from another module that are
1038-
// now unused, just remove them from the module.
1039-
//
1040-
// We do this with a simple linear scan, because transparent functions that
1041-
// reference each other have already been flattened.
1042-
for (auto FI = M->begin(), E = M->end(); FI != E; ) {
1043-
SILFunction &F = *FI++;
1044-
1045-
invalidateAnalysis(&F, SILAnalysis::InvalidationKind::Everything);
1046-
1047-
if (F.getRefCount() != 0) continue;
1048-
1049-
// Leave non-transparent functions alone.
1050-
if (!F.isTransparent())
1051-
continue;
1052-
1053-
// We discard functions that don't have external linkage,
1054-
// e.g. deserialized functions, internal functions, and thunks.
1055-
// Being marked transparent controls this.
1056-
if (F.isPossiblyUsedExternally()) continue;
1057-
1058-
// ObjC functions are called through the runtime and are therefore alive
1059-
// even if not referenced inside SIL.
1060-
if (F.getRepresentation() == SILFunctionTypeRepresentation::ObjCMethod)
1061-
continue;
1062-
1063-
// Okay, just erase the function from the module.
1064-
FuncBuilder.eraseFunction(&F);
1046+
for (auto *F : changedFunctions) {
1047+
invalidateAnalysis(F, SILAnalysis::InvalidationKind::Everything);
10651048
}
10661049
}
10671050

test/SILOptimizer/mandatory_inlining.sil

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -960,9 +960,7 @@ bb0(%0 : $Builtin.Int8):
960960
return %5 : $Builtin.Int8
961961
}
962962

963-
// We delete this now.
964-
//
965-
// CHECK-NOT: sil shared [transparent] @identity_closure
963+
// This isn't removed in Onone anymore.
966964
sil shared [transparent] @identity_closure : $@convention(thin) (Builtin.Int8) -> Builtin.Int8 {
967965
bb0(%0 : $Builtin.Int8):
968966
return %0 : $Builtin.Int8
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: %target-sil-opt -compute-dominance-info -mandatory-inlining -enable-sil-verify-all %s
2+
3+
// This test ensures that functions which are inlined into also get invalidated
4+
// with invalidateAnalysis.
5+
6+
import Builtin
7+
import Swift
8+
9+
sil @f : $@convention(thin) () -> () {
10+
bb0:
11+
// function_ref g()
12+
%0 = function_ref @g : $@convention(thin) () -> ()
13+
%1 = apply %0() : $@convention(thin) () -> ()
14+
%2 = tuple ()
15+
return %2 : $()
16+
}
17+
18+
sil [transparent] @h : $@convention(thin) () -> Builtin.Int1 {
19+
bb0:
20+
%0 = integer_literal $Builtin.Int1, 0
21+
br bb2
22+
bb1:
23+
return %0 : $Builtin.Int1
24+
bb2:
25+
br bb1
26+
}
27+
28+
sil [transparent] @g : $@convention(thin) () -> () {
29+
bb0:
30+
// function_ref h()
31+
%0 = function_ref @h : $@convention(thin) () -> Builtin.Int1
32+
%1 = apply %0() : $@convention(thin) () -> Builtin.Int1
33+
%2 = tuple ()
34+
return %2 : $()
35+
}

0 commit comments

Comments
 (0)