1 //===- Liveness.cpp - Liveness analysis for MLIR --------------------------===// 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 // Implementation of the liveness analysis. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "mlir/Analysis/Liveness.h" 14 #include "mlir/IR/Block.h" 15 #include "mlir/IR/Operation.h" 16 #include "mlir/IR/Region.h" 17 #include "mlir/IR/Value.h" 18 #include "llvm/ADT/SetOperations.h" 19 #include "llvm/ADT/SetVector.h" 20 #include "llvm/Support/raw_ostream.h" 21 22 using namespace mlir; 23 24 namespace { 25 /// Builds and holds block information during the construction phase. 26 struct BlockInfoBuilder { 27 using ValueSetT = Liveness::ValueSetT; 28 29 /// Constructs an empty block builder. 30 BlockInfoBuilder() : block(nullptr) {} 31 32 /// Fills the block builder with initial liveness information. 33 BlockInfoBuilder(Block *block) : block(block) { 34 auto gatherOutValues = [&](Value value) { 35 // Check whether this value will be in the outValues set (its uses escape 36 // this block). Due to the SSA properties of the program, the uses must 37 // occur after the definition. Therefore, we do not have to check 38 // additional conditions to detect an escaping value. 39 for (Operation *useOp : value.getUsers()) { 40 Block *ownerBlock = useOp->getBlock(); 41 // Find an owner block in the current region. Note that a value does not 42 // escape this block if it is used in a nested region. 43 ownerBlock = block->getParent()->findAncestorBlockInRegion(*ownerBlock); 44 assert(ownerBlock && "Use leaves the current parent region"); 45 if (ownerBlock != block) { 46 outValues.insert(value); 47 break; 48 } 49 } 50 }; 51 52 // Mark all block arguments (phis) as defined. 53 for (BlockArgument argument : block->getArguments()) { 54 // Insert value into the set of defined values. 55 defValues.insert(argument); 56 57 // Gather all out values of all arguments in the current block. 58 gatherOutValues(argument); 59 } 60 61 // Gather out values of all operations in the current block. 62 for (Operation &operation : *block) 63 for (Value result : operation.getResults()) 64 gatherOutValues(result); 65 66 // Mark all nested operation results as defined. 67 block->walk([&](Operation *op) { 68 for (Value result : op->getResults()) 69 defValues.insert(result); 70 }); 71 72 // Check all operations for used operands. 73 block->walk([&](Operation *op) { 74 for (Value operand : op->getOperands()) { 75 // If the operand is already defined in the scope of this 76 // block, we can skip the value in the use set. 77 if (!defValues.count(operand)) 78 useValues.insert(operand); 79 } 80 }); 81 } 82 83 /// Updates live-in information of the current block. To do so it uses the 84 /// default liveness-computation formula: newIn = use union out \ def. The 85 /// methods returns true, if the set has changed (newIn != in), false 86 /// otherwise. 87 bool updateLiveIn() { 88 ValueSetT newIn = useValues; 89 llvm::set_union(newIn, outValues); 90 llvm::set_subtract(newIn, defValues); 91 92 // It is sufficient to check the set sizes (instead of their contents) since 93 // the live-in set can only grow monotonically during all update operations. 94 if (newIn.size() == inValues.size()) 95 return false; 96 97 inValues = newIn; 98 return true; 99 } 100 101 /// Updates live-out information of the current block. It iterates over all 102 /// successors and unifies their live-in values with the current live-out 103 /// values. 104 template <typename SourceT> void updateLiveOut(SourceT &source) { 105 for (Block *succ : block->getSuccessors()) { 106 BlockInfoBuilder &builder = source[succ]; 107 llvm::set_union(outValues, builder.inValues); 108 } 109 } 110 111 /// The current block. 112 Block *block; 113 114 /// The set of all live in values. 115 ValueSetT inValues; 116 117 /// The set of all live out values. 118 ValueSetT outValues; 119 120 /// The set of all defined values. 121 ValueSetT defValues; 122 123 /// The set of all used values. 124 ValueSetT useValues; 125 }; 126 } // namespace 127 128 /// Builds the internal liveness block mapping. 129 static void buildBlockMapping(Operation *operation, 130 DenseMap<Block *, BlockInfoBuilder> &builders) { 131 SetVector<Block *> toProcess; 132 133 operation->walk<WalkOrder::PreOrder>([&](Block *block) { 134 BlockInfoBuilder &builder = 135 builders.try_emplace(block, block).first->second; 136 137 if (builder.updateLiveIn()) 138 toProcess.insert(block->pred_begin(), block->pred_end()); 139 }); 140 141 // Propagate the in and out-value sets (fixpoint iteration) 142 while (!toProcess.empty()) { 143 Block *current = toProcess.pop_back_val(); 144 BlockInfoBuilder &builder = builders[current]; 145 146 // Update the current out values. 147 builder.updateLiveOut(builders); 148 149 // Compute (potentially) updated live in values. 150 if (builder.updateLiveIn()) 151 toProcess.insert(current->pred_begin(), current->pred_end()); 152 } 153 } 154 155 //===----------------------------------------------------------------------===// 156 // Liveness 157 //===----------------------------------------------------------------------===// 158 159 /// Creates a new Liveness analysis that computes liveness information for all 160 /// associated regions. 161 Liveness::Liveness(Operation *op) : operation(op) { build(); } 162 163 /// Initializes the internal mappings. 164 void Liveness::build() { 165 166 // Build internal block mapping. 167 DenseMap<Block *, BlockInfoBuilder> builders; 168 buildBlockMapping(operation, builders); 169 170 // Store internal block data. 171 for (auto &entry : builders) { 172 BlockInfoBuilder &builder = entry.second; 173 LivenessBlockInfo &info = blockMapping[entry.first]; 174 175 info.block = builder.block; 176 info.inValues = std::move(builder.inValues); 177 info.outValues = std::move(builder.outValues); 178 } 179 } 180 181 /// Gets liveness info (if any) for the given value. 182 Liveness::OperationListT Liveness::resolveLiveness(Value value) const { 183 OperationListT result; 184 SmallPtrSet<Block *, 32> visited; 185 SmallVector<Block *, 8> toProcess; 186 187 // Start with the defining block 188 Block *currentBlock; 189 if (Operation *defOp = value.getDefiningOp()) 190 currentBlock = defOp->getBlock(); 191 else 192 currentBlock = value.cast<BlockArgument>().getOwner(); 193 toProcess.push_back(currentBlock); 194 visited.insert(currentBlock); 195 196 // Start with all associated blocks 197 for (OpOperand &use : value.getUses()) { 198 Block *useBlock = use.getOwner()->getBlock(); 199 if (visited.insert(useBlock).second) 200 toProcess.push_back(useBlock); 201 } 202 203 while (!toProcess.empty()) { 204 // Get block and block liveness information. 205 Block *block = toProcess.back(); 206 toProcess.pop_back(); 207 const LivenessBlockInfo *blockInfo = getLiveness(block); 208 209 // Note that start and end will be in the same block. 210 Operation *start = blockInfo->getStartOperation(value); 211 Operation *end = blockInfo->getEndOperation(value, start); 212 213 result.push_back(start); 214 while (start != end) { 215 start = start->getNextNode(); 216 result.push_back(start); 217 } 218 219 for (Block *successor : block->getSuccessors()) { 220 if (getLiveness(successor)->isLiveIn(value) && 221 visited.insert(successor).second) 222 toProcess.push_back(successor); 223 } 224 } 225 226 return result; 227 } 228 229 /// Gets liveness info (if any) for the block. 230 const LivenessBlockInfo *Liveness::getLiveness(Block *block) const { 231 auto it = blockMapping.find(block); 232 return it == blockMapping.end() ? nullptr : &it->second; 233 } 234 235 /// Returns a reference to a set containing live-in values. 236 const Liveness::ValueSetT &Liveness::getLiveIn(Block *block) const { 237 return getLiveness(block)->in(); 238 } 239 240 /// Returns a reference to a set containing live-out values. 241 const Liveness::ValueSetT &Liveness::getLiveOut(Block *block) const { 242 return getLiveness(block)->out(); 243 } 244 245 /// Returns true if the given operation represent the last use of the given 246 /// value. 247 bool Liveness::isLastUse(Value value, Operation *operation) const { 248 Block *block = operation->getBlock(); 249 const LivenessBlockInfo *blockInfo = getLiveness(block); 250 251 // The given value escapes the associated block. 252 if (blockInfo->isLiveOut(value)) 253 return false; 254 255 Operation *endOperation = blockInfo->getEndOperation(value, operation); 256 // If the operation is a real user of `value` the first check is sufficient. 257 // If not, we will have to test whether the end operation is executed before 258 // the given operation in the block. 259 return endOperation == operation || endOperation->isBeforeInBlock(operation); 260 } 261 262 /// Dumps the liveness information in a human readable format. 263 void Liveness::dump() const { print(llvm::errs()); } 264 265 /// Dumps the liveness information to the given stream. 266 void Liveness::print(raw_ostream &os) const { 267 os << "// ---- Liveness -----\n"; 268 269 // Builds unique block/value mappings for testing purposes. 270 DenseMap<Block *, size_t> blockIds; 271 DenseMap<Operation *, size_t> operationIds; 272 DenseMap<Value, size_t> valueIds; 273 operation->walk<WalkOrder::PreOrder>([&](Block *block) { 274 blockIds.insert({block, blockIds.size()}); 275 for (BlockArgument argument : block->getArguments()) 276 valueIds.insert({argument, valueIds.size()}); 277 for (Operation &operation : *block) { 278 operationIds.insert({&operation, operationIds.size()}); 279 for (Value result : operation.getResults()) 280 valueIds.insert({result, valueIds.size()}); 281 } 282 }); 283 284 // Local printing helpers 285 auto printValueRef = [&](Value value) { 286 if (value.getDefiningOp()) 287 os << "val_" << valueIds[value]; 288 else { 289 auto blockArg = value.cast<BlockArgument>(); 290 os << "arg" << blockArg.getArgNumber() << "@" 291 << blockIds[blockArg.getOwner()]; 292 } 293 os << " "; 294 }; 295 296 auto printValueRefs = [&](const ValueSetT &values) { 297 std::vector<Value> orderedValues(values.begin(), values.end()); 298 std::sort(orderedValues.begin(), orderedValues.end(), 299 [&](Value left, Value right) { 300 return valueIds[left] < valueIds[right]; 301 }); 302 for (Value value : orderedValues) 303 printValueRef(value); 304 }; 305 306 // Dump information about in and out values. 307 operation->walk<WalkOrder::PreOrder>([&](Block *block) { 308 os << "// - Block: " << blockIds[block] << "\n"; 309 const auto *liveness = getLiveness(block); 310 os << "// --- LiveIn: "; 311 printValueRefs(liveness->inValues); 312 os << "\n// --- LiveOut: "; 313 printValueRefs(liveness->outValues); 314 os << "\n"; 315 316 // Print liveness intervals. 317 os << "// --- BeginLiveness"; 318 for (Operation &op : *block) { 319 if (op.getNumResults() < 1) 320 continue; 321 os << "\n"; 322 for (Value result : op.getResults()) { 323 os << "// "; 324 printValueRef(result); 325 os << ":"; 326 auto liveOperations = resolveLiveness(result); 327 std::sort(liveOperations.begin(), liveOperations.end(), 328 [&](Operation *left, Operation *right) { 329 return operationIds[left] < operationIds[right]; 330 }); 331 for (Operation *operation : liveOperations) { 332 os << "\n// "; 333 operation->print(os); 334 } 335 } 336 } 337 os << "\n// --- EndLiveness\n"; 338 }); 339 os << "// -------------------\n"; 340 } 341 342 //===----------------------------------------------------------------------===// 343 // LivenessBlockInfo 344 //===----------------------------------------------------------------------===// 345 346 /// Returns true if the given value is in the live-in set. 347 bool LivenessBlockInfo::isLiveIn(Value value) const { 348 return inValues.count(value); 349 } 350 351 /// Returns true if the given value is in the live-out set. 352 bool LivenessBlockInfo::isLiveOut(Value value) const { 353 return outValues.count(value); 354 } 355 356 /// Gets the start operation for the given value (must be referenced in this 357 /// block). 358 Operation *LivenessBlockInfo::getStartOperation(Value value) const { 359 Operation *definingOp = value.getDefiningOp(); 360 // The given value is either live-in or is defined 361 // in the scope of this block. 362 if (isLiveIn(value) || !definingOp) 363 return &block->front(); 364 return definingOp; 365 } 366 367 /// Gets the end operation for the given value using the start operation 368 /// provided (must be referenced in this block). 369 Operation *LivenessBlockInfo::getEndOperation(Value value, 370 Operation *startOperation) const { 371 // The given value is either dying in this block or live-out. 372 if (isLiveOut(value)) 373 return &block->back(); 374 375 // Resolve the last operation (must exist by definition). 376 Operation *endOperation = startOperation; 377 for (Operation *useOp : value.getUsers()) { 378 // Find the associated operation in the current block (if any). 379 useOp = block->findAncestorOpInBlock(*useOp); 380 // Check whether the use is in our block and after the current end 381 // operation. 382 if (useOp && endOperation->isBeforeInBlock(useOp)) 383 endOperation = useOp; 384 } 385 return endOperation; 386 } 387