MLIR  20.0.0git
SliceWalk.cpp
Go to the documentation of this file.
3 
4 using namespace mlir;
5 
7  WalkCallback walkCallback) {
8  // Search the backward slice starting from the root values.
9  SmallVector<Value> workList = rootValues;
10  llvm::SmallDenseSet<Value, 16> seenValues;
11  while (!workList.empty()) {
12  // Search the backward slice of the current value.
13  Value current = workList.pop_back_val();
14 
15  // Skip the current value if it has already been seen.
16  if (!seenValues.insert(current).second)
17  continue;
18 
19  // Call the walk callback with the current value.
20  WalkContinuation continuation = walkCallback(current);
21  if (continuation.wasInterrupted())
22  return continuation;
23  if (continuation.wasSkipped())
24  continue;
25 
26  assert(continuation.wasAdvancedTo());
27  // Add the next values to the work list if the walk should continue.
28  workList.append(continuation.getNextValues().begin(),
29  continuation.getNextValues().end());
30  }
31 
32  return WalkContinuation::skip();
33 }
34 
35 /// Returns the operands from all predecessor regions that match `operandNumber`
36 /// for the `successor` region within `regionOp`.
37 static SmallVector<Value>
38 getRegionPredecessorOperands(RegionBranchOpInterface regionOp,
39  RegionSuccessor successor,
40  unsigned operandNumber) {
41  SmallVector<Value> predecessorOperands;
42 
43  // Returns true if `successors` contains `successor`.
44  auto isContained = [](ArrayRef<RegionSuccessor> successors,
45  RegionSuccessor successor) {
46  auto *it = llvm::find_if(successors, [&successor](RegionSuccessor curr) {
47  return curr.getSuccessor() == successor.getSuccessor();
48  });
49  return it != successors.end();
50  };
51 
52  // Search the operand ranges on the region operation itself.
53  SmallVector<Attribute> operandAttributes(regionOp->getNumOperands());
55  regionOp.getEntrySuccessorRegions(operandAttributes, successors);
56  if (isContained(successors, successor)) {
57  OperandRange operands = regionOp.getEntrySuccessorOperands(successor);
58  predecessorOperands.push_back(operands[operandNumber]);
59  }
60 
61  // Search the operand ranges on region terminators.
62  for (Region &region : regionOp->getRegions()) {
63  for (Block &block : region) {
64  auto terminatorOp =
65  dyn_cast<RegionBranchTerminatorOpInterface>(block.getTerminator());
66  if (!terminatorOp)
67  continue;
68  SmallVector<Attribute> operandAttributes(terminatorOp->getNumOperands());
70  terminatorOp.getSuccessorRegions(operandAttributes, successors);
71  if (isContained(successors, successor)) {
72  OperandRange operands = terminatorOp.getSuccessorOperands(successor);
73  predecessorOperands.push_back(operands[operandNumber]);
74  }
75  }
76  }
77 
78  return predecessorOperands;
79 }
80 
81 /// Returns the predecessor branch operands that match `blockArg`, or nullopt if
82 /// some of the predecessor terminators do not implement the BranchOpInterface.
83 static std::optional<SmallVector<Value>>
85  Block *block = blockArg.getOwner();
86 
87  // Search the predecessor operands for all predecessor terminators.
88  SmallVector<Value> predecessorOperands;
89  for (auto it = block->pred_begin(); it != block->pred_end(); ++it) {
90  Block *predecessor = *it;
91  auto branchOp = dyn_cast<BranchOpInterface>(predecessor->getTerminator());
92  if (!branchOp)
93  return std::nullopt;
94  SuccessorOperands successorOperands =
95  branchOp.getSuccessorOperands(it.getSuccessorIndex());
96  // Store the predecessor operand if the block argument matches an operand
97  // and is not produced by the terminator.
98  if (Value operand = successorOperands[blockArg.getArgNumber()])
99  predecessorOperands.push_back(operand);
100  }
101 
102  return predecessorOperands;
103 }
104 
105 std::optional<SmallVector<Value>>
107  if (OpResult opResult = dyn_cast<OpResult>(value)) {
108  if (auto selectOp = opResult.getDefiningOp<SelectLikeOpInterface>())
109  return SmallVector<Value>(
110  {selectOp.getTrueValue(), selectOp.getFalseValue()});
111  auto regionOp = opResult.getDefiningOp<RegionBranchOpInterface>();
112  // If the interface is not implemented, there are no control flow
113  // predecessors to work with.
114  if (!regionOp)
115  return std::nullopt;
116  // Add the control flow predecessor operands to the work list.
117  RegionSuccessor region(regionOp->getResults());
118  SmallVector<Value> predecessorOperands = getRegionPredecessorOperands(
119  regionOp, region, opResult.getResultNumber());
120  return predecessorOperands;
121  }
122 
123  auto blockArg = cast<BlockArgument>(value);
124  Block *block = blockArg.getOwner();
125  // Search the region predecessor operands for structured control flow.
126  if (block->isEntryBlock()) {
127  if (auto regionBranchOp =
128  dyn_cast<RegionBranchOpInterface>(block->getParentOp())) {
129  RegionSuccessor region(blockArg.getParentRegion());
130  SmallVector<Value> predecessorOperands = getRegionPredecessorOperands(
131  regionBranchOp, region, blockArg.getArgNumber());
132  return predecessorOperands;
133  }
134  // If the interface is not implemented, there are no control flow
135  // predecessors to work with.
136  return std::nullopt;
137  }
138 
139  // Search the block predecessor operands for unstructured control flow.
140  return getBlockPredecessorOperands(blockArg);
141 }
static std::optional< SmallVector< Value > > getBlockPredecessorOperands(BlockArgument blockArg)
Returns the predecessor branch operands that match blockArg, or nullopt if some of the predecessor te...
Definition: SliceWalk.cpp:84
static SmallVector< Value > getRegionPredecessorOperands(RegionBranchOpInterface regionOp, RegionSuccessor successor, unsigned operandNumber)
Returns the operands from all predecessor regions that match operandNumber for the successor region w...
Definition: SliceWalk.cpp:38
This class represents an argument of a Block.
Definition: Value.h:319
Block * getOwner() const
Returns the block that owns this argument.
Definition: Value.h:328
unsigned getArgNumber() const
Returns the number of this argument.
Definition: Value.h:331
Block represents an ordered list of Operations.
Definition: Block.h:31
pred_iterator pred_begin()
Definition: Block.h:231
Operation * getTerminator()
Get the terminator operation of this block.
Definition: Block.cpp:243
bool isEntryBlock()
Return if this block is the entry block in the parent region.
Definition: Block.cpp:35
pred_iterator pred_end()
Definition: Block.h:234
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
Definition: Block.cpp:30
This is a value defined by a result of an operation.
Definition: Value.h:457
This class implements the operand iterators for the Operation class.
Definition: ValueRange.h:42
This class represents a successor of a region.
Region * getSuccessor() const
Return the given region successor.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition: Region.h:26
This class models how operands are forwarded to block arguments in control flow.
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:381
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
A class to signal how to proceed with the walk of the backward slice:
Definition: SliceWalk.h:20
bool wasInterrupted() const
Returns true if the walk was interrupted.
Definition: SliceWalk.h:60
bool wasAdvancedTo() const
Returns true if the walk was advanced to user-specified values.
Definition: SliceWalk.h:66
static WalkContinuation skip()
Creates a continuation that advances the walk without adding any predecessor values to the work list.
Definition: SliceWalk.h:55
mlir::ArrayRef< mlir::Value > getNextValues() const
Returns the next values to continue the walk with.
Definition: SliceWalk.h:69
bool wasSkipped() const
Returns true if the walk was skipped.
Definition: SliceWalk.h:63
Include the generated interface declarations.
std::optional< SmallVector< Value > > getControlFlowPredecessors(Value value)
Computes a vector of all control predecessors of value.
Definition: SliceWalk.cpp:106
WalkContinuation walkSlice(mlir::ValueRange rootValues, WalkCallback walkCallback)
Walks the slice starting from the rootValues using a depth-first traversal.
Definition: SliceWalk.cpp:6