20#include <mlir/Analysis/DataFlow/DeadCodeAnalysis.h>
21#include <mlir/Analysis/DataFlowFramework.h>
22#include <mlir/IR/Block.h>
23#include <mlir/IR/Operation.h>
24#include <mlir/IR/Region.h>
25#include <mlir/Interfaces/CallInterfaces.h>
26#include <mlir/Interfaces/ControlFlowInterfaces.h>
27#include <mlir/Support/LLVM.h>
28#include <mlir/Support/LogicalResult.h>
30#include <llvm/ADT/STLExtras.h>
31#include <llvm/Support/Casting.h>
41using namespace function;
50 for (Region ®ion : top->getRegions()) {
51 for (Block &block : region) {
52 ProgramPoint *point = solver.getProgramPointBefore(&block);
53 (void)solver.getOrCreateState<
Executable>(point)->setToLive();
54 for (Operation &oper : block) {
70 for (Region ®ion : top->getRegions()) {
71 for (Block &block : region) {
73 for (Operation &op : block) {
84 if (!point->isBlockStart()) {
87 visitBlock(point->getBlock());
93void AbstractDenseForwardDataFlowAnalysis::visitCallOperation(
99 if (!getSolverConfig().isInterprocedural() ||
100 (succeeded(callable) && !callable->get().getCallableRegion())) {
106 SmallVector<Operation *> predecessors;
107 callable->get().walk([&predecessors](
ReturnOp ret)
mutable { predecessors.push_back(ret); });
111 if (predecessors.empty()) {
115 for (Operation *predecessor : predecessors) {
131 getLatticeFor(getProgramPointAfter(call.getOperation()), getProgramPointAfter(predecessor));
133 call, CallControlFlowAction::ExitCallee, *latticeAtCalleeReturn, latticeAfterCall
139 ProgramPoint *point = getProgramPointAfter(op);
141 if (op->getBlock() !=
nullptr &&
142 !getOrCreateFor<Executable>(point, getProgramPointBefore(op->getBlock()))->isLive()) {
154 if (
auto branch = dyn_cast<RegionBranchOpInterface>(op)) {
161 if (
auto call = dyn_cast<CallOpInterface>(op)) {
162 visitCallOperation(call, *before, after);
172void AbstractDenseForwardDataFlowAnalysis::visitBlock(Block *block) {
174 ProgramPoint *point = getProgramPointBefore(block);
175 if (!getOrCreateFor<Executable>(point, point)->isLive()) {
184 if (block->isEntryBlock()) {
186 auto callable = dyn_cast<CallableOpInterface>(block->getParentOp());
187 if (callable && callable.getCallableRegion() == block->getParent()) {
188 if (!getSolverConfig().isInterprocedural()) {
193 ensure(succeeded(moduleOpRes),
"could not get root module from callable");
194 SmallVector<Operation *> callsites;
195 moduleOpRes->walk([
this, &callable, &callsites](CallOp call)
mutable {
197 if (succeeded(calledFnRes) &&
198 calledFnRes->get().getCallableRegion() == callable.getCallableRegion()) {
199 callsites.push_back(call);
203 for (Operation *callsite : callsites) {
208 llvm::cast<CallOpInterface>(callsite), CallControlFlowAction::EnterCallee, *before,
216 if (
auto branch = dyn_cast<RegionBranchOpInterface>(block->getParentOp())) {
225 for (Block::pred_iterator it = block->pred_begin(), e = block->pred_end(); it != e; ++it) {
227 Block *predecessor = *it;
228 if (!getOrCreateFor<Executable>(point, getLatticeAnchor<CFGEdge>(predecessor, block))
234 join(after, *
getLatticeFor(point, getProgramPointAfter(predecessor->getTerminator())));
242 Operation *op = point->isBlockStart() ? point->getBlock()->getParentOp() : point->getPrevOp();
266 std::optional<unsigned> regionFrom =
267 op == branch ? std::optional<unsigned>() : op->getBlock()->getParent()->getRegionNumber();
268 if (point->isBlockStart()) {
269 unsigned regionTo = point->getBlock()->getParent()->getRegionNumber();
272 assert(point->getPrevOp() == branch &&
"expected to be visiting the branch itself");
275 if (op->getParentOp() == branch || op == branch) {
277 branch, regionFrom, std::nullopt, *before, after
280 join(after, *before);
289 addDependency(state, dependent);
mlir::dataflow::Executable Executable
mlir::dataflow::CFGEdge CFGEdge
This file implements (LLZK-tailored) dense data-flow analysis using the data-flow analysis framework.
void join(AbstractDenseLattice *lhs, const AbstractDenseLattice &rhs)
Join a lattice with another and propagate an update if it changed.
virtual void visitCallControlFlowTransfer(mlir::CallOpInterface, CallControlFlowAction action, const AbstractDenseLattice &before, AbstractDenseLattice *after)
Propagate the dense lattice forward along the call control flow edge, which can be either entering or...
virtual mlir::LogicalResult processOperation(mlir::Operation *op)
Visit an operation.
virtual AbstractDenseLattice * getLattice(mlir::LatticeAnchor anchor)=0
Get the dense lattice on the given lattice anchor.
mlir::LogicalResult visit(mlir::ProgramPoint *point) override
Visit a program point that modifies the state of the program.
void visitRegionBranchOperation(mlir::ProgramPoint *point, mlir::RegionBranchOpInterface branch, AbstractDenseLattice *after)
Visit a program point within a region branch operation with predecessors in it.
mlir::SymbolTableCollection tables
LLZK: Added for use of symbol helper caching.
virtual void setToEntryState(AbstractDenseLattice *lattice)=0
Set the dense lattice at control flow entry point and propagate an update if it changed.
mlir::LogicalResult initialize(mlir::Operation *top) override
Initialize the analysis by visiting every program point whose execution may modify the program state;...
virtual void visitRegionBranchControlFlowTransfer(mlir::RegionBranchOpInterface, std::optional< unsigned > regionFrom, std::optional< unsigned > regionTo, const AbstractDenseLattice &before, AbstractDenseLattice *after)
Propagate the dense lattice forward along the control flow edge from regionFrom to regionTo regions o...
const AbstractDenseLattice * getLatticeFor(mlir::ProgramPoint *dependent, mlir::LatticeAnchor anchor)
Get the dense lattice on the given lattice anchor and add dependent as its dependency.
virtual mlir::LogicalResult visitOperationImpl(mlir::Operation *op, const AbstractDenseLattice &before, AbstractDenseLattice *after)=0
Propagate the dense lattice before the execution of an operation to the lattice after its execution.
void markAllOpsAsLive(DataFlowSolver &solver, Operation *top)
mlir::dataflow::AbstractDenseLattice AbstractDenseLattice
void ensure(bool condition, const llvm::Twine &errMsg)
mlir::FailureOr< SymbolLookupResult< T > > resolveCallable(mlir::SymbolTableCollection &symbolTable, mlir::CallOpInterface call)
Based on mlir::CallOpInterface::resolveCallable, but using LLZK lookup helpers.
FailureOr< ModuleOp > getTopRootModule(Operation *from)