Skip to content

Commit 7b611fc

Browse files
authored
Merge pull request #29410 from atrick/escape-verify-unmapped
Add EscapeAnalysis verification to catch unmapped SILValues.
2 parents 96cd8fa + 06645d3 commit 7b611fc

File tree

2 files changed

+79
-44
lines changed

2 files changed

+79
-44
lines changed

include/swift/SILOptimizer/Analysis/EscapeAnalysis.h

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
660660
: F(F), EA(EA), isSummaryGraph(isSummaryGraph) {}
661661

662662
/// Returns true if the connection graph is empty.
663-
bool isEmpty() {
663+
bool isEmpty() const {
664664
return Values2Nodes.empty() && Nodes.empty() && UsePoints.empty();
665665
}
666666

@@ -906,11 +906,10 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
906906
/// Dump the connection graph to a DOT file for remote debugging.
907907
void dumpCG() const;
908908

909-
/// Checks if the graph is OK.
910-
void verify(bool allowMerge = false) const;
909+
/// Checks if the graph is valid and complete.
910+
void verify() const;
911911

912-
/// Just verifies the graph structure. This function can also be called
913-
/// during the graph is modified, e.g. in mergeAllScheduledNodes().
912+
/// Just verifies the graph nodes.
914913
void verifyStructure(bool allowMerge = false) const;
915914

916915
friend struct ::CGForDotView;
@@ -1045,8 +1044,9 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
10451044

10461045
/// If \p ai is an optimizable @_semantics("array.uninitialized") call, return
10471046
/// valid call information.
1048-
ArrayUninitCall canOptimizeArrayUninitializedCall(ApplyInst *ai,
1049-
ConnectionGraph *conGraph);
1047+
ArrayUninitCall
1048+
canOptimizeArrayUninitializedCall(ApplyInst *ai,
1049+
const ConnectionGraph *conGraph);
10501050

10511051
/// Return true of this tuple_extract is the result of an optimizable
10521052
/// @_semantics("array.uninitialized") call.
@@ -1174,25 +1174,9 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
11741174

11751175
virtual bool needsNotifications() override { return true; }
11761176

1177-
virtual void verify() const override {
1178-
#ifndef NDEBUG
1179-
for (auto Iter : Function2Info) {
1180-
FunctionInfo *FInfo = Iter.second;
1181-
FInfo->Graph.verify();
1182-
FInfo->SummaryGraph.verify();
1183-
}
1184-
#endif
1185-
}
1186-
1187-
virtual void verify(SILFunction *F) const override {
1188-
#ifndef NDEBUG
1189-
if (FunctionInfo *FInfo = Function2Info.lookup(F)) {
1190-
FInfo->Graph.verify();
1191-
FInfo->SummaryGraph.verify();
1192-
}
1193-
#endif
1194-
}
1177+
virtual void verify() const override;
11951178

1179+
virtual void verify(SILFunction *F) const override;
11961180
};
11971181

11981182
} // end namespace swift

lib/SILOptimizer/Analysis/EscapeAnalysis.cpp

Lines changed: 70 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,7 @@ void EscapeAnalysis::ConnectionGraph::mergeAllScheduledNodes() {
609609
// To pointsTo-> NodeB (but still has a pointsTo edge to NodeB)
610610
while (!ToMerge.empty()) {
611611
if (EnableInternalVerify)
612-
verify(/*allowMerge=*/true);
612+
verifyStructure(true /*allowMerge*/);
613613

614614
CGNode *From = ToMerge.pop_back_val();
615615
CGNode *To = From->getMergeTarget();
@@ -745,7 +745,6 @@ void EscapeAnalysis::ConnectionGraph::mergeAllScheduledNodes() {
745745
From->isMerged = true;
746746

747747
if (From->mappedValue) {
748-
// If possible, transfer 'From's mappedValue to 'To' for clarity. Any
749748
// values previously mapped to 'From' but not transferred to 'To's
750749
// mappedValue must remain mapped to 'From'. Lookups on those values will
751750
// find 'To' via the mergeTarget. Dropping a value's mapping is illegal
@@ -762,7 +761,7 @@ void EscapeAnalysis::ConnectionGraph::mergeAllScheduledNodes() {
762761
From->pointsTo = nullptr;
763762
}
764763
if (EnableInternalVerify)
765-
verify(/*allowMerge=*/true);
764+
verifyStructure(true /*allowMerge*/);
766765
}
767766

768767
// As a result of a merge, update the pointsTo field of initialNode and
@@ -1574,21 +1573,40 @@ bool CGNode::matchPointToOfDefers(bool allowMerge) const {
15741573
return true;
15751574
}
15761575

1577-
void EscapeAnalysis::ConnectionGraph::verify(bool allowMerge) const {
1576+
void EscapeAnalysis::ConnectionGraph::verify() const {
15781577
#ifndef NDEBUG
1579-
verifyStructure(allowMerge);
1578+
// Invalidating EscapeAnalysis clears the connection graph.
1579+
if (isEmpty())
1580+
return;
15801581

1581-
// Check graph invariants
1582-
for (CGNode *Nd : Nodes) {
1583-
// ConnectionGraph invariant #4: For any node N, all paths starting at N
1584-
// which consist of only defer-edges and a single trailing points-to edge
1585-
// must lead to the same
1586-
assert(Nd->matchPointToOfDefers(allowMerge));
1587-
if (Nd->mappedValue && !(allowMerge && Nd->isMerged)) {
1588-
assert(Nd == Values2Nodes.lookup(Nd->mappedValue));
1589-
assert(EA->isPointer(Nd->mappedValue));
1590-
// Nodes must always be mapped from the pointer root value.
1591-
assert(Nd->mappedValue == EA->getPointerRoot(Nd->mappedValue));
1582+
verifyStructure();
1583+
1584+
// Verify that all pointer nodes are still mapped, otherwise the process of
1585+
// merging nodes may have lost information.
1586+
for (SILBasicBlock &BB : *F) {
1587+
for (auto &I : BB) {
1588+
if (isNonWritableMemoryAddress(&I))
1589+
continue;
1590+
1591+
if (auto ai = dyn_cast<ApplyInst>(&I)) {
1592+
if (EA->canOptimizeArrayUninitializedCall(ai, this).isValid())
1593+
continue;
1594+
}
1595+
for (auto result : I.getResults()) {
1596+
if (EA->getPointerBase(result))
1597+
continue;
1598+
1599+
if (!EA->isPointer(result))
1600+
continue;
1601+
1602+
if (!Values2Nodes.lookup(result)) {
1603+
llvm::dbgs() << "No CG mapping for ";
1604+
result->dumpInContext();
1605+
llvm::dbgs() << " in:\n";
1606+
F->dump();
1607+
llvm_unreachable("Missing escape connection graph mapping");
1608+
}
1609+
}
15921610
}
15931611
}
15941612
#endif
@@ -1597,6 +1615,7 @@ void EscapeAnalysis::ConnectionGraph::verify(bool allowMerge) const {
15971615
void EscapeAnalysis::ConnectionGraph::verifyStructure(bool allowMerge) const {
15981616
#ifndef NDEBUG
15991617
for (CGNode *Nd : Nodes) {
1618+
// Verify the graph structure...
16001619
if (Nd->isMerged) {
16011620
assert(Nd->mergeTo);
16021621
assert(!Nd->pointsTo);
@@ -1625,6 +1644,19 @@ void EscapeAnalysis::ConnectionGraph::verifyStructure(bool allowMerge) const {
16251644
}
16261645
if (Nd->isInterior())
16271646
assert(Nd->pointsTo && "Interior content node requires a pointsTo node");
1647+
1648+
// ConnectionGraph invariant #4: For any node N, all paths starting at N
1649+
// which consist of only defer-edges and a single trailing points-to edge
1650+
// must lead to the same
1651+
assert(Nd->matchPointToOfDefers(allowMerge));
1652+
1653+
// Verify the node to value mapping...
1654+
if (Nd->mappedValue && !(allowMerge && Nd->isMerged)) {
1655+
assert(Nd == Values2Nodes.lookup(Nd->mappedValue));
1656+
assert(EA->isPointer(Nd->mappedValue));
1657+
// Nodes must always be mapped from the pointer root value.
1658+
assert(Nd->mappedValue == EA->getPointerRoot(Nd->mappedValue));
1659+
}
16281660
}
16291661
#endif
16301662
}
@@ -1780,8 +1812,8 @@ bool EscapeAnalysis::buildConnectionGraphForDestructor(
17801812
}
17811813

17821814
EscapeAnalysis::ArrayUninitCall
1783-
EscapeAnalysis::canOptimizeArrayUninitializedCall(ApplyInst *ai,
1784-
ConnectionGraph *conGraph) {
1815+
EscapeAnalysis::canOptimizeArrayUninitializedCall(
1816+
ApplyInst *ai, const ConnectionGraph *conGraph) {
17851817
ArrayUninitCall call;
17861818
// This must be an exact match so we don't accidentally optimize
17871819
// "array.uninitialized_intrinsic".
@@ -2425,7 +2457,7 @@ void EscapeAnalysis::recompute(FunctionInfo *Initial) {
24252457
if (BottomUpOrder.wasRecomputedWithCurrentUpdateID(FInfo)) {
24262458
FInfo->Graph.computeUsePoints();
24272459
FInfo->Graph.verify();
2428-
FInfo->SummaryGraph.verify();
2460+
FInfo->SummaryGraph.verifyStructure();
24292461
}
24302462
}
24312463
}
@@ -2766,6 +2798,25 @@ void EscapeAnalysis::handleDeleteNotification(SILNode *node) {
27662798
}
27672799
}
27682800

2801+
void EscapeAnalysis::verify() const {
2802+
#ifndef NDEBUG
2803+
for (auto Iter : Function2Info) {
2804+
FunctionInfo *FInfo = Iter.second;
2805+
FInfo->Graph.verify();
2806+
FInfo->SummaryGraph.verifyStructure();
2807+
}
2808+
#endif
2809+
}
2810+
2811+
void EscapeAnalysis::verify(SILFunction *F) const {
2812+
#ifndef NDEBUG
2813+
if (FunctionInfo *FInfo = Function2Info.lookup(F)) {
2814+
FInfo->Graph.verify();
2815+
FInfo->SummaryGraph.verifyStructure();
2816+
}
2817+
#endif
2818+
}
2819+
27692820
SILAnalysis *swift::createEscapeAnalysis(SILModule *M) {
27702821
return new EscapeAnalysis(M);
27712822
}

0 commit comments

Comments
 (0)