@@ -52,7 +52,7 @@ def ForOp : Loop_Op<"for",
52
52
53
53
The body region must contain exactly one block that terminates with
54
54
"loop.yield". Calling ForOp::build will create such a region and insert
55
- the terminator implicitly if none is defined, so will the parsing even
55
+ the terminator implicitly if none is defined, so will the parsing even
56
56
in cases when it is absent from the custom format. For example:
57
57
58
58
```mlir
@@ -62,17 +62,17 @@ def ForOp : Loop_Op<"for",
62
62
```
63
63
64
64
"loop.for" can also operate on loop-carried variables and returns the final values
65
- after loop termination. The initial values of the variables are passed as additional SSA
65
+ after loop termination. The initial values of the variables are passed as additional SSA
66
66
operands to the "loop.for" following the 3 loop control SSA values mentioned above
67
- (lower bound, upper bound and step). The operation region has equivalent arguments
67
+ (lower bound, upper bound and step). The operation region has equivalent arguments
68
68
for each variable representing the value of the variable at the current iteration.
69
-
70
- The region must terminate with a "loop.yield" that passes all the current iteration
69
+
70
+ The region must terminate with a "loop.yield" that passes all the current iteration
71
71
variables to the next iteration, or to the "loop.for" result, if at the last iteration.
72
- "loop.for" results hold the final values after the last iteration.
73
-
72
+ "loop.for" results hold the final values after the last iteration.
73
+
74
74
For example, to sum-reduce a memref:
75
-
75
+
76
76
```mlir
77
77
func @reduce(%buffer: memref<1024xf32>, %lb: index, %ub: index, %step: index) -> (f32) {
78
78
// Initial sum set to 0.
@@ -85,14 +85,14 @@ def ForOp : Loop_Op<"for",
85
85
loop.yield %sum_next : f32
86
86
}
87
87
return %sum : f32
88
- }
88
+ }
89
89
```
90
90
91
- If the "loop.for" defines any values, a yield must be explicitly present.
92
- The number and types of the "loop.for" results must match the initial values
91
+ If the "loop.for" defines any values, a yield must be explicitly present.
92
+ The number and types of the "loop.for" results must match the initial values
93
93
in the "iter_args" binding and the yield operands.
94
-
95
- Another example with a nested "loop.if" (see "loop.if" for details)
94
+
95
+ Another example with a nested "loop.if" (see "loop.if" for details)
96
96
to perform conditional reduction:
97
97
98
98
```mlir
@@ -118,7 +118,7 @@ def ForOp : Loop_Op<"for",
118
118
Index:$upperBound,
119
119
Index:$step,
120
120
Variadic<AnyType>:$initArgs);
121
- let results = (outs Variadic<AnyType>:$results);
121
+ let results = (outs Variadic<AnyType>:$results);
122
122
let regions = (region SizedRegion<1>:$region);
123
123
124
124
let skipDefaultBuilders = 1;
@@ -143,15 +143,15 @@ def ForOp : Loop_Op<"for",
143
143
void setLowerBound(Value bound) { getOperation()->setOperand(0, bound); }
144
144
void setUpperBound(Value bound) { getOperation()->setOperand(1, bound); }
145
145
void setStep(Value step) { getOperation()->setOperand(2, step); }
146
-
146
+
147
147
/// Number of region arguments for loop-carried values
148
148
unsigned getNumRegionIterArgs() {
149
- return getBody()->getNumArguments() - 1;
149
+ return getBody()->getNumArguments() - 1;
150
150
}
151
151
/// Number of operands controlling the loop: lb, ub, step
152
152
unsigned getNumControlOperands() { return 3; }
153
153
/// Does the operation hold operands for loop-carried values
154
- bool hasIterOperands() {
154
+ bool hasIterOperands() {
155
155
return getOperation()->getNumOperands() > getNumControlOperands();
156
156
}
157
157
/// Get Number of loop-carried values
@@ -178,16 +178,16 @@ def IfOp : Loop_Op<"if",
178
178
```
179
179
180
180
"loop.if" may also return results that are defined in its regions. The values
181
- defined are determined by which execution path is taken.
181
+ defined are determined by which execution path is taken.
182
182
For example:
183
183
```mlir
184
184
%x, %y = loop.if %b -> (f32, f32) {
185
185
%x_true = ...
186
186
%y_true = ...
187
187
loop.yield %x_true, %y_true : f32, f32
188
188
} else {
189
- %x_false = ...
190
- %y_false = ...
189
+ %x_false = ...
190
+ %y_false = ...
191
191
loop.yield %x_false, %y_false : f32, f32
192
192
}
193
193
```
@@ -196,7 +196,7 @@ def IfOp : Loop_Op<"if",
196
196
defines no values, the "loop.yield" can be left out, and will be
197
197
inserted implicitly. Otherwise, it must be explicit.
198
198
Also, if "loop.if" defines one or more values, the 'else' block cannot
199
- be omitted.
199
+ be omitted.
200
200
201
201
For example:
202
202
```mlir
@@ -230,18 +230,20 @@ def IfOp : Loop_Op<"if",
230
230
}
231
231
232
232
def ParallelOp : Loop_Op<"parallel",
233
- [SameVariadicOperandSize , SingleBlockImplicitTerminator<"YieldOp">]> {
233
+ [AttrSizedOperandSegments , SingleBlockImplicitTerminator<"YieldOp">]> {
234
234
let summary = "parallel for operation";
235
235
let description = [{
236
- The "loop.parallel" operation represents a loop nest taking 3 groups of SSA
237
- values as operands that represent the lower bounds, upper bounds and steps,
238
- respectively. The operation defines a variadic number of SSA values for its
239
- induction variables. It has one region capturing the loop body. The
240
- induction variables are represented as an argument of this region. These SSA
241
- values always have type index, which is the size of the machine word. The
242
- steps are values of type index, required to be positive.
243
- The lower and upper bounds specify a half-open range: the range includes the
244
- lower bound but does not include the upper bound.
236
+ The "loop.parallel" operation represents a loop nest taking 4 groups of SSA
237
+ values as operands that represent the lower bounds, upper bounds, steps and
238
+ initial values, respectively. The operation defines a variadic number of
239
+ SSA values for its induction variables. It has one region capturing the
240
+ loop body. The induction variables are represented as an argument of this
241
+ region. These SSA values always have type index, which is the size of the
242
+ machine word. The steps are values of type index, required to be positive.
243
+ The lower and upper bounds specify a half-open range: the range includes
244
+ the lower bound but does not include the upper bound. The initial values
245
+ have the same types as results of "loop.parallel". If there are no results,
246
+ the keyword `init` can be omitted.
245
247
246
248
Semantically we require that the iteration space can be iterated in any
247
249
order, and the loop body can be executed in parallel. If there are data
@@ -250,10 +252,11 @@ def ParallelOp : Loop_Op<"parallel",
250
252
The parallel loop operation supports reduction of values produced by
251
253
individual iterations into a single result. This is modeled using the
252
254
loop.reduce operation (see loop.reduce for details). Each result of a
253
- loop.parallel operation is associated with a reduce operation that is an
254
- immediate child. Reduces are matched to result values in order of their
255
- appearance in the body. Consequently, we require that the body region has
256
- the same number of results as it has reduce operations.
255
+ loop.parallel operation is associated with an initial value operand and
256
+ reduce operation that is an immediate child. Reductions are matched to result
257
+ and initial values in order of their appearance in the body. Consequently,
258
+ we require that the body region has the same number of results and initial
259
+ values as it has reduce operations.
257
260
258
261
The body region must contain exactly one block that terminates with
259
262
"loop.yield" without operands. Parsing ParallelOp will create such a region
@@ -273,18 +276,16 @@ def ParallelOp : Loop_Op<"parallel",
273
276
274
277
let arguments = (ins Variadic<Index>:$lowerBound,
275
278
Variadic<Index>:$upperBound,
276
- Variadic<Index>:$step);
279
+ Variadic<Index>:$step,
280
+ Variadic<AnyType>:$initVals);
277
281
let results = (outs Variadic<AnyType>:$results);
278
282
let regions = (region SizedRegion<1>:$region);
279
283
280
284
let skipDefaultBuilders = 1;
281
285
let builders = [
282
286
OpBuilder<"Builder *builder, OperationState &result, "
283
287
"ValueRange lowerBounds, ValueRange upperBounds, "
284
- "ValueRange steps">,
285
- OpBuilder<"Builder *builder, OperationState &result, "
286
- "ValueRange lowerBounds, ValueRange upperBounds, "
287
- "ValueRange steps, ArrayRef<Type> resultTypes">
288
+ "ValueRange steps, ValueRange initVals = {}">,
288
289
];
289
290
290
291
let extraClassDeclaration = [{
@@ -293,9 +294,10 @@ def ParallelOp : Loop_Op<"parallel",
293
294
return getBody()->getNumArguments();
294
295
}
295
296
iterator_range<Block::args_iterator> getInductionVars() {
296
- return { getBody()->args_begin(), getBody()->args_end()} ;
297
+ return getBody()->getArguments() ;
297
298
}
298
299
unsigned getNumLoops() { return step().size(); }
300
+ unsigned getNumReductions() { return initVals().size(); }
299
301
}];
300
302
}
301
303
@@ -369,13 +371,13 @@ def YieldOp : Loop_Op<"yield", [Terminator]> {
369
371
let description = [{
370
372
"loop.yield" yields an SSA value from a loop dialect op region and
371
373
terminates the regions. The semantics of how the values are yielded
372
- is defined by the parent operation.
374
+ is defined by the parent operation.
373
375
If "loop.yield" has any operands, the operands must match the parent
374
- operation's results.
375
- If the parent operation defines no values, then the "loop.yield" may be
376
+ operation's results.
377
+ If the parent operation defines no values, then the "loop.yield" may be
376
378
left out in the custom syntax and the builders will insert one implicitly.
377
379
Otherwise, it has to be present in the syntax to indicate which values
378
- are yielded.
380
+ are yielded.
379
381
}];
380
382
381
383
let arguments = (ins Variadic<AnyType>:$results);
0 commit comments