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 &region : 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 &region : 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 &region : 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