17
17
include "mlir/IR/OpBase.td"
18
18
include "mlir/Interfaces/SideEffectInterfaces.td"
19
19
include "mlir/Interfaces/ControlFlowInterfaces.td"
20
- include "mlir/Dialect/LLVMIR/LLVMOpBase .td"
20
+ include "mlir/IR/SymbolInterfaces .td"
21
21
include "mlir/Dialect/OpenMP/OmpCommon.td"
22
+ include "mlir/Dialect/LLVMIR/LLVMOpBase.td"
22
23
23
24
def OpenMP_Dialect : Dialect {
24
25
let name = "omp";
25
26
let cppNamespace = "::mlir::omp";
27
+ let dependentDialects = ["::mlir::LLVM::LLVMDialect"];
26
28
}
27
29
28
30
class OpenMP_Op<string mnemonic, list<OpTrait> traits = []> :
@@ -31,6 +33,27 @@ class OpenMP_Op<string mnemonic, list<OpTrait> traits = []> :
31
33
// Type which can be constraint accepting standard integers and indices.
32
34
def IntLikeType : AnyTypeOf<[AnyInteger, Index]>;
33
35
36
+ def OpenMP_PointerLikeTypeInterface : TypeInterface<"PointerLikeType"> {
37
+ let cppNamespace = "::mlir::omp";
38
+
39
+ let description = [{
40
+ An interface for pointer-like types suitable to contain a value that OpenMP
41
+ specification refers to as variable.
42
+ }];
43
+
44
+ let methods = [
45
+ InterfaceMethod<
46
+ /*description=*/"Returns the pointee type.",
47
+ /*retTy=*/"::mlir::Type",
48
+ /*methodName=*/"getElementType"
49
+ >,
50
+ ];
51
+ }
52
+
53
+ def OpenMP_PointerLikeType : Type<
54
+ CPred<"$_self.isa<::mlir::omp::PointerLikeType>()">,
55
+ "OpenMP-compatible variable type", "::mlir::omp::PointerLikeType">;
56
+
34
57
//===----------------------------------------------------------------------===//
35
58
// 2.6 parallel Construct
36
59
//===----------------------------------------------------------------------===//
@@ -146,6 +169,18 @@ def WsLoopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments,
146
169
that the `linear_vars` and `linear_step_vars` variadic lists should contain
147
170
the same number of elements.
148
171
172
+ Reductions can be performed in a workshare loop by specifying reduction
173
+ accumulator variables in `reduction_vars` and symbols referring to reduction
174
+ declarations in the `reductions` attribute. Each reduction is identified
175
+ by the accumulator it uses and accumulators must not be repeated in the same
176
+ reduction. The `omp.reduction` operation accepts the accumulator and a
177
+ partial value which is considered to be produced by the current loop
178
+ iteration for the given reduction. If multiple values are produced for the
179
+ same accumulator, i.e. there are multiple `omp.reduction`s, the last value
180
+ is taken. The reduction declaration specifies how to combine the values from
181
+ each iteration into the final value, which is available in the accumulator
182
+ after the loop completes.
183
+
149
184
The optional `schedule_val` attribute specifies the loop schedule for this
150
185
loop, determining how the loop is distributed across the parallel threads.
151
186
The optional `schedule_chunk_var` associated with this determines further
@@ -173,6 +208,9 @@ def WsLoopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments,
173
208
Variadic<AnyType>:$lastprivate_vars,
174
209
Variadic<AnyType>:$linear_vars,
175
210
Variadic<AnyType>:$linear_step_vars,
211
+ Variadic<OpenMP_PointerLikeType>:$reduction_vars,
212
+ OptionalAttr<TypedArrayAttrBase<SymbolRefAttr,
213
+ "array of symbol references">>:$reductions,
176
214
OptionalAttr<ScheduleKind>:$schedule_val,
177
215
Optional<AnyType>:$schedule_chunk_var,
178
216
Confined<OptionalAttr<I64Attr>, [IntMinValue<0>]>:$collapse_val,
@@ -191,11 +229,11 @@ def WsLoopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments,
191
229
"ValueRange":$upperBound, "ValueRange":$step,
192
230
"ValueRange":$privateVars, "ValueRange":$firstprivateVars,
193
231
"ValueRange":$lastprivate_vars, "ValueRange":$linear_vars,
194
- "ValueRange":$linear_step_vars, "StringAttr ":$schedule_val ,
195
- "Value ":$schedule_chunk_var , "IntegerAttr ":$collapse_val ,
196
- "UnitAttr ":$nowait , "IntegerAttr ":$ordered_val ,
197
- "StringAttr ":$order_val , "UnitAttr ":$inclusive, CArg<"bool" ,
198
- "true">:$buildBody)>,
232
+ "ValueRange":$linear_step_vars, "ValueRange ":$reduction_vars ,
233
+ "StringAttr ":$schedule_val , "Value ":$schedule_chunk_var ,
234
+ "IntegerAttr ":$collapse_val , "UnitAttr ":$nowait ,
235
+ "IntegerAttr ":$ordered_val , "StringAttr ":$order_val ,
236
+ "UnitAttr":$inclusive, CArg<"bool", " true">:$buildBody)>,
199
237
OpBuilder<(ins "TypeRange":$resultTypes, "ValueRange":$operands,
200
238
CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes)>
201
239
];
@@ -205,13 +243,18 @@ def WsLoopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments,
205
243
let extraClassDeclaration = [{
206
244
/// Returns the number of loops in the workshape loop nest.
207
245
unsigned getNumLoops() { return lowerBound().size(); }
246
+
247
+ /// Returns the number of reduction variables.
248
+ unsigned getNumReductionVars() { return reduction_vars().size(); }
208
249
}];
209
250
let parser = [{ return parseWsLoopOp(parser, result); }];
210
251
let printer = [{ return printWsLoopOp(p, *this); }];
252
+ let verifier = [{ return ::verifyWsLoopOp(*this); }];
211
253
}
212
254
213
- def YieldOp : OpenMP_Op<"yield", [NoSideEffect, ReturnLike, Terminator,
214
- HasParent<"WsLoopOp">]> {
255
+ def YieldOp : OpenMP_Op<"yield",
256
+ [NoSideEffect, ReturnLike, Terminator,
257
+ ParentOneOf<["WsLoopOp", "ReductionDeclareOp"]>]> {
215
258
let summary = "loop yield and termination operation";
216
259
let description = [{
217
260
"omp.yield" yields SSA values from the OpenMP dialect op region and
@@ -334,4 +377,78 @@ def TaskwaitOp : OpenMP_Op<"taskwait"> {
334
377
let assemblyFormat = "attr-dict";
335
378
}
336
379
380
+ //===----------------------------------------------------------------------===//
381
+ // 2.19.5.7 declare reduction Directive
382
+ //===----------------------------------------------------------------------===//
383
+
384
+ def ReductionDeclareOp : OpenMP_Op<"reduction.declare", [Symbol]> {
385
+ let summary = "declares a reduction kind";
386
+
387
+ let description = [{
388
+ Declares an OpenMP reduction kind. This requires two mandatory and one
389
+ optional region.
390
+
391
+ 1. The initializer region specifies how to initialize the thread-local
392
+ reduction value. This is usually the neutral element of the reduction.
393
+ For convenience, the region has an argument that contains the value
394
+ of the reduction accumulator at the start of the reduction. It is
395
+ expected to `omp.yield` the new value on all control flow paths.
396
+ 2. The reduction region specifies how to combine two values into one, i.e.
397
+ the reduction operator. It accepts the two values as arguments and is
398
+ expected to `omp.yield` the combined value on all control flow paths.
399
+ 3. The atomic reduction region is optional and specifies how two values
400
+ can be combined atomically given local accumulator variables. It is
401
+ expected to store the combined value in the first accumulator variable.
402
+
403
+ Note that the MLIR type system does not allow for type-polymorphic
404
+ reductions. Separate reduction declarations should be created for different
405
+ element and accumulator types.
406
+ }];
407
+
408
+ let arguments = (ins SymbolNameAttr:$sym_name,
409
+ TypeAttr:$type);
410
+
411
+ let regions = (region AnyRegion:$initializerRegion,
412
+ AnyRegion:$reductionRegion,
413
+ AnyRegion:$atomicReductionRegion);
414
+ let verifier = "return ::verifyReductionDeclareOp(*this);";
415
+
416
+ let assemblyFormat = "$sym_name `:` $type attr-dict-with-keyword "
417
+ "`init` $initializerRegion "
418
+ "`combiner` $reductionRegion "
419
+ "custom<AtomicReductionRegion>($atomicReductionRegion)";
420
+
421
+ let extraClassDeclaration = [{
422
+ PointerLikeType getAccumulatorType() {
423
+ if (atomicReductionRegion().empty())
424
+ return {};
425
+
426
+ return atomicReductionRegion().front().getArgument(0).getType();
427
+ }
428
+ }];
429
+ }
430
+
431
+ //===----------------------------------------------------------------------===//
432
+ // 2.19.5.4 reduction clause
433
+ //===----------------------------------------------------------------------===//
434
+
435
+ def ReductionOp : OpenMP_Op<"reduction", [
436
+ TypesMatchWith<"value types matches accumulator element type",
437
+ "accumulator", "operand",
438
+ "$_self.cast<::mlir::omp::PointerLikeType>().getElementType()">
439
+ ]> {
440
+ let summary = "reduction construct";
441
+ let description = [{
442
+ Indicates the value that is produced by the current reduction-participating
443
+ entity for a reduction requested in some ancestor. The reduction is
444
+ identified by the accumulator, but the value of the accumulator may not be
445
+ updated immediately.
446
+ }];
447
+
448
+ let arguments= (ins AnyType:$operand, OpenMP_PointerLikeType:$accumulator);
449
+ let assemblyFormat =
450
+ "$operand `,` $accumulator attr-dict `:` type($accumulator)";
451
+ let verifier = "return ::verifyReductionOp(*this);";
452
+ }
453
+
337
454
#endif // OPENMP_OPS
0 commit comments