1 //===- DeadCodeAnalysis.cpp - Dead code analysis --------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "mlir/Analysis/DataFlow/DeadCodeAnalysis.h"
10 #include "mlir/Analysis/DataFlow/ConstantPropagationAnalysis.h"
11 #include "mlir/Analysis/DataFlow/SparseAnalysis.h"
12 #include "mlir/Analysis/DataFlowFramework.h"
13 #include "mlir/IR/Attributes.h"
14 #include "mlir/IR/Block.h"
15 #include "mlir/IR/Diagnostics.h"
16 #include "mlir/IR/Location.h"
17 #include "mlir/IR/Operation.h"
18 #include "mlir/IR/SymbolTable.h"
19 #include "mlir/IR/Value.h"
20 #include "mlir/IR/ValueRange.h"
21 #include "mlir/Interfaces/CallInterfaces.h"
22 #include "mlir/Interfaces/ControlFlowInterfaces.h"
23 #include "mlir/Support/LLVM.h"
24 #include "llvm/Support/Casting.h"
29 using namespace mlir::dataflow
;
31 //===----------------------------------------------------------------------===//
33 //===----------------------------------------------------------------------===//
35 ChangeResult
Executable::setToLive() {
37 return ChangeResult::NoChange
;
39 return ChangeResult::Change
;
42 void Executable::print(raw_ostream
&os
) const {
43 os
<< (live
? "live" : "dead");
46 void Executable::onUpdate(DataFlowSolver
*solver
) const {
47 AnalysisState::onUpdate(solver
);
49 if (ProgramPoint
*pp
= llvm::dyn_cast_if_present
<ProgramPoint
*>(anchor
)) {
50 if (pp
->isBlockStart()) {
51 // Re-invoke the analyses on the block itself.
52 for (DataFlowAnalysis
*analysis
: subscribers
)
53 solver
->enqueue({pp
, analysis
});
54 // Re-invoke the analyses on all operations in the block.
55 for (DataFlowAnalysis
*analysis
: subscribers
)
56 for (Operation
&op
: *pp
->getBlock())
57 solver
->enqueue({solver
->getProgramPointAfter(&op
), analysis
});
59 } else if (auto *latticeAnchor
=
60 llvm::dyn_cast_if_present
<GenericLatticeAnchor
*>(anchor
)) {
61 // Re-invoke the analysis on the successor block.
62 if (auto *edge
= dyn_cast
<CFGEdge
>(latticeAnchor
)) {
63 for (DataFlowAnalysis
*analysis
: subscribers
)
65 {solver
->getProgramPointBefore(edge
->getTo()), analysis
});
70 //===----------------------------------------------------------------------===//
72 //===----------------------------------------------------------------------===//
74 void PredecessorState::print(raw_ostream
&os
) const {
75 if (allPredecessorsKnown())
77 os
<< "predecessors:\n";
78 for (Operation
*op
: getKnownPredecessors())
79 os
<< " " << *op
<< "\n";
82 ChangeResult
PredecessorState::join(Operation
*predecessor
) {
83 return knownPredecessors
.insert(predecessor
) ? ChangeResult::Change
84 : ChangeResult::NoChange
;
87 ChangeResult
PredecessorState::join(Operation
*predecessor
, ValueRange inputs
) {
88 ChangeResult result
= join(predecessor
);
89 if (!inputs
.empty()) {
90 ValueRange
&curInputs
= successorInputs
[predecessor
];
91 if (curInputs
!= inputs
) {
93 result
|= ChangeResult::Change
;
99 //===----------------------------------------------------------------------===//
101 //===----------------------------------------------------------------------===//
103 Location
CFGEdge::getLoc() const {
104 return FusedLoc::get(
105 getFrom()->getParent()->getContext(),
106 {getFrom()->getParent()->getLoc(), getTo()->getParent()->getLoc()});
109 void CFGEdge::print(raw_ostream
&os
) const {
110 getFrom()->print(os
);
115 //===----------------------------------------------------------------------===//
117 //===----------------------------------------------------------------------===//
119 DeadCodeAnalysis::DeadCodeAnalysis(DataFlowSolver
&solver
)
120 : DataFlowAnalysis(solver
) {
121 registerAnchorKind
<CFGEdge
>();
124 LogicalResult
DeadCodeAnalysis::initialize(Operation
*top
) {
125 // Mark the top-level blocks as executable.
126 for (Region
®ion
: top
->getRegions()) {
130 getOrCreate
<Executable
>(getProgramPointBefore(®ion
.front()));
131 propagateIfChanged(state
, state
->setToLive());
134 // Mark as overdefined the predecessors of symbol callables with potentially
135 // unknown predecessors.
136 initializeSymbolCallables(top
);
138 return initializeRecursively(top
);
141 void DeadCodeAnalysis::initializeSymbolCallables(Operation
*top
) {
143 auto walkFn
= [&](Operation
*symTable
, bool allUsesVisible
) {
144 Region
&symbolTableRegion
= symTable
->getRegion(0);
145 Block
*symbolTableBlock
= &symbolTableRegion
.front();
147 bool foundSymbolCallable
= false;
148 for (auto callable
: symbolTableBlock
->getOps
<CallableOpInterface
>()) {
149 Region
*callableRegion
= callable
.getCallableRegion();
152 auto symbol
= dyn_cast
<SymbolOpInterface
>(callable
.getOperation());
156 // Public symbol callables or those for which we can't see all uses have
157 // potentially unknown callsites.
158 if (symbol
.isPublic() || (!allUsesVisible
&& symbol
.isNested())) {
160 getOrCreate
<PredecessorState
>(getProgramPointAfter(callable
));
161 propagateIfChanged(state
, state
->setHasUnknownPredecessors());
163 foundSymbolCallable
= true;
166 // Exit early if no eligible symbol callables were found in the table.
167 if (!foundSymbolCallable
)
170 // Walk the symbol table to check for non-call uses of symbols.
171 std::optional
<SymbolTable::UseRange
> uses
=
172 SymbolTable::getSymbolUses(&symbolTableRegion
);
174 // If we couldn't gather the symbol uses, conservatively assume that
175 // we can't track information for any nested symbols.
176 return top
->walk([&](CallableOpInterface callable
) {
178 getOrCreate
<PredecessorState
>(getProgramPointAfter(callable
));
179 propagateIfChanged(state
, state
->setHasUnknownPredecessors());
183 for (const SymbolTable::SymbolUse
&use
: *uses
) {
184 if (isa
<CallOpInterface
>(use
.getUser()))
186 // If a callable symbol has a non-call use, then we can't be guaranteed to
187 // know all callsites.
188 Operation
*symbol
= symbolTable
.lookupSymbolIn(top
, use
.getSymbolRef());
191 auto *state
= getOrCreate
<PredecessorState
>(getProgramPointAfter(symbol
));
192 propagateIfChanged(state
, state
->setHasUnknownPredecessors());
195 SymbolTable::walkSymbolTables(top
, /*allSymUsesVisible=*/!top
->getBlock(),
199 /// Returns true if the operation is a returning terminator in region
200 /// control-flow or the terminator of a callable region.
201 static bool isRegionOrCallableReturn(Operation
*op
) {
202 return op
->getBlock() != nullptr && !op
->getNumSuccessors() &&
203 isa
<RegionBranchOpInterface
, CallableOpInterface
>(op
->getParentOp()) &&
204 op
->getBlock()->getTerminator() == op
;
207 LogicalResult
DeadCodeAnalysis::initializeRecursively(Operation
*op
) {
208 // Initialize the analysis by visiting every op with control-flow semantics.
209 if (op
->getNumRegions() || op
->getNumSuccessors() ||
210 isRegionOrCallableReturn(op
) || isa
<CallOpInterface
>(op
)) {
211 // When the liveness of the parent block changes, make sure to re-invoke the
212 // analysis on the op.
214 getOrCreate
<Executable
>(getProgramPointBefore(op
->getBlock()))
215 ->blockContentSubscribe(this);
217 if (failed(visit(getProgramPointAfter(op
))))
220 // Recurse on nested operations.
221 for (Region
®ion
: op
->getRegions())
222 for (Operation
&op
: region
.getOps())
223 if (failed(initializeRecursively(&op
)))
228 void DeadCodeAnalysis::markEdgeLive(Block
*from
, Block
*to
) {
229 auto *state
= getOrCreate
<Executable
>(getProgramPointBefore(to
));
230 propagateIfChanged(state
, state
->setToLive());
232 getOrCreate
<Executable
>(getLatticeAnchor
<CFGEdge
>(from
, to
));
233 propagateIfChanged(edgeState
, edgeState
->setToLive());
236 void DeadCodeAnalysis::markEntryBlocksLive(Operation
*op
) {
237 for (Region
®ion
: op
->getRegions()) {
241 getOrCreate
<Executable
>(getProgramPointBefore(®ion
.front()));
242 propagateIfChanged(state
, state
->setToLive());
246 LogicalResult
DeadCodeAnalysis::visit(ProgramPoint
*point
) {
247 if (point
->isBlockStart())
249 Operation
*op
= point
->getPrevOp();
251 // If the parent block is not executable, there is nothing to do.
252 if (op
->getBlock() != nullptr &&
253 !getOrCreate
<Executable
>(getProgramPointBefore(op
->getBlock()))->isLive())
256 // We have a live call op. Add this as a live predecessor of the callee.
257 if (auto call
= dyn_cast
<CallOpInterface
>(op
))
258 visitCallOperation(call
);
260 // Visit the regions.
261 if (op
->getNumRegions()) {
262 // Check if we can reason about the region control-flow.
263 if (auto branch
= dyn_cast
<RegionBranchOpInterface
>(op
)) {
264 visitRegionBranchOperation(branch
);
266 // Check if this is a callable operation.
267 } else if (auto callable
= dyn_cast
<CallableOpInterface
>(op
)) {
268 const auto *callsites
= getOrCreateFor
<PredecessorState
>(
269 getProgramPointAfter(op
), getProgramPointAfter(callable
));
271 // If the callsites could not be resolved or are known to be non-empty,
272 // mark the callable as executable.
273 if (!callsites
->allPredecessorsKnown() ||
274 !callsites
->getKnownPredecessors().empty())
275 markEntryBlocksLive(callable
);
277 // Otherwise, conservatively mark all entry blocks as executable.
279 markEntryBlocksLive(op
);
283 if (isRegionOrCallableReturn(op
)) {
284 if (auto branch
= dyn_cast
<RegionBranchOpInterface
>(op
->getParentOp())) {
285 // Visit the exiting terminator of a region.
286 visitRegionTerminator(op
, branch
);
287 } else if (auto callable
=
288 dyn_cast
<CallableOpInterface
>(op
->getParentOp())) {
289 // Visit the exiting terminator of a callable.
290 visitCallableTerminator(op
, callable
);
293 // Visit the successors.
294 if (op
->getNumSuccessors()) {
295 // Check if we can reason about the control-flow.
296 if (auto branch
= dyn_cast
<BranchOpInterface
>(op
)) {
297 visitBranchOperation(branch
);
299 // Otherwise, conservatively mark all successors as exectuable.
301 for (Block
*successor
: op
->getSuccessors())
302 markEdgeLive(op
->getBlock(), successor
);
309 void DeadCodeAnalysis::visitCallOperation(CallOpInterface call
) {
310 Operation
*callableOp
= call
.resolveCallableInTable(&symbolTable
);
312 // A call to a externally-defined callable has unknown predecessors.
313 const auto isExternalCallable
= [this](Operation
*op
) {
314 // A callable outside the analysis scope is an external callable.
315 if (!analysisScope
->isAncestor(op
))
317 // Otherwise, check if the callable region is defined.
318 if (auto callable
= dyn_cast
<CallableOpInterface
>(op
))
319 return !callable
.getCallableRegion();
323 // TODO: Add support for non-symbol callables when necessary. If the
324 // callable has non-call uses we would mark as having reached pessimistic
325 // fixpoint, otherwise allow for propagating the return values out.
326 if (isa_and_nonnull
<SymbolOpInterface
>(callableOp
) &&
327 !isExternalCallable(callableOp
)) {
328 // Add the live callsite.
330 getOrCreate
<PredecessorState
>(getProgramPointAfter(callableOp
));
331 propagateIfChanged(callsites
, callsites
->join(call
));
333 // Mark this call op's predecessors as overdefined.
335 getOrCreate
<PredecessorState
>(getProgramPointAfter(call
));
336 propagateIfChanged(predecessors
, predecessors
->setHasUnknownPredecessors());
340 /// Get the constant values of the operands of an operation. If any of the
341 /// constant value lattices are uninitialized, return std::nullopt to indicate
342 /// the analysis should bail out.
343 static std::optional
<SmallVector
<Attribute
>> getOperandValuesImpl(
345 function_ref
<const Lattice
<ConstantValue
> *(Value
)> getLattice
) {
346 SmallVector
<Attribute
> operands
;
347 operands
.reserve(op
->getNumOperands());
348 for (Value operand
: op
->getOperands()) {
349 const Lattice
<ConstantValue
> *cv
= getLattice(operand
);
350 // If any of the operands' values are uninitialized, bail out.
351 if (cv
->getValue().isUninitialized())
353 operands
.push_back(cv
->getValue().getConstantValue());
358 std::optional
<SmallVector
<Attribute
>>
359 DeadCodeAnalysis::getOperandValues(Operation
*op
) {
360 return getOperandValuesImpl(op
, [&](Value value
) {
361 auto *lattice
= getOrCreate
<Lattice
<ConstantValue
>>(value
);
362 lattice
->useDefSubscribe(this);
367 void DeadCodeAnalysis::visitBranchOperation(BranchOpInterface branch
) {
368 // Try to deduce a single successor for the branch.
369 std::optional
<SmallVector
<Attribute
>> operands
= getOperandValues(branch
);
373 if (Block
*successor
= branch
.getSuccessorForOperands(*operands
)) {
374 markEdgeLive(branch
->getBlock(), successor
);
376 // Otherwise, mark all successors as executable and outgoing edges.
377 for (Block
*successor
: branch
->getSuccessors())
378 markEdgeLive(branch
->getBlock(), successor
);
382 void DeadCodeAnalysis::visitRegionBranchOperation(
383 RegionBranchOpInterface branch
) {
384 // Try to deduce which regions are executable.
385 std::optional
<SmallVector
<Attribute
>> operands
= getOperandValues(branch
);
389 SmallVector
<RegionSuccessor
> successors
;
390 branch
.getEntrySuccessorRegions(*operands
, successors
);
391 for (const RegionSuccessor
&successor
: successors
) {
392 // The successor can be either an entry block or the parent operation.
393 ProgramPoint
*point
=
394 successor
.getSuccessor()
395 ? getProgramPointBefore(&successor
.getSuccessor()->front())
396 : getProgramPointAfter(branch
);
397 // Mark the entry block as executable.
398 auto *state
= getOrCreate
<Executable
>(point
);
399 propagateIfChanged(state
, state
->setToLive());
400 // Add the parent op as a predecessor.
401 auto *predecessors
= getOrCreate
<PredecessorState
>(point
);
404 predecessors
->join(branch
, successor
.getSuccessorInputs()));
408 void DeadCodeAnalysis::visitRegionTerminator(Operation
*op
,
409 RegionBranchOpInterface branch
) {
410 std::optional
<SmallVector
<Attribute
>> operands
= getOperandValues(op
);
414 SmallVector
<RegionSuccessor
> successors
;
415 if (auto terminator
= dyn_cast
<RegionBranchTerminatorOpInterface
>(op
))
416 terminator
.getSuccessorRegions(*operands
, successors
);
418 branch
.getSuccessorRegions(op
->getParentRegion(), successors
);
420 // Mark successor region entry blocks as executable and add this op to the
421 // list of predecessors.
422 for (const RegionSuccessor
&successor
: successors
) {
423 PredecessorState
*predecessors
;
424 if (Region
*region
= successor
.getSuccessor()) {
426 getOrCreate
<Executable
>(getProgramPointBefore(®ion
->front()));
427 propagateIfChanged(state
, state
->setToLive());
428 predecessors
= getOrCreate
<PredecessorState
>(
429 getProgramPointBefore(®ion
->front()));
431 // Add this terminator as a predecessor to the parent op.
433 getOrCreate
<PredecessorState
>(getProgramPointAfter(branch
));
435 propagateIfChanged(predecessors
,
436 predecessors
->join(op
, successor
.getSuccessorInputs()));
440 void DeadCodeAnalysis::visitCallableTerminator(Operation
*op
,
441 CallableOpInterface callable
) {
442 // Add as predecessors to all callsites this return op.
443 auto *callsites
= getOrCreateFor
<PredecessorState
>(
444 getProgramPointAfter(op
), getProgramPointAfter(callable
));
445 bool canResolve
= op
->hasTrait
<OpTrait::ReturnLike
>();
446 for (Operation
*predecessor
: callsites
->getKnownPredecessors()) {
447 assert(isa
<CallOpInterface
>(predecessor
));
449 getOrCreate
<PredecessorState
>(getProgramPointAfter(predecessor
));
451 propagateIfChanged(predecessors
, predecessors
->join(op
));
453 // If the terminator is not a return-like, then conservatively assume we
454 // can't resolve the predecessor.
455 propagateIfChanged(predecessors
,
456 predecessors
->setHasUnknownPredecessors());