Skip to content

Commit 96e1edb

Browse files
authored
Merge pull request #18767 from gottesmm/pr-0983614e249bfc12a55e18d548d5ea5de9cd00fa
2 parents 387c656 + 3c58cd5 commit 96e1edb

File tree

2 files changed

+52
-18
lines changed

2 files changed

+52
-18
lines changed

include/swift/SILOptimizer/Analysis/PassManagerVerifierAnalysis.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "swift/SIL/SILFunction.h"
1717
#include "swift/SILOptimizer/Analysis/Analysis.h"
1818
#include "llvm/ADT/DenseSet.h"
19+
#include "llvm/ADT/StringSet.h"
1920

2021
namespace swift {
2122

@@ -28,10 +29,12 @@ class PassManagerVerifierAnalysis : public SILAnalysis {
2829
LLVM_ATTRIBUTE_UNUSED
2930
SILModule &mod;
3031

31-
/// The set of "live" functions that we are tracking.
32+
/// The set of "live" functions that we are tracking. We store the names of
33+
/// the functions so that if a function is deleted we do not need to touch its
34+
/// memory to get its name.
3235
///
3336
/// All functions in mod must be in liveFunctions and vis-a-versa.
34-
llvm::DenseSet<SILFunction *> liveFunctions;
37+
llvm::StringSet<> liveFunctionNames;
3538

3639
public:
3740
PassManagerVerifierAnalysis(SILModule *mod);
@@ -58,7 +61,7 @@ class PassManagerVerifierAnalysis : public SILAnalysis {
5861
void invalidateFunctionTables() override final;
5962

6063
/// Run the entire verification.
61-
void verify() const override final;
64+
void verifyFull() const override final;
6265
};
6366

6467
} // namespace swift

lib/SILOptimizer/Analysis/PassManagerVerifierAnalysis.cpp

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ PassManagerVerifierAnalysis::PassManagerVerifierAnalysis(SILModule *mod)
3131
for (auto &fn : *mod) {
3232
LLVM_DEBUG(llvm::dbgs() << "PMVerifierAnalysis. Add: " << fn.getName()
3333
<< '\n');
34-
liveFunctions.insert(&fn);
34+
liveFunctionNames.insert(fn.getName());
3535
}
3636
#endif
3737
}
@@ -52,7 +52,7 @@ void PassManagerVerifierAnalysis::notifyAddedOrModifiedFunction(
5252
return;
5353
LLVM_DEBUG(llvm::dbgs() << "PMVerifierAnalysis. Add|Mod: " << f->getName()
5454
<< '\n');
55-
liveFunctions.insert(f);
55+
liveFunctionNames.insert(f->getName());
5656
#endif
5757
}
5858

@@ -63,9 +63,13 @@ void PassManagerVerifierAnalysis::notifyWillDeleteFunction(SILFunction *f) {
6363
return;
6464
LLVM_DEBUG(llvm::dbgs() << "PMVerifierAnalysis. Delete: " << f->getName()
6565
<< '\n');
66-
assert(liveFunctions.count(f) &&
67-
"Tried to delete function that analysis was not aware of?!");
68-
liveFunctions.erase(f);
66+
if (liveFunctionNames.erase(f->getName()))
67+
return;
68+
69+
llvm::errs()
70+
<< "Error! Tried to delete function that analysis was not aware of: "
71+
<< f->getName() << '\n';
72+
llvm_unreachable("triggering standard assertion failure routine");
6973
#endif
7074
}
7175

@@ -74,22 +78,49 @@ void PassManagerVerifierAnalysis::notifyWillDeleteFunction(SILFunction *f) {
7478
void PassManagerVerifierAnalysis::invalidateFunctionTables() {}
7579

7680
/// Run the entire verification.
77-
void PassManagerVerifierAnalysis::verify() const {
81+
void PassManagerVerifierAnalysis::verifyFull() const {
7882
#ifndef NDEBUG
7983
if (!EnableVerifier)
8084
return;
8185

82-
// We check that all functions in the module are in liveFunctions /and/ then
83-
// make sure that liveFunctions has the same number of elements. If we have
84-
// too many elements, this means we missed a delete event.
85-
unsigned funcCount = 0;
86+
// We check that liveFunctionNames is in sync with the module's function list
87+
// by going through the module's function list and attempting to remove all
88+
// functions in the module. If we fail to remove fn, then we know that a
89+
// function was added to the module without an appropriate message being sent
90+
// by the pass manager.
91+
bool foundError = false;
92+
93+
unsigned count = 0;
8694
for (auto &fn : mod) {
87-
++funcCount;
88-
assert(liveFunctions.count(&fn) &&
89-
"Found function in module that verifier is not aware of?!");
95+
if (liveFunctionNames.count(fn.getName())) {
96+
++count;
97+
continue;
98+
}
99+
llvm::errs() << "Found function in module that was not added to verifier: "
100+
<< fn.getName() << '\n';
101+
foundError = true;
90102
}
91-
assert(liveFunctions.size() == funcCount &&
92-
"Analysis has state for deleted functions?!");
103+
104+
// Ok, so now we know that function(mod) is a subset of
105+
// liveFunctionNames. Relying on the uniqueness provided by the module's
106+
// function list, we know that liveFunction should be exactly count in
107+
// size. Otherwise, we must have an error. If and only if we detect this
108+
// error, do the expensive work of finding the missing deletes. This is an
109+
// important performance optimization to avoid a large copy on the hot path.
110+
if (liveFunctionNames.size() != count) {
111+
auto liveFunctionNamesCopy = llvm::StringSet<>(liveFunctionNames);
112+
for (auto &fn : mod) {
113+
liveFunctionNamesCopy.erase(fn.getName());
114+
}
115+
for (auto &iter : liveFunctionNamesCopy) {
116+
llvm::errs() << "Missing delete message for function: " << iter.first()
117+
<< '\n';
118+
foundError = true;
119+
}
120+
}
121+
122+
// We assert here so we emit /all/ errors before asserting.
123+
assert(!foundError && "triggering standard assertion failure routine");
93124
#endif
94125
}
95126

0 commit comments

Comments
 (0)