Skip to content

Commit 075cb69

Browse files
authored
[MLIR] Add logging/tracing to DataFlow analysis and RemoveDeadValues (NFC) (#144695)
Debugging issues with this pass is quite difficult at the moment, this should help.
1 parent 6ae5b89 commit 075cb69

File tree

3 files changed

+176
-12
lines changed

3 files changed

+176
-12
lines changed

mlir/lib/Analysis/DataFlow/DeadCodeAnalysis.cpp

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,14 @@
2222
#include "mlir/Interfaces/ControlFlowInterfaces.h"
2323
#include "mlir/Support/LLVM.h"
2424
#include "llvm/Support/Casting.h"
25+
#include "llvm/Support/Debug.h"
2526
#include <cassert>
2627
#include <optional>
2728

29+
#define DEBUG_TYPE "dead-code-analysis"
30+
#define DBGS() (llvm::dbgs() << '[' << DEBUG_TYPE << "] ")
31+
#define LDBG(X) LLVM_DEBUG(DBGS() << X << "\n")
32+
2833
using namespace mlir;
2934
using namespace mlir::dataflow;
3035

@@ -122,13 +127,15 @@ DeadCodeAnalysis::DeadCodeAnalysis(DataFlowSolver &solver)
122127
}
123128

124129
LogicalResult DeadCodeAnalysis::initialize(Operation *top) {
130+
LDBG("Initializing DeadCodeAnalysis for top-level op: " << top->getName());
125131
// Mark the top-level blocks as executable.
126132
for (Region &region : top->getRegions()) {
127133
if (region.empty())
128134
continue;
129135
auto *state =
130136
getOrCreate<Executable>(getProgramPointBefore(&region.front()));
131137
propagateIfChanged(state, state->setToLive());
138+
LDBG("Marked entry block live for region in op: " << top->getName());
132139
}
133140

134141
// Mark as overdefined the predecessors of symbol callables with potentially
@@ -139,13 +146,18 @@ LogicalResult DeadCodeAnalysis::initialize(Operation *top) {
139146
}
140147

141148
void DeadCodeAnalysis::initializeSymbolCallables(Operation *top) {
149+
LDBG("[init] Entering initializeSymbolCallables for top-level op: "
150+
<< top->getName());
142151
analysisScope = top;
143152
auto walkFn = [&](Operation *symTable, bool allUsesVisible) {
153+
LDBG("[init] Processing symbol table op: " << symTable->getName());
144154
Region &symbolTableRegion = symTable->getRegion(0);
145155
Block *symbolTableBlock = &symbolTableRegion.front();
146156

147157
bool foundSymbolCallable = false;
148158
for (auto callable : symbolTableBlock->getOps<CallableOpInterface>()) {
159+
LDBG("[init] Found CallableOpInterface: "
160+
<< callable.getOperation()->getName());
149161
Region *callableRegion = callable.getCallableRegion();
150162
if (!callableRegion)
151163
continue;
@@ -159,6 +171,8 @@ void DeadCodeAnalysis::initializeSymbolCallables(Operation *top) {
159171
auto *state =
160172
getOrCreate<PredecessorState>(getProgramPointAfter(callable));
161173
propagateIfChanged(state, state->setHasUnknownPredecessors());
174+
LDBG("[init] Marked callable as having unknown predecessors: "
175+
<< callable.getOperation()->getName());
162176
}
163177
foundSymbolCallable = true;
164178
}
@@ -173,10 +187,15 @@ void DeadCodeAnalysis::initializeSymbolCallables(Operation *top) {
173187
if (!uses) {
174188
// If we couldn't gather the symbol uses, conservatively assume that
175189
// we can't track information for any nested symbols.
190+
LDBG("[init] Could not gather symbol uses, conservatively marking "
191+
"all nested callables as having unknown predecessors");
176192
return top->walk([&](CallableOpInterface callable) {
177193
auto *state =
178194
getOrCreate<PredecessorState>(getProgramPointAfter(callable));
179195
propagateIfChanged(state, state->setHasUnknownPredecessors());
196+
LDBG("[init] Marked nested callable as "
197+
"having unknown predecessors: "
198+
<< callable.getOperation()->getName());
180199
});
181200
}
182201

@@ -190,10 +209,15 @@ void DeadCodeAnalysis::initializeSymbolCallables(Operation *top) {
190209
continue;
191210
auto *state = getOrCreate<PredecessorState>(getProgramPointAfter(symbol));
192211
propagateIfChanged(state, state->setHasUnknownPredecessors());
212+
LDBG("[init] Found non-call use for symbol, "
213+
"marked as having unknown predecessors: "
214+
<< symbol->getName());
193215
}
194216
};
195217
SymbolTable::walkSymbolTables(top, /*allSymUsesVisible=*/!top->getBlock(),
196218
walkFn);
219+
LDBG("[init] Finished initializeSymbolCallables for top-level op: "
220+
<< top->getName());
197221
}
198222

199223
/// Returns true if the operation is a returning terminator in region
@@ -205,9 +229,12 @@ static bool isRegionOrCallableReturn(Operation *op) {
205229
}
206230

207231
LogicalResult DeadCodeAnalysis::initializeRecursively(Operation *op) {
232+
LDBG("[init] Entering initializeRecursively for op: " << op->getName()
233+
<< " at " << op);
208234
// Initialize the analysis by visiting every op with control-flow semantics.
209235
if (op->getNumRegions() || op->getNumSuccessors() ||
210236
isRegionOrCallableReturn(op) || isa<CallOpInterface>(op)) {
237+
LDBG("[init] Visiting op with control-flow semantics: " << *op);
211238
// When the liveness of the parent block changes, make sure to re-invoke the
212239
// analysis on the op.
213240
if (op->getBlock())
@@ -218,14 +245,22 @@ LogicalResult DeadCodeAnalysis::initializeRecursively(Operation *op) {
218245
return failure();
219246
}
220247
// Recurse on nested operations.
221-
for (Region &region : op->getRegions())
222-
for (Operation &op : region.getOps())
223-
if (failed(initializeRecursively(&op)))
248+
for (Region &region : op->getRegions()) {
249+
LDBG("[init] Recursing into region of op: " << op->getName());
250+
for (Operation &nestedOp : region.getOps()) {
251+
LDBG("[init] Recursing into nested op: " << nestedOp.getName() << " at "
252+
<< &nestedOp);
253+
if (failed(initializeRecursively(&nestedOp)))
224254
return failure();
255+
}
256+
}
257+
LDBG("[init] Finished initializeRecursively for op: " << op->getName()
258+
<< " at " << op);
225259
return success();
226260
}
227261

228262
void DeadCodeAnalysis::markEdgeLive(Block *from, Block *to) {
263+
LDBG("Marking edge live from block " << from << " to block " << to);
229264
auto *state = getOrCreate<Executable>(getProgramPointBefore(to));
230265
propagateIfChanged(state, state->setToLive());
231266
auto *edgeState =
@@ -234,37 +269,48 @@ void DeadCodeAnalysis::markEdgeLive(Block *from, Block *to) {
234269
}
235270

236271
void DeadCodeAnalysis::markEntryBlocksLive(Operation *op) {
272+
LDBG("Marking entry blocks live for op: " << op->getName());
237273
for (Region &region : op->getRegions()) {
238274
if (region.empty())
239275
continue;
240276
auto *state =
241277
getOrCreate<Executable>(getProgramPointBefore(&region.front()));
242278
propagateIfChanged(state, state->setToLive());
279+
LDBG("Marked entry block live for region in op: " << op->getName());
243280
}
244281
}
245282

246283
LogicalResult DeadCodeAnalysis::visit(ProgramPoint *point) {
284+
LDBG("Visiting program point: " << point << " " << *point);
247285
if (point->isBlockStart())
248286
return success();
249287
Operation *op = point->getPrevOp();
288+
LDBG("Visiting operation: " << *op);
250289

251290
// If the parent block is not executable, there is nothing to do.
252291
if (op->getBlock() != nullptr &&
253-
!getOrCreate<Executable>(getProgramPointBefore(op->getBlock()))->isLive())
292+
!getOrCreate<Executable>(getProgramPointBefore(op->getBlock()))
293+
->isLive()) {
294+
LDBG("Parent block not live, skipping op: " << *op);
254295
return success();
296+
}
255297

256298
// We have a live call op. Add this as a live predecessor of the callee.
257-
if (auto call = dyn_cast<CallOpInterface>(op))
299+
if (auto call = dyn_cast<CallOpInterface>(op)) {
300+
LDBG("Visiting call operation: " << *op);
258301
visitCallOperation(call);
302+
}
259303

260304
// Visit the regions.
261305
if (op->getNumRegions()) {
262306
// Check if we can reason about the region control-flow.
263307
if (auto branch = dyn_cast<RegionBranchOpInterface>(op)) {
308+
LDBG("Visiting region branch operation: " << *op);
264309
visitRegionBranchOperation(branch);
265310

266311
// Check if this is a callable operation.
267312
} else if (auto callable = dyn_cast<CallableOpInterface>(op)) {
313+
LDBG("Visiting callable operation: " << *op);
268314
const auto *callsites = getOrCreateFor<PredecessorState>(
269315
getProgramPointAfter(op), getProgramPointAfter(callable));
270316

@@ -276,16 +322,19 @@ LogicalResult DeadCodeAnalysis::visit(ProgramPoint *point) {
276322

277323
// Otherwise, conservatively mark all entry blocks as executable.
278324
} else {
325+
LDBG("Marking all entry blocks live for op: " << *op);
279326
markEntryBlocksLive(op);
280327
}
281328
}
282329

283330
if (isRegionOrCallableReturn(op)) {
284331
if (auto branch = dyn_cast<RegionBranchOpInterface>(op->getParentOp())) {
332+
LDBG("Visiting region terminator: " << *op);
285333
// Visit the exiting terminator of a region.
286334
visitRegionTerminator(op, branch);
287335
} else if (auto callable =
288336
dyn_cast<CallableOpInterface>(op->getParentOp())) {
337+
LDBG("Visiting callable terminator: " << *op);
289338
// Visit the exiting terminator of a callable.
290339
visitCallableTerminator(op, callable);
291340
}
@@ -294,10 +343,12 @@ LogicalResult DeadCodeAnalysis::visit(ProgramPoint *point) {
294343
if (op->getNumSuccessors()) {
295344
// Check if we can reason about the control-flow.
296345
if (auto branch = dyn_cast<BranchOpInterface>(op)) {
346+
LDBG("Visiting branch operation: " << *op);
297347
visitBranchOperation(branch);
298348

299349
// Otherwise, conservatively mark all successors as exectuable.
300350
} else {
351+
LDBG("Marking all successors live for op: " << *op);
301352
for (Block *successor : op->getSuccessors())
302353
markEdgeLive(op->getBlock(), successor);
303354
}
@@ -307,6 +358,7 @@ LogicalResult DeadCodeAnalysis::visit(ProgramPoint *point) {
307358
}
308359

309360
void DeadCodeAnalysis::visitCallOperation(CallOpInterface call) {
361+
LDBG("visitCallOperation: " << call.getOperation()->getName());
310362
Operation *callableOp = call.resolveCallableInTable(&symbolTable);
311363

312364
// A call to a externally-defined callable has unknown predecessors.
@@ -329,11 +381,15 @@ void DeadCodeAnalysis::visitCallOperation(CallOpInterface call) {
329381
auto *callsites =
330382
getOrCreate<PredecessorState>(getProgramPointAfter(callableOp));
331383
propagateIfChanged(callsites, callsites->join(call));
384+
LDBG("Added callsite as predecessor for callable: "
385+
<< callableOp->getName());
332386
} else {
333387
// Mark this call op's predecessors as overdefined.
334388
auto *predecessors =
335389
getOrCreate<PredecessorState>(getProgramPointAfter(call));
336390
propagateIfChanged(predecessors, predecessors->setHasUnknownPredecessors());
391+
LDBG("Marked call op's predecessors as unknown for: "
392+
<< call.getOperation()->getName());
337393
}
338394
}
339395

@@ -365,22 +421,26 @@ DeadCodeAnalysis::getOperandValues(Operation *op) {
365421
}
366422

367423
void DeadCodeAnalysis::visitBranchOperation(BranchOpInterface branch) {
424+
LDBG("visitBranchOperation: " << branch.getOperation()->getName());
368425
// Try to deduce a single successor for the branch.
369426
std::optional<SmallVector<Attribute>> operands = getOperandValues(branch);
370427
if (!operands)
371428
return;
372429

373430
if (Block *successor = branch.getSuccessorForOperands(*operands)) {
374431
markEdgeLive(branch->getBlock(), successor);
432+
LDBG("Branch has single successor: " << successor);
375433
} else {
376434
// Otherwise, mark all successors as executable and outgoing edges.
377435
for (Block *successor : branch->getSuccessors())
378436
markEdgeLive(branch->getBlock(), successor);
437+
LDBG("Branch has multiple/all successors live");
379438
}
380439
}
381440

382441
void DeadCodeAnalysis::visitRegionBranchOperation(
383442
RegionBranchOpInterface branch) {
443+
LDBG("visitRegionBranchOperation: " << branch.getOperation()->getName());
384444
// Try to deduce which regions are executable.
385445
std::optional<SmallVector<Attribute>> operands = getOperandValues(branch);
386446
if (!operands)
@@ -397,16 +457,19 @@ void DeadCodeAnalysis::visitRegionBranchOperation(
397457
// Mark the entry block as executable.
398458
auto *state = getOrCreate<Executable>(point);
399459
propagateIfChanged(state, state->setToLive());
460+
LDBG("Marked region successor live: " << point);
400461
// Add the parent op as a predecessor.
401462
auto *predecessors = getOrCreate<PredecessorState>(point);
402463
propagateIfChanged(
403464
predecessors,
404465
predecessors->join(branch, successor.getSuccessorInputs()));
466+
LDBG("Added region branch as predecessor for successor: " << point);
405467
}
406468
}
407469

408470
void DeadCodeAnalysis::visitRegionTerminator(Operation *op,
409471
RegionBranchOpInterface branch) {
472+
LDBG("visitRegionTerminator: " << *op);
410473
std::optional<SmallVector<Attribute>> operands = getOperandValues(op);
411474
if (!operands)
412475
return;
@@ -425,6 +488,7 @@ void DeadCodeAnalysis::visitRegionTerminator(Operation *op,
425488
auto *state =
426489
getOrCreate<Executable>(getProgramPointBefore(&region->front()));
427490
propagateIfChanged(state, state->setToLive());
491+
LDBG("Marked region entry block live for region: " << region);
428492
predecessors = getOrCreate<PredecessorState>(
429493
getProgramPointBefore(&region->front()));
430494
} else {
@@ -434,11 +498,14 @@ void DeadCodeAnalysis::visitRegionTerminator(Operation *op,
434498
}
435499
propagateIfChanged(predecessors,
436500
predecessors->join(op, successor.getSuccessorInputs()));
501+
LDBG("Added region terminator as predecessor for successor: "
502+
<< (successor.getSuccessor() ? "region entry" : "parent op"));
437503
}
438504
}
439505

440506
void DeadCodeAnalysis::visitCallableTerminator(Operation *op,
441507
CallableOpInterface callable) {
508+
LDBG("visitCallableTerminator: " << *op);
442509
// Add as predecessors to all callsites this return op.
443510
auto *callsites = getOrCreateFor<PredecessorState>(
444511
getProgramPointAfter(op), getProgramPointAfter(callable));
@@ -449,11 +516,15 @@ void DeadCodeAnalysis::visitCallableTerminator(Operation *op,
449516
getOrCreate<PredecessorState>(getProgramPointAfter(predecessor));
450517
if (canResolve) {
451518
propagateIfChanged(predecessors, predecessors->join(op));
519+
LDBG("Added callable terminator as predecessor for callsite: "
520+
<< predecessor->getName());
452521
} else {
453522
// If the terminator is not a return-like, then conservatively assume we
454523
// can't resolve the predecessor.
455524
propagateIfChanged(predecessors,
456525
predecessors->setHasUnknownPredecessors());
526+
LDBG("Could not resolve callable terminator for callsite: "
527+
<< predecessor->getName());
457528
}
458529
}
459530
}

0 commit comments

Comments
 (0)