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 ®ion : 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 ®ion : 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 = ®ion->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