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