1 //===- ControlFlowInterfaces.h - ControlFlow Interfaces ---------*- C++ -*-===//
2 //
3 // Part of the LLVM 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 // 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).
43 class SuccessorOperands {
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.
size()56   unsigned size() const {
57     return producedOperandCount + forwardedOperands.size();
58   }
59 
60   /// Returns true if there are no successor operands.
empty()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.
getProducedOperandCount()65   unsigned getProducedOperandCount() const { return producedOperandCount; }
66 
67   /// Returns true if the successor operand denoted by `index` is produced by
68   /// the operation.
isOperandProduced(unsigned index)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.
getForwardedOperands()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.
slice(unsigned subStart,unsigned subLen)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.
append(ValueRange valueRange)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.
getOperandIndex(unsigned blockArgumentIndex)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.
131 Optional<BlockArgument>
132 getBranchSuccessorArgument(const SuccessorOperands &operands,
133                            unsigned operandIndex, Block *successor);
134 
135 /// Verify that the given operands match those of the given successor block.
136 LogicalResult verifyBranchSuccessorOperands(Operation *op, unsigned succNo,
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.
146 LogicalResult verifyTypesAlongControlFlowEdges(Operation *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.
160 class RegionSuccessor {
161 public:
162   /// Initialize a successor that branches to another region of the parent
163   /// operation.
164   RegionSuccessor(Region *region, Block::BlockArgListType regionInputs = {})
region(region)165       : region(region), inputs(regionInputs) {}
166   /// Initialize a successor that branches back to/out of the parent operation.
167   RegionSuccessor(Optional<Operation::result_range> results = {})
168       : inputs(results ? ValueRange(*results) : ValueRange()) {}
169 
170   /// Return the given region successor. Returns nullptr if the successor is the
171   /// parent operation.
getSuccessor()172   Region *getSuccessor() const { return region; }
173 
174   /// Return true if the successor is the parent operation.
isParent()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.
getSuccessorInputs()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.
189 class InvocationBounds {
190 public:
191   /// Create invocation bounds. The lower bound must be at least 0 and only the
192   /// upper bound can be unknown.
InvocationBounds(unsigned lb,Optional<unsigned> ub)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.
getLowerBound()198   unsigned getLowerBound() const { return lower; }
199 
200   /// Return the upper bound.
getUpperBound()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.
getUnknown()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.
217 bool insideMutuallyExclusiveRegions(Operation *a, Operation *b);
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.
222 Region *getEnclosingRepetitiveRegion(Operation *op);
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.
227 Region *getEnclosingRepetitiveRegion(Value value);
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.
244 Optional<MutableOperandRange>
245 getMutableRegionBranchSuccessorOperands(Operation *operation,
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.
251 Optional<OperandRange>
252 getRegionBranchSuccessorOperands(Operation *operation,
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> {
verifyTraitReturnLike266   static LogicalResult verifyTrait(Operation *op) {
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
288