Skip to content

Commit 3dff622

Browse files
authored
Merge pull request swiftlang#28484 from zoecarver/optimize/mandatory-function-cleanup-pass
Remove dead function cleanup from mandatory inlining
2 parents 08d9680 + 6def04d commit 3dff622

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
@@ -822,12 +822,12 @@ static SILInstruction *tryDevirtualizeApplyHelper(FullApplySite InnerAI,
822822
///
823823
/// \returns true if successful, false if failed due to circular inlining.
824824
static bool
825-
runOnFunctionRecursively(SILOptFunctionBuilder &FuncBuilder,
826-
SILFunction *F, FullApplySite AI,
827-
DenseFunctionSet &FullyInlinedSet,
825+
runOnFunctionRecursively(SILOptFunctionBuilder &FuncBuilder, SILFunction *F,
826+
FullApplySite AI, DenseFunctionSet &FullyInlinedSet,
828827
ImmutableFunctionSet::Factory &SetFactory,
829828
ImmutableFunctionSet CurrentInliningSet,
830-
ClassHierarchyAnalysis *CHA) {
829+
ClassHierarchyAnalysis *CHA,
830+
DenseFunctionSet &changedFunctions) {
831831
// Avoid reprocessing functions needlessly.
832832
if (FullyInlinedSet.count(F))
833833
return true;
@@ -874,6 +874,10 @@ runOnFunctionRecursively(SILOptFunctionBuilder &FuncBuilder,
874874
// but a casted result of InnerAI or even a block argument due to
875875
// abstraction changes when calling the witness or class method.
876876
auto *devirtInst = tryDevirtualizeApplyHelper(InnerAI, CHA);
877+
// If devirtualization succeeds, make sure we record that this function
878+
// changed.
879+
if (devirtInst != InnerAI.getInstruction())
880+
changedFunctions.insert(F);
877881
// Restore II to the current apply site.
878882
II = devirtInst->getReverseIterator();
879883
// If the devirtualized call result is no longer a invalid FullApplySite,
@@ -892,9 +896,9 @@ runOnFunctionRecursively(SILOptFunctionBuilder &FuncBuilder,
892896
continue;
893897

894898
// Then recursively process it first before trying to inline it.
895-
if (!runOnFunctionRecursively(FuncBuilder, CalleeFunction, InnerAI,
896-
FullyInlinedSet, SetFactory,
897-
CurrentInliningSet, CHA)) {
899+
if (!runOnFunctionRecursively(
900+
FuncBuilder, CalleeFunction, InnerAI, FullyInlinedSet, SetFactory,
901+
CurrentInliningSet, CHA, changedFunctions)) {
898902
// If we failed due to circular inlining, then emit some notes to
899903
// trace back the failure if we have more information.
900904
// FIXME: possibly it could be worth recovering and attempting other
@@ -984,6 +988,10 @@ runOnFunctionRecursively(SILOptFunctionBuilder &FuncBuilder,
984988
closureCleanup.cleanupDeadClosures(F);
985989
invalidatedStackNesting |= closureCleanup.invalidatedStackNesting;
986990

991+
// Record that we inlined into this function so that we can invalidate it
992+
// later.
993+
changedFunctions.insert(F);
994+
987995
// Resume inlining within nextBB, which contains only the inlined
988996
// instructions and possibly instructions in the original call block that
989997
// have not yet been visited.
@@ -993,6 +1001,7 @@ runOnFunctionRecursively(SILOptFunctionBuilder &FuncBuilder,
9931001

9941002
if (invalidatedStackNesting) {
9951003
StackNesting().correctStackNesting(F);
1004+
changedFunctions.insert(F);
9961005
}
9971006

9981007
// Keep track of full inlined functions so we don't waste time recursively
@@ -1012,10 +1021,10 @@ class MandatoryInlining : public SILModuleTransform {
10121021
void run() override {
10131022
ClassHierarchyAnalysis *CHA = getAnalysis<ClassHierarchyAnalysis>();
10141023
SILModule *M = getModule();
1015-
bool ShouldCleanup = !getOptions().DebugSerialization;
10161024
bool SILVerifyAll = getOptions().VerifyAll;
10171025
DenseFunctionSet FullyInlinedSet;
10181026
ImmutableFunctionSet::Factory SetFactory;
1027+
DenseFunctionSet changedFunctions;
10191028

10201029
SILOptFunctionBuilder FuncBuilder(*this);
10211030
for (auto &F : *M) {
@@ -1027,13 +1036,15 @@ class MandatoryInlining : public SILModuleTransform {
10271036
if (F.wasDeserializedCanonical())
10281037
continue;
10291038

1030-
runOnFunctionRecursively(FuncBuilder, &F,
1031-
FullApplySite(), FullyInlinedSet, SetFactory,
1032-
SetFactory.getEmptySet(), CHA);
1039+
runOnFunctionRecursively(FuncBuilder, &F, FullApplySite(),
1040+
FullyInlinedSet, SetFactory,
1041+
SetFactory.getEmptySet(), CHA, changedFunctions);
10331042

10341043
// The inliner splits blocks at call sites. Re-merge trivial branches
10351044
// to reestablish a canonical CFG.
1036-
mergeBasicBlocks(&F);
1045+
if (mergeBasicBlocks(&F)) {
1046+
changedFunctions.insert(&F);
1047+
}
10371048

10381049
// If we are asked to perform SIL verify all, perform that now so that we
10391050
// can discover the immediate inlining trigger of the problematic
@@ -1043,38 +1054,10 @@ class MandatoryInlining : public SILModuleTransform {
10431054
}
10441055
}
10451056

1046-
if (!ShouldCleanup)
1057+
if (getOptions().DebugSerialization)
10471058
return;
1048-
1049-
// Now that we've inlined some functions, clean up. If there are any
1050-
// transparent functions that are deserialized from another module that are
1051-
// now unused, just remove them from the module.
1052-
//
1053-
// We do this with a simple linear scan, because transparent functions that
1054-
// reference each other have already been flattened.
1055-
for (auto FI = M->begin(), E = M->end(); FI != E; ) {
1056-
SILFunction &F = *FI++;
1057-
1058-
invalidateAnalysis(&F, SILAnalysis::InvalidationKind::Everything);
1059-
1060-
if (F.getRefCount() != 0) continue;
1061-
1062-
// Leave non-transparent functions alone.
1063-
if (!F.isTransparent())
1064-
continue;
1065-
1066-
// We discard functions that don't have external linkage,
1067-
// e.g. deserialized functions, internal functions, and thunks.
1068-
// Being marked transparent controls this.
1069-
if (F.isPossiblyUsedExternally()) continue;
1070-
1071-
// ObjC functions are called through the runtime and are therefore alive
1072-
// even if not referenced inside SIL.
1073-
if (F.getRepresentation() == SILFunctionTypeRepresentation::ObjCMethod)
1074-
continue;
1075-
1076-
// Okay, just erase the function from the module.
1077-
FuncBuilder.eraseFunction(&F);
1059+
for (auto *F : changedFunctions) {
1060+
invalidateAnalysis(F, SILAnalysis::InvalidationKind::Everything);
10781061
}
10791062
}
10801063

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)