Skip to content

Commit d28ab08

Browse files
authored
Merge pull request swiftlang#30473 from atrick/fix-devirtualizer-invalidate
SILOptimizer: Fix analysis invalidation after devirtualization.
2 parents c04a8a9 + 70678ab commit d28ab08

File tree

5 files changed

+99
-69
lines changed

5 files changed

+99
-69
lines changed

include/swift/SILOptimizer/Utils/Devirtualize.h

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,11 @@ SubstitutionMap getWitnessMethodSubstitutions(SILModule &Module, ApplySite AI,
6565
///
6666
/// If this succeeds, the caller must call deleteDevirtualizedApply on
6767
/// the original apply site.
68-
ApplySite tryDevirtualizeApply(ApplySite AI,
69-
ClassHierarchyAnalysis *CHA,
70-
OptRemark::Emitter *ORE = nullptr);
68+
///
69+
/// Return the new apply and true if the CFG was also modified.
70+
std::pair<ApplySite, bool>
71+
tryDevirtualizeApply(ApplySite AI, ClassHierarchyAnalysis *CHA,
72+
OptRemark::Emitter *ORE = nullptr);
7173
bool canDevirtualizeApply(FullApplySite AI, ClassHierarchyAnalysis *CHA);
7274
bool canDevirtualizeClassMethod(FullApplySite AI, ClassDecl *CD,
7375
OptRemark::Emitter *ORE = nullptr,
@@ -79,21 +81,23 @@ CanType getSelfInstanceType(CanType ClassOrMetatypeType);
7981
/// Devirtualize the given apply site, which is known to be devirtualizable.
8082
///
8183
/// The caller must call deleteDevirtualizedApply on the original apply site.
82-
FullApplySite devirtualizeClassMethod(FullApplySite AI,
83-
SILValue ClassInstance,
84-
ClassDecl *CD,
85-
OptRemark::Emitter *ORE);
84+
///
85+
/// Return the new apply and true if the CFG was also modified.
86+
std::pair<FullApplySite, bool> devirtualizeClassMethod(FullApplySite AI,
87+
SILValue ClassInstance,
88+
ClassDecl *CD,
89+
OptRemark::Emitter *ORE);
8690

8791
/// Attempt to devirtualize the given apply site, which is known to be
8892
/// of a class method. If this fails, the returned FullApplySite will be null.
8993
///
9094
/// If this succeeds, the caller must call deleteDevirtualizedApply on
9195
/// the original apply site.
92-
FullApplySite
93-
tryDevirtualizeClassMethod(FullApplySite AI,
94-
SILValue ClassInstance,
95-
ClassDecl *CD,
96-
OptRemark::Emitter *ORE,
96+
///
97+
/// Return the new apply and true if the CFG was also modified.
98+
std::pair<FullApplySite, bool>
99+
tryDevirtualizeClassMethod(FullApplySite AI, SILValue ClassInstance,
100+
ClassDecl *CD, OptRemark::Emitter *ORE,
97101
bool isEffectivelyFinalMethod = false);
98102

99103
/// Attempt to devirtualize the given apply site, which is known to be
@@ -102,7 +106,9 @@ tryDevirtualizeClassMethod(FullApplySite AI,
102106
///
103107
/// If this succeeds, the caller must call deleteDevirtualizedApply on
104108
/// the original apply site.
105-
ApplySite tryDevirtualizeWitnessMethod(ApplySite AI, OptRemark::Emitter *ORE);
109+
///
110+
/// Return the new apply and true if the CFG was also modified.
111+
std::pair<ApplySite, bool> tryDevirtualizeWitnessMethod(ApplySite AI, OptRemark::Emitter *ORE);
106112

107113
/// Delete a successfully-devirtualized apply site. This must always be
108114
/// called after devirtualizing an apply; not only is it not semantically

lib/SILOptimizer/Mandatory/MandatoryInlining.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -760,7 +760,7 @@ getCalleeFunction(SILFunction *F, FullApplySite AI, bool &IsThick,
760760

761761
static SILInstruction *tryDevirtualizeApplyHelper(FullApplySite InnerAI,
762762
ClassHierarchyAnalysis *CHA) {
763-
auto NewInst = tryDevirtualizeApply(InnerAI, CHA);
763+
auto NewInst = tryDevirtualizeApply(InnerAI, CHA).first;
764764
if (!NewInst)
765765
return InnerAI.getInstruction();
766766

lib/SILOptimizer/Transforms/Devirtualizer.cpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ using namespace swift;
3030
namespace {
3131

3232
class Devirtualizer : public SILFunctionTransform {
33+
bool Changed = false;
34+
bool ChangedCFG = false;
3335

34-
bool devirtualizeAppliesInFunction(SILFunction &F,
36+
void devirtualizeAppliesInFunction(SILFunction &F,
3537
ClassHierarchyAnalysis *CHA);
3638

3739
/// The entry point to the transformation.
@@ -41,17 +43,22 @@ class Devirtualizer : public SILFunctionTransform {
4143
LLVM_DEBUG(llvm::dbgs() << "***** Devirtualizer on function:" << F.getName()
4244
<< " *****\n");
4345

44-
if (devirtualizeAppliesInFunction(F, CHA))
46+
Changed = false;
47+
ChangedCFG = false;
48+
devirtualizeAppliesInFunction(F, CHA);
49+
if (ChangedCFG)
50+
invalidateAnalysis(SILAnalysis::InvalidationKind::Everything);
51+
else if (Changed)
4552
invalidateAnalysis(SILAnalysis::InvalidationKind::CallsAndInstructions);
4653
}
4754

4855
};
4956

5057
} // end anonymous namespace
5158

52-
bool Devirtualizer::devirtualizeAppliesInFunction(SILFunction &F,
59+
// Return true if any calls changed, and true if the CFG also changed.
60+
void Devirtualizer::devirtualizeAppliesInFunction(SILFunction &F,
5361
ClassHierarchyAnalysis *CHA) {
54-
bool Changed = false;
5562
llvm::SmallVector<ApplySite, 8> NewApplies;
5663
OptRemark::Emitter ORE(DEBUG_TYPE, F.getModule());
5764

@@ -69,11 +76,14 @@ bool Devirtualizer::devirtualizeAppliesInFunction(SILFunction &F,
6976
}
7077
}
7178
for (auto Apply : Applies) {
72-
auto NewInst = tryDevirtualizeApply(Apply, CHA, &ORE);
79+
ApplySite NewInst;
80+
bool modifiedCFG;
81+
std::tie(NewInst, modifiedCFG) = tryDevirtualizeApply(Apply, CHA, &ORE);
7382
if (!NewInst)
7483
continue;
7584

7685
Changed = true;
86+
ChangedCFG |= modifiedCFG;
7787

7888
deleteDevirtualizedApply(Apply);
7989
NewApplies.push_back(NewInst);
@@ -105,8 +115,6 @@ bool Devirtualizer::devirtualizeAppliesInFunction(SILFunction &F,
105115
if (CalleeFn->isDefinition() && CalleeFn->shouldOptimize())
106116
addFunctionToPassManagerWorklist(CalleeFn, nullptr);
107117
}
108-
109-
return Changed;
110118
}
111119

112120
SILTransform *swift::createDevirtualizer() { return new Devirtualizer(); }

lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,8 @@ static FullApplySite speculateMonomorphicTarget(FullApplySite AI,
229229

230230
// Devirtualize the apply instruction on the identical path.
231231
auto NewInst =
232-
devirtualizeClassMethod(IdenAI, DownCastedClassInstance, CD, nullptr);
232+
devirtualizeClassMethod(IdenAI, DownCastedClassInstance, CD, nullptr)
233+
.first;
233234
assert(NewInst && "Expected to be able to devirtualize apply!");
234235
(void)NewInst;
235236

@@ -414,7 +415,8 @@ static bool tryToSpeculateTarget(FullApplySite AI, ClassHierarchyAnalysis *CHA,
414415
// try to devirtualize it completely.
415416
ClassHierarchyAnalysis::ClassList Subs;
416417
if (isDefaultCaseKnown(CHA, AI, CD, Subs)) {
417-
auto NewInst = tryDevirtualizeClassMethod(AI, SubTypeValue, CD, &ORE);
418+
auto NewInst =
419+
tryDevirtualizeClassMethod(AI, SubTypeValue, CD, &ORE).first;
418420
if (NewInst)
419421
deleteDevirtualizedApply(AI);
420422
return bool(NewInst);
@@ -574,7 +576,8 @@ static bool tryToSpeculateTarget(FullApplySite AI, ClassHierarchyAnalysis *CHA,
574576
ORE.emit(RB);
575577
return true;
576578
}
577-
auto NewInst = tryDevirtualizeClassMethod(AI, SubTypeValue, CD, nullptr);
579+
auto NewInst =
580+
tryDevirtualizeClassMethod(AI, SubTypeValue, CD, nullptr).first;
578581
if (NewInst) {
579582
ORE.emit(RB);
580583
deleteDevirtualizedApply(AI);

lib/SILOptimizer/Utils/Devirtualize.cpp

Lines changed: 58 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -482,12 +482,12 @@ static ApplyInst *replaceApplyInst(SILBuilder &builder, SILLocation loc,
482482
return newAI;
483483
}
484484

485-
static TryApplyInst *replaceTryApplyInst(SILBuilder &builder, SILLocation loc,
486-
TryApplyInst *oldTAI, SILValue newFn,
487-
SubstitutionMap newSubs,
488-
ArrayRef<SILValue> newArgs,
489-
SILFunctionConventions conv,
490-
ArrayRef<SILValue> newArgBorrows) {
485+
// Return the new try_apply and true if a cast required CFG modification.
486+
static std::pair<TryApplyInst *, bool>
487+
replaceTryApplyInst(SILBuilder &builder, SILLocation loc, TryApplyInst *oldTAI,
488+
SILValue newFn, SubstitutionMap newSubs,
489+
ArrayRef<SILValue> newArgs, SILFunctionConventions conv,
490+
ArrayRef<SILValue> newArgBorrows) {
491491
SILBasicBlock *normalBB = oldTAI->getNormalBB();
492492
SILBasicBlock *resultBB = nullptr;
493493

@@ -537,7 +537,7 @@ static TryApplyInst *replaceTryApplyInst(SILBuilder &builder, SILLocation loc,
537537
}
538538

539539
builder.setInsertionPoint(normalBB->begin());
540-
return newTAI;
540+
return {newTAI, resultCastRequired};
541541
}
542542

543543
static BeginApplyInst *
@@ -599,17 +599,18 @@ replacePartialApplyInst(SILBuilder &builder, SILLocation loc,
599599
return newPAI;
600600
}
601601

602-
static ApplySite replaceApplySite(SILBuilder &builder, SILLocation loc,
603-
ApplySite oldAS, SILValue newFn,
604-
SubstitutionMap newSubs,
605-
ArrayRef<SILValue> newArgs,
606-
SILFunctionConventions conv,
607-
ArrayRef<SILValue> newArgBorrows) {
602+
// Return the new apply and true if the CFG was also modified.
603+
static std::pair<ApplySite, bool>
604+
replaceApplySite(SILBuilder &builder, SILLocation loc, ApplySite oldAS,
605+
SILValue newFn, SubstitutionMap newSubs,
606+
ArrayRef<SILValue> newArgs, SILFunctionConventions conv,
607+
ArrayRef<SILValue> newArgBorrows) {
608608
switch (oldAS.getKind()) {
609609
case ApplySiteKind::ApplyInst: {
610610
auto *oldAI = cast<ApplyInst>(oldAS);
611-
return replaceApplyInst(builder, loc, oldAI, newFn, newSubs, newArgs,
612-
newArgBorrows);
611+
return {replaceApplyInst(builder, loc, oldAI, newFn, newSubs, newArgs,
612+
newArgBorrows),
613+
false};
613614
}
614615
case ApplySiteKind::TryApplyInst: {
615616
auto *oldTAI = cast<TryApplyInst>(oldAS);
@@ -618,14 +619,16 @@ static ApplySite replaceApplySite(SILBuilder &builder, SILLocation loc,
618619
}
619620
case ApplySiteKind::BeginApplyInst: {
620621
auto *oldBAI = dyn_cast<BeginApplyInst>(oldAS);
621-
return replaceBeginApplyInst(builder, loc, oldBAI, newFn, newSubs, newArgs,
622-
newArgBorrows);
622+
return {replaceBeginApplyInst(builder, loc, oldBAI, newFn, newSubs, newArgs,
623+
newArgBorrows),
624+
false};
623625
}
624626
case ApplySiteKind::PartialApplyInst: {
625627
assert(newArgBorrows.empty());
626628
auto *oldPAI = cast<PartialApplyInst>(oldAS);
627-
return replacePartialApplyInst(builder, loc, oldPAI, newFn, newSubs,
628-
newArgs);
629+
return {
630+
replacePartialApplyInst(builder, loc, oldPAI, newFn, newSubs, newArgs),
631+
false};
629632
}
630633
}
631634
llvm_unreachable("covered switch");
@@ -729,10 +732,12 @@ bool swift::canDevirtualizeClassMethod(FullApplySite applySite, ClassDecl *cd,
729732
/// \p ClassOrMetatype is a class value or metatype value that is the
730733
/// self argument of the apply we will devirtualize.
731734
/// return the result value of the new ApplyInst if created one or null.
732-
FullApplySite swift::devirtualizeClassMethod(FullApplySite applySite,
733-
SILValue classOrMetatype,
734-
ClassDecl *cd,
735-
OptRemark::Emitter *ore) {
735+
///
736+
/// Return the new apply and true if the CFG was also modified.
737+
std::pair<FullApplySite, bool>
738+
swift::devirtualizeClassMethod(FullApplySite applySite,
739+
SILValue classOrMetatype, ClassDecl *cd,
740+
OptRemark::Emitter *ore) {
736741
LLVM_DEBUG(llvm::dbgs() << " Trying to devirtualize : "
737742
<< *applySite.getInstruction());
738743

@@ -793,8 +798,10 @@ FullApplySite swift::devirtualizeClassMethod(FullApplySite applySite,
793798
newArgs.push_back(arg);
794799
++paramArgIter;
795800
}
796-
ApplySite newAS = replaceApplySite(builder, loc, applySite, fri, subs,
797-
newArgs, substConv, newArgBorrows);
801+
ApplySite newAS;
802+
bool modifiedCFG;
803+
std::tie(newAS, modifiedCFG) = replaceApplySite(
804+
builder, loc, applySite, fri, subs, newArgs, substConv, newArgBorrows);
798805
FullApplySite newAI = FullApplySite::isa(newAS.getInstruction());
799806
assert(newAI);
800807

@@ -808,16 +815,14 @@ FullApplySite swift::devirtualizeClassMethod(FullApplySite applySite,
808815
});
809816
NumClassDevirt++;
810817

811-
return newAI;
818+
return {newAI, modifiedCFG};
812819
}
813820

814-
FullApplySite swift::tryDevirtualizeClassMethod(FullApplySite applySite,
815-
SILValue classInstance,
816-
ClassDecl *cd,
817-
OptRemark::Emitter *ore,
818-
bool isEffectivelyFinalMethod) {
821+
std::pair<FullApplySite, bool> swift::tryDevirtualizeClassMethod(
822+
FullApplySite applySite, SILValue classInstance, ClassDecl *cd,
823+
OptRemark::Emitter *ore, bool isEffectivelyFinalMethod) {
819824
if (!canDevirtualizeClassMethod(applySite, cd, ore, isEffectivelyFinalMethod))
820-
return FullApplySite();
825+
return {FullApplySite(), false};
821826
return devirtualizeClassMethod(applySite, classInstance, cd, ore);
822827
}
823828

@@ -960,9 +965,12 @@ swift::getWitnessMethodSubstitutions(SILModule &module, ApplySite applySite,
960965
/// Generate a new apply of a function_ref to replace an apply of a
961966
/// witness_method when we've determined the actual function we'll end
962967
/// up calling.
963-
static ApplySite devirtualizeWitnessMethod(ApplySite applySite, SILFunction *f,
964-
ProtocolConformanceRef cRef,
965-
OptRemark::Emitter *ore) {
968+
///
969+
/// Return the new apply and true if the CFG was also modified.
970+
static std::pair<ApplySite, bool>
971+
devirtualizeWitnessMethod(ApplySite applySite, SILFunction *f,
972+
ProtocolConformanceRef cRef,
973+
OptRemark::Emitter *ore) {
966974
// We know the witness thunk and the corresponding set of substitutions
967975
// required to invoke the protocol method at this point.
968976
auto &module = applySite.getModule();
@@ -1017,7 +1025,9 @@ static ApplySite devirtualizeWitnessMethod(ApplySite applySite, SILFunction *f,
10171025
SILLocation loc = applySite.getLoc();
10181026
auto *fri = applyBuilder.createFunctionRefFor(loc, f);
10191027

1020-
ApplySite newApplySite =
1028+
ApplySite newApplySite;
1029+
bool modifiedCFG;
1030+
std::tie(newApplySite, modifiedCFG) =
10211031
replaceApplySite(applyBuilder, loc, applySite, fri, subMap, arguments,
10221032
substConv, borrowedArgs);
10231033

@@ -1029,7 +1039,7 @@ static ApplySite devirtualizeWitnessMethod(ApplySite applySite, SILFunction *f,
10291039
<< "Devirtualized call to " << NV("Method", f);
10301040
});
10311041
NumWitnessDevirt++;
1032-
return newApplySite;
1042+
return {newApplySite, modifiedCFG};
10331043
}
10341044

10351045
static bool canDevirtualizeWitnessMethod(ApplySite applySite) {
@@ -1066,10 +1076,11 @@ static bool canDevirtualizeWitnessMethod(ApplySite applySite) {
10661076
/// In the cases where we can statically determine the function that
10671077
/// we'll call to, replace an apply of a witness_method with an apply
10681078
/// of a function_ref, returning the new apply.
1069-
ApplySite swift::tryDevirtualizeWitnessMethod(ApplySite applySite,
1070-
OptRemark::Emitter *ore) {
1079+
std::pair<ApplySite, bool>
1080+
swift::tryDevirtualizeWitnessMethod(ApplySite applySite,
1081+
OptRemark::Emitter *ore) {
10711082
if (!canDevirtualizeWitnessMethod(applySite))
1072-
return ApplySite();
1083+
return {ApplySite(), false};
10731084

10741085
SILFunction *f;
10751086
SILWitnessTable *wt;
@@ -1088,9 +1099,11 @@ ApplySite swift::tryDevirtualizeWitnessMethod(ApplySite applySite,
10881099

10891100
/// Attempt to devirtualize the given apply if possible, and return a
10901101
/// new instruction in that case, or nullptr otherwise.
1091-
ApplySite swift::tryDevirtualizeApply(ApplySite applySite,
1092-
ClassHierarchyAnalysis *cha,
1093-
OptRemark::Emitter *ore) {
1102+
///
1103+
/// Return the new apply and true if the CFG was also modified.
1104+
std::pair<ApplySite, bool>
1105+
swift::tryDevirtualizeApply(ApplySite applySite, ClassHierarchyAnalysis *cha,
1106+
OptRemark::Emitter *ore) {
10941107
LLVM_DEBUG(llvm::dbgs() << " Trying to devirtualize: "
10951108
<< *applySite.getInstruction());
10961109

@@ -1105,7 +1118,7 @@ ApplySite swift::tryDevirtualizeApply(ApplySite applySite,
11051118
// TODO: check if we can also de-virtualize partial applies of class methods.
11061119
FullApplySite fas = FullApplySite::isa(applySite.getInstruction());
11071120
if (!fas)
1108-
return ApplySite();
1121+
return {ApplySite(), false};
11091122

11101123
/// Optimize a class_method and alloc_ref pair into a direct function
11111124
/// reference:
@@ -1151,7 +1164,7 @@ ApplySite swift::tryDevirtualizeApply(ApplySite applySite,
11511164
return tryDevirtualizeClassMethod(fas, instance, cd, ore);
11521165
}
11531166

1154-
return ApplySite();
1167+
return {ApplySite(), false};
11551168
}
11561169

11571170
bool swift::canDevirtualizeApply(FullApplySite applySite,

0 commit comments

Comments
 (0)