Skip to content

Commit 5561e08

Browse files
committed
[clang][dataflow] Identify post-visit state changes in the HTML logger.
Previously, post-visit state changes were indistinguishable from ordinary iterations, which could give a confusing picture of how many iterations a block needs to converge. Now, post-visit state changes are marked with "post-visit" instead of an iteration number (see attached screenshot for an example).
1 parent cf1d2e4 commit 5561e08

File tree

6 files changed

+63
-28
lines changed

6 files changed

+63
-28
lines changed

clang/include/clang/Analysis/FlowSensitive/Logger.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ class Logger {
5050
/// Called when we start (re-)processing a block in the CFG.
5151
/// The target program point is the entry to the specified block.
5252
/// Calls to log() describe transferBranch(), join() etc.
53-
virtual void enterBlock(const CFGBlock &) {}
53+
/// `PostVisit` specifies whether we're processing the block for the
54+
/// post-visit callback.
55+
virtual void enterBlock(const CFGBlock &, bool PostVisit) {}
5456
/// Called when we start processing an element in the current CFG block.
5557
/// The target program point is after the specified element.
5658
/// Calls to log() describe the transfer() function.

clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -146,15 +146,21 @@ class ModelDumper {
146146
};
147147

148148
class HTMLLogger : public Logger {
149+
struct Iteration {
150+
const CFGBlock *Block;
151+
unsigned Iter;
152+
bool PostVisit;
153+
};
154+
149155
StreamFactory Streams;
150156
std::unique_ptr<llvm::raw_ostream> OS;
151157
std::optional<llvm::json::OStream> JOS;
152158

153159
const ControlFlowContext *CFG;
154160
// Timeline of iterations of CFG block visitation.
155-
std::vector<std::pair<const CFGBlock *, unsigned>> Iters;
161+
std::vector<Iteration> Iters;
156162
// Number of times each CFG block has been seen.
157-
llvm::DenseMap<const CFGBlock *, unsigned> BlockIters;
163+
llvm::DenseMap<const CFGBlock *, llvm::SmallVector<Iteration>> BlockIters;
158164
// The messages logged in the current context but not yet written.
159165
std::string ContextLogs;
160166
// The number of elements we have visited within the current CFG block.
@@ -198,8 +204,9 @@ class HTMLLogger : public Logger {
198204
JOS->attributeArray("timeline", [&] {
199205
for (const auto &E : Iters) {
200206
JOS->object([&] {
201-
JOS->attribute("block", blockID(E.first->getBlockID()));
202-
JOS->attribute("iter", E.second);
207+
JOS->attribute("block", blockID(E.Block->getBlockID()));
208+
JOS->attribute("iter", E.Iter);
209+
JOS->attribute("post_visit", E.PostVisit);
203210
});
204211
}
205212
});
@@ -214,8 +221,11 @@ class HTMLLogger : public Logger {
214221
*OS << llvm::StringRef(HTMLLogger_html).split("<?INJECT?>").second;
215222
}
216223

217-
void enterBlock(const CFGBlock &B) override {
218-
Iters.emplace_back(&B, ++BlockIters[&B]);
224+
void enterBlock(const CFGBlock &B, bool PostVisit) override {
225+
llvm::SmallVector<Iteration> &BIter = BlockIters[&B];
226+
unsigned IterNum = BIter.size() + 1;
227+
BIter.push_back({&B, IterNum, PostVisit});
228+
Iters.push_back({&B, IterNum, PostVisit});
219229
ElementIndex = 0;
220230
}
221231
void enterElement(const CFGElement &E) override {
@@ -243,17 +253,19 @@ class HTMLLogger : public Logger {
243253
// - meaningful names for values
244254
// - which boolean values are implied true/false by the flow condition
245255
void recordState(TypeErasedDataflowAnalysisState &State) override {
246-
unsigned Block = Iters.back().first->getBlockID();
247-
unsigned Iter = Iters.back().second;
256+
unsigned Block = Iters.back().Block->getBlockID();
257+
unsigned Iter = Iters.back().Iter;
258+
bool PostVisit = Iters.back().PostVisit;
248259
JOS->attributeObject(elementIterID(Block, Iter, ElementIndex), [&] {
249260
JOS->attribute("block", blockID(Block));
250261
JOS->attribute("iter", Iter);
262+
JOS->attribute("post_visit", PostVisit);
251263
JOS->attribute("element", ElementIndex);
252264

253265
// If this state immediately follows an Expr, show its built-in model.
254266
if (ElementIndex > 0) {
255267
auto S =
256-
Iters.back().first->Elements[ElementIndex - 1].getAs<CFGStmt>();
268+
Iters.back().Block->Elements[ElementIndex - 1].getAs<CFGStmt>();
257269
if (const Expr *E = S ? llvm::dyn_cast<Expr>(S->getStmt()) : nullptr) {
258270
if (E->isPRValue()) {
259271
if (auto *V = State.Env.getValue(*E))
@@ -289,9 +301,16 @@ class HTMLLogger : public Logger {
289301
// Write the CFG block details.
290302
// Currently this is just the list of elements in execution order.
291303
// FIXME: an AST dump would be a useful view, too.
292-
void writeBlock(const CFGBlock &B, unsigned Iters) {
304+
void writeBlock(const CFGBlock &B, llvm::ArrayRef<Iteration> ItersForB) {
293305
JOS->attributeObject(blockID(B.getBlockID()), [&] {
294-
JOS->attribute("iters", Iters);
306+
JOS->attributeArray("iters", [&] {
307+
for (const auto &Iter : ItersForB) {
308+
JOS->object([&] {
309+
JOS->attribute("iter", Iter.Iter);
310+
JOS->attribute("post_visit", Iter.PostVisit);
311+
});
312+
}
313+
});
295314
JOS->attributeArray("elements", [&] {
296315
for (const auto &Elt : B.Elements) {
297316
std::string Dump;

clang/lib/Analysis/FlowSensitive/HTMLLogger.html

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,11 @@
4141
<section id="timeline" data-selection="">
4242
<header>Timeline</header>
4343
<template data-for="entry in timeline">
44-
<div id="{{entry.block}}:{{entry.iter}}" data-bb="{{entry.block}}" class="entry">{{entry.block}} ({{entry.iter}})</div>
44+
<div id="{{entry.block}}:{{entry.iter}}" data-bb="{{entry.block}}" class="entry">
45+
{{entry.block}}
46+
<template data-if="entry.post_visit">(post-visit)</template>
47+
<template data-if="!entry.post_visit">({{entry.iter}})</template>
48+
</div>
4549
</template>
4650
</section>
4751

@@ -54,8 +58,11 @@
5458
<section id="block" data-selection="bb">
5559
<header><template>Block {{selection.bb}}</template></header>
5660
<div id="iterations">
57-
<template data-for="i in Array(cfg[selection.bb].iters).keys()">
58-
<a class="chooser {{selection.bb}}:{{i+1}}" data-iter="{{selection.bb}}:{{i+1}}">Iteration {{i+1}}</a>
61+
<template data-for="iter in cfg[selection.bb].iters">
62+
<a class="chooser {{selection.bb}}:{{iter.iter}}" data-iter="{{selection.bb}}:{{iter.iter}}">
63+
<template data-if="iter.post_visit">Post-visit</template>
64+
<template data-if="!iter.post_visit">Iteration {{iter.iter}}</template>
65+
</a>
5966
</template>
6067
</div>
6168
<table id="bb-elements">
@@ -77,8 +84,10 @@
7784
<section id="element" data-selection="iter,elt">
7885
<template data-let="state = states[selection.iter + '_' + selection.elt]">
7986
<header>
80-
<template data-if="state.element == 0">{{state.block}} (iteration {{state.iter}}) initial state</template>
81-
<template data-if="state.element != 0">Element {{selection.elt}} (iteration {{state.iter}})</template>
87+
<template data-if="state.element == 0">{{state.block}} initial state</template>
88+
<template data-if="state.element != 0">Element {{selection.elt}}</template>
89+
<template data-if="state.post_visit"> (post-visit)</template>
90+
<template data-if="!state.post_visit"> (iteration {{state.iter}})</template>
8291
</header>
8392
<template data-if="state.value" data-let="v = state.value">
8493
<h2>Value</h2>

clang/lib/Analysis/FlowSensitive/Logger.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,16 @@ struct TextualLogger final : Logger {
5757
llvm::errs() << "=== Finished analysis: " << Blocks << " blocks in "
5858
<< Steps << " total steps ===\n";
5959
}
60-
virtual void enterBlock(const CFGBlock &Block) override {
60+
virtual void enterBlock(const CFGBlock &Block, bool PostVisit) override {
6161
unsigned Count = ++VisitCount[&Block];
6262
{
6363
llvm::WithColor Header(OS, llvm::raw_ostream::Colors::RED, /*Bold=*/true);
64-
OS << "=== Entering block B" << Block.getBlockID() << " (iteration "
65-
<< Count << ") ===\n";
64+
OS << "=== Entering block B" << Block.getBlockID();
65+
if (PostVisit)
66+
OS << " (post-visit)";
67+
else
68+
OS << " (iteration " << Count << ")";
69+
OS << " ===\n";
6670
}
6771
Block.print(OS, CurrentCFG, CurrentAnalysis->getASTContext().getLangOpts(),
6872
ShowColors);

clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ transferCFGBlock(const CFGBlock &Block, AnalysisContext &AC,
469469
std::function<void(const CFGElement &,
470470
const TypeErasedDataflowAnalysisState &)>
471471
PostVisitCFG = nullptr) {
472-
AC.Log.enterBlock(Block);
472+
AC.Log.enterBlock(Block, PostVisitCFG != nullptr);
473473
auto State = computeBlockInputState(Block, AC);
474474
AC.Log.recordState(State);
475475
int ElementIdx = 1;

clang/unittests/Analysis/FlowSensitive/LoggerTest.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,9 @@ class TestLogger : public Logger {
6464
}
6565
void endAnalysis() override { logText("\nendAnalysis()"); }
6666

67-
void enterBlock(const CFGBlock &B) override {
68-
OS << "\nenterBlock(" << B.BlockID << ")\n";
67+
void enterBlock(const CFGBlock &B, bool PostVisit) override {
68+
OS << "\nenterBlock(" << B.BlockID << ", " << (PostVisit ? "true" : "false")
69+
<< ")\n";
6970
}
7071
void enterElement(const CFGElement &E) override {
7172
// we don't want the trailing \n
@@ -114,7 +115,7 @@ TEST(LoggerTest, Sequence) {
114115

115116
EXPECT_EQ(Log, R"(beginAnalysis()
116117
117-
enterBlock(4)
118+
enterBlock(4, false)
118119
recordState(Elements=0, Branches=0, Joins=0)
119120
enterElement(b)
120121
transfer()
@@ -123,21 +124,21 @@ enterElement(b (ImplicitCastExpr, LValueToRValue, _Bool))
123124
transfer()
124125
recordState(Elements=2, Branches=0, Joins=0)
125126
126-
enterBlock(3)
127+
enterBlock(3, false)
127128
transferBranch(0)
128129
recordState(Elements=2, Branches=1, Joins=0)
129130
enterElement(q)
130131
transfer()
131132
recordState(Elements=3, Branches=1, Joins=0)
132133
133-
enterBlock(2)
134+
enterBlock(2, false)
134135
transferBranch(1)
135136
recordState(Elements=2, Branches=1, Joins=0)
136137
enterElement(p)
137138
transfer()
138139
recordState(Elements=3, Branches=1, Joins=0)
139140
140-
enterBlock(1)
141+
enterBlock(1, false)
141142
recordState(Elements=6, Branches=2, Joins=1)
142143
enterElement(b ? p : q)
143144
transfer()
@@ -149,7 +150,7 @@ enterElement(return b ? p : q;)
149150
transfer()
150151
recordState(Elements=9, Branches=2, Joins=1)
151152
152-
enterBlock(0)
153+
enterBlock(0, false)
153154
recordState(Elements=9, Branches=2, Joins=1)
154155
155156
endAnalysis()

0 commit comments

Comments
 (0)