MLIR  16.0.0git
ControlFlowInterfaces.h
Go to the documentation of this file.
1 //===- ControlFlowInterfaces.h - ControlFlow Interfaces ---------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains the definitions of the branch interfaces defined in
10 // ControlFlowInterfaces.td.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef MLIR_INTERFACES_CONTROLFLOWINTERFACES_H
15 #define MLIR_INTERFACES_CONTROLFLOWINTERFACES_H
16
17 #include "mlir/IR/OpDefinition.h"
18
19 namespace mlir {
20 class BranchOpInterface;
21 class RegionBranchOpInterface;
22
23 /// This class models how operands are forwarded to block arguments in control
24 /// flow. It consists of a number, denoting how many of the successors block
25 /// arguments are produced by the operation, followed by a range of operands
26 /// that are forwarded. The produced operands are passed to the first few
27 /// block arguments of the successor, followed by the forwarded operands.
28 /// It is unsupported to pass them in a different order.
29 ///
30 /// An example operation with both of these concepts would be a branch-on-error
31 /// operation, that internally produces an error object on the error path:
32 ///
33 /// invoke %function(%0)
34 /// label ^success ^error(%1 : i32)
35 ///
36 /// ^error(%e: !error, %arg0 : i32):
37 /// ...
38 ///
39 /// This operation would return an instance of SuccessorOperands with a produced
40 /// operand count of 1 (mapped to %e in the successor) and a forwarded
41 /// operands range consisting of %1 in the example above (mapped to %arg0 in the
42 /// successor).
44 public:
45  /// Constructs a SuccessorOperands with no produced operands that simply
46  /// forwards operands to the successor.
47  explicit SuccessorOperands(MutableOperandRange forwardedOperands);
48
49  /// Constructs a SuccessorOperands with the given amount of produced operands
50  /// and forwarded operands.
51  SuccessorOperands(unsigned producedOperandCount,
52  MutableOperandRange forwardedOperands);
53
54  /// Returns the amount of operands passed to the successor. This consists both
55  /// of produced operands by the operation as well as forwarded ones.
56  unsigned size() const {
57  return producedOperandCount + forwardedOperands.size();
58  }
59
60  /// Returns true if there are no successor operands.
61  bool empty() const { return size() == 0; }
62
63  /// Returns the amount of operands that are produced internally by the
64  /// operation. These are passed to the first few block arguments.
65  unsigned getProducedOperandCount() const { return producedOperandCount; }
66
67  /// Returns true if the successor operand denoted by index is produced by
68  /// the operation.
69  bool isOperandProduced(unsigned index) const {
70  return index < producedOperandCount;
71  }
72
73  /// Returns the Value that is passed to the successors block argument denoted
74  /// by index. If it is produced by the operation, no such value exists and
75  /// a null Value is returned.
76  Value operator[](unsigned index) const {
77  if (isOperandProduced(index))
78  return Value();
79  return forwardedOperands[index - producedOperandCount];
80  }
81
82  /// Get the range of operands that are simply forwarded to the successor.
83  OperandRange getForwardedOperands() const { return forwardedOperands; }
84
85  /// Get a slice of the operands forwarded to the successor. The given range
86  /// must not contain any operands produced by the operation.
87  MutableOperandRange slice(unsigned subStart, unsigned subLen) const {
88  assert(!isOperandProduced(subStart) &&
89  "can't slice operands produced by the operation");
90  return forwardedOperands.slice(subStart - producedOperandCount, subLen);
91  }
92
93  /// Erase operands forwarded to the successor. The given range must
94  /// not contain any operands produced by the operation.
95  void erase(unsigned subStart, unsigned subLen = 1) {
96  assert(!isOperandProduced(subStart) &&
97  "can't erase operands produced by the operation");
98  forwardedOperands.erase(subStart - producedOperandCount, subLen);
99  }
100
101  /// Add new operands that are forwarded to the successor.
102  void append(ValueRange valueRange) { forwardedOperands.append(valueRange); }
103
104  /// Gets the index of the forwarded operand within the operation which maps
105  /// to the block argument denoted by blockArgumentIndex. The block argument
106  /// must be mapped to a forwarded operand.
107  unsigned getOperandIndex(unsigned blockArgumentIndex) const {
108  assert(!isOperandProduced(blockArgumentIndex) &&
109  "can't map operand produced by the operation");
110  OperandRange operands = forwardedOperands;
111  return operands.getBeginOperandIndex() +
112  (blockArgumentIndex - producedOperandCount);
113  }
114
115 private:
116  /// Amount of operands that are produced internally within the operation and
117  /// passed to the first few block arguments.
118  unsigned producedOperandCount;
119  /// Range of operands that are forwarded to the remaining block arguments.
120  MutableOperandRange forwardedOperands;
121 };
122
123 //===----------------------------------------------------------------------===//
124 // BranchOpInterface
125 //===----------------------------------------------------------------------===//
126
127 namespace detail {
128 /// Return the BlockArgument corresponding to operand operandIndex in some
129 /// successor if operandIndex is within the range of operands, or None if
130 /// operandIndex isn't a successor operand index.
133  unsigned operandIndex, Block *successor);
134
135 /// Verify that the given operands match those of the given successor block.
137  const SuccessorOperands &operands);
138 } // namespace detail
139
140 //===----------------------------------------------------------------------===//
141 // RegionBranchOpInterface
142 //===----------------------------------------------------------------------===//
143
144 namespace detail {
145 /// Verify that types match along control flow edges described the given op.
147 } // namespace detail
148
149 /// This class represents a successor of a region. A region successor can either
150 /// be another region, or the parent operation. If the successor is a region,
151 /// this class represents the destination region, as well as a set of arguments
152 /// from that region that will be populated when control flows into the region.
153 /// If the successor is the parent operation, this class represents an optional
154 /// set of results that will be populated when control returns to the parent
155 /// operation.
156 ///
157 /// This interface assumes that the values from the current region that are used
158 /// to populate the successor inputs are the operands of the return-like
159 /// terminator operations in the blocks within this region.
161 public:
162  /// Initialize a successor that branches to another region of the parent
163  /// operation.
164  RegionSuccessor(Region *region, Block::BlockArgListType regionInputs = {})
165  : region(region), inputs(regionInputs) {}
166  /// Initialize a successor that branches back to/out of the parent operation.
168  : inputs(results ? ValueRange(*results) : ValueRange()) {}
169
170  /// Return the given region successor. Returns nullptr if the successor is the
171  /// parent operation.
172  Region *getSuccessor() const { return region; }
173
174  /// Return true if the successor is the parent operation.
175  bool isParent() const { return region == nullptr; }
176
177  /// Return the inputs to the successor that are remapped by the exit values of
178  /// the current region.
179  ValueRange getSuccessorInputs() const { return inputs; }
180
181 private:
182  Region *region{nullptr};
183  ValueRange inputs;
184 };
185
186 /// This class represents upper and lower bounds on the number of times a region
187 /// of a RegionBranchOpInterface can be invoked. The lower bound is at least
188 /// zero, but the upper bound may not be known.
190 public:
191  /// Create invocation bounds. The lower bound must be at least 0 and only the
192  /// upper bound can be unknown.
193  InvocationBounds(unsigned lb, Optional<unsigned> ub) : lower(lb), upper(ub) {
194  assert((!ub || ub >= lb) && "upper bound cannot be less than lower bound");
195  }
196
197  /// Return the lower bound.
198  unsigned getLowerBound() const { return lower; }
199
200  /// Return the upper bound.
201  Optional<unsigned> getUpperBound() const { return upper; }
202
203  /// Returns the unknown invocation bounds, i.e., there is no information on
204  /// how many times a region may be invoked.
205  static InvocationBounds getUnknown() { return {0, llvm::None}; }
206
207 private:
208  /// The minimum number of times the successor region will be invoked.
209  unsigned lower;
210  /// The maximum number of times the successor region will be invoked or None
211  /// if an upper bound is not known.
212  Optional<unsigned> upper;
213 };
214
215 /// Return true if a and b are in mutually exclusive regions as per
216 /// RegionBranchOpInterface.
218
219 /// Return the first enclosing region of the given op that may be executed
220 /// repetitively as per RegionBranchOpInterface or nullptr if no such region
221 /// exists.
223
224 /// Return the first enclosing region of the given Value that may be executed
225 /// repetitively as per RegionBranchOpInterface or nullptr if no such region
226 /// exists.
228
229 //===----------------------------------------------------------------------===//
230 // RegionBranchTerminatorOpInterface
231 //===----------------------------------------------------------------------===//
232
233 /// Returns true if the given operation is either annotated with the
234 /// ReturnLike trait or implements the RegionBranchTerminatorOpInterface.
235 bool isRegionReturnLike(Operation *operation);
236
237 /// Returns the mutable operands that are passed to the region with the given
238 /// regionIndex. If the operation does not implement the
239 /// RegionBranchTerminatorOpInterface and is not marked as ReturnLike, the
240 /// result will be llvm::None. In all other cases, the resulting
241 /// OperandRange represents all operands that are passed to the specified
242 /// successor region. If regionIndex is llvm::None, all operands that are
243 /// passed to the parent operation will be returned.
246  Optional<unsigned> regionIndex);
247
248 /// Returns the read only operands that are passed to the region with the given
249 /// regionIndex. See getMutableRegionBranchSuccessorOperands for more
250 /// information.
253  Optional<unsigned> regionIndex);
254
255 //===----------------------------------------------------------------------===//
256 // ControlFlow Traits
257 //===----------------------------------------------------------------------===//
258
259 namespace OpTrait {
260 /// This trait indicates that a terminator operation is "return-like". This
261 /// means that it exits its current region and forwards its operands as "exit"
262 /// values to the parent region. Operations with this trait are not permitted to
263 /// contain successors or produce results.
264 template <typename ConcreteType>
265 struct ReturnLike : public TraitBase<ConcreteType, ReturnLike> {
267  static_assert(ConcreteType::template hasTrait<IsTerminator>(),
268  "expected operation to be a terminator");
269  static_assert(ConcreteType::template hasTrait<ZeroResults>(),
270  "expected operation to have zero results");
271  static_assert(ConcreteType::template hasTrait<ZeroSuccessors>(),
272  "expected operation to have zero successors");
273  return success();
274  }
275 };
276 } // namespace OpTrait
277
278 } // namespace mlir
279
280 //===----------------------------------------------------------------------===//
281 // ControlFlow Interfaces
282 //===----------------------------------------------------------------------===//
283
284 /// Include the generated interface declarations.
285 #include "mlir/Interfaces/ControlFlowInterfaces.h.inc"
286
287 #endif // MLIR_INTERFACES_CONTROLFLOWINTERFACES_H
void append(ValueRange valueRange)
Add new operands that are forwarded to the successor.
Include the generated interface declarations.
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 represents upper and lower bounds on the number of times a region of a RegionBranchOpInter...
static LogicalResult verifyTrait(Operation *op)
Optional< OperandRange > getRegionBranchSuccessorOperands(Operation *operation, Optional< unsigned > regionIndex)
Returns the read only operands that are passed to the region with the given regionIndex.
SuccessorOperands(MutableOperandRange forwardedOperands)
Constructs a SuccessorOperands with no produced operands that simply forwards operands to the success...
Operation is a basic unit of execution within MLIR.
Definition: Operation.h:28
RegionSuccessor(Optional< Operation::result_range > results={})
Initialize a successor that branches back to/out of the parent operation.
Block represents an ordered list of Operations.
Definition: Block.h:29
unsigned getOperandIndex(unsigned blockArgumentIndex) const
Gets the index of the forwarded operand within the operation which maps to the block argument denoted...
bool empty() const
Returns true if there are no successor operands.
bool isRegionReturnLike(Operation *operation)
Returns true if the given operation is either annotated with the ReturnLike trait or implements the R...
void append(ValueRange values)
Append the given values to the range.
void erase(unsigned subStart, unsigned subLen=1)
Erase operands forwarded to the successor.
Value operator[](unsigned index) const
Returns the Value that is passed to the successors block argument denoted by index.
Optional< unsigned > getUpperBound() const
Return the upper bound.
static constexpr const bool value
Region * getSuccessor() const
Return the given region successor.
unsigned getLowerBound() const
Return the lower bound.
unsigned getBeginOperandIndex() const
Return the operand index of the first element of this range.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
void erase(unsigned subStart, unsigned subLen=1)
Erase the operands within the given sub-range.
unsigned size() const
Returns the amount of operands passed to the successor.
LogicalResult verifyTypesAlongControlFlowEdges(Operation *op)
Verify that types match along control flow edges described the given op.
Optional< MutableOperandRange > getMutableRegionBranchSuccessorOperands(Operation *operation, Optional< unsigned > regionIndex)
Returns the mutable operands that are passed to the region with the given regionIndex.
This class provides a mutable adaptor for a range of operands.
Definition: ValueRange.h:114
bool isOperandProduced(unsigned index) const
Returns true if the successor operand denoted by index is produced by the operation.
This class models how operands are forwarded to block arguments in control flow.
Optional< BlockArgument > getBranchSuccessorArgument(const SuccessorOperands &operands, unsigned operandIndex, Block *successor)
Return the BlockArgument corresponding to operand operandIndex in some successor if operandIndex is w...
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:85
OperandRange getForwardedOperands() const
Get the range of operands that are simply forwarded to the successor.
Helper class for implementing traits.
Definition: OpDefinition.h:316
This class represents a successor of a region.
MutableOperandRange slice(unsigned subStart, unsigned subLen, Optional< OperandSegment > segment=llvm::None) const
Slice this range into a sub range, with the additional operand segment.
unsigned size() const
Returns the current size of the range.
Definition: ValueRange.h:149
InvocationBounds(unsigned lb, Optional< unsigned > ub)
Create invocation bounds.
LogicalResult verifyBranchSuccessorOperands(Operation *op, unsigned succNo, const SuccessorOperands &operands)
Verify that the given operands match those of the given successor block.
bool isParent() const
Return true if the successor is the parent operation.
unsigned getProducedOperandCount() const
Returns the amount of operands that are produced internally by the operation.
static InvocationBounds getUnknown()
Returns the unknown invocation bounds, i.e., there is no information on how many times a region may b...
Region * getEnclosingRepetitiveRegion(Operation *op)
Return the first enclosing region of the given op that may be executed repetitively as per RegionBran...
This class implements the operand iterators for the Operation class.
Definition: ValueRange.h:40
ValueRange getSuccessorInputs() const
Return the inputs to the successor that are remapped by the exit values of the current region...
bool insideMutuallyExclusiveRegions(Operation *a, Operation *b)
Return true if a and b are in mutually exclusive regions as per RegionBranchOpInterface.
RegionSuccessor(Region *region, Block::BlockArgListType regionInputs={})
Initialize a successor that branches to another region of the parent operation.
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:345
MutableOperandRange slice(unsigned subStart, unsigned subLen) const
Get a slice of the operands forwarded to the successor.
This trait indicates that a terminator operation is "return-like".