@@ -117,27 +117,58 @@ def BranchOpInterface : OpInterface<"BranchOpInterface"> {
117
117
118
118
def RegionBranchOpInterface : OpInterface<"RegionBranchOpInterface"> {
119
119
let description = [{
120
- This interface provides information for region operations that contain
121
- branching behavior between held regions, i .e. this interface allows for
120
+ This interface provides information for region operations that exhibit
121
+ branching behavior between held regions. I .e., this interface allows for
122
122
expressing control flow information for region holding operations.
123
123
124
- This interface is meant to model well-defined cases of control-flow of
124
+ This interface is meant to model well-defined cases of control-flow and
125
125
value propagation, where what occurs along control-flow edges is assumed to
126
- be side-effect free. For example, corresponding successor operands and
127
- successor block arguments may have different types. In such cases,
128
- `areTypesCompatible` can be implemented to compare types along control-flow
129
- edges. By default, type equality is used.
126
+ be side-effect free.
127
+
128
+ A "region branch point" indicates a point from which a branch originates. It
129
+ can indicate either a region of this op or `RegionBranchPoint::parent()`. In
130
+ the latter case, the branch originates from outside of the op, i.e., when
131
+ first executing this op.
132
+
133
+ A "region successor" indicates the target of a branch. It can indicate
134
+ either a region of this op or this op. In the former case, the region
135
+ successor is a region pointer and a range of block arguments to which the
136
+ "successor operands" are forwarded to. In the latter case, the control flow
137
+ leaves this op and the region successor is a range of results of this op to
138
+ which the successor operands are forwarded to.
139
+
140
+ By default, successor operands and successor block arguments/successor
141
+ results must have the same type. `areTypesCompatible` can be implemented to
142
+ allow non-equal types.
143
+
144
+ Example:
145
+
146
+ ```
147
+ %r = scf.for %iv = %lb to %ub step %step iter_args(%a = %b)
148
+ -> tensor<5xf32> {
149
+ ...
150
+ scf.yield %c : tensor<5xf32>
151
+ }
152
+ ```
153
+
154
+ `scf.for` has one region. The region has two region successors: the region
155
+ itself and the `scf.for` op. %b is an entry successor operand. %c is a
156
+ successor operand. %a is a successor block argument. %r is a successor
157
+ result.
130
158
}];
131
159
let cppNamespace = "::mlir";
132
160
133
161
let methods = [
134
162
InterfaceMethod<[{
135
- Returns the operands of this operation used as the entry arguments when
136
- branching from `point`, which was specified as a successor of
137
- this operation by `getEntrySuccessorRegions`, or the operands forwarded
138
- to the operation's results when it branches back to itself. These operands
139
- should correspond 1-1 with the successor inputs specified in
140
- `getEntrySuccessorRegions`.
163
+ Returns the operands of this operation that are forwarded to the region
164
+ successor's block arguments or this operation's results when branching
165
+ to `point`. `point` is guaranteed to be among the successors that are
166
+ returned by `getEntrySuccessorRegions`/`getSuccessorRegions(parent())`.
167
+
168
+ Example: In the above example, this method returns the operand %b of the
169
+ `scf.for` op, regardless of the value of `point`. I.e., this op always
170
+ forwards the same operands, regardless of whether the loop has 0 or more
171
+ iterations.
141
172
}],
142
173
"::mlir::OperandRange", "getEntrySuccessorOperands",
143
174
(ins "::mlir::RegionBranchPoint":$point), [{}],
@@ -147,32 +178,47 @@ def RegionBranchOpInterface : OpInterface<"RegionBranchOpInterface"> {
147
178
}]
148
179
>,
149
180
InterfaceMethod<[{
150
- Returns the viable region successors that are branched to when first
151
- executing the op.
181
+ Returns the potential region successors when first executing the op.
182
+
152
183
Unlike `getSuccessorRegions`, this method also passes along the
153
- constant operands of this op. Based on these, different region
154
- successors can be determined.
155
- `operands` contains an entry for every operand of the implementing
156
- op with a null attribute if the operand has no constant value or
157
- the corresponding attribute if it is a constant.
184
+ constant operands of this op. Based on these, the implementation may
185
+ filter out certain successors. By default, simply dispatches to
186
+ `getSuccessorRegions`. `operands` contains an entry for every
187
+ operand of this op, with a null attribute if the operand has no constant
188
+ value.
189
+
190
+ Note: The control flow does not necessarily have to enter any region of
191
+ this op.
158
192
159
- By default, simply dispatches to `getSuccessorRegions`.
193
+ Example: In the above example, this method may return two region
194
+ region successors: the single region of the `scf.for` op and the
195
+ `scf.for` operation (that implements this interface). If %lb, %ub, %step
196
+ are constants and it can be determined the loop does not have any
197
+ iterations, this method may choose to return only this operation.
198
+ Similarly, if it can be determined that the loop has at least one
199
+ iteration, this method may choose to return only the region of the loop.
160
200
}],
161
201
"void", "getEntrySuccessorRegions",
162
202
(ins "::llvm::ArrayRef<::mlir::Attribute>":$operands,
163
- "::llvm::SmallVectorImpl<::mlir::RegionSuccessor> &":$regions),
164
- [{}], [{
203
+ "::llvm::SmallVectorImpl<::mlir::RegionSuccessor> &":$regions), [{}],
204
+ /*defaultImplementation=*/ [{
165
205
$_op.getSuccessorRegions(mlir::RegionBranchPoint::parent(), regions);
166
206
}]
167
207
>,
168
208
InterfaceMethod<[{
169
- Returns the viable successors of `point`. These are the regions that may
170
- be selected during the flow of control. The parent operation, may
171
- specify itself as successor, which indicates that the control flow may
172
- not enter any region at all. This method allows for describing which
173
- regions may be executed when entering an operation, and which regions
174
- are executed after having executed another region of the parent op. The
175
- successor region must be non-empty.
209
+ Returns the potential region successors when branching from `point`.
210
+ These are the regions that may be selected during the flow of control.
211
+
212
+ When `point = RegionBranchPoint::parent()`, this method returns the
213
+ region successors when entering the operation. Otherwise, this method
214
+ returns the successor regions when branching from the region indicated
215
+ by `point`.
216
+
217
+ Example: In the above example, this method returns the region of the
218
+ `scf.for` and this operation for either region branch point (`parent`
219
+ and the region of the `scf.for`). An implementation may choose to filter
220
+ out region successors when it is statically known (e.g., by examining
221
+ the operands of this op) that those successors are not branched to.
176
222
}],
177
223
"void", "getSuccessorRegions",
178
224
(ins "::mlir::RegionBranchPoint":$point,
@@ -183,12 +229,12 @@ def RegionBranchOpInterface : OpInterface<"RegionBranchOpInterface"> {
183
229
times this operation will invoke the attached regions (assuming the
184
230
regions yield normally, i.e. do not abort or invoke an infinite loop).
185
231
The minimum number of invocations is at least 0. If the maximum number
186
- of invocations cannot be statically determined, then it will not have a
187
- value (i.e., it is set to `std::nullopt`) .
232
+ of invocations cannot be statically determined, then it will be set to
233
+ `InvocationBounds::getUnknown()` .
188
234
189
- `operands` is a set of optional attributes that either correspond to
190
- constant values for each operand of this operation or null if that
191
- operand is not a constant.
235
+ This method also passes along the constant operands of this op.
236
+ `operands` contains an entry for every operand of this op, with a null
237
+ attribute if the operand has no constant value .
192
238
193
239
This method may be called speculatively on operations where the provided
194
240
operands are not necessarily the same as the operation's current
@@ -199,16 +245,18 @@ def RegionBranchOpInterface : OpInterface<"RegionBranchOpInterface"> {
199
245
(ins "::llvm::ArrayRef<::mlir::Attribute>":$operands,
200
246
"::llvm::SmallVectorImpl<::mlir::InvocationBounds> &"
201
247
:$invocationBounds), [{}],
202
- [{ invocationBounds.append($_op->getNumRegions(),
203
- ::mlir::InvocationBounds::getUnknown()); }]
248
+ /*defaultImplementation=*/[{
249
+ invocationBounds.append($_op->getNumRegions(),
250
+ ::mlir::InvocationBounds::getUnknown());
251
+ }]
204
252
>,
205
253
InterfaceMethod<[{
206
254
This method is called to compare types along control-flow edges. By
207
255
default, the types are checked as equal.
208
256
}],
209
257
"bool", "areTypesCompatible",
210
258
(ins "::mlir::Type":$lhs, "::mlir::Type":$rhs), [{}],
211
- [{ return lhs == rhs; }]
259
+ /*defaultImplementation=*/ [{ return lhs == rhs; }]
212
260
>,
213
261
];
214
262
@@ -235,34 +283,34 @@ def RegionBranchTerminatorOpInterface :
235
283
OpInterface<"RegionBranchTerminatorOpInterface"> {
236
284
let description = [{
237
285
This interface provides information for branching terminator operations
238
- in the presence of a parent RegionBranchOpInterface implementation. It
286
+ in the presence of a parent ` RegionBranchOpInterface` implementation. It
239
287
specifies which operands are passed to which successor region.
240
288
}];
241
289
let cppNamespace = "::mlir";
242
290
243
291
let methods = [
244
292
InterfaceMethod<[{
245
293
Returns a mutable range of operands that are semantically "returned" by
246
- passing them to the region successor given by `point`.
294
+ passing them to the region successor indicated by `point`.
247
295
}],
248
296
"::mlir::MutableOperandRange", "getMutableSuccessorOperands",
249
297
(ins "::mlir::RegionBranchPoint":$point)
250
298
>,
251
299
InterfaceMethod<[{
252
- Returns the viable region successors that are branched to after this
300
+ Returns the potential region successors that are branched to after this
253
301
terminator based on the given constant operands.
254
302
255
- `operands` contains an entry for every operand of the
256
- implementing op with a null attribute if the operand has no constant
257
- value or the corresponding attribute if it is a constant.
303
+ This method also passes along the constant operands of this op.
304
+ `operands` contains an entry for every operand of this op, with a null
305
+ attribute if the operand has no constant value .
258
306
259
- Default implementation simply dispatches to the parent
307
+ The default implementation simply dispatches to the parent
260
308
`RegionBranchOpInterface`'s `getSuccessorRegions` implementation.
261
309
}],
262
310
"void", "getSuccessorRegions",
263
311
(ins "::llvm::ArrayRef<::mlir::Attribute>":$operands,
264
312
"::llvm::SmallVectorImpl<::mlir::RegionSuccessor> &":$regions), [{}],
265
- [{
313
+ /*defaultImplementation=*/ [{
266
314
::mlir::Operation *op = $_op;
267
315
::llvm::cast<::mlir::RegionBranchOpInterface>(op->getParentOp())
268
316
.getSuccessorRegions(op->getParentRegion(), regions);
0 commit comments