xref: /llvm-project/mlir/lib/Analysis/DataFlow/DenseAnalysis.cpp (revision 4b3f251bada55cfc20a2c72321fa0bbfd7a759d5)
1d80c271cSMogball //===- DenseAnalysis.cpp - Dense data-flow analysis -----------------------===//
2d80c271cSMogball //
3d80c271cSMogball // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4d80c271cSMogball // See https://llvm.org/LICENSE.txt for license information.
5d80c271cSMogball // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d80c271cSMogball //
7d80c271cSMogball //===----------------------------------------------------------------------===//
8d80c271cSMogball 
9d80c271cSMogball #include "mlir/Analysis/DataFlow/DenseAnalysis.h"
10d80c271cSMogball #include "mlir/Analysis/DataFlow/DeadCodeAnalysis.h"
11fba3951bSMehdi Amini #include "mlir/Analysis/DataFlowFramework.h"
12fba3951bSMehdi Amini #include "mlir/IR/Block.h"
13fba3951bSMehdi Amini #include "mlir/IR/OpDefinition.h"
14fba3951bSMehdi Amini #include "mlir/IR/Operation.h"
15fba3951bSMehdi Amini #include "mlir/IR/Region.h"
16d80c271cSMogball #include "mlir/Interfaces/CallInterfaces.h"
17d80c271cSMogball #include "mlir/Interfaces/ControlFlowInterfaces.h"
18fba3951bSMehdi Amini #include "mlir/Support/LLVM.h"
19fba3951bSMehdi Amini #include "llvm/ADT/STLExtras.h"
20fba3951bSMehdi Amini #include "llvm/Support/Casting.h"
21fba3951bSMehdi Amini #include <cassert>
22fba3951bSMehdi Amini #include <optional>
23d80c271cSMogball 
24d80c271cSMogball using namespace mlir;
25d80c271cSMogball using namespace mlir::dataflow;
26d80c271cSMogball 
27d80c271cSMogball //===----------------------------------------------------------------------===//
28b2b7efb9SAlex Zinenko // AbstractDenseForwardDataFlowAnalysis
29d80c271cSMogball //===----------------------------------------------------------------------===//
30d80c271cSMogball 
31b2b7efb9SAlex Zinenko LogicalResult AbstractDenseForwardDataFlowAnalysis::initialize(Operation *top) {
32d80c271cSMogball   // Visit every operation and block.
3315e915a4SIvan Butygin   if (failed(processOperation(top)))
3415e915a4SIvan Butygin     return failure();
3515e915a4SIvan Butygin 
36d80c271cSMogball   for (Region &region : top->getRegions()) {
37d80c271cSMogball     for (Block &block : region) {
38d80c271cSMogball       visitBlock(&block);
39d80c271cSMogball       for (Operation &op : block)
40d80c271cSMogball         if (failed(initialize(&op)))
41d80c271cSMogball           return failure();
42d80c271cSMogball     }
43d80c271cSMogball   }
44d80c271cSMogball   return success();
45d80c271cSMogball }
46d80c271cSMogball 
47*4b3f251bSdonald chen LogicalResult AbstractDenseForwardDataFlowAnalysis::visit(ProgramPoint *point) {
48*4b3f251bSdonald chen   if (!point->isBlockStart())
49*4b3f251bSdonald chen     return processOperation(point->getPrevOp());
50*4b3f251bSdonald chen   visitBlock(point->getBlock());
51d80c271cSMogball   return success();
52d80c271cSMogball }
53d80c271cSMogball 
54b2b7efb9SAlex Zinenko void AbstractDenseForwardDataFlowAnalysis::visitCallOperation(
5532a4e3fcSOleksandr "Alex" Zinenko     CallOpInterface call, const AbstractDenseLattice &before,
5632a4e3fcSOleksandr "Alex" Zinenko     AbstractDenseLattice *after) {
5732a4e3fcSOleksandr "Alex" Zinenko   // Allow for customizing the behavior of calls to external symbols, including
5832a4e3fcSOleksandr "Alex" Zinenko   // when the analysis is explicitly marked as non-interprocedural.
5932a4e3fcSOleksandr "Alex" Zinenko   auto callable =
6032a4e3fcSOleksandr "Alex" Zinenko       dyn_cast_if_present<CallableOpInterface>(call.resolveCallable());
6132a4e3fcSOleksandr "Alex" Zinenko   if (!getSolverConfig().isInterprocedural() ||
6232a4e3fcSOleksandr "Alex" Zinenko       (callable && !callable.getCallableRegion())) {
6332a4e3fcSOleksandr "Alex" Zinenko     return visitCallControlFlowTransfer(
6432a4e3fcSOleksandr "Alex" Zinenko         call, CallControlFlowAction::ExternalCallee, before, after);
6532a4e3fcSOleksandr "Alex" Zinenko   }
665d8813deSAlex Zinenko 
67*4b3f251bSdonald chen   const auto *predecessors = getOrCreateFor<PredecessorState>(
68*4b3f251bSdonald chen       getProgramPointAfter(call.getOperation()), getProgramPointAfter(call));
6932a4e3fcSOleksandr "Alex" Zinenko   // Otherwise, if not all return sites are known, then conservatively assume we
7032a4e3fcSOleksandr "Alex" Zinenko   // can't reason about the data-flow.
715d8813deSAlex Zinenko   if (!predecessors->allPredecessorsKnown())
725d8813deSAlex Zinenko     return setToEntryState(after);
735d8813deSAlex Zinenko 
745d8813deSAlex Zinenko   for (Operation *predecessor : predecessors->getKnownPredecessors()) {
755d8813deSAlex Zinenko     // Get the lattices at callee return:
765d8813deSAlex Zinenko     //
775d8813deSAlex Zinenko     //   func.func @callee() {
785d8813deSAlex Zinenko     //     ...
795d8813deSAlex Zinenko     //     return  // predecessor
805d8813deSAlex Zinenko     //     // latticeAtCalleeReturn
815d8813deSAlex Zinenko     //   }
825d8813deSAlex Zinenko     //   func.func @caller() {
835d8813deSAlex Zinenko     //     ...
845d8813deSAlex Zinenko     //     call @callee
855d8813deSAlex Zinenko     //     // latticeAfterCall
865d8813deSAlex Zinenko     //     ...
875d8813deSAlex Zinenko     //   }
885d8813deSAlex Zinenko     AbstractDenseLattice *latticeAfterCall = after;
895d8813deSAlex Zinenko     const AbstractDenseLattice *latticeAtCalleeReturn =
90*4b3f251bSdonald chen         getLatticeFor(getProgramPointAfter(call.getOperation()),
91*4b3f251bSdonald chen                       getProgramPointAfter(predecessor));
925d8813deSAlex Zinenko     visitCallControlFlowTransfer(call, CallControlFlowAction::ExitCallee,
935d8813deSAlex Zinenko                                  *latticeAtCalleeReturn, latticeAfterCall);
945d8813deSAlex Zinenko   }
955d8813deSAlex Zinenko }
965d8813deSAlex Zinenko 
9715e915a4SIvan Butygin LogicalResult
9815e915a4SIvan Butygin AbstractDenseForwardDataFlowAnalysis::processOperation(Operation *op) {
99*4b3f251bSdonald chen   ProgramPoint *point = getProgramPointAfter(op);
100d80c271cSMogball   // If the containing block is not executable, bail out.
101*4b3f251bSdonald chen   if (op->getBlock() != nullptr &&
102*4b3f251bSdonald chen       !getOrCreateFor<Executable>(point, getProgramPointBefore(op->getBlock()))
103*4b3f251bSdonald chen            ->isLive())
10415e915a4SIvan Butygin     return success();
105d80c271cSMogball 
106d80c271cSMogball   // Get the dense lattice to update.
107*4b3f251bSdonald chen   AbstractDenseLattice *after = getLattice(point);
108d80c271cSMogball 
1095d8813deSAlex Zinenko   // Get the dense state before the execution of the op.
110*4b3f251bSdonald chen   const AbstractDenseLattice *before =
111*4b3f251bSdonald chen       getLatticeFor(point, getProgramPointBefore(op));
1125d8813deSAlex Zinenko 
113d80c271cSMogball   // If this op implements region control-flow, then control-flow dictates its
114d80c271cSMogball   // transfer function.
11515e915a4SIvan Butygin   if (auto branch = dyn_cast<RegionBranchOpInterface>(op)) {
116*4b3f251bSdonald chen     visitRegionBranchOperation(point, branch, after);
11715e915a4SIvan Butygin     return success();
11815e915a4SIvan Butygin   }
119d80c271cSMogball 
120d80c271cSMogball   // If this is a call operation, then join its lattices across known return
121d80c271cSMogball   // sites.
12215e915a4SIvan Butygin   if (auto call = dyn_cast<CallOpInterface>(op)) {
12315e915a4SIvan Butygin     visitCallOperation(call, *before, after);
12415e915a4SIvan Butygin     return success();
12515e915a4SIvan Butygin   }
126d80c271cSMogball 
127d80c271cSMogball   // Invoke the operation transfer function.
12815e915a4SIvan Butygin   return visitOperationImpl(op, *before, after);
129d80c271cSMogball }
130d80c271cSMogball 
131b2b7efb9SAlex Zinenko void AbstractDenseForwardDataFlowAnalysis::visitBlock(Block *block) {
132d80c271cSMogball   // If the block is not executable, bail out.
133*4b3f251bSdonald chen   ProgramPoint *point = getProgramPointBefore(block);
134*4b3f251bSdonald chen   if (!getOrCreateFor<Executable>(point, point)->isLive())
135d80c271cSMogball     return;
136d80c271cSMogball 
137d80c271cSMogball   // Get the dense lattice to update.
138*4b3f251bSdonald chen   AbstractDenseLattice *after = getLattice(point);
139d80c271cSMogball 
140d80c271cSMogball   // The dense lattices of entry blocks are set by region control-flow or the
141d80c271cSMogball   // callgraph.
142d80c271cSMogball   if (block->isEntryBlock()) {
143d80c271cSMogball     // Check if this block is the entry block of a callable region.
144d80c271cSMogball     auto callable = dyn_cast<CallableOpInterface>(block->getParentOp());
145d80c271cSMogball     if (callable && callable.getCallableRegion() == block->getParent()) {
146*4b3f251bSdonald chen       const auto *callsites = getOrCreateFor<PredecessorState>(
147*4b3f251bSdonald chen           point, getProgramPointAfter(callable));
148d80c271cSMogball       // If not all callsites are known, conservatively mark all lattices as
14932a4e3fcSOleksandr "Alex" Zinenko       // having reached their pessimistic fixpoints. Do the same if
15032a4e3fcSOleksandr "Alex" Zinenko       // interprocedural analysis is not enabled.
15132a4e3fcSOleksandr "Alex" Zinenko       if (!callsites->allPredecessorsKnown() ||
15232a4e3fcSOleksandr "Alex" Zinenko           !getSolverConfig().isInterprocedural())
153de0ebc52SZhixun Tan         return setToEntryState(after);
154d80c271cSMogball       for (Operation *callsite : callsites->getKnownPredecessors()) {
155d80c271cSMogball         // Get the dense lattice before the callsite.
1565d8813deSAlex Zinenko         const AbstractDenseLattice *before;
157*4b3f251bSdonald chen         before = getLatticeFor(point, getProgramPointBefore(callsite));
1585d8813deSAlex Zinenko 
1595d8813deSAlex Zinenko         visitCallControlFlowTransfer(cast<CallOpInterface>(callsite),
1605d8813deSAlex Zinenko                                      CallControlFlowAction::EnterCallee,
1615d8813deSAlex Zinenko                                      *before, after);
162d80c271cSMogball       }
163d80c271cSMogball       return;
164d80c271cSMogball     }
165d80c271cSMogball 
166d80c271cSMogball     // Check if we can reason about the control-flow.
167d80c271cSMogball     if (auto branch = dyn_cast<RegionBranchOpInterface>(block->getParentOp()))
168*4b3f251bSdonald chen       return visitRegionBranchOperation(point, branch, after);
169d80c271cSMogball 
170d80c271cSMogball     // Otherwise, we can't reason about the data-flow.
171de0ebc52SZhixun Tan     return setToEntryState(after);
172d80c271cSMogball   }
173d80c271cSMogball 
174d80c271cSMogball   // Join the state with the state after the block's predecessors.
175d80c271cSMogball   for (Block::pred_iterator it = block->pred_begin(), e = block->pred_end();
176d80c271cSMogball        it != e; ++it) {
177d80c271cSMogball     // Skip control edges that aren't executable.
178d80c271cSMogball     Block *predecessor = *it;
179d80c271cSMogball     if (!getOrCreateFor<Executable>(
180*4b3f251bSdonald chen              point, getLatticeAnchor<CFGEdge>(predecessor, block))
181d80c271cSMogball              ->isLive())
182d80c271cSMogball       continue;
183d80c271cSMogball 
184d80c271cSMogball     // Merge in the state from the predecessor's terminator.
185*4b3f251bSdonald chen     join(after, *getLatticeFor(
186*4b3f251bSdonald chen                     point, getProgramPointAfter(predecessor->getTerminator())));
187d80c271cSMogball   }
188d80c271cSMogball }
189d80c271cSMogball 
190b2b7efb9SAlex Zinenko void AbstractDenseForwardDataFlowAnalysis::visitRegionBranchOperation(
191*4b3f251bSdonald chen     ProgramPoint *point, RegionBranchOpInterface branch,
192d80c271cSMogball     AbstractDenseLattice *after) {
193d80c271cSMogball   // Get the terminator predecessors.
194d80c271cSMogball   const auto *predecessors = getOrCreateFor<PredecessorState>(point, point);
195d80c271cSMogball   assert(predecessors->allPredecessorsKnown() &&
196d80c271cSMogball          "unexpected unresolved region successors");
197d80c271cSMogball 
198d80c271cSMogball   for (Operation *op : predecessors->getKnownPredecessors()) {
199d80c271cSMogball     const AbstractDenseLattice *before;
200d80c271cSMogball     // If the predecessor is the parent, get the state before the parent.
201d80c271cSMogball     if (op == branch) {
202*4b3f251bSdonald chen       before = getLatticeFor(point, getProgramPointBefore(op));
203d80c271cSMogball       // Otherwise, get the state after the terminator.
204d80c271cSMogball     } else {
205*4b3f251bSdonald chen       before = getLatticeFor(point, getProgramPointAfter(op));
206d80c271cSMogball     }
2075d8813deSAlex Zinenko 
2085d8813deSAlex Zinenko     // This function is called in two cases:
209*4b3f251bSdonald chen     //   1. when visiting the block (point = block start);
210*4b3f251bSdonald chen     //   2. when visiting the parent operation (point = iter after parent op).
2115d8813deSAlex Zinenko     // In both cases, we are looking for predecessor operations of the point,
2125d8813deSAlex Zinenko     //   1. predecessor may be the terminator of another block from another
2135d8813deSAlex Zinenko     //   region (assuming that the block does belong to another region via an
2145d8813deSAlex Zinenko     //   assertion) or the parent (when parent can transfer control to this
2155d8813deSAlex Zinenko     //   region);
2165d8813deSAlex Zinenko     //   2. predecessor may be the terminator of a block that exits the
2175d8813deSAlex Zinenko     //   region (when region transfers control to the parent) or the operation
2185d8813deSAlex Zinenko     //   before the parent.
2195d8813deSAlex Zinenko     // In the latter case, just perform the join as it isn't the control flow
2205d8813deSAlex Zinenko     // affected by the region.
2215d8813deSAlex Zinenko     std::optional<unsigned> regionFrom =
2225d8813deSAlex Zinenko         op == branch ? std::optional<unsigned>()
2235d8813deSAlex Zinenko                      : op->getBlock()->getParent()->getRegionNumber();
224*4b3f251bSdonald chen     if (point->isBlockStart()) {
225*4b3f251bSdonald chen       unsigned regionTo = point->getBlock()->getParent()->getRegionNumber();
2265d8813deSAlex Zinenko       visitRegionBranchControlFlowTransfer(branch, regionFrom, regionTo,
2275d8813deSAlex Zinenko                                            *before, after);
2285d8813deSAlex Zinenko     } else {
229*4b3f251bSdonald chen       assert(point->getPrevOp() == branch &&
2305d8813deSAlex Zinenko              "expected to be visiting the branch itself");
2315d8813deSAlex Zinenko       // Only need to call the arc transfer when the predecessor is the region
2325d8813deSAlex Zinenko       // or the op itself, not the previous op.
2335d8813deSAlex Zinenko       if (op->getParentOp() == branch || op == branch) {
2345d8813deSAlex Zinenko         visitRegionBranchControlFlowTransfer(
2355d8813deSAlex Zinenko             branch, regionFrom, /*regionTo=*/std::nullopt, *before, after);
2365d8813deSAlex Zinenko       } else {
237d80c271cSMogball         join(after, *before);
238d80c271cSMogball       }
239d80c271cSMogball     }
2405d8813deSAlex Zinenko   }
2415d8813deSAlex Zinenko }
242d80c271cSMogball 
243d80c271cSMogball const AbstractDenseLattice *
244*4b3f251bSdonald chen AbstractDenseForwardDataFlowAnalysis::getLatticeFor(ProgramPoint *dependent,
245b6603e1bSdonald chen                                                     LatticeAnchor anchor) {
246b6603e1bSdonald chen   AbstractDenseLattice *state = getLattice(anchor);
247d80c271cSMogball   addDependency(state, dependent);
248d80c271cSMogball   return state;
249d80c271cSMogball }
2508a918c54SAlex Zinenko 
2518a918c54SAlex Zinenko //===----------------------------------------------------------------------===//
2528a918c54SAlex Zinenko // AbstractDenseBackwardDataFlowAnalysis
2538a918c54SAlex Zinenko //===----------------------------------------------------------------------===//
2548a918c54SAlex Zinenko 
2558a918c54SAlex Zinenko LogicalResult
2568a918c54SAlex Zinenko AbstractDenseBackwardDataFlowAnalysis::initialize(Operation *top) {
2578a918c54SAlex Zinenko   // Visit every operation and block.
25815e915a4SIvan Butygin   if (failed(processOperation(top)))
25915e915a4SIvan Butygin     return failure();
26015e915a4SIvan Butygin 
2618a918c54SAlex Zinenko   for (Region &region : top->getRegions()) {
2628a918c54SAlex Zinenko     for (Block &block : region) {
2638a918c54SAlex Zinenko       visitBlock(&block);
2648a918c54SAlex Zinenko       for (Operation &op : llvm::reverse(block)) {
2658a918c54SAlex Zinenko         if (failed(initialize(&op)))
2668a918c54SAlex Zinenko           return failure();
2678a918c54SAlex Zinenko       }
2688a918c54SAlex Zinenko     }
2698a918c54SAlex Zinenko   }
2708a918c54SAlex Zinenko   return success();
2718a918c54SAlex Zinenko }
2728a918c54SAlex Zinenko 
273*4b3f251bSdonald chen LogicalResult
274*4b3f251bSdonald chen AbstractDenseBackwardDataFlowAnalysis::visit(ProgramPoint *point) {
275*4b3f251bSdonald chen   if (!point->isBlockEnd())
276*4b3f251bSdonald chen     return processOperation(point->getNextOp());
277*4b3f251bSdonald chen   visitBlock(point->getBlock());
2788a918c54SAlex Zinenko   return success();
2798a918c54SAlex Zinenko }
2808a918c54SAlex Zinenko 
2815d8813deSAlex Zinenko void AbstractDenseBackwardDataFlowAnalysis::visitCallOperation(
28232a4e3fcSOleksandr "Alex" Zinenko     CallOpInterface call, const AbstractDenseLattice &after,
28332a4e3fcSOleksandr "Alex" Zinenko     AbstractDenseLattice *before) {
2845d8813deSAlex Zinenko   // Find the callee.
285d1cad229SHenrich Lauko   Operation *callee = call.resolveCallableInTable(&symbolTable);
2865d8813deSAlex Zinenko 
2872bd66425Sdrblallo   auto callable = dyn_cast_or_null<CallableOpInterface>(callee);
28832a4e3fcSOleksandr "Alex" Zinenko   // No region means the callee is only declared in this module.
2892bd66425Sdrblallo   // If that is the case or if the solver is not interprocedural,
2902bd66425Sdrblallo   // let the hook handle it.
2912bd66425Sdrblallo   if (!getSolverConfig().isInterprocedural() ||
2922bd66425Sdrblallo       (callable && (!callable.getCallableRegion() ||
2932bd66425Sdrblallo                     callable.getCallableRegion()->empty()))) {
29432a4e3fcSOleksandr "Alex" Zinenko     return visitCallControlFlowTransfer(
29532a4e3fcSOleksandr "Alex" Zinenko         call, CallControlFlowAction::ExternalCallee, after, before);
29632a4e3fcSOleksandr "Alex" Zinenko   }
2975d8813deSAlex Zinenko 
2982bd66425Sdrblallo   if (!callable)
2992bd66425Sdrblallo     return setToExitState(before);
3002bd66425Sdrblallo 
3012bd66425Sdrblallo   Region *region = callable.getCallableRegion();
3022bd66425Sdrblallo 
3035d8813deSAlex Zinenko   // Call-level control flow specifies the data flow here.
3045d8813deSAlex Zinenko   //
3055d8813deSAlex Zinenko   //   func.func @callee() {
3065d8813deSAlex Zinenko   //     ^calleeEntryBlock:
3075d8813deSAlex Zinenko   //     // latticeAtCalleeEntry
3085d8813deSAlex Zinenko   //     ...
3095d8813deSAlex Zinenko   //   }
3105d8813deSAlex Zinenko   //   func.func @caller() {
3115d8813deSAlex Zinenko   //     ...
3125d8813deSAlex Zinenko   //     // latticeBeforeCall
3135d8813deSAlex Zinenko   //     call @callee
3145d8813deSAlex Zinenko   //     ...
3155d8813deSAlex Zinenko   //   }
3165d8813deSAlex Zinenko   Block *calleeEntryBlock = &region->front();
317*4b3f251bSdonald chen   ProgramPoint *calleeEntry = getProgramPointBefore(calleeEntryBlock);
3185d8813deSAlex Zinenko   const AbstractDenseLattice &latticeAtCalleeEntry =
319*4b3f251bSdonald chen       *getLatticeFor(getProgramPointBefore(call.getOperation()), calleeEntry);
3205d8813deSAlex Zinenko   AbstractDenseLattice *latticeBeforeCall = before;
3215d8813deSAlex Zinenko   visitCallControlFlowTransfer(call, CallControlFlowAction::EnterCallee,
3225d8813deSAlex Zinenko                                latticeAtCalleeEntry, latticeBeforeCall);
3235d8813deSAlex Zinenko }
3245d8813deSAlex Zinenko 
32515e915a4SIvan Butygin LogicalResult
32615e915a4SIvan Butygin AbstractDenseBackwardDataFlowAnalysis::processOperation(Operation *op) {
327*4b3f251bSdonald chen   ProgramPoint *point = getProgramPointBefore(op);
3288a918c54SAlex Zinenko   // If the containing block is not executable, bail out.
329*4b3f251bSdonald chen   if (op->getBlock() != nullptr &&
330*4b3f251bSdonald chen       !getOrCreateFor<Executable>(point, getProgramPointBefore(op->getBlock()))
331*4b3f251bSdonald chen            ->isLive())
33215e915a4SIvan Butygin     return success();
3338a918c54SAlex Zinenko 
3348a918c54SAlex Zinenko   // Get the dense lattice to update.
335*4b3f251bSdonald chen   AbstractDenseLattice *before = getLattice(point);
3368a918c54SAlex Zinenko 
3378a918c54SAlex Zinenko   // Get the dense state after execution of this op.
338*4b3f251bSdonald chen   const AbstractDenseLattice *after =
339*4b3f251bSdonald chen       getLatticeFor(point, getProgramPointAfter(op));
3408a918c54SAlex Zinenko 
3415d8813deSAlex Zinenko   // Special cases where control flow may dictate data flow.
34215e915a4SIvan Butygin   if (auto branch = dyn_cast<RegionBranchOpInterface>(op)) {
343*4b3f251bSdonald chen     visitRegionBranchOperation(point, branch, RegionBranchPoint::parent(),
344*4b3f251bSdonald chen                                before);
34515e915a4SIvan Butygin     return success();
34615e915a4SIvan Butygin   }
34715e915a4SIvan Butygin   if (auto call = dyn_cast<CallOpInterface>(op)) {
34815e915a4SIvan Butygin     visitCallOperation(call, *after, before);
34915e915a4SIvan Butygin     return success();
35015e915a4SIvan Butygin   }
3515d8813deSAlex Zinenko 
3528a918c54SAlex Zinenko   // Invoke the operation transfer function.
35315e915a4SIvan Butygin   return visitOperationImpl(op, *after, before);
3548a918c54SAlex Zinenko }
3558a918c54SAlex Zinenko 
3568a918c54SAlex Zinenko void AbstractDenseBackwardDataFlowAnalysis::visitBlock(Block *block) {
357*4b3f251bSdonald chen   ProgramPoint *point = getProgramPointAfter(block);
3588a918c54SAlex Zinenko   // If the block is not executable, bail out.
359*4b3f251bSdonald chen   if (!getOrCreateFor<Executable>(point, getProgramPointBefore(block))
360*4b3f251bSdonald chen            ->isLive())
3618a918c54SAlex Zinenko     return;
3628a918c54SAlex Zinenko 
363*4b3f251bSdonald chen   AbstractDenseLattice *before = getLattice(point);
3648a918c54SAlex Zinenko 
3658a918c54SAlex Zinenko   // We need "exit" blocks, i.e. the blocks that may return control to the
3668a918c54SAlex Zinenko   // parent operation.
3678a918c54SAlex Zinenko   auto isExitBlock = [](Block *b) {
3688a918c54SAlex Zinenko     // Treat empty and terminator-less blocks as exit blocks.
3698a918c54SAlex Zinenko     if (b->empty() || !b->back().mightHaveTrait<OpTrait::IsTerminator>())
3708a918c54SAlex Zinenko       return true;
3718a918c54SAlex Zinenko 
3728a918c54SAlex Zinenko     // There may be a weird case where a terminator may be transferring control
3738a918c54SAlex Zinenko     // either to the parent or to another block, so exit blocks and successors
3748a918c54SAlex Zinenko     // are not mutually exclusive.
37510ae8ae8SMarkus Böck     return isa_and_nonnull<RegionBranchTerminatorOpInterface>(
37610ae8ae8SMarkus Böck         b->getTerminator());
3778a918c54SAlex Zinenko   };
3788a918c54SAlex Zinenko   if (isExitBlock(block)) {
3798a918c54SAlex Zinenko     // If this block is exiting from a callable, the successors of exiting from
3808a918c54SAlex Zinenko     // a callable are the successors of all call sites. And the call sites
3818a918c54SAlex Zinenko     // themselves are predecessors of the callable.
3828a918c54SAlex Zinenko     auto callable = dyn_cast<CallableOpInterface>(block->getParentOp());
3838a918c54SAlex Zinenko     if (callable && callable.getCallableRegion() == block->getParent()) {
384*4b3f251bSdonald chen       const auto *callsites = getOrCreateFor<PredecessorState>(
385*4b3f251bSdonald chen           point, getProgramPointAfter(callable));
3868a918c54SAlex Zinenko       // If not all call sites are known, conservative mark all lattices as
3878a918c54SAlex Zinenko       // having reached their pessimistic fix points.
38832a4e3fcSOleksandr "Alex" Zinenko       if (!callsites->allPredecessorsKnown() ||
38932a4e3fcSOleksandr "Alex" Zinenko           !getSolverConfig().isInterprocedural()) {
3908a918c54SAlex Zinenko         return setToExitState(before);
39132a4e3fcSOleksandr "Alex" Zinenko       }
3928a918c54SAlex Zinenko 
3938a918c54SAlex Zinenko       for (Operation *callsite : callsites->getKnownPredecessors()) {
394*4b3f251bSdonald chen         const AbstractDenseLattice *after =
395*4b3f251bSdonald chen             getLatticeFor(point, getProgramPointAfter(callsite));
3965d8813deSAlex Zinenko         visitCallControlFlowTransfer(cast<CallOpInterface>(callsite),
3975d8813deSAlex Zinenko                                      CallControlFlowAction::ExitCallee, *after,
3985d8813deSAlex Zinenko                                      before);
3998a918c54SAlex Zinenko       }
4008a918c54SAlex Zinenko       return;
4018a918c54SAlex Zinenko     }
4028a918c54SAlex Zinenko 
4038a918c54SAlex Zinenko     // If this block is exiting from an operation with region-based control
4045d8813deSAlex Zinenko     // flow, propagate the lattice back along the control flow edge.
4058a918c54SAlex Zinenko     if (auto branch = dyn_cast<RegionBranchOpInterface>(block->getParentOp())) {
406*4b3f251bSdonald chen       visitRegionBranchOperation(point, branch, block->getParent(), before);
4078a918c54SAlex Zinenko       return;
4088a918c54SAlex Zinenko     }
4098a918c54SAlex Zinenko 
4108a918c54SAlex Zinenko     // Cannot reason about successors of an exit block, set the pessimistic
4118a918c54SAlex Zinenko     // fixpoint.
4128a918c54SAlex Zinenko     return setToExitState(before);
4138a918c54SAlex Zinenko   }
4148a918c54SAlex Zinenko 
4158a918c54SAlex Zinenko   // Meet the state with the state before block's successors.
4168a918c54SAlex Zinenko   for (Block *successor : block->getSuccessors()) {
417*4b3f251bSdonald chen     if (!getOrCreateFor<Executable>(point,
418b6603e1bSdonald chen                                     getLatticeAnchor<CFGEdge>(block, successor))
4198a918c54SAlex Zinenko              ->isLive())
4208a918c54SAlex Zinenko       continue;
4218a918c54SAlex Zinenko 
4228a918c54SAlex Zinenko     // Merge in the state from the successor: either the first operation, or the
4238a918c54SAlex Zinenko     // block itself when empty.
424*4b3f251bSdonald chen     meet(before, *getLatticeFor(point, getProgramPointBefore(successor)));
4258a918c54SAlex Zinenko   }
4268a918c54SAlex Zinenko }
4278a918c54SAlex Zinenko 
4288a918c54SAlex Zinenko void AbstractDenseBackwardDataFlowAnalysis::visitRegionBranchOperation(
429*4b3f251bSdonald chen     ProgramPoint *point, RegionBranchOpInterface branch,
4304dd744acSMarkus Böck     RegionBranchPoint branchPoint, AbstractDenseLattice *before) {
4318a918c54SAlex Zinenko 
4328a918c54SAlex Zinenko   // The successors of the operation may be either the first operation of the
4338a918c54SAlex Zinenko   // entry block of each possible successor region, or the next operation when
4348a918c54SAlex Zinenko   // the branch is a successor of itself.
4358a918c54SAlex Zinenko   SmallVector<RegionSuccessor> successors;
4364dd744acSMarkus Böck   branch.getSuccessorRegions(branchPoint, successors);
4378a918c54SAlex Zinenko   for (const RegionSuccessor &successor : successors) {
4388a918c54SAlex Zinenko     const AbstractDenseLattice *after;
4398a918c54SAlex Zinenko     if (successor.isParent() || successor.getSuccessor()->empty()) {
440*4b3f251bSdonald chen       after = getLatticeFor(point, getProgramPointAfter(branch));
4418a918c54SAlex Zinenko     } else {
4428a918c54SAlex Zinenko       Region *successorRegion = successor.getSuccessor();
4438a918c54SAlex Zinenko       assert(!successorRegion->empty() && "unexpected empty successor region");
4448a918c54SAlex Zinenko       Block *successorBlock = &successorRegion->front();
4458a918c54SAlex Zinenko 
446*4b3f251bSdonald chen       if (!getOrCreateFor<Executable>(point,
447*4b3f251bSdonald chen                                       getProgramPointBefore(successorBlock))
448*4b3f251bSdonald chen                ->isLive())
4498a918c54SAlex Zinenko         continue;
4508a918c54SAlex Zinenko 
451*4b3f251bSdonald chen       after = getLatticeFor(point, getProgramPointBefore(successorBlock));
4528a918c54SAlex Zinenko     }
4534dd744acSMarkus Böck 
4544dd744acSMarkus Böck     visitRegionBranchControlFlowTransfer(branch, branchPoint, successor, *after,
4555d8813deSAlex Zinenko                                          before);
4568a918c54SAlex Zinenko   }
4578a918c54SAlex Zinenko }
4588a918c54SAlex Zinenko 
4598a918c54SAlex Zinenko const AbstractDenseLattice *
460*4b3f251bSdonald chen AbstractDenseBackwardDataFlowAnalysis::getLatticeFor(ProgramPoint *dependent,
461b6603e1bSdonald chen                                                      LatticeAnchor anchor) {
462b6603e1bSdonald chen   AbstractDenseLattice *state = getLattice(anchor);
4638a918c54SAlex Zinenko   addDependency(state, dependent);
4648a918c54SAlex Zinenko   return state;
4658a918c54SAlex Zinenko }
466