@@ -46,15 +46,18 @@ bool Evaluator::checkDependency(const AnyRequest &request) {
46
46
return false ;
47
47
}
48
48
49
+ // Diagnose cycle.
49
50
switch (shouldDiagnoseCycles) {
50
51
case CycleDiagnosticKind::NoDiagnose:
51
52
return true ;
52
53
53
54
case CycleDiagnosticKind::DebugDiagnose: {
54
- llvm::dbgs () << " ===CYCLE DETECTED===\n " ;
55
- llvm::DenseSet<AnyRequest> visited;
55
+ llvm::errs () << " ===CYCLE DETECTED===\n " ;
56
+ llvm::DenseSet<AnyRequest> visitedAnywhere;
57
+ llvm::SmallVector<AnyRequest, 4 > visitedAlongPath;
56
58
std::string prefixStr;
57
- printDependencies (activeRequests.front (), llvm::dbgs (), visited,
59
+ printDependencies (activeRequests.front (), llvm::errs (), visitedAnywhere,
60
+ visitedAlongPath, activeRequests.getArrayRef (),
58
61
prefixStr, /* lastChild=*/ true );
59
62
return true ;
60
63
}
@@ -78,27 +81,52 @@ void Evaluator::diagnoseCycle(const AnyRequest &request) {
78
81
llvm_unreachable (" Diagnosed a cycle but it wasn't represented in the stack" );
79
82
}
80
83
81
- void Evaluator::printDependencies (const AnyRequest &request,
82
- llvm::raw_ostream &out,
83
- llvm::DenseSet<AnyRequest> &visited,
84
- std::string &prefixStr,
85
- bool lastChild) const {
84
+ void Evaluator::printDependencies (
85
+ const AnyRequest &request,
86
+ llvm::raw_ostream &out,
87
+ llvm::DenseSet<AnyRequest> &visitedAnywhere,
88
+ llvm::SmallVectorImpl<AnyRequest> &visitedAlongPath,
89
+ llvm::ArrayRef<AnyRequest> highlightPath,
90
+ std::string &prefixStr,
91
+ bool lastChild) const {
86
92
out << prefixStr << " `--" ;
87
93
94
+ // Determine whether this node should be highlighted.
95
+ bool isHighlighted = false ;
96
+ if (std::find (highlightPath.begin (), highlightPath.end (), request)
97
+ != highlightPath.end ()) {
98
+ isHighlighted = true ;
99
+ out.changeColor (llvm::buffer_ostream::Colors::GREEN);
100
+ }
101
+
88
102
// Print this node.
89
103
simple_display (out, request);
90
104
105
+ // Turn off the highlight.
106
+ if (isHighlighted) {
107
+ out.resetColor ();
108
+ }
109
+
91
110
// Print the cached value, if known.
92
111
auto cachedValue = cache.find (request);
93
112
if (cachedValue != cache.end ()) {
94
113
out << " -> " ;
95
114
PrintEscapedString (cachedValue->second .getAsString (), out);
96
115
}
97
116
98
- if (!visited.insert (request).second ) {
99
- // We've already seed this node, so we have a cyclic dependency.
100
- out.changeColor (llvm::raw_ostream::RED);
101
- out << " (cyclic dependency)\n " ;
117
+ if (!visitedAnywhere.insert (request).second ) {
118
+ // We've already seed this node. Check whether it's part of a cycle.
119
+ if (std::find (visitedAlongPath.begin (), visitedAlongPath.end (), request)
120
+ != visitedAlongPath.end ()) {
121
+ // We have a cyclic dependency.
122
+ out.changeColor (llvm::raw_ostream::RED);
123
+ out << " (cyclic dependency)\n " ;
124
+ } else {
125
+ // We have seen this node before, but it's not a cycle. Elide its
126
+ // children.
127
+ out << " (elided)\n " ;
128
+ }
129
+
102
130
out.resetColor ();
103
131
} else if (dependencies.count (request) == 0 ) {
104
132
// We have not seen this node before, so we don't know its dependencies.
@@ -107,7 +135,7 @@ void Evaluator::printDependencies(const AnyRequest &request,
107
135
out.resetColor ();
108
136
109
137
// Remove from the visited set.
110
- visited .erase (request);
138
+ visitedAnywhere .erase (request);
111
139
} else {
112
140
// Print children.
113
141
out << " \n " ;
@@ -117,26 +145,33 @@ void Evaluator::printDependencies(const AnyRequest &request,
117
145
prefixStr += (lastChild ? ' ' : ' |' );
118
146
prefixStr += " " ;
119
147
148
+ // Note that this request is along the path.
149
+ visitedAlongPath.push_back (request);
150
+
120
151
// Print the children.
121
152
auto &dependsOn = dependencies.find (request)->second ;
122
153
for (unsigned i : indices (dependsOn)) {
123
- printDependencies (dependsOn[i], out, visited, prefixStr ,
124
- i == dependsOn.size ()-1 );
154
+ printDependencies (dependsOn[i], out, visitedAnywhere, visitedAlongPath ,
155
+ highlightPath, prefixStr, i == dependsOn.size ()-1 );
125
156
}
126
157
127
158
// Drop our changes to the prefix.
128
159
prefixStr.erase (prefixStr.end () - 4 , prefixStr.end ());
129
160
130
- // Remove from the visited set.
131
- visited.erase (request);
161
+ // Remove from the visited set and path.
162
+ visitedAnywhere.erase (request);
163
+ assert (visitedAlongPath.back () == request);
164
+ visitedAlongPath.pop_back ();
132
165
}
133
166
}
134
167
135
168
void Evaluator::printDependencies (const AnyRequest &request,
136
169
llvm::raw_ostream &out) const {
137
170
std::string prefixStr;
138
- llvm::DenseSet<AnyRequest> visited;
139
- printDependencies (request, out, visited, prefixStr, /* lastChild=*/ true );
171
+ llvm::DenseSet<AnyRequest> visitedAnywhere;
172
+ llvm::SmallVector<AnyRequest, 4 > visitedAlongPath;
173
+ printDependencies (request, out, visitedAnywhere, visitedAlongPath, { },
174
+ prefixStr, /* lastChild=*/ true );
140
175
}
141
176
142
177
void Evaluator::dumpDependencies (const AnyRequest &request) const {
0 commit comments