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
22
include "mlir/Dialect/OpenMP/OpenMPOpsInterfaces.td"
23
+ include "mlir/Dialect/LLVMIR/LLVMOpBase.td"
23
24
24
25
def OpenMP_Dialect : Dialect {
25
26
let name = "omp";
26
27
let cppNamespace = "::mlir::omp";
28
+ let dependentDialects = ["::mlir::LLVM::LLVMDialect"];
27
29
}
28
30
29
31
class OpenMP_Op<string mnemonic, list<OpTrait> traits = []> :
@@ -33,6 +35,27 @@ class OpenMP_Op<string mnemonic, list<OpTrait> traits = []> :
33
35
// LLVM integer types.
34
36
def IntLikeType : AnyTypeOf<[AnyInteger, Index, LLVM_AnyInteger]>;
35
37
38
+ def OpenMP_PointerLikeTypeInterface : TypeInterface<"PointerLikeType"> {
39
+ let cppNamespace = "::mlir::omp";
40
+
41
+ let description = [{
42
+ An interface for pointer-like types suitable to contain a value that OpenMP
43
+ specification refers to as variable.
44
+ }];
45
+
46
+ let methods = [
47
+ InterfaceMethod<
48
+ /*description=*/"Returns the pointee type.",
49
+ /*retTy=*/"::mlir::Type",
50
+ /*methodName=*/"getElementType"
51
+ >,
52
+ ];
53
+ }
54
+
55
+ def OpenMP_PointerLikeType : Type<
56
+ CPred<"$_self.isa<::mlir::omp::PointerLikeType>()">,
57
+ "OpenMP-compatible variable type", "::mlir::omp::PointerLikeType">;
58
+
36
59
//===----------------------------------------------------------------------===//
37
60
// 2.6 parallel Construct
38
61
//===----------------------------------------------------------------------===//
@@ -163,6 +186,18 @@ def WsLoopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments,
163
186
that the `linear_vars` and `linear_step_vars` variadic lists should contain
164
187
the same number of elements.
165
188
189
+ Reductions can be performed in a workshare loop by specifying reduction
190
+ accumulator variables in `reduction_vars` and symbols referring to reduction
191
+ declarations in the `reductions` attribute. Each reduction is identified
192
+ by the accumulator it uses and accumulators must not be repeated in the same
193
+ reduction. The `omp.reduction` operation accepts the accumulator and a
194
+ partial value which is considered to be produced by the current loop
195
+ iteration for the given reduction. If multiple values are produced for the
196
+ same accumulator, i.e. there are multiple `omp.reduction`s, the last value
197
+ is taken. The reduction declaration specifies how to combine the values from
198
+ each iteration into the final value, which is available in the accumulator
199
+ after the loop completes.
200
+
166
201
The optional `schedule_val` attribute specifies the loop schedule for this
167
202
loop, determining how the loop is distributed across the parallel threads.
168
203
The optional `schedule_chunk_var` associated with this determines further
@@ -190,6 +225,9 @@ def WsLoopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments,
190
225
Variadic<AnyType>:$lastprivate_vars,
191
226
Variadic<AnyType>:$linear_vars,
192
227
Variadic<AnyType>:$linear_step_vars,
228
+ Variadic<OpenMP_PointerLikeType>:$reduction_vars,
229
+ OptionalAttr<TypedArrayAttrBase<SymbolRefAttr,
230
+ "array of symbol references">>:$reductions,
193
231
OptionalAttr<ScheduleKind>:$schedule_val,
194
232
Optional<AnyType>:$schedule_chunk_var,
195
233
OptionalAttr<ScheduleModifier>:$schedule_modifiers,
@@ -210,11 +248,11 @@ def WsLoopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments,
210
248
"ValueRange":$upperBound, "ValueRange":$step,
211
249
"ValueRange":$privateVars, "ValueRange":$firstprivateVars,
212
250
"ValueRange":$lastprivate_vars, "ValueRange":$linear_vars,
213
- "ValueRange":$linear_step_vars, "StringAttr ":$schedule_val ,
214
- "Value ":$schedule_chunk_var , "IntegerAttr ":$collapse_val ,
215
- "UnitAttr ":$nowait , "IntegerAttr ":$ordered_val ,
216
- "StringAttr ":$order_val , "UnitAttr ":$inclusive, CArg<"bool" ,
217
- "true">:$buildBody)>,
251
+ "ValueRange":$linear_step_vars, "ValueRange ":$reduction_vars ,
252
+ "StringAttr ":$schedule_val , "Value ":$schedule_chunk_var ,
253
+ "IntegerAttr ":$collapse_val , "UnitAttr ":$nowait ,
254
+ "IntegerAttr ":$ordered_val , "StringAttr ":$order_val ,
255
+ "UnitAttr":$inclusive, CArg<"bool", " true">:$buildBody)>,
218
256
OpBuilder<(ins "TypeRange":$resultTypes, "ValueRange":$operands,
219
257
CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes)>
220
258
];
@@ -224,13 +262,18 @@ def WsLoopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments,
224
262
let extraClassDeclaration = [{
225
263
/// Returns the number of loops in the workshape loop nest.
226
264
unsigned getNumLoops() { return lowerBound().size(); }
265
+
266
+ /// Returns the number of reduction variables.
267
+ unsigned getNumReductionVars() { return reduction_vars().size(); }
227
268
}];
228
269
let parser = [{ return parseWsLoopOp(parser, result); }];
229
270
let printer = [{ return printWsLoopOp(p, *this); }];
271
+ let verifier = [{ return ::verifyWsLoopOp(*this); }];
230
272
}
231
273
232
- def YieldOp : OpenMP_Op<"yield", [NoSideEffect, ReturnLike, Terminator,
233
- HasParent<"WsLoopOp">]> {
274
+ def YieldOp : OpenMP_Op<"yield",
275
+ [NoSideEffect, ReturnLike, Terminator,
276
+ ParentOneOf<["WsLoopOp", "ReductionDeclareOp"]>]> {
234
277
let summary = "loop yield and termination operation";
235
278
let description = [{
236
279
"omp.yield" yields SSA values from the OpenMP dialect op region and
@@ -319,4 +362,78 @@ def TaskwaitOp : OpenMP_Op<"taskwait"> {
319
362
let assemblyFormat = "attr-dict";
320
363
}
321
364
365
+ //===----------------------------------------------------------------------===//
366
+ // 2.19.5.7 declare reduction Directive
367
+ //===----------------------------------------------------------------------===//
368
+
369
+ def ReductionDeclareOp : OpenMP_Op<"reduction.declare", [Symbol]> {
370
+ let summary = "declares a reduction kind";
371
+
372
+ let description = [{
373
+ Declares an OpenMP reduction kind. This requires two mandatory and one
374
+ optional region.
375
+
376
+ 1. The initializer region specifies how to initialize the thread-local
377
+ reduction value. This is usually the neutral element of the reduction.
378
+ For convenience, the region has an argument that contains the value
379
+ of the reduction accumulator at the start of the reduction. It is
380
+ expected to `omp.yield` the new value on all control flow paths.
381
+ 2. The reduction region specifies how to combine two values into one, i.e.
382
+ the reduction operator. It accepts the two values as arguments and is
383
+ expected to `omp.yield` the combined value on all control flow paths.
384
+ 3. The atomic reduction region is optional and specifies how two values
385
+ can be combined atomically given local accumulator variables. It is
386
+ expected to store the combined value in the first accumulator variable.
387
+
388
+ Note that the MLIR type system does not allow for type-polymorphic
389
+ reductions. Separate reduction declarations should be created for different
390
+ element and accumulator types.
391
+ }];
392
+
393
+ let arguments = (ins SymbolNameAttr:$sym_name,
394
+ TypeAttr:$type);
395
+
396
+ let regions = (region AnyRegion:$initializerRegion,
397
+ AnyRegion:$reductionRegion,
398
+ AnyRegion:$atomicReductionRegion);
399
+ let verifier = "return ::verifyReductionDeclareOp(*this);";
400
+
401
+ let assemblyFormat = "$sym_name `:` $type attr-dict-with-keyword "
402
+ "`init` $initializerRegion "
403
+ "`combiner` $reductionRegion "
404
+ "custom<AtomicReductionRegion>($atomicReductionRegion)";
405
+
406
+ let extraClassDeclaration = [{
407
+ PointerLikeType getAccumulatorType() {
408
+ if (atomicReductionRegion().empty())
409
+ return {};
410
+
411
+ return atomicReductionRegion().front().getArgument(0).getType();
412
+ }
413
+ }];
414
+ }
415
+
416
+ //===----------------------------------------------------------------------===//
417
+ // 2.19.5.4 reduction clause
418
+ //===----------------------------------------------------------------------===//
419
+
420
+ def ReductionOp : OpenMP_Op<"reduction", [
421
+ TypesMatchWith<"value types matches accumulator element type",
422
+ "accumulator", "operand",
423
+ "$_self.cast<::mlir::omp::PointerLikeType>().getElementType()">
424
+ ]> {
425
+ let summary = "reduction construct";
426
+ let description = [{
427
+ Indicates the value that is produced by the current reduction-participating
428
+ entity for a reduction requested in some ancestor. The reduction is
429
+ identified by the accumulator, but the value of the accumulator may not be
430
+ updated immediately.
431
+ }];
432
+
433
+ let arguments= (ins AnyType:$operand, OpenMP_PointerLikeType:$accumulator);
434
+ let assemblyFormat =
435
+ "$operand `,` $accumulator attr-dict `:` type($accumulator)";
436
+ let verifier = "return ::verifyReductionOp(*this);";
437
+ }
438
+
322
439
#endif // OPENMP_OPS
0 commit comments