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