22
22
#include " mlir/Interfaces/ControlFlowInterfaces.h"
23
23
#include " mlir/Support/LLVM.h"
24
24
#include " llvm/Support/Casting.h"
25
+ #include " llvm/Support/Debug.h"
25
26
#include < cassert>
26
27
#include < optional>
27
28
29
+ #define DEBUG_TYPE " dead-code-analysis"
30
+ #define DBGS () (llvm::dbgs() << ' [' << DEBUG_TYPE << " ] " )
31
+ #define LDBG (X ) LLVM_DEBUG(DBGS() << X << " \n " )
32
+
28
33
using namespace mlir ;
29
34
using namespace mlir ::dataflow;
30
35
@@ -122,13 +127,15 @@ DeadCodeAnalysis::DeadCodeAnalysis(DataFlowSolver &solver)
122
127
}
123
128
124
129
LogicalResult DeadCodeAnalysis::initialize (Operation *top) {
130
+ LDBG (" Initializing DeadCodeAnalysis for top-level op: " << top->getName ());
125
131
// Mark the top-level blocks as executable.
126
132
for (Region ®ion : top->getRegions ()) {
127
133
if (region.empty ())
128
134
continue ;
129
135
auto *state =
130
136
getOrCreate<Executable>(getProgramPointBefore (®ion.front ()));
131
137
propagateIfChanged (state, state->setToLive ());
138
+ LDBG (" Marked entry block live for region in op: " << top->getName ());
132
139
}
133
140
134
141
// Mark as overdefined the predecessors of symbol callables with potentially
@@ -139,13 +146,18 @@ LogicalResult DeadCodeAnalysis::initialize(Operation *top) {
139
146
}
140
147
141
148
void DeadCodeAnalysis::initializeSymbolCallables (Operation *top) {
149
+ LDBG (" [init] Entering initializeSymbolCallables for top-level op: "
150
+ << top->getName ());
142
151
analysisScope = top;
143
152
auto walkFn = [&](Operation *symTable, bool allUsesVisible) {
153
+ LDBG (" [init] Processing symbol table op: " << symTable->getName ());
144
154
Region &symbolTableRegion = symTable->getRegion (0 );
145
155
Block *symbolTableBlock = &symbolTableRegion.front ();
146
156
147
157
bool foundSymbolCallable = false ;
148
158
for (auto callable : symbolTableBlock->getOps <CallableOpInterface>()) {
159
+ LDBG (" [init] Found CallableOpInterface: "
160
+ << callable.getOperation ()->getName ());
149
161
Region *callableRegion = callable.getCallableRegion ();
150
162
if (!callableRegion)
151
163
continue ;
@@ -159,6 +171,8 @@ void DeadCodeAnalysis::initializeSymbolCallables(Operation *top) {
159
171
auto *state =
160
172
getOrCreate<PredecessorState>(getProgramPointAfter (callable));
161
173
propagateIfChanged (state, state->setHasUnknownPredecessors ());
174
+ LDBG (" [init] Marked callable as having unknown predecessors: "
175
+ << callable.getOperation ()->getName ());
162
176
}
163
177
foundSymbolCallable = true ;
164
178
}
@@ -173,10 +187,15 @@ void DeadCodeAnalysis::initializeSymbolCallables(Operation *top) {
173
187
if (!uses) {
174
188
// If we couldn't gather the symbol uses, conservatively assume that
175
189
// 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" );
176
192
return top->walk ([&](CallableOpInterface callable) {
177
193
auto *state =
178
194
getOrCreate<PredecessorState>(getProgramPointAfter (callable));
179
195
propagateIfChanged (state, state->setHasUnknownPredecessors ());
196
+ LDBG (" [init] Marked nested callable as "
197
+ " having unknown predecessors: "
198
+ << callable.getOperation ()->getName ());
180
199
});
181
200
}
182
201
@@ -190,10 +209,15 @@ void DeadCodeAnalysis::initializeSymbolCallables(Operation *top) {
190
209
continue ;
191
210
auto *state = getOrCreate<PredecessorState>(getProgramPointAfter (symbol));
192
211
propagateIfChanged (state, state->setHasUnknownPredecessors ());
212
+ LDBG (" [init] Found non-call use for symbol, "
213
+ " marked as having unknown predecessors: "
214
+ << symbol->getName ());
193
215
}
194
216
};
195
217
SymbolTable::walkSymbolTables (top, /* allSymUsesVisible=*/ !top->getBlock (),
196
218
walkFn);
219
+ LDBG (" [init] Finished initializeSymbolCallables for top-level op: "
220
+ << top->getName ());
197
221
}
198
222
199
223
// / Returns true if the operation is a returning terminator in region
@@ -205,9 +229,12 @@ static bool isRegionOrCallableReturn(Operation *op) {
205
229
}
206
230
207
231
LogicalResult DeadCodeAnalysis::initializeRecursively (Operation *op) {
232
+ LDBG (" [init] Entering initializeRecursively for op: " << op->getName ()
233
+ << " at " << op);
208
234
// Initialize the analysis by visiting every op with control-flow semantics.
209
235
if (op->getNumRegions () || op->getNumSuccessors () ||
210
236
isRegionOrCallableReturn (op) || isa<CallOpInterface>(op)) {
237
+ LDBG (" [init] Visiting op with control-flow semantics: " << *op);
211
238
// When the liveness of the parent block changes, make sure to re-invoke the
212
239
// analysis on the op.
213
240
if (op->getBlock ())
@@ -218,14 +245,22 @@ LogicalResult DeadCodeAnalysis::initializeRecursively(Operation *op) {
218
245
return failure ();
219
246
}
220
247
// Recurse on nested operations.
221
- for (Region ®ion : op->getRegions ())
222
- for (Operation &op : region.getOps ())
223
- if (failed (initializeRecursively (&op)))
248
+ for (Region ®ion : 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)))
224
254
return failure ();
255
+ }
256
+ }
257
+ LDBG (" [init] Finished initializeRecursively for op: " << op->getName ()
258
+ << " at " << op);
225
259
return success ();
226
260
}
227
261
228
262
void DeadCodeAnalysis::markEdgeLive (Block *from, Block *to) {
263
+ LDBG (" Marking edge live from block " << from << " to block " << to);
229
264
auto *state = getOrCreate<Executable>(getProgramPointBefore (to));
230
265
propagateIfChanged (state, state->setToLive ());
231
266
auto *edgeState =
@@ -234,37 +269,48 @@ void DeadCodeAnalysis::markEdgeLive(Block *from, Block *to) {
234
269
}
235
270
236
271
void DeadCodeAnalysis::markEntryBlocksLive (Operation *op) {
272
+ LDBG (" Marking entry blocks live for op: " << op->getName ());
237
273
for (Region ®ion : op->getRegions ()) {
238
274
if (region.empty ())
239
275
continue ;
240
276
auto *state =
241
277
getOrCreate<Executable>(getProgramPointBefore (®ion.front ()));
242
278
propagateIfChanged (state, state->setToLive ());
279
+ LDBG (" Marked entry block live for region in op: " << op->getName ());
243
280
}
244
281
}
245
282
246
283
LogicalResult DeadCodeAnalysis::visit (ProgramPoint *point) {
284
+ LDBG (" Visiting program point: " << point << " " << *point);
247
285
if (point->isBlockStart ())
248
286
return success ();
249
287
Operation *op = point->getPrevOp ();
288
+ LDBG (" Visiting operation: " << *op);
250
289
251
290
// If the parent block is not executable, there is nothing to do.
252
291
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);
254
295
return success ();
296
+ }
255
297
256
298
// 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);
258
301
visitCallOperation (call);
302
+ }
259
303
260
304
// Visit the regions.
261
305
if (op->getNumRegions ()) {
262
306
// Check if we can reason about the region control-flow.
263
307
if (auto branch = dyn_cast<RegionBranchOpInterface>(op)) {
308
+ LDBG (" Visiting region branch operation: " << *op);
264
309
visitRegionBranchOperation (branch);
265
310
266
311
// Check if this is a callable operation.
267
312
} else if (auto callable = dyn_cast<CallableOpInterface>(op)) {
313
+ LDBG (" Visiting callable operation: " << *op);
268
314
const auto *callsites = getOrCreateFor<PredecessorState>(
269
315
getProgramPointAfter (op), getProgramPointAfter (callable));
270
316
@@ -276,16 +322,19 @@ LogicalResult DeadCodeAnalysis::visit(ProgramPoint *point) {
276
322
277
323
// Otherwise, conservatively mark all entry blocks as executable.
278
324
} else {
325
+ LDBG (" Marking all entry blocks live for op: " << *op);
279
326
markEntryBlocksLive (op);
280
327
}
281
328
}
282
329
283
330
if (isRegionOrCallableReturn (op)) {
284
331
if (auto branch = dyn_cast<RegionBranchOpInterface>(op->getParentOp ())) {
332
+ LDBG (" Visiting region terminator: " << *op);
285
333
// Visit the exiting terminator of a region.
286
334
visitRegionTerminator (op, branch);
287
335
} else if (auto callable =
288
336
dyn_cast<CallableOpInterface>(op->getParentOp ())) {
337
+ LDBG (" Visiting callable terminator: " << *op);
289
338
// Visit the exiting terminator of a callable.
290
339
visitCallableTerminator (op, callable);
291
340
}
@@ -294,10 +343,12 @@ LogicalResult DeadCodeAnalysis::visit(ProgramPoint *point) {
294
343
if (op->getNumSuccessors ()) {
295
344
// Check if we can reason about the control-flow.
296
345
if (auto branch = dyn_cast<BranchOpInterface>(op)) {
346
+ LDBG (" Visiting branch operation: " << *op);
297
347
visitBranchOperation (branch);
298
348
299
349
// Otherwise, conservatively mark all successors as exectuable.
300
350
} else {
351
+ LDBG (" Marking all successors live for op: " << *op);
301
352
for (Block *successor : op->getSuccessors ())
302
353
markEdgeLive (op->getBlock (), successor);
303
354
}
@@ -307,6 +358,7 @@ LogicalResult DeadCodeAnalysis::visit(ProgramPoint *point) {
307
358
}
308
359
309
360
void DeadCodeAnalysis::visitCallOperation (CallOpInterface call) {
361
+ LDBG (" visitCallOperation: " << call.getOperation ()->getName ());
310
362
Operation *callableOp = call.resolveCallableInTable (&symbolTable);
311
363
312
364
// A call to a externally-defined callable has unknown predecessors.
@@ -329,11 +381,15 @@ void DeadCodeAnalysis::visitCallOperation(CallOpInterface call) {
329
381
auto *callsites =
330
382
getOrCreate<PredecessorState>(getProgramPointAfter (callableOp));
331
383
propagateIfChanged (callsites, callsites->join (call));
384
+ LDBG (" Added callsite as predecessor for callable: "
385
+ << callableOp->getName ());
332
386
} else {
333
387
// Mark this call op's predecessors as overdefined.
334
388
auto *predecessors =
335
389
getOrCreate<PredecessorState>(getProgramPointAfter (call));
336
390
propagateIfChanged (predecessors, predecessors->setHasUnknownPredecessors ());
391
+ LDBG (" Marked call op's predecessors as unknown for: "
392
+ << call.getOperation ()->getName ());
337
393
}
338
394
}
339
395
@@ -365,22 +421,26 @@ DeadCodeAnalysis::getOperandValues(Operation *op) {
365
421
}
366
422
367
423
void DeadCodeAnalysis::visitBranchOperation (BranchOpInterface branch) {
424
+ LDBG (" visitBranchOperation: " << branch.getOperation ()->getName ());
368
425
// Try to deduce a single successor for the branch.
369
426
std::optional<SmallVector<Attribute>> operands = getOperandValues (branch);
370
427
if (!operands)
371
428
return ;
372
429
373
430
if (Block *successor = branch.getSuccessorForOperands (*operands)) {
374
431
markEdgeLive (branch->getBlock (), successor);
432
+ LDBG (" Branch has single successor: " << successor);
375
433
} else {
376
434
// Otherwise, mark all successors as executable and outgoing edges.
377
435
for (Block *successor : branch->getSuccessors ())
378
436
markEdgeLive (branch->getBlock (), successor);
437
+ LDBG (" Branch has multiple/all successors live" );
379
438
}
380
439
}
381
440
382
441
void DeadCodeAnalysis::visitRegionBranchOperation (
383
442
RegionBranchOpInterface branch) {
443
+ LDBG (" visitRegionBranchOperation: " << branch.getOperation ()->getName ());
384
444
// Try to deduce which regions are executable.
385
445
std::optional<SmallVector<Attribute>> operands = getOperandValues (branch);
386
446
if (!operands)
@@ -397,16 +457,19 @@ void DeadCodeAnalysis::visitRegionBranchOperation(
397
457
// Mark the entry block as executable.
398
458
auto *state = getOrCreate<Executable>(point);
399
459
propagateIfChanged (state, state->setToLive ());
460
+ LDBG (" Marked region successor live: " << point);
400
461
// Add the parent op as a predecessor.
401
462
auto *predecessors = getOrCreate<PredecessorState>(point);
402
463
propagateIfChanged (
403
464
predecessors,
404
465
predecessors->join (branch, successor.getSuccessorInputs ()));
466
+ LDBG (" Added region branch as predecessor for successor: " << point);
405
467
}
406
468
}
407
469
408
470
void DeadCodeAnalysis::visitRegionTerminator (Operation *op,
409
471
RegionBranchOpInterface branch) {
472
+ LDBG (" visitRegionTerminator: " << *op);
410
473
std::optional<SmallVector<Attribute>> operands = getOperandValues (op);
411
474
if (!operands)
412
475
return ;
@@ -425,6 +488,7 @@ void DeadCodeAnalysis::visitRegionTerminator(Operation *op,
425
488
auto *state =
426
489
getOrCreate<Executable>(getProgramPointBefore (®ion->front ()));
427
490
propagateIfChanged (state, state->setToLive ());
491
+ LDBG (" Marked region entry block live for region: " << region);
428
492
predecessors = getOrCreate<PredecessorState>(
429
493
getProgramPointBefore (®ion->front ()));
430
494
} else {
@@ -434,11 +498,14 @@ void DeadCodeAnalysis::visitRegionTerminator(Operation *op,
434
498
}
435
499
propagateIfChanged (predecessors,
436
500
predecessors->join (op, successor.getSuccessorInputs ()));
501
+ LDBG (" Added region terminator as predecessor for successor: "
502
+ << (successor.getSuccessor () ? " region entry" : " parent op" ));
437
503
}
438
504
}
439
505
440
506
void DeadCodeAnalysis::visitCallableTerminator (Operation *op,
441
507
CallableOpInterface callable) {
508
+ LDBG (" visitCallableTerminator: " << *op);
442
509
// Add as predecessors to all callsites this return op.
443
510
auto *callsites = getOrCreateFor<PredecessorState>(
444
511
getProgramPointAfter (op), getProgramPointAfter (callable));
@@ -449,11 +516,15 @@ void DeadCodeAnalysis::visitCallableTerminator(Operation *op,
449
516
getOrCreate<PredecessorState>(getProgramPointAfter (predecessor));
450
517
if (canResolve) {
451
518
propagateIfChanged (predecessors, predecessors->join (op));
519
+ LDBG (" Added callable terminator as predecessor for callsite: "
520
+ << predecessor->getName ());
452
521
} else {
453
522
// If the terminator is not a return-like, then conservatively assume we
454
523
// can't resolve the predecessor.
455
524
propagateIfChanged (predecessors,
456
525
predecessors->setHasUnknownPredecessors ());
526
+ LDBG (" Could not resolve callable terminator for callsite: "
527
+ << predecessor->getName ());
457
528
}
458
529
}
459
530
}
0 commit comments