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() = default;
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, and nested operation
67     // operands as used. All defined value will be removed from the used set
68     // at the end.
69     block->walk([&](Operation *op) {
70       for (Value result : op->getResults())
71         defValues.insert(result);
72       for (Value operand : op->getOperands())
73         useValues.insert(operand);
74     });
75     llvm::set_subtract(useValues, defValues);
76   }
77 
78   /// Updates live-in information of the current block. To do so it uses the
79   /// default liveness-computation formula: newIn = use union out \ def. The
80   /// methods returns true, if the set has changed (newIn != in), false
81   /// otherwise.
82   bool updateLiveIn() {
83     ValueSetT newIn = useValues;
84     llvm::set_union(newIn, outValues);
85     llvm::set_subtract(newIn, defValues);
86 
87     // It is sufficient to check the set sizes (instead of their contents) since
88     // the live-in set can only grow monotonically during all update operations.
89     if (newIn.size() == inValues.size())
90       return false;
91 
92     inValues = std::move(newIn);
93     return true;
94   }
95 
96   /// Updates live-out information of the current block. It iterates over all
97   /// successors and unifies their live-in values with the current live-out
98   /// values.
99   void updateLiveOut(const DenseMap<Block *, BlockInfoBuilder> &builders) {
100     for (Block *succ : block->getSuccessors()) {
101       const BlockInfoBuilder &builder = builders.find(succ)->second;
102       llvm::set_union(outValues, builder.inValues);
103     }
104   }
105 
106   /// The current block.
107   Block *block{nullptr};
108 
109   /// The set of all live in values.
110   ValueSetT inValues;
111 
112   /// The set of all live out values.
113   ValueSetT outValues;
114 
115   /// The set of all defined values.
116   ValueSetT defValues;
117 
118   /// The set of all used values.
119   ValueSetT useValues;
120 };
121 } // namespace
122 
123 /// Builds the internal liveness block mapping.
124 static void buildBlockMapping(Operation *operation,
125                               DenseMap<Block *, BlockInfoBuilder> &builders) {
126   SetVector<Block *> toProcess;
127 
128   operation->walk<WalkOrder::PreOrder>([&](Block *block) {
129     BlockInfoBuilder &builder =
130         builders.try_emplace(block, block).first->second;
131 
132     if (builder.updateLiveIn())
133       toProcess.insert(block->pred_begin(), block->pred_end());
134   });
135 
136   // Propagate the in and out-value sets (fixpoint iteration).
137   while (!toProcess.empty()) {
138     Block *current = toProcess.pop_back_val();
139     BlockInfoBuilder &builder = builders[current];
140 
141     // Update the current out values.
142     builder.updateLiveOut(builders);
143 
144     // Compute (potentially) updated live in values.
145     if (builder.updateLiveIn())
146       toProcess.insert(current->pred_begin(), current->pred_end());
147   }
148 }
149 
150 //===----------------------------------------------------------------------===//
151 // Liveness
152 //===----------------------------------------------------------------------===//
153 
154 /// Creates a new Liveness analysis that computes liveness information for all
155 /// associated regions.
156 Liveness::Liveness(Operation *op) : operation(op) { build(); }
157 
158 /// Initializes the internal mappings.
159 void Liveness::build() {
160   // Build internal block mapping.
161   DenseMap<Block *, BlockInfoBuilder> builders;
162   buildBlockMapping(operation, builders);
163 
164   // Store internal block data.
165   for (auto &entry : builders) {
166     BlockInfoBuilder &builder = entry.second;
167     LivenessBlockInfo &info = blockMapping[entry.first];
168 
169     info.block = builder.block;
170     info.inValues = std::move(builder.inValues);
171     info.outValues = std::move(builder.outValues);
172   }
173 }
174 
175 /// Gets liveness info (if any) for the given value.
176 Liveness::OperationListT Liveness::resolveLiveness(Value value) const {
177   OperationListT result;
178   SmallPtrSet<Block *, 32> visited;
179   SmallVector<Block *, 8> toProcess;
180 
181   // Start with the defining block
182   Block *currentBlock;
183   if (Operation *defOp = value.getDefiningOp())
184     currentBlock = defOp->getBlock();
185   else
186     currentBlock = value.cast<BlockArgument>().getOwner();
187   toProcess.push_back(currentBlock);
188   visited.insert(currentBlock);
189 
190   // Start with all associated blocks
191   for (OpOperand &use : value.getUses()) {
192     Block *useBlock = use.getOwner()->getBlock();
193     if (visited.insert(useBlock).second)
194       toProcess.push_back(useBlock);
195   }
196 
197   while (!toProcess.empty()) {
198     // Get block and block liveness information.
199     Block *block = toProcess.back();
200     toProcess.pop_back();
201     const LivenessBlockInfo *blockInfo = getLiveness(block);
202 
203     // Note that start and end will be in the same block.
204     Operation *start = blockInfo->getStartOperation(value);
205     Operation *end = blockInfo->getEndOperation(value, start);
206 
207     result.push_back(start);
208     while (start != end) {
209       start = start->getNextNode();
210       result.push_back(start);
211     }
212 
213     for (Block *successor : block->getSuccessors()) {
214       if (getLiveness(successor)->isLiveIn(value) &&
215           visited.insert(successor).second)
216         toProcess.push_back(successor);
217     }
218   }
219 
220   return result;
221 }
222 
223 /// Gets liveness info (if any) for the block.
224 const LivenessBlockInfo *Liveness::getLiveness(Block *block) const {
225   auto it = blockMapping.find(block);
226   return it == blockMapping.end() ? nullptr : &it->second;
227 }
228 
229 /// Returns a reference to a set containing live-in values.
230 const Liveness::ValueSetT &Liveness::getLiveIn(Block *block) const {
231   return getLiveness(block)->in();
232 }
233 
234 /// Returns a reference to a set containing live-out values.
235 const Liveness::ValueSetT &Liveness::getLiveOut(Block *block) const {
236   return getLiveness(block)->out();
237 }
238 
239 /// Returns true if `value` is not live after `operation`.
240 bool Liveness::isDeadAfter(Value value, Operation *operation) const {
241   Block *block = operation->getBlock();
242   const LivenessBlockInfo *blockInfo = getLiveness(block);
243 
244   // The given value escapes the associated block.
245   if (blockInfo->isLiveOut(value))
246     return false;
247 
248   Operation *endOperation = blockInfo->getEndOperation(value, operation);
249   // If the operation is a real user of `value` the first check is sufficient.
250   // If not, we will have to test whether the end operation is executed before
251   // the given operation in the block.
252   return endOperation == operation || endOperation->isBeforeInBlock(operation);
253 }
254 
255 /// Dumps the liveness information in a human readable format.
256 void Liveness::dump() const { print(llvm::errs()); }
257 
258 /// Dumps the liveness information to the given stream.
259 void Liveness::print(raw_ostream &os) const {
260   os << "// ---- Liveness -----\n";
261 
262   // Builds unique block/value mappings for testing purposes.
263   DenseMap<Block *, size_t> blockIds;
264   DenseMap<Operation *, size_t> operationIds;
265   DenseMap<Value, size_t> valueIds;
266   operation->walk<WalkOrder::PreOrder>([&](Block *block) {
267     blockIds.insert({block, blockIds.size()});
268     for (BlockArgument argument : block->getArguments())
269       valueIds.insert({argument, valueIds.size()});
270     for (Operation &operation : *block) {
271       operationIds.insert({&operation, operationIds.size()});
272       for (Value result : operation.getResults())
273         valueIds.insert({result, valueIds.size()});
274     }
275   });
276 
277   // Local printing helpers
278   auto printValueRef = [&](Value value) {
279     if (value.getDefiningOp())
280       os << "val_" << valueIds[value];
281     else {
282       auto blockArg = value.cast<BlockArgument>();
283       os << "arg" << blockArg.getArgNumber() << "@"
284          << blockIds[blockArg.getOwner()];
285     }
286     os << " ";
287   };
288 
289   auto printValueRefs = [&](const ValueSetT &values) {
290     std::vector<Value> orderedValues(values.begin(), values.end());
291     std::sort(orderedValues.begin(), orderedValues.end(),
292               [&](Value left, Value right) {
293                 return valueIds[left] < valueIds[right];
294               });
295     for (Value value : orderedValues)
296       printValueRef(value);
297   };
298 
299   // Dump information about in and out values.
300   operation->walk<WalkOrder::PreOrder>([&](Block *block) {
301     os << "// - Block: " << blockIds[block] << "\n";
302     const auto *liveness = getLiveness(block);
303     os << "// --- LiveIn: ";
304     printValueRefs(liveness->inValues);
305     os << "\n// --- LiveOut: ";
306     printValueRefs(liveness->outValues);
307     os << "\n";
308 
309     // Print liveness intervals.
310     os << "// --- BeginLivenessIntervals";
311     for (Operation &op : *block) {
312       if (op.getNumResults() < 1)
313         continue;
314       os << "\n";
315       for (Value result : op.getResults()) {
316         os << "// ";
317         printValueRef(result);
318         os << ":";
319         auto liveOperations = resolveLiveness(result);
320         std::sort(liveOperations.begin(), liveOperations.end(),
321                   [&](Operation *left, Operation *right) {
322                     return operationIds[left] < operationIds[right];
323                   });
324         for (Operation *operation : liveOperations) {
325           os << "\n//     ";
326           operation->print(os);
327         }
328       }
329     }
330     os << "\n// --- EndLivenessIntervals\n";
331 
332     // Print currently live values.
333     os << "// --- BeginCurrentlyLive\n";
334     for (Operation &op : *block) {
335       auto currentlyLive = liveness->currentlyLiveValues(&op);
336       if (currentlyLive.empty())
337         continue;
338       os << "//     ";
339       op.print(os);
340       os << " [";
341       printValueRefs(currentlyLive);
342       os << "\b]\n";
343     }
344     os << "// --- EndCurrentlyLive\n";
345   });
346   os << "// -------------------\n";
347 }
348 
349 //===----------------------------------------------------------------------===//
350 // LivenessBlockInfo
351 //===----------------------------------------------------------------------===//
352 
353 /// Returns true if the given value is in the live-in set.
354 bool LivenessBlockInfo::isLiveIn(Value value) const {
355   return inValues.count(value);
356 }
357 
358 /// Returns true if the given value is in the live-out set.
359 bool LivenessBlockInfo::isLiveOut(Value value) const {
360   return outValues.count(value);
361 }
362 
363 /// Gets the start operation for the given value (must be referenced in this
364 /// block).
365 Operation *LivenessBlockInfo::getStartOperation(Value value) const {
366   Operation *definingOp = value.getDefiningOp();
367   // The given value is either live-in or is defined
368   // in the scope of this block.
369   if (isLiveIn(value) || !definingOp)
370     return &block->front();
371   return definingOp;
372 }
373 
374 /// Gets the end operation for the given value using the start operation
375 /// provided (must be referenced in this block).
376 Operation *LivenessBlockInfo::getEndOperation(Value value,
377                                               Operation *startOperation) const {
378   // The given value is either dying in this block or live-out.
379   if (isLiveOut(value))
380     return &block->back();
381 
382   // Resolve the last operation (must exist by definition).
383   Operation *endOperation = startOperation;
384   for (Operation *useOp : value.getUsers()) {
385     // Find the associated operation in the current block (if any).
386     useOp = block->findAncestorOpInBlock(*useOp);
387     // Check whether the use is in our block and after the current end
388     // operation.
389     if (useOp && endOperation->isBeforeInBlock(useOp))
390       endOperation = useOp;
391   }
392   return endOperation;
393 }
394 
395 /// Return the values that are currently live as of the given operation.
396 LivenessBlockInfo::ValueSetT
397 LivenessBlockInfo::currentlyLiveValues(Operation *op) const {
398   ValueSetT liveSet;
399 
400   // Given a value, check which ops are within its live range. For each of
401   // those ops, add the value to the set of live values as-of that op.
402   auto addValueToCurrentlyLiveSets = [&](Value value) {
403     // Determine the live range of this value inside this block.
404     Operation *startOfLiveRange = value.getDefiningOp();
405     Operation *endOfLiveRange = nullptr;
406     // If it's a live in or a block argument, then the start is the beginning
407     // of the block.
408     if (isLiveIn(value) || value.isa<BlockArgument>())
409       startOfLiveRange = &block->front();
410     else
411       startOfLiveRange = block->findAncestorOpInBlock(*startOfLiveRange);
412 
413     // If it's a live out, then the end is the back of the block.
414     if (isLiveOut(value))
415       endOfLiveRange = &block->back();
416 
417     // We must have at least a startOfLiveRange at this point. Given this, we
418     // can use the existing getEndOperation to find the end of the live range.
419     if (startOfLiveRange && !endOfLiveRange)
420       endOfLiveRange = getEndOperation(value, startOfLiveRange);
421 
422     assert(endOfLiveRange && "Must have endOfLiveRange at this point!");
423     // If this op is within the live range, insert the value into the set.
424     if (!(op->isBeforeInBlock(startOfLiveRange) ||
425           endOfLiveRange->isBeforeInBlock(op)))
426       liveSet.insert(value);
427   };
428 
429   // Handle block arguments if any.
430   for (Value arg : block->getArguments())
431     addValueToCurrentlyLiveSets(arg);
432 
433   // Handle live-ins. Between the live ins and all the op results that gives us
434   // every value in the block.
435   for (Value in : inValues)
436     addValueToCurrentlyLiveSets(in);
437 
438   // Now walk the block and handle all values used in the block and values
439   // defined by the block.
440   for (Operation &walkOp :
441        llvm::make_range(block->begin(), ++op->getIterator()))
442     for (auto result : walkOp.getResults())
443       addValueToCurrentlyLiveSets(result);
444 
445   return liveSet;
446 }
447