18 #include "llvm/ADT/STLExtras.h"
19 #include "llvm/ADT/SetOperations.h"
20 #include "llvm/ADT/SetVector.h"
21 #include "llvm/Support/raw_ostream.h"
27 struct BlockInfoBuilder {
31 BlockInfoBuilder() =
default;
34 BlockInfoBuilder(
Block *block) : block(block) {
35 auto gatherOutValues = [&](
Value value) {
41 Block *ownerBlock = useOp->getBlock();
45 assert(ownerBlock &&
"Use leaves the current parent region");
46 if (ownerBlock != block) {
47 outValues.insert(value);
56 defValues.insert(argument);
59 gatherOutValues(argument);
64 for (
Value result : operation.getResults())
65 gatherOutValues(result);
72 defValues.insert(result);
74 useValues.insert(operand);
76 for (
Block &child : region.getBlocks())
78 defValues.insert(arg);
80 llvm::set_subtract(useValues, defValues);
88 ValueSetT newIn = useValues;
89 llvm::set_union(newIn, outValues);
90 llvm::set_subtract(newIn, defValues);
94 if (newIn.size() == inValues.size())
97 inValues = std::move(newIn);
106 const BlockInfoBuilder &builder = builders.find(succ)->second;
107 llvm::set_union(outValues, builder.inValues);
112 Block *block{
nullptr};
134 BlockInfoBuilder &builder =
135 builders.try_emplace(block, block).first->second;
137 if (builder.updateLiveIn())
138 toProcess.insert(block->pred_begin(), block->pred_end());
142 while (!toProcess.empty()) {
143 Block *current = toProcess.pop_back_val();
144 BlockInfoBuilder &builder = builders[current];
147 builder.updateLiveOut(builders);
150 if (builder.updateLiveIn())
164 void Liveness::build() {
170 for (
auto &entry : builders) {
171 BlockInfoBuilder &builder = entry.second;
174 info.block = builder.block;
175 info.inValues = std::move(builder.inValues);
176 info.outValues = std::move(builder.outValues);
189 currentBlock = defOp->getBlock();
191 currentBlock = cast<BlockArgument>(value).getOwner();
192 toProcess.push_back(currentBlock);
193 visited.insert(currentBlock);
197 Block *useBlock = use.getOwner()->getBlock();
198 if (visited.insert(useBlock).second)
199 toProcess.push_back(useBlock);
202 while (!toProcess.empty()) {
204 Block *block = toProcess.back();
205 toProcess.pop_back();
212 result.push_back(start);
213 while (start != end) {
214 start = start->getNextNode();
215 result.push_back(start);
220 visited.insert(successor).second)
221 toProcess.push_back(successor);
230 auto it = blockMapping.find(block);
231 return it == blockMapping.end() ? nullptr : &it->second;
257 return endOperation == operation || endOperation->
isBeforeInBlock(operation);
265 os <<
"// ---- Liveness -----\n";
272 blockIds.insert({block, blockIds.size()});
274 valueIds.insert({argument, valueIds.size()});
276 operationIds.insert({&operation, operationIds.size()});
278 valueIds.insert({result, valueIds.size()});
283 auto printValueRef = [&](
Value value) {
284 if (value.getDefiningOp())
285 os <<
"val_" << valueIds[value];
287 auto blockArg = cast<BlockArgument>(value);
288 os <<
"arg" << blockArg.getArgNumber() <<
"@"
289 << blockIds[blockArg.getOwner()];
294 auto printValueRefs = [&](
const ValueSetT &values) {
295 std::vector<Value> orderedValues(values.begin(), values.end());
296 llvm::sort(orderedValues, [&](
Value left,
Value right) {
297 return valueIds[left] < valueIds[right];
299 for (
Value value : orderedValues)
300 printValueRef(value);
304 operation->walk<WalkOrder::PreOrder>([&](
Block *block) {
305 os <<
"// - Block: " << blockIds[block] <<
"\n";
306 const auto *liveness = getLiveness(block);
307 os <<
"// --- LiveIn: ";
308 printValueRefs(liveness->inValues);
309 os <<
"\n// --- LiveOut: ";
310 printValueRefs(liveness->outValues);
314 os <<
"// --- BeginLivenessIntervals";
321 printValueRef(result);
323 auto liveOperations = resolveLiveness(result);
325 return operationIds[left] < operationIds[right];
327 for (
Operation *operation : liveOperations) {
329 operation->print(os);
333 os <<
"\n// --- EndLivenessIntervals\n";
336 os <<
"// --- BeginCurrentlyLive\n";
338 auto currentlyLive = liveness->currentlyLiveValues(&op);
339 if (currentlyLive.empty())
344 printValueRefs(currentlyLive);
347 os <<
"// --- EndCurrentlyLive\n";
349 os <<
"// -------------------\n";
357 bool LivenessBlockInfo::isLiveIn(
Value value)
const {
358 return inValues.count(value);
363 return outValues.count(value);
373 return &block->front();
383 return &block->back();
386 Operation *endOperation = startOperation;
389 useOp = block->findAncestorOpInBlock(*useOp);
393 endOperation = useOp;
405 auto addValueToCurrentlyLiveSets = [&](
Value value) {
407 Operation *startOfLiveRange = value.getDefiningOp();
411 if (
isLiveIn(value) || isa<BlockArgument>(value))
412 startOfLiveRange = &block->front();
414 startOfLiveRange = block->findAncestorOpInBlock(*startOfLiveRange);
418 endOfLiveRange = &block->back();
422 if (startOfLiveRange && !endOfLiveRange)
425 assert(endOfLiveRange &&
"Must have endOfLiveRange at this point!");
429 liveSet.insert(value);
433 for (
Value arg : block->getArguments())
434 addValueToCurrentlyLiveSets(arg);
439 addValueToCurrentlyLiveSets(
in);
444 llvm::make_range(block->begin(), ++op->getIterator()))
445 for (
auto result : walkOp.getResults())
446 addValueToCurrentlyLiveSets(result);
static void buildBlockMapping(Operation *operation, DenseMap< Block *, BlockInfoBuilder > &builders)
Builds the internal liveness block mapping.
This class represents an argument of a Block.
Block represents an ordered list of Operations.
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
pred_iterator pred_begin()
SuccessorRange getSuccessors()
BlockArgListType getArguments()
This class represents liveness information on block level.
bool isLiveIn(Value value) const
Returns true if the given value is in the live-in set.
Operation * getStartOperation(Value value) const
Gets the start operation for the given value.
const ValueSetT & in() const
Returns all values that are live at the beginning of the block (unordered).
ValueSetT currentlyLiveValues(Operation *op) const
Get the set of values that are currently live (if any) for the current op.
bool isLiveOut(Value value) const
Returns true if the given value is in the live-out set.
const ValueSetT & out() const
Returns all values that are live at the end of the block (unordered).
Operation * getEndOperation(Value value, Operation *startOperation) const
Gets the end operation for the given value using the start operation provided (must be referenced in ...
bool isDeadAfter(Value value, Operation *operation) const
Returns true if value is not live after operation.
Liveness(Operation *op)
Creates a new Liveness analysis that computes liveness information for all associated regions.
OperationListT resolveLiveness(Value value) const
Gets liveness info (if any) for the given value.
const LivenessBlockInfo * getLiveness(Block *block) const
Gets liveness info (if any) for the block.
SmallPtrSet< Value, 16 > ValueSetT
void print(raw_ostream &os) const
Dumps the liveness information to the given stream.
const ValueSetT & getLiveOut(Block *block) const
Returns a reference to a set containing live-out values (unordered).
const ValueSetT & getLiveIn(Block *block) const
Returns a reference to a set containing live-in values (unordered).
std::vector< Operation * > OperationListT
void dump() const
Dumps the liveness information in a human readable format.
This class represents an operand of an operation.
Operation is the basic unit of execution within MLIR.
bool isBeforeInBlock(Operation *other)
Given an operation 'other' that is within the same parent block, return whether the current operation...
std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==1, RetT > walk(FnT &&callback)
Walk the operation by calling the callback for each nested operation (including this one),...
void print(raw_ostream &os, const OpPrintingFlags &flags=std::nullopt)
Block * getBlock()
Returns the operation block that contains this operation.
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
operand_range getOperands()
Returns an iterator on the underlying Value's.
user_range getUsers()
Returns a range of all users.
result_range getResults()
unsigned getNumResults()
Return the number of results held by this operation.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Block * findAncestorBlockInRegion(Block &block)
Returns 'block' if 'block' lies in this region, or otherwise finds the ancestor of 'block' that lies ...
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
use_range getUses() const
Returns a range of all uses, which is useful for iterating over all uses.
user_range getUsers() const
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Include the generated interface declarations.