14b0198acSAlexander Belyaev //===- Liveness.cpp - Liveness analysis for MLIR --------------------------===//
24b0198acSAlexander Belyaev //
330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64b0198acSAlexander Belyaev //
756222a06SMehdi Amini //===----------------------------------------------------------------------===//
84b0198acSAlexander Belyaev //
94b0198acSAlexander Belyaev // Implementation of the liveness analysis.
104b0198acSAlexander Belyaev //
114b0198acSAlexander Belyaev //===----------------------------------------------------------------------===//
124b0198acSAlexander Belyaev
134b0198acSAlexander Belyaev #include "mlir/Analysis/Liveness.h"
144b0198acSAlexander Belyaev #include "mlir/IR/Block.h"
154b0198acSAlexander Belyaev #include "mlir/IR/Operation.h"
164b0198acSAlexander Belyaev #include "mlir/IR/Region.h"
174b0198acSAlexander Belyaev #include "mlir/IR/Value.h"
18aba43035SDmitri Gribenko #include "llvm/ADT/STLExtras.h"
194b0198acSAlexander Belyaev #include "llvm/ADT/SetOperations.h"
204b0198acSAlexander Belyaev #include "llvm/ADT/SetVector.h"
214b0198acSAlexander Belyaev #include "llvm/Support/raw_ostream.h"
224b0198acSAlexander Belyaev
234b0198acSAlexander Belyaev using namespace mlir;
244b0198acSAlexander Belyaev
25df186507SBenjamin Kramer namespace {
264b0198acSAlexander Belyaev /// Builds and holds block information during the construction phase.
274b0198acSAlexander Belyaev struct BlockInfoBuilder {
284b0198acSAlexander Belyaev using ValueSetT = Liveness::ValueSetT;
294b0198acSAlexander Belyaev
304b0198acSAlexander Belyaev /// Constructs an empty block builder.
31abb336d2SMehdi Amini BlockInfoBuilder() = default;
324b0198acSAlexander Belyaev
334b0198acSAlexander Belyaev /// Fills the block builder with initial liveness information.
BlockInfoBuilder__anonf9c92e380111::BlockInfoBuilder344b0198acSAlexander Belyaev BlockInfoBuilder(Block *block) : block(block) {
35c79227caSMarcel Koester auto gatherOutValues = [&](Value value) {
36c79227caSMarcel Koester // Check whether this value will be in the outValues set (its uses escape
37c79227caSMarcel Koester // this block). Due to the SSA properties of the program, the uses must
38c79227caSMarcel Koester // occur after the definition. Therefore, we do not have to check
394b0198acSAlexander Belyaev // additional conditions to detect an escaping value.
40c79227caSMarcel Koester for (Operation *useOp : value.getUsers()) {
41c79227caSMarcel Koester Block *ownerBlock = useOp->getBlock();
42c79227caSMarcel Koester // Find an owner block in the current region. Note that a value does not
43c79227caSMarcel Koester // escape this block if it is used in a nested region.
44c79227caSMarcel Koester ownerBlock = block->getParent()->findAncestorBlockInRegion(*ownerBlock);
45c79227caSMarcel Koester assert(ownerBlock && "Use leaves the current parent region");
46c79227caSMarcel Koester if (ownerBlock != block) {
47c79227caSMarcel Koester outValues.insert(value);
484b0198acSAlexander Belyaev break;
494b0198acSAlexander Belyaev }
504b0198acSAlexander Belyaev }
51c79227caSMarcel Koester };
52c79227caSMarcel Koester
53c79227caSMarcel Koester // Mark all block arguments (phis) as defined.
54c79227caSMarcel Koester for (BlockArgument argument : block->getArguments()) {
55c79227caSMarcel Koester // Insert value into the set of defined values.
56c79227caSMarcel Koester defValues.insert(argument);
57c79227caSMarcel Koester
58c79227caSMarcel Koester // Gather all out values of all arguments in the current block.
59c79227caSMarcel Koester gatherOutValues(argument);
60c79227caSMarcel Koester }
61c79227caSMarcel Koester
62c79227caSMarcel Koester // Gather out values of all operations in the current block.
63c79227caSMarcel Koester for (Operation &operation : *block)
64c79227caSMarcel Koester for (Value result : operation.getResults())
65c79227caSMarcel Koester gatherOutValues(result);
66c79227caSMarcel Koester
6717de7ed5SRahul Joshi // Mark all nested operation results as defined, and nested operation
6817de7ed5SRahul Joshi // operands as used. All defined value will be removed from the used set
6917de7ed5SRahul Joshi // at the end.
70c79227caSMarcel Koester block->walk([&](Operation *op) {
71c79227caSMarcel Koester for (Value result : op->getResults())
72c79227caSMarcel Koester defValues.insert(result);
7317de7ed5SRahul Joshi for (Value operand : op->getOperands())
744b0198acSAlexander Belyaev useValues.insert(operand);
75*63e8c0a0SIvan Kulagin for (Region ®ion : op->getRegions())
76*63e8c0a0SIvan Kulagin for (Block &child : region.getBlocks())
77*63e8c0a0SIvan Kulagin for (BlockArgument arg : child.getArguments())
78*63e8c0a0SIvan Kulagin defValues.insert(arg);
79c79227caSMarcel Koester });
8017de7ed5SRahul Joshi llvm::set_subtract(useValues, defValues);
814b0198acSAlexander Belyaev }
824b0198acSAlexander Belyaev
83c79227caSMarcel Koester /// Updates live-in information of the current block. To do so it uses the
84c79227caSMarcel Koester /// default liveness-computation formula: newIn = use union out \ def. The
85c79227caSMarcel Koester /// methods returns true, if the set has changed (newIn != in), false
86c79227caSMarcel Koester /// otherwise.
updateLiveIn__anonf9c92e380111::BlockInfoBuilder874b0198acSAlexander Belyaev bool updateLiveIn() {
884b0198acSAlexander Belyaev ValueSetT newIn = useValues;
894b0198acSAlexander Belyaev llvm::set_union(newIn, outValues);
904b0198acSAlexander Belyaev llvm::set_subtract(newIn, defValues);
914b0198acSAlexander Belyaev
92c79227caSMarcel Koester // It is sufficient to check the set sizes (instead of their contents) since
93c79227caSMarcel Koester // the live-in set can only grow monotonically during all update operations.
944b0198acSAlexander Belyaev if (newIn.size() == inValues.size())
954b0198acSAlexander Belyaev return false;
964b0198acSAlexander Belyaev
9717de7ed5SRahul Joshi inValues = std::move(newIn);
984b0198acSAlexander Belyaev return true;
994b0198acSAlexander Belyaev }
1004b0198acSAlexander Belyaev
101c79227caSMarcel Koester /// Updates live-out information of the current block. It iterates over all
102c79227caSMarcel Koester /// successors and unifies their live-in values with the current live-out
103c79227caSMarcel Koester /// values.
updateLiveOut__anonf9c92e380111::BlockInfoBuilder10417de7ed5SRahul Joshi void updateLiveOut(const DenseMap<Block *, BlockInfoBuilder> &builders) {
1054b0198acSAlexander Belyaev for (Block *succ : block->getSuccessors()) {
10617de7ed5SRahul Joshi const BlockInfoBuilder &builder = builders.find(succ)->second;
1074b0198acSAlexander Belyaev llvm::set_union(outValues, builder.inValues);
1084b0198acSAlexander Belyaev }
1094b0198acSAlexander Belyaev }
1104b0198acSAlexander Belyaev
1114b0198acSAlexander Belyaev /// The current block.
112e5639b3fSMehdi Amini Block *block{nullptr};
1134b0198acSAlexander Belyaev
1144b0198acSAlexander Belyaev /// The set of all live in values.
1154b0198acSAlexander Belyaev ValueSetT inValues;
1164b0198acSAlexander Belyaev
1174b0198acSAlexander Belyaev /// The set of all live out values.
1184b0198acSAlexander Belyaev ValueSetT outValues;
1194b0198acSAlexander Belyaev
1204b0198acSAlexander Belyaev /// The set of all defined values.
1214b0198acSAlexander Belyaev ValueSetT defValues;
1224b0198acSAlexander Belyaev
1234b0198acSAlexander Belyaev /// The set of all used values.
1244b0198acSAlexander Belyaev ValueSetT useValues;
1254b0198acSAlexander Belyaev };
126df186507SBenjamin Kramer } // namespace
1274b0198acSAlexander Belyaev
1284b0198acSAlexander Belyaev /// Builds the internal liveness block mapping.
buildBlockMapping(Operation * operation,DenseMap<Block *,BlockInfoBuilder> & builders)1291664462dSFrederik Gossen static void buildBlockMapping(Operation *operation,
1304b0198acSAlexander Belyaev DenseMap<Block *, BlockInfoBuilder> &builders) {
1314efb7754SRiver Riddle SetVector<Block *> toProcess;
1324b0198acSAlexander Belyaev
13371a86245SDiego Caballero operation->walk<WalkOrder::PreOrder>([&](Block *block) {
1344b0198acSAlexander Belyaev BlockInfoBuilder &builder =
1351664462dSFrederik Gossen builders.try_emplace(block, block).first->second;
1364b0198acSAlexander Belyaev
1374b0198acSAlexander Belyaev if (builder.updateLiveIn())
1381664462dSFrederik Gossen toProcess.insert(block->pred_begin(), block->pred_end());
139c79227caSMarcel Koester });
1404b0198acSAlexander Belyaev
14117de7ed5SRahul Joshi // Propagate the in and out-value sets (fixpoint iteration).
1424b0198acSAlexander Belyaev while (!toProcess.empty()) {
1434b0198acSAlexander Belyaev Block *current = toProcess.pop_back_val();
1444b0198acSAlexander Belyaev BlockInfoBuilder &builder = builders[current];
1454b0198acSAlexander Belyaev
1464b0198acSAlexander Belyaev // Update the current out values.
1474b0198acSAlexander Belyaev builder.updateLiveOut(builders);
1484b0198acSAlexander Belyaev
1494b0198acSAlexander Belyaev // Compute (potentially) updated live in values.
1504b0198acSAlexander Belyaev if (builder.updateLiveIn())
1514b0198acSAlexander Belyaev toProcess.insert(current->pred_begin(), current->pred_end());
1524b0198acSAlexander Belyaev }
1534b0198acSAlexander Belyaev }
1544b0198acSAlexander Belyaev
1554b0198acSAlexander Belyaev //===----------------------------------------------------------------------===//
1564b0198acSAlexander Belyaev // Liveness
1574b0198acSAlexander Belyaev //===----------------------------------------------------------------------===//
1584b0198acSAlexander Belyaev
159c79227caSMarcel Koester /// Creates a new Liveness analysis that computes liveness information for all
160c79227caSMarcel Koester /// associated regions.
Liveness(Operation * op)1611664462dSFrederik Gossen Liveness::Liveness(Operation *op) : operation(op) { build(); }
1624b0198acSAlexander Belyaev
1634b0198acSAlexander Belyaev /// Initializes the internal mappings.
build()1641664462dSFrederik Gossen void Liveness::build() {
1654b0198acSAlexander Belyaev // Build internal block mapping.
1664b0198acSAlexander Belyaev DenseMap<Block *, BlockInfoBuilder> builders;
1671664462dSFrederik Gossen buildBlockMapping(operation, builders);
1684b0198acSAlexander Belyaev
1694b0198acSAlexander Belyaev // Store internal block data.
1704b0198acSAlexander Belyaev for (auto &entry : builders) {
1714b0198acSAlexander Belyaev BlockInfoBuilder &builder = entry.second;
1724b0198acSAlexander Belyaev LivenessBlockInfo &info = blockMapping[entry.first];
1734b0198acSAlexander Belyaev
1744b0198acSAlexander Belyaev info.block = builder.block;
1754b0198acSAlexander Belyaev info.inValues = std::move(builder.inValues);
1764b0198acSAlexander Belyaev info.outValues = std::move(builder.outValues);
1774b0198acSAlexander Belyaev }
1784b0198acSAlexander Belyaev }
1794b0198acSAlexander Belyaev
1804b0198acSAlexander Belyaev /// Gets liveness info (if any) for the given value.
resolveLiveness(Value value) const181e62a6956SRiver Riddle Liveness::OperationListT Liveness::resolveLiveness(Value value) const {
1824b0198acSAlexander Belyaev OperationListT result;
1834b0198acSAlexander Belyaev SmallPtrSet<Block *, 32> visited;
1844b0198acSAlexander Belyaev SmallVector<Block *, 8> toProcess;
1854b0198acSAlexander Belyaev
1864b0198acSAlexander Belyaev // Start with the defining block
1874b0198acSAlexander Belyaev Block *currentBlock;
1882bdf33ccSRiver Riddle if (Operation *defOp = value.getDefiningOp())
1894b0198acSAlexander Belyaev currentBlock = defOp->getBlock();
1904b0198acSAlexander Belyaev else
1915550c821STres Popp currentBlock = cast<BlockArgument>(value).getOwner();
1924b0198acSAlexander Belyaev toProcess.push_back(currentBlock);
1934b0198acSAlexander Belyaev visited.insert(currentBlock);
1944b0198acSAlexander Belyaev
1954b0198acSAlexander Belyaev // Start with all associated blocks
1962bdf33ccSRiver Riddle for (OpOperand &use : value.getUses()) {
1974b0198acSAlexander Belyaev Block *useBlock = use.getOwner()->getBlock();
1984b0198acSAlexander Belyaev if (visited.insert(useBlock).second)
1994b0198acSAlexander Belyaev toProcess.push_back(useBlock);
2004b0198acSAlexander Belyaev }
2014b0198acSAlexander Belyaev
2024b0198acSAlexander Belyaev while (!toProcess.empty()) {
2034b0198acSAlexander Belyaev // Get block and block liveness information.
2044b0198acSAlexander Belyaev Block *block = toProcess.back();
2054b0198acSAlexander Belyaev toProcess.pop_back();
2064b0198acSAlexander Belyaev const LivenessBlockInfo *blockInfo = getLiveness(block);
2074b0198acSAlexander Belyaev
2084b0198acSAlexander Belyaev // Note that start and end will be in the same block.
2094b0198acSAlexander Belyaev Operation *start = blockInfo->getStartOperation(value);
2104b0198acSAlexander Belyaev Operation *end = blockInfo->getEndOperation(value, start);
2114b0198acSAlexander Belyaev
2124b0198acSAlexander Belyaev result.push_back(start);
2134b0198acSAlexander Belyaev while (start != end) {
2144b0198acSAlexander Belyaev start = start->getNextNode();
2154b0198acSAlexander Belyaev result.push_back(start);
2164b0198acSAlexander Belyaev }
2174b0198acSAlexander Belyaev
2184b0198acSAlexander Belyaev for (Block *successor : block->getSuccessors()) {
2194b0198acSAlexander Belyaev if (getLiveness(successor)->isLiveIn(value) &&
2204b0198acSAlexander Belyaev visited.insert(successor).second)
2214b0198acSAlexander Belyaev toProcess.push_back(successor);
2224b0198acSAlexander Belyaev }
2234b0198acSAlexander Belyaev }
2244b0198acSAlexander Belyaev
2254b0198acSAlexander Belyaev return result;
2264b0198acSAlexander Belyaev }
2274b0198acSAlexander Belyaev
2284b0198acSAlexander Belyaev /// Gets liveness info (if any) for the block.
getLiveness(Block * block) const2294b0198acSAlexander Belyaev const LivenessBlockInfo *Liveness::getLiveness(Block *block) const {
2304b0198acSAlexander Belyaev auto it = blockMapping.find(block);
2314b0198acSAlexander Belyaev return it == blockMapping.end() ? nullptr : &it->second;
2324b0198acSAlexander Belyaev }
2334b0198acSAlexander Belyaev
2344b0198acSAlexander Belyaev /// Returns a reference to a set containing live-in values.
getLiveIn(Block * block) const2354b0198acSAlexander Belyaev const Liveness::ValueSetT &Liveness::getLiveIn(Block *block) const {
2364b0198acSAlexander Belyaev return getLiveness(block)->in();
2374b0198acSAlexander Belyaev }
2384b0198acSAlexander Belyaev
2394b0198acSAlexander Belyaev /// Returns a reference to a set containing live-out values.
getLiveOut(Block * block) const2404b0198acSAlexander Belyaev const Liveness::ValueSetT &Liveness::getLiveOut(Block *block) const {
2414b0198acSAlexander Belyaev return getLiveness(block)->out();
2424b0198acSAlexander Belyaev }
2434b0198acSAlexander Belyaev
24417de7ed5SRahul Joshi /// Returns true if `value` is not live after `operation`.
isDeadAfter(Value value,Operation * operation) const24517de7ed5SRahul Joshi bool Liveness::isDeadAfter(Value value, Operation *operation) const {
2464b0198acSAlexander Belyaev Block *block = operation->getBlock();
2474b0198acSAlexander Belyaev const LivenessBlockInfo *blockInfo = getLiveness(block);
2484b0198acSAlexander Belyaev
2494b0198acSAlexander Belyaev // The given value escapes the associated block.
2504b0198acSAlexander Belyaev if (blockInfo->isLiveOut(value))
2514b0198acSAlexander Belyaev return false;
2524b0198acSAlexander Belyaev
2534b0198acSAlexander Belyaev Operation *endOperation = blockInfo->getEndOperation(value, operation);
2544b0198acSAlexander Belyaev // If the operation is a real user of `value` the first check is sufficient.
2554b0198acSAlexander Belyaev // If not, we will have to test whether the end operation is executed before
2564b0198acSAlexander Belyaev // the given operation in the block.
2574b0198acSAlexander Belyaev return endOperation == operation || endOperation->isBeforeInBlock(operation);
2584b0198acSAlexander Belyaev }
2594b0198acSAlexander Belyaev
2604b0198acSAlexander Belyaev /// Dumps the liveness information in a human readable format.
dump() const2614b0198acSAlexander Belyaev void Liveness::dump() const { print(llvm::errs()); }
2624b0198acSAlexander Belyaev
2634b0198acSAlexander Belyaev /// Dumps the liveness information to the given stream.
print(raw_ostream & os) const2644b0198acSAlexander Belyaev void Liveness::print(raw_ostream &os) const {
2654b0198acSAlexander Belyaev os << "// ---- Liveness -----\n";
2664b0198acSAlexander Belyaev
2674b0198acSAlexander Belyaev // Builds unique block/value mappings for testing purposes.
2684b0198acSAlexander Belyaev DenseMap<Block *, size_t> blockIds;
2694b0198acSAlexander Belyaev DenseMap<Operation *, size_t> operationIds;
270e62a6956SRiver Riddle DenseMap<Value, size_t> valueIds;
27171a86245SDiego Caballero operation->walk<WalkOrder::PreOrder>([&](Block *block) {
2721664462dSFrederik Gossen blockIds.insert({block, blockIds.size()});
2731664462dSFrederik Gossen for (BlockArgument argument : block->getArguments())
2744b0198acSAlexander Belyaev valueIds.insert({argument, valueIds.size()});
2751664462dSFrederik Gossen for (Operation &operation : *block) {
2764b0198acSAlexander Belyaev operationIds.insert({&operation, operationIds.size()});
277e62a6956SRiver Riddle for (Value result : operation.getResults())
2784b0198acSAlexander Belyaev valueIds.insert({result, valueIds.size()});
2794b0198acSAlexander Belyaev }
280c79227caSMarcel Koester });
2814b0198acSAlexander Belyaev
2824b0198acSAlexander Belyaev // Local printing helpers
283e62a6956SRiver Riddle auto printValueRef = [&](Value value) {
2848e640ca5SMarcel Koester if (value.getDefiningOp())
285c79227caSMarcel Koester os << "val_" << valueIds[value];
2864b0198acSAlexander Belyaev else {
2875550c821STres Popp auto blockArg = cast<BlockArgument>(value);
2882bdf33ccSRiver Riddle os << "arg" << blockArg.getArgNumber() << "@"
2892bdf33ccSRiver Riddle << blockIds[blockArg.getOwner()];
2904b0198acSAlexander Belyaev }
2914b0198acSAlexander Belyaev os << " ";
2924b0198acSAlexander Belyaev };
2934b0198acSAlexander Belyaev
2944b0198acSAlexander Belyaev auto printValueRefs = [&](const ValueSetT &values) {
295e62a6956SRiver Riddle std::vector<Value> orderedValues(values.begin(), values.end());
296aba43035SDmitri Gribenko llvm::sort(orderedValues, [&](Value left, Value right) {
2974b0198acSAlexander Belyaev return valueIds[left] < valueIds[right];
2984b0198acSAlexander Belyaev });
299e62a6956SRiver Riddle for (Value value : orderedValues)
3004b0198acSAlexander Belyaev printValueRef(value);
3014b0198acSAlexander Belyaev };
3024b0198acSAlexander Belyaev
3034b0198acSAlexander Belyaev // Dump information about in and out values.
30471a86245SDiego Caballero operation->walk<WalkOrder::PreOrder>([&](Block *block) {
3051664462dSFrederik Gossen os << "// - Block: " << blockIds[block] << "\n";
3061664462dSFrederik Gossen const auto *liveness = getLiveness(block);
3074b0198acSAlexander Belyaev os << "// --- LiveIn: ";
3084b0198acSAlexander Belyaev printValueRefs(liveness->inValues);
3094b0198acSAlexander Belyaev os << "\n// --- LiveOut: ";
3104b0198acSAlexander Belyaev printValueRefs(liveness->outValues);
3114b0198acSAlexander Belyaev os << "\n";
3124b0198acSAlexander Belyaev
3134b0198acSAlexander Belyaev // Print liveness intervals.
314f382dfc0Sbzcheeseman os << "// --- BeginLivenessIntervals";
3151664462dSFrederik Gossen for (Operation &op : *block) {
3164b0198acSAlexander Belyaev if (op.getNumResults() < 1)
3174b0198acSAlexander Belyaev continue;
3184b0198acSAlexander Belyaev os << "\n";
319e62a6956SRiver Riddle for (Value result : op.getResults()) {
3204b0198acSAlexander Belyaev os << "// ";
3214b0198acSAlexander Belyaev printValueRef(result);
3224b0198acSAlexander Belyaev os << ":";
3234b0198acSAlexander Belyaev auto liveOperations = resolveLiveness(result);
324aba43035SDmitri Gribenko llvm::sort(liveOperations, [&](Operation *left, Operation *right) {
3254b0198acSAlexander Belyaev return operationIds[left] < operationIds[right];
3264b0198acSAlexander Belyaev });
3274b0198acSAlexander Belyaev for (Operation *operation : liveOperations) {
3284b0198acSAlexander Belyaev os << "\n// ";
3294b0198acSAlexander Belyaev operation->print(os);
3304b0198acSAlexander Belyaev }
3314b0198acSAlexander Belyaev }
3324b0198acSAlexander Belyaev }
333f382dfc0Sbzcheeseman os << "\n// --- EndLivenessIntervals\n";
334f382dfc0Sbzcheeseman
335f382dfc0Sbzcheeseman // Print currently live values.
336f382dfc0Sbzcheeseman os << "// --- BeginCurrentlyLive\n";
337f382dfc0Sbzcheeseman for (Operation &op : *block) {
338f382dfc0Sbzcheeseman auto currentlyLive = liveness->currentlyLiveValues(&op);
339f382dfc0Sbzcheeseman if (currentlyLive.empty())
340f382dfc0Sbzcheeseman continue;
341f382dfc0Sbzcheeseman os << "// ";
342f382dfc0Sbzcheeseman op.print(os);
343f382dfc0Sbzcheeseman os << " [";
344f382dfc0Sbzcheeseman printValueRefs(currentlyLive);
345f382dfc0Sbzcheeseman os << "\b]\n";
346f382dfc0Sbzcheeseman }
347f382dfc0Sbzcheeseman os << "// --- EndCurrentlyLive\n";
348c79227caSMarcel Koester });
3494b0198acSAlexander Belyaev os << "// -------------------\n";
3504b0198acSAlexander Belyaev }
3514b0198acSAlexander Belyaev
3524b0198acSAlexander Belyaev //===----------------------------------------------------------------------===//
3534b0198acSAlexander Belyaev // LivenessBlockInfo
3544b0198acSAlexander Belyaev //===----------------------------------------------------------------------===//
3554b0198acSAlexander Belyaev
3564b0198acSAlexander Belyaev /// Returns true if the given value is in the live-in set.
isLiveIn(Value value) const357e62a6956SRiver Riddle bool LivenessBlockInfo::isLiveIn(Value value) const {
3584b0198acSAlexander Belyaev return inValues.count(value);
3594b0198acSAlexander Belyaev }
3604b0198acSAlexander Belyaev
3614b0198acSAlexander Belyaev /// Returns true if the given value is in the live-out set.
isLiveOut(Value value) const362e62a6956SRiver Riddle bool LivenessBlockInfo::isLiveOut(Value value) const {
3634b0198acSAlexander Belyaev return outValues.count(value);
3644b0198acSAlexander Belyaev }
3654b0198acSAlexander Belyaev
366c79227caSMarcel Koester /// Gets the start operation for the given value (must be referenced in this
367c79227caSMarcel Koester /// block).
getStartOperation(Value value) const368e62a6956SRiver Riddle Operation *LivenessBlockInfo::getStartOperation(Value value) const {
3692bdf33ccSRiver Riddle Operation *definingOp = value.getDefiningOp();
3704b0198acSAlexander Belyaev // The given value is either live-in or is defined
3714b0198acSAlexander Belyaev // in the scope of this block.
3724b0198acSAlexander Belyaev if (isLiveIn(value) || !definingOp)
3734b0198acSAlexander Belyaev return &block->front();
3744b0198acSAlexander Belyaev return definingOp;
3754b0198acSAlexander Belyaev }
3764b0198acSAlexander Belyaev
3774b0198acSAlexander Belyaev /// Gets the end operation for the given value using the start operation
3784b0198acSAlexander Belyaev /// provided (must be referenced in this block).
getEndOperation(Value value,Operation * startOperation) const379e62a6956SRiver Riddle Operation *LivenessBlockInfo::getEndOperation(Value value,
3804b0198acSAlexander Belyaev Operation *startOperation) const {
3814b0198acSAlexander Belyaev // The given value is either dying in this block or live-out.
3824b0198acSAlexander Belyaev if (isLiveOut(value))
3834b0198acSAlexander Belyaev return &block->back();
3844b0198acSAlexander Belyaev
3854b0198acSAlexander Belyaev // Resolve the last operation (must exist by definition).
3864b0198acSAlexander Belyaev Operation *endOperation = startOperation;
387c79227caSMarcel Koester for (Operation *useOp : value.getUsers()) {
388c79227caSMarcel Koester // Find the associated operation in the current block (if any).
389c79227caSMarcel Koester useOp = block->findAncestorOpInBlock(*useOp);
390c79227caSMarcel Koester // Check whether the use is in our block and after the current end
391c79227caSMarcel Koester // operation.
392c79227caSMarcel Koester if (useOp && endOperation->isBeforeInBlock(useOp))
393c79227caSMarcel Koester endOperation = useOp;
3944b0198acSAlexander Belyaev }
3954b0198acSAlexander Belyaev return endOperation;
3964b0198acSAlexander Belyaev }
397f382dfc0Sbzcheeseman
398f382dfc0Sbzcheeseman /// Return the values that are currently live as of the given operation.
399f382dfc0Sbzcheeseman LivenessBlockInfo::ValueSetT
currentlyLiveValues(Operation * op) const400f382dfc0Sbzcheeseman LivenessBlockInfo::currentlyLiveValues(Operation *op) const {
401f382dfc0Sbzcheeseman ValueSetT liveSet;
402f382dfc0Sbzcheeseman
403f382dfc0Sbzcheeseman // Given a value, check which ops are within its live range. For each of
404f382dfc0Sbzcheeseman // those ops, add the value to the set of live values as-of that op.
405f382dfc0Sbzcheeseman auto addValueToCurrentlyLiveSets = [&](Value value) {
406f382dfc0Sbzcheeseman // Determine the live range of this value inside this block.
407f382dfc0Sbzcheeseman Operation *startOfLiveRange = value.getDefiningOp();
408f382dfc0Sbzcheeseman Operation *endOfLiveRange = nullptr;
409f382dfc0Sbzcheeseman // If it's a live in or a block argument, then the start is the beginning
410f382dfc0Sbzcheeseman // of the block.
4115550c821STres Popp if (isLiveIn(value) || isa<BlockArgument>(value))
412f382dfc0Sbzcheeseman startOfLiveRange = &block->front();
413f382dfc0Sbzcheeseman else
414f382dfc0Sbzcheeseman startOfLiveRange = block->findAncestorOpInBlock(*startOfLiveRange);
415f382dfc0Sbzcheeseman
416f382dfc0Sbzcheeseman // If it's a live out, then the end is the back of the block.
417f382dfc0Sbzcheeseman if (isLiveOut(value))
418f382dfc0Sbzcheeseman endOfLiveRange = &block->back();
419f382dfc0Sbzcheeseman
420f382dfc0Sbzcheeseman // We must have at least a startOfLiveRange at this point. Given this, we
421f382dfc0Sbzcheeseman // can use the existing getEndOperation to find the end of the live range.
422f382dfc0Sbzcheeseman if (startOfLiveRange && !endOfLiveRange)
423f382dfc0Sbzcheeseman endOfLiveRange = getEndOperation(value, startOfLiveRange);
424f382dfc0Sbzcheeseman
425f382dfc0Sbzcheeseman assert(endOfLiveRange && "Must have endOfLiveRange at this point!");
426f382dfc0Sbzcheeseman // If this op is within the live range, insert the value into the set.
427f382dfc0Sbzcheeseman if (!(op->isBeforeInBlock(startOfLiveRange) ||
428f382dfc0Sbzcheeseman endOfLiveRange->isBeforeInBlock(op)))
429f382dfc0Sbzcheeseman liveSet.insert(value);
430f382dfc0Sbzcheeseman };
431f382dfc0Sbzcheeseman
432f382dfc0Sbzcheeseman // Handle block arguments if any.
433f382dfc0Sbzcheeseman for (Value arg : block->getArguments())
434f382dfc0Sbzcheeseman addValueToCurrentlyLiveSets(arg);
435f382dfc0Sbzcheeseman
436f382dfc0Sbzcheeseman // Handle live-ins. Between the live ins and all the op results that gives us
437f382dfc0Sbzcheeseman // every value in the block.
438f382dfc0Sbzcheeseman for (Value in : inValues)
439f382dfc0Sbzcheeseman addValueToCurrentlyLiveSets(in);
440f382dfc0Sbzcheeseman
441f382dfc0Sbzcheeseman // Now walk the block and handle all values used in the block and values
442f382dfc0Sbzcheeseman // defined by the block.
443f382dfc0Sbzcheeseman for (Operation &walkOp :
444f382dfc0Sbzcheeseman llvm::make_range(block->begin(), ++op->getIterator()))
445f382dfc0Sbzcheeseman for (auto result : walkOp.getResults())
446f382dfc0Sbzcheeseman addValueToCurrentlyLiveSets(result);
447f382dfc0Sbzcheeseman
448f382dfc0Sbzcheeseman return liveSet;
449f382dfc0Sbzcheeseman }
450