diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
index 47915958750d1..8aef1d6f46089 100644
--- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
+++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
@@ -150,6 +150,7 @@ class HTMLLogger : public Logger {
const CFGBlock *Block;
unsigned Iter;
bool PostVisit;
+ bool Converged;
};
StreamFactory Streams;
@@ -159,8 +160,8 @@ class HTMLLogger : public Logger {
const ControlFlowContext *CFG;
// Timeline of iterations of CFG block visitation.
std::vector Iters;
- // Number of times each CFG block has been seen.
- llvm::DenseMap> BlockIters;
+ // Indexes in `Iters` of the iterations for each block.
+ llvm::DenseMap> BlockIters;
// The messages logged in the current context but not yet written.
std::string ContextLogs;
// The number of elements we have visited within the current CFG block.
@@ -207,6 +208,7 @@ class HTMLLogger : public Logger {
JOS->attribute("block", blockID(E.Block->getBlockID()));
JOS->attribute("iter", E.Iter);
JOS->attribute("post_visit", E.PostVisit);
+ JOS->attribute("converged", E.Converged);
});
}
});
@@ -222,10 +224,10 @@ class HTMLLogger : public Logger {
}
void enterBlock(const CFGBlock &B, bool PostVisit) override {
- llvm::SmallVector &BIter = BlockIters[&B];
+ llvm::SmallVector &BIter = BlockIters[&B];
unsigned IterNum = BIter.size() + 1;
- BIter.push_back({&B, IterNum, PostVisit});
- Iters.push_back({&B, IterNum, PostVisit});
+ BIter.push_back(Iters.size());
+ Iters.push_back({&B, IterNum, PostVisit, /*Converged=*/false});
ElementIndex = 0;
}
void enterElement(const CFGElement &E) override {
@@ -290,7 +292,7 @@ class HTMLLogger : public Logger {
}
});
}
- void blockConverged() override { logText("Block converged"); }
+ void blockConverged() override { Iters.back().Converged = true; }
void logText(llvm::StringRef S) override {
ContextLogs.append(S.begin(), S.end());
@@ -301,13 +303,15 @@ class HTMLLogger : public Logger {
// Write the CFG block details.
// Currently this is just the list of elements in execution order.
// FIXME: an AST dump would be a useful view, too.
- void writeBlock(const CFGBlock &B, llvm::ArrayRef ItersForB) {
+ void writeBlock(const CFGBlock &B, llvm::ArrayRef ItersForB) {
JOS->attributeObject(blockID(B.getBlockID()), [&] {
JOS->attributeArray("iters", [&] {
- for (const auto &Iter : ItersForB) {
+ for (size_t IterIdx : ItersForB) {
+ const Iteration &Iter = Iters[IterIdx];
JOS->object([&] {
JOS->attribute("iter", Iter.Iter);
JOS->attribute("post_visit", Iter.PostVisit);
+ JOS->attribute("converged", Iter.Converged);
});
}
});
diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.html b/clang/lib/Analysis/FlowSensitive/HTMLLogger.html
index 6d866d57e1448..ec9d74c71d35d 100644
--- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.html
+++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.html
@@ -45,6 +45,7 @@
{{entry.block}}
(post-visit)
({{entry.iter}})
+ →|
@@ -62,6 +63,7 @@
Post-visit
Iteration {{iter.iter}}
+ →|