19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/Support/Casting.h"
37 for (
Block &block : region) {
54 void AbstractDenseForwardDataFlowAnalysis::visitCallOperation(
60 dyn_cast_if_present<CallableOpInterface>(call.resolveCallable());
62 (callable && !callable.getCallableRegion())) {
67 const auto *predecessors = getOrCreateFor<PredecessorState>(
71 if (!predecessors->allPredecessorsKnown())
74 for (
Operation *predecessor : predecessors->getKnownPredecessors()) {
93 *latticeAtCalleeReturn, latticeAfterCall);
115 if (
auto branch = dyn_cast<RegionBranchOpInterface>(op)) {
122 if (
auto call = dyn_cast<CallOpInterface>(op)) {
123 visitCallOperation(call, *before, after);
131 void AbstractDenseForwardDataFlowAnalysis::visitBlock(
Block *block) {
134 if (!getOrCreateFor<Executable>(point, point)->isLive())
144 auto callable = dyn_cast<CallableOpInterface>(block->
getParentOp());
145 if (callable && callable.getCallableRegion() == block->
getParent()) {
146 const auto *callsites = getOrCreateFor<PredecessorState>(
151 if (!callsites->allPredecessorsKnown() ||
154 for (
Operation *callsite : callsites->getKnownPredecessors()) {
167 if (
auto branch = dyn_cast<RegionBranchOpInterface>(block->
getParentOp()))
178 Block *predecessor = *it;
179 if (!getOrCreateFor<Executable>(
180 point, getLatticeAnchor<CFGEdge>(predecessor, block))
194 const auto *predecessors = getOrCreateFor<PredecessorState>(point, point);
195 assert(predecessors->allPredecessorsKnown() &&
196 "unexpected unresolved region successors");
198 for (
Operation *op : predecessors->getKnownPredecessors()) {
221 std::optional<unsigned> regionFrom =
222 op == branch ? std::optional<unsigned>()
223 : op->getBlock()->getParent()->getRegionNumber();
230 "expected to be visiting the branch itself");
233 if (op->getParentOp() == branch || op == branch) {
235 branch, regionFrom, std::nullopt, *before, after);
237 join(after, *before);
262 for (
Block &block : region) {
264 for (
Operation &op : llvm::reverse(block)) {
281 void AbstractDenseBackwardDataFlowAnalysis::visitCallOperation(
285 Operation *callee = call.resolveCallableInTable(&symbolTable);
287 auto callable = dyn_cast_or_null<CallableOpInterface>(callee);
292 (callable && (!callable.getCallableRegion() ||
293 callable.getCallableRegion()->empty()))) {
301 Region *region = callable.getCallableRegion();
322 latticeAtCalleeEntry, latticeBeforeCall);
342 if (
auto branch = dyn_cast<RegionBranchOpInterface>(op)) {
347 if (
auto call = dyn_cast<CallOpInterface>(op)) {
348 visitCallOperation(call, *after, before);
356 void AbstractDenseBackwardDataFlowAnalysis::visitBlock(
Block *block) {
367 auto isExitBlock = [](
Block *b) {
375 return isa_and_nonnull<RegionBranchTerminatorOpInterface>(
378 if (isExitBlock(block)) {
382 auto callable = dyn_cast<CallableOpInterface>(block->
getParentOp());
383 if (callable && callable.getCallableRegion() == block->
getParent()) {
384 const auto *callsites = getOrCreateFor<PredecessorState>(
388 if (!callsites->allPredecessorsKnown() ||
393 for (
Operation *callsite : callsites->getKnownPredecessors()) {
405 if (
auto branch = dyn_cast<RegionBranchOpInterface>(block->
getParentOp())) {
406 visitRegionBranchOperation(point, branch, block->
getParent(), before);
417 if (!getOrCreateFor<Executable>(point,
418 getLatticeAnchor<CFGEdge>(block, successor))
428 void AbstractDenseBackwardDataFlowAnalysis::visitRegionBranchOperation(
436 branch.getSuccessorRegions(branchPoint, successors);
439 if (successor.isParent() || successor.getSuccessor()->empty()) {
442 Region *successorRegion = successor.getSuccessor();
443 assert(!successorRegion->
empty() &&
"unexpected empty successor region");
444 Block *successorBlock = &successorRegion->
front();
446 if (!getOrCreateFor<Executable>(point,
Block represents an ordered list of Operations.
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
pred_iterator pred_begin()
SuccessorRange getSuccessors()
Operation * getTerminator()
Get the terminator operation of this block.
bool isEntryBlock()
Return if this block is the entry block in the parent region.
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
void addDependency(AnalysisState *state, ProgramPoint *point)
Create a dependency between the given analysis state and lattice anchor on this analysis.
ProgramPoint * getProgramPointAfter(Operation *op)
ProgramPoint * getProgramPointBefore(Operation *op)
Get a uniqued program point instance.
const DataFlowConfig & getSolverConfig() const
Return the configuration of the solver used for this analysis.
This class provides the API for ops that are known to be terminators.
Operation is the basic unit of execution within MLIR.
Block * getBlock()
Returns the operation block that contains this operation.
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
Implement a predecessor iterator for blocks.
This class represents a point being branched from in the methods of the RegionBranchOpInterface.
static constexpr RegionBranchPoint parent()
Returns an instance of RegionBranchPoint representing the parent operation.
This class represents a successor of a region.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
unsigned getRegionNumber()
Return the number of this region in the parent operation.
virtual void setToExitState(AbstractDenseLattice *lattice)=0
Set the dense lattice before at the control flow exit point and propagate the update if it changed.
LogicalResult initialize(Operation *top) override
Initialize the analysis by visiting every program point whose execution may modify the program state;...
virtual void visitCallControlFlowTransfer(CallOpInterface call, CallControlFlowAction action, const AbstractDenseLattice &after, AbstractDenseLattice *before)
Propagate the dense lattice backwards along the call control flow edge, which can be either entering ...
const AbstractDenseLattice * getLatticeFor(ProgramPoint *dependent, LatticeAnchor anchor)
Get the dense lattice on the given lattice anchor and add dependent as its dependency.
LogicalResult visit(ProgramPoint *point) override
Visit a program point that modifies the state of the program.
virtual LogicalResult visitOperationImpl(Operation *op, const AbstractDenseLattice &after, AbstractDenseLattice *before)=0
Propagate the dense lattice after the execution of an operation to the lattice before its execution.
void meet(AbstractDenseLattice *lhs, const AbstractDenseLattice &rhs)
Meet a lattice with another lattice and propagate an update if it changed.
virtual LogicalResult processOperation(Operation *op)
Visit an operation.
virtual AbstractDenseLattice * getLattice(LatticeAnchor anchor)=0
Get the dense lattice before the execution of the lattice anchor.
virtual void visitRegionBranchControlFlowTransfer(RegionBranchOpInterface branch, RegionBranchPoint regionFrom, RegionBranchPoint regionTo, const AbstractDenseLattice &after, AbstractDenseLattice *before)
Propagate the dense lattice backwards along the control flow edge from regionFrom to regionTo regions...
virtual LogicalResult visitOperationImpl(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 visitRegionBranchOperation(ProgramPoint *point, RegionBranchOpInterface branch, AbstractDenseLattice *after)
Visit a program point within a region branch operation with predecessors in it.
void join(AbstractDenseLattice *lhs, const AbstractDenseLattice &rhs)
Join a lattice with another and propagate an update if it changed.
const AbstractDenseLattice * getLatticeFor(ProgramPoint *dependent, LatticeAnchor anchor)
Get the dense lattice on the given lattice anchor and add dependent as its dependency.
virtual void setToEntryState(AbstractDenseLattice *lattice)=0
Set the dense lattice at control flow entry point and propagate an update if it changed.
LogicalResult initialize(Operation *top) override
Initialize the analysis by visiting every program point whose execution may modify the program state;...
virtual void visitCallControlFlowTransfer(CallOpInterface call, 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 LogicalResult processOperation(Operation *op)
Visit an operation.
virtual void visitRegionBranchControlFlowTransfer(RegionBranchOpInterface branch, 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...
virtual AbstractDenseLattice * getLattice(LatticeAnchor anchor)=0
Get the dense lattice on the given lattice anchor.
LogicalResult visit(ProgramPoint *point) override
Visit a program point that modifies the state of the program.
This class represents a dense lattice.
Include the generated interface declarations.
Fundamental IR components are supported as first-class lattice anchor.
Program point represents a specific location in the execution of a program.
bool isBlockStart() const
Operation * getPrevOp() const
Get the previous operation of this program point.
Operation * getNextOp() const
Get the next operation of this program point.
Block * getBlock() const
Get the block contains this program point.