@@ -31,7 +31,7 @@ PassManagerVerifierAnalysis::PassManagerVerifierAnalysis(SILModule *mod)
31
31
for (auto &fn : *mod) {
32
32
LLVM_DEBUG (llvm::dbgs () << " PMVerifierAnalysis. Add: " << fn.getName ()
33
33
<< ' \n ' );
34
- liveFunctions .insert (&fn );
34
+ liveFunctionNames .insert (fn. getName () );
35
35
}
36
36
#endif
37
37
}
@@ -52,7 +52,7 @@ void PassManagerVerifierAnalysis::notifyAddedOrModifiedFunction(
52
52
return ;
53
53
LLVM_DEBUG (llvm::dbgs () << " PMVerifierAnalysis. Add|Mod: " << f->getName ()
54
54
<< ' \n ' );
55
- liveFunctions .insert (f);
55
+ liveFunctionNames .insert (f-> getName () );
56
56
#endif
57
57
}
58
58
@@ -63,9 +63,13 @@ void PassManagerVerifierAnalysis::notifyWillDeleteFunction(SILFunction *f) {
63
63
return ;
64
64
LLVM_DEBUG (llvm::dbgs () << " PMVerifierAnalysis. Delete: " << f->getName ()
65
65
<< ' \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" );
69
73
#endif
70
74
}
71
75
@@ -74,22 +78,49 @@ void PassManagerVerifierAnalysis::notifyWillDeleteFunction(SILFunction *f) {
74
78
void PassManagerVerifierAnalysis::invalidateFunctionTables () {}
75
79
76
80
// / Run the entire verification.
77
- void PassManagerVerifierAnalysis::verify () const {
81
+ void PassManagerVerifierAnalysis::verifyFull () const {
78
82
#ifndef NDEBUG
79
83
if (!EnableVerifier)
80
84
return ;
81
85
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 ;
86
94
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 ;
90
102
}
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" );
93
124
#endif
94
125
}
95
126
0 commit comments