xref: /llvm-project/mlir/lib/Analysis/DataFlow/DenseAnalysis.cpp (revision 4b3f251bada55cfc20a2c72321fa0bbfd7a759d5)
1 //===- DenseAnalysis.cpp - Dense data-flow analysis -----------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "mlir/Analysis/DataFlow/DenseAnalysis.h"
10 #include "mlir/Analysis/DataFlow/DeadCodeAnalysis.h"
11 #include "mlir/Analysis/DataFlowFramework.h"
12 #include "mlir/IR/Block.h"
13 #include "mlir/IR/OpDefinition.h"
14 #include "mlir/IR/Operation.h"
15 #include "mlir/IR/Region.h"
16 #include "mlir/Interfaces/CallInterfaces.h"
17 #include "mlir/Interfaces/ControlFlowInterfaces.h"
18 #include "mlir/Support/LLVM.h"
19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/Support/Casting.h"
21 #include <cassert>
22 #include <optional>
23 
24 using namespace mlir;
25 using namespace mlir::dataflow;
26 
27 //===----------------------------------------------------------------------===//
28 // AbstractDenseForwardDataFlowAnalysis
29 //===----------------------------------------------------------------------===//
30 
31 LogicalResult AbstractDenseForwardDataFlowAnalysis::initialize(Operation *top) {
32   // Visit every operation and block.
33   if (failed(processOperation(top)))
34     return failure();
35 
36   for (Region &region : top->getRegions()) {
37     for (Block &block : region) {
38       visitBlock(&block);
39       for (Operation &op : block)
40         if (failed(initialize(&op)))
41           return failure();
42     }
43   }
44   return success();
45 }
46 
47 LogicalResult AbstractDenseForwardDataFlowAnalysis::visit(ProgramPoint *point) {
48   if (!point->isBlockStart())
49     return processOperation(point->getPrevOp());
50   visitBlock(point->getBlock());
51   return success();
52 }
53 
54 void AbstractDenseForwardDataFlowAnalysis::visitCallOperation(
55     CallOpInterface call, const AbstractDenseLattice &before,
56     AbstractDenseLattice *after) {
57   // Allow for customizing the behavior of calls to external symbols, including
58   // when the analysis is explicitly marked as non-interprocedural.
59   auto callable =
60       dyn_cast_if_present<CallableOpInterface>(call.resolveCallable());
61   if (!getSolverConfig().isInterprocedural() ||
62       (callable && !callable.getCallableRegion())) {
63     return visitCallControlFlowTransfer(
64         call, CallControlFlowAction::ExternalCallee, before, after);
65   }
66 
67   const auto *predecessors = getOrCreateFor<PredecessorState>(
68       getProgramPointAfter(call.getOperation()), getProgramPointAfter(call));
69   // Otherwise, if not all return sites are known, then conservatively assume we
70   // can't reason about the data-flow.
71   if (!predecessors->allPredecessorsKnown())
72     return setToEntryState(after);
73 
74   for (Operation *predecessor : predecessors->getKnownPredecessors()) {
75     // Get the lattices at callee return:
76     //
77     //   func.func @callee() {
78     //     ...
79     //     return  // predecessor
80     //     // latticeAtCalleeReturn
81     //   }
82     //   func.func @caller() {
83     //     ...
84     //     call @callee
85     //     // latticeAfterCall
86     //     ...
87     //   }
88     AbstractDenseLattice *latticeAfterCall = after;
89     const AbstractDenseLattice *latticeAtCalleeReturn =
90         getLatticeFor(getProgramPointAfter(call.getOperation()),
91                       getProgramPointAfter(predecessor));
92     visitCallControlFlowTransfer(call, CallControlFlowAction::ExitCallee,
93                                  *latticeAtCalleeReturn, latticeAfterCall);
94   }
95 }
96 
97 LogicalResult
98 AbstractDenseForwardDataFlowAnalysis::processOperation(Operation *op) {
99   ProgramPoint *point = getProgramPointAfter(op);
100   // If the containing block is not executable, bail out.
101   if (op->getBlock() != nullptr &&
102       !getOrCreateFor<Executable>(point, getProgramPointBefore(op->getBlock()))
103            ->isLive())
104     return success();
105 
106   // Get the dense lattice to update.
107   AbstractDenseLattice *after = getLattice(point);
108 
109   // Get the dense state before the execution of the op.
110   const AbstractDenseLattice *before =
111       getLatticeFor(point, getProgramPointBefore(op));
112 
113   // If this op implements region control-flow, then control-flow dictates its
114   // transfer function.
115   if (auto branch = dyn_cast<RegionBranchOpInterface>(op)) {
116     visitRegionBranchOperation(point, branch, after);
117     return success();
118   }
119 
120   // If this is a call operation, then join its lattices across known return
121   // sites.
122   if (auto call = dyn_cast<CallOpInterface>(op)) {
123     visitCallOperation(call, *before, after);
124     return success();
125   }
126 
127   // Invoke the operation transfer function.
128   return visitOperationImpl(op, *before, after);
129 }
130 
131 void AbstractDenseForwardDataFlowAnalysis::visitBlock(Block *block) {
132   // If the block is not executable, bail out.
133   ProgramPoint *point = getProgramPointBefore(block);
134   if (!getOrCreateFor<Executable>(point, point)->isLive())
135     return;
136 
137   // Get the dense lattice to update.
138   AbstractDenseLattice *after = getLattice(point);
139 
140   // The dense lattices of entry blocks are set by region control-flow or the
141   // callgraph.
142   if (block->isEntryBlock()) {
143     // Check if this block is the entry block of a callable region.
144     auto callable = dyn_cast<CallableOpInterface>(block->getParentOp());
145     if (callable && callable.getCallableRegion() == block->getParent()) {
146       const auto *callsites = getOrCreateFor<PredecessorState>(
147           point, getProgramPointAfter(callable));
148       // If not all callsites are known, conservatively mark all lattices as
149       // having reached their pessimistic fixpoints. Do the same if
150       // interprocedural analysis is not enabled.
151       if (!callsites->allPredecessorsKnown() ||
152           !getSolverConfig().isInterprocedural())
153         return setToEntryState(after);
154       for (Operation *callsite : callsites->getKnownPredecessors()) {
155         // Get the dense lattice before the callsite.
156         const AbstractDenseLattice *before;
157         before = getLatticeFor(point, getProgramPointBefore(callsite));
158 
159         visitCallControlFlowTransfer(cast<CallOpInterface>(callsite),
160                                      CallControlFlowAction::EnterCallee,
161                                      *before, after);
162       }
163       return;
164     }
165 
166     // Check if we can reason about the control-flow.
167     if (auto branch = dyn_cast<RegionBranchOpInterface>(block->getParentOp()))
168       return visitRegionBranchOperation(point, branch, after);
169 
170     // Otherwise, we can't reason about the data-flow.
171     return setToEntryState(after);
172   }
173 
174   // Join the state with the state after the block's predecessors.
175   for (Block::pred_iterator it = block->pred_begin(), e = block->pred_end();
176        it != e; ++it) {
177     // Skip control edges that aren't executable.
178     Block *predecessor = *it;
179     if (!getOrCreateFor<Executable>(
180              point, getLatticeAnchor<CFGEdge>(predecessor, block))
181              ->isLive())
182       continue;
183 
184     // Merge in the state from the predecessor's terminator.
185     join(after, *getLatticeFor(
186                     point, getProgramPointAfter(predecessor->getTerminator())));
187   }
188 }
189 
190 void AbstractDenseForwardDataFlowAnalysis::visitRegionBranchOperation(
191     ProgramPoint *point, RegionBranchOpInterface branch,
192     AbstractDenseLattice *after) {
193   // Get the terminator predecessors.
194   const auto *predecessors = getOrCreateFor<PredecessorState>(point, point);
195   assert(predecessors->allPredecessorsKnown() &&
196          "unexpected unresolved region successors");
197 
198   for (Operation *op : predecessors->getKnownPredecessors()) {
199     const AbstractDenseLattice *before;
200     // If the predecessor is the parent, get the state before the parent.
201     if (op == branch) {
202       before = getLatticeFor(point, getProgramPointBefore(op));
203       // Otherwise, get the state after the terminator.
204     } else {
205       before = getLatticeFor(point, getProgramPointAfter(op));
206     }
207 
208     // This function is called in two cases:
209     //   1. when visiting the block (point = block start);
210     //   2. when visiting the parent operation (point = iter after parent op).
211     // In both cases, we are looking for predecessor operations of the point,
212     //   1. predecessor may be the terminator of another block from another
213     //   region (assuming that the block does belong to another region via an
214     //   assertion) or the parent (when parent can transfer control to this
215     //   region);
216     //   2. predecessor may be the terminator of a block that exits the
217     //   region (when region transfers control to the parent) or the operation
218     //   before the parent.
219     // In the latter case, just perform the join as it isn't the control flow
220     // affected by the region.
221     std::optional<unsigned> regionFrom =
222         op == branch ? std::optional<unsigned>()
223                      : op->getBlock()->getParent()->getRegionNumber();
224     if (point->isBlockStart()) {
225       unsigned regionTo = point->getBlock()->getParent()->getRegionNumber();
226       visitRegionBranchControlFlowTransfer(branch, regionFrom, regionTo,
227                                            *before, after);
228     } else {
229       assert(point->getPrevOp() == branch &&
230              "expected to be visiting the branch itself");
231       // Only need to call the arc transfer when the predecessor is the region
232       // or the op itself, not the previous op.
233       if (op->getParentOp() == branch || op == branch) {
234         visitRegionBranchControlFlowTransfer(
235             branch, regionFrom, /*regionTo=*/std::nullopt, *before, after);
236       } else {
237         join(after, *before);
238       }
239     }
240   }
241 }
242 
243 const AbstractDenseLattice *
244 AbstractDenseForwardDataFlowAnalysis::getLatticeFor(ProgramPoint *dependent,
245                                                     LatticeAnchor anchor) {
246   AbstractDenseLattice *state = getLattice(anchor);
247   addDependency(state, dependent);
248   return state;
249 }
250 
251 //===----------------------------------------------------------------------===//
252 // AbstractDenseBackwardDataFlowAnalysis
253 //===----------------------------------------------------------------------===//
254 
255 LogicalResult
256 AbstractDenseBackwardDataFlowAnalysis::initialize(Operation *top) {
257   // Visit every operation and block.
258   if (failed(processOperation(top)))
259     return failure();
260 
261   for (Region &region : top->getRegions()) {
262     for (Block &block : region) {
263       visitBlock(&block);
264       for (Operation &op : llvm::reverse(block)) {
265         if (failed(initialize(&op)))
266           return failure();
267       }
268     }
269   }
270   return success();
271 }
272 
273 LogicalResult
274 AbstractDenseBackwardDataFlowAnalysis::visit(ProgramPoint *point) {
275   if (!point->isBlockEnd())
276     return processOperation(point->getNextOp());
277   visitBlock(point->getBlock());
278   return success();
279 }
280 
281 void AbstractDenseBackwardDataFlowAnalysis::visitCallOperation(
282     CallOpInterface call, const AbstractDenseLattice &after,
283     AbstractDenseLattice *before) {
284   // Find the callee.
285   Operation *callee = call.resolveCallableInTable(&symbolTable);
286 
287   auto callable = dyn_cast_or_null<CallableOpInterface>(callee);
288   // No region means the callee is only declared in this module.
289   // If that is the case or if the solver is not interprocedural,
290   // let the hook handle it.
291   if (!getSolverConfig().isInterprocedural() ||
292       (callable && (!callable.getCallableRegion() ||
293                     callable.getCallableRegion()->empty()))) {
294     return visitCallControlFlowTransfer(
295         call, CallControlFlowAction::ExternalCallee, after, before);
296   }
297 
298   if (!callable)
299     return setToExitState(before);
300 
301   Region *region = callable.getCallableRegion();
302 
303   // Call-level control flow specifies the data flow here.
304   //
305   //   func.func @callee() {
306   //     ^calleeEntryBlock:
307   //     // latticeAtCalleeEntry
308   //     ...
309   //   }
310   //   func.func @caller() {
311   //     ...
312   //     // latticeBeforeCall
313   //     call @callee
314   //     ...
315   //   }
316   Block *calleeEntryBlock = &region->front();
317   ProgramPoint *calleeEntry = getProgramPointBefore(calleeEntryBlock);
318   const AbstractDenseLattice &latticeAtCalleeEntry =
319       *getLatticeFor(getProgramPointBefore(call.getOperation()), calleeEntry);
320   AbstractDenseLattice *latticeBeforeCall = before;
321   visitCallControlFlowTransfer(call, CallControlFlowAction::EnterCallee,
322                                latticeAtCalleeEntry, latticeBeforeCall);
323 }
324 
325 LogicalResult
326 AbstractDenseBackwardDataFlowAnalysis::processOperation(Operation *op) {
327   ProgramPoint *point = getProgramPointBefore(op);
328   // If the containing block is not executable, bail out.
329   if (op->getBlock() != nullptr &&
330       !getOrCreateFor<Executable>(point, getProgramPointBefore(op->getBlock()))
331            ->isLive())
332     return success();
333 
334   // Get the dense lattice to update.
335   AbstractDenseLattice *before = getLattice(point);
336 
337   // Get the dense state after execution of this op.
338   const AbstractDenseLattice *after =
339       getLatticeFor(point, getProgramPointAfter(op));
340 
341   // Special cases where control flow may dictate data flow.
342   if (auto branch = dyn_cast<RegionBranchOpInterface>(op)) {
343     visitRegionBranchOperation(point, branch, RegionBranchPoint::parent(),
344                                before);
345     return success();
346   }
347   if (auto call = dyn_cast<CallOpInterface>(op)) {
348     visitCallOperation(call, *after, before);
349     return success();
350   }
351 
352   // Invoke the operation transfer function.
353   return visitOperationImpl(op, *after, before);
354 }
355 
356 void AbstractDenseBackwardDataFlowAnalysis::visitBlock(Block *block) {
357   ProgramPoint *point = getProgramPointAfter(block);
358   // If the block is not executable, bail out.
359   if (!getOrCreateFor<Executable>(point, getProgramPointBefore(block))
360            ->isLive())
361     return;
362 
363   AbstractDenseLattice *before = getLattice(point);
364 
365   // We need "exit" blocks, i.e. the blocks that may return control to the
366   // parent operation.
367   auto isExitBlock = [](Block *b) {
368     // Treat empty and terminator-less blocks as exit blocks.
369     if (b->empty() || !b->back().mightHaveTrait<OpTrait::IsTerminator>())
370       return true;
371 
372     // There may be a weird case where a terminator may be transferring control
373     // either to the parent or to another block, so exit blocks and successors
374     // are not mutually exclusive.
375     return isa_and_nonnull<RegionBranchTerminatorOpInterface>(
376         b->getTerminator());
377   };
378   if (isExitBlock(block)) {
379     // If this block is exiting from a callable, the successors of exiting from
380     // a callable are the successors of all call sites. And the call sites
381     // themselves are predecessors of the callable.
382     auto callable = dyn_cast<CallableOpInterface>(block->getParentOp());
383     if (callable && callable.getCallableRegion() == block->getParent()) {
384       const auto *callsites = getOrCreateFor<PredecessorState>(
385           point, getProgramPointAfter(callable));
386       // If not all call sites are known, conservative mark all lattices as
387       // having reached their pessimistic fix points.
388       if (!callsites->allPredecessorsKnown() ||
389           !getSolverConfig().isInterprocedural()) {
390         return setToExitState(before);
391       }
392 
393       for (Operation *callsite : callsites->getKnownPredecessors()) {
394         const AbstractDenseLattice *after =
395             getLatticeFor(point, getProgramPointAfter(callsite));
396         visitCallControlFlowTransfer(cast<CallOpInterface>(callsite),
397                                      CallControlFlowAction::ExitCallee, *after,
398                                      before);
399       }
400       return;
401     }
402 
403     // If this block is exiting from an operation with region-based control
404     // flow, propagate the lattice back along the control flow edge.
405     if (auto branch = dyn_cast<RegionBranchOpInterface>(block->getParentOp())) {
406       visitRegionBranchOperation(point, branch, block->getParent(), before);
407       return;
408     }
409 
410     // Cannot reason about successors of an exit block, set the pessimistic
411     // fixpoint.
412     return setToExitState(before);
413   }
414 
415   // Meet the state with the state before block's successors.
416   for (Block *successor : block->getSuccessors()) {
417     if (!getOrCreateFor<Executable>(point,
418                                     getLatticeAnchor<CFGEdge>(block, successor))
419              ->isLive())
420       continue;
421 
422     // Merge in the state from the successor: either the first operation, or the
423     // block itself when empty.
424     meet(before, *getLatticeFor(point, getProgramPointBefore(successor)));
425   }
426 }
427 
428 void AbstractDenseBackwardDataFlowAnalysis::visitRegionBranchOperation(
429     ProgramPoint *point, RegionBranchOpInterface branch,
430     RegionBranchPoint branchPoint, AbstractDenseLattice *before) {
431 
432   // The successors of the operation may be either the first operation of the
433   // entry block of each possible successor region, or the next operation when
434   // the branch is a successor of itself.
435   SmallVector<RegionSuccessor> successors;
436   branch.getSuccessorRegions(branchPoint, successors);
437   for (const RegionSuccessor &successor : successors) {
438     const AbstractDenseLattice *after;
439     if (successor.isParent() || successor.getSuccessor()->empty()) {
440       after = getLatticeFor(point, getProgramPointAfter(branch));
441     } else {
442       Region *successorRegion = successor.getSuccessor();
443       assert(!successorRegion->empty() && "unexpected empty successor region");
444       Block *successorBlock = &successorRegion->front();
445 
446       if (!getOrCreateFor<Executable>(point,
447                                       getProgramPointBefore(successorBlock))
448                ->isLive())
449         continue;
450 
451       after = getLatticeFor(point, getProgramPointBefore(successorBlock));
452     }
453 
454     visitRegionBranchControlFlowTransfer(branch, branchPoint, successor, *after,
455                                          before);
456   }
457 }
458 
459 const AbstractDenseLattice *
460 AbstractDenseBackwardDataFlowAnalysis::getLatticeFor(ProgramPoint *dependent,
461                                                      LatticeAnchor anchor) {
462   AbstractDenseLattice *state = getLattice(anchor);
463   addDependency(state, dependent);
464   return state;
465 }
466