Skip to content

Commit 713ca6b

Browse files
ftynsekiranchandramohan
authored andcommitted
[mlir] add support for reductions in OpenMP WsLoopOp
Use a modeling similar to SCF ParallelOp to support arbitrary parallel reductions. The two main differences are: (1) reductions are named and declared beforehand similarly to functions using a special op that provides the neutral element, the reduction code and optionally the atomic reduction code; (2) reductions go through memory instead because this is closer to the OpenMP semantics. See https://llvm.discourse.group/t/rfc-openmp-reduction-support/3367. Reviewed By: kiranchandramohan Differential Revision: https://reviews.llvm.org/D105358
1 parent e0c2e79 commit 713ca6b

File tree

10 files changed

+624
-29
lines changed

10 files changed

+624
-29
lines changed

flang/lib/Lower/OpenMP.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
423423
auto currentLocation = converter.getCurrentLocation();
424424
SmallVector<Value, 4> lowerBound, upperBound, step, privateClauseOperands,
425425
firstPrivateClauseOperands, lastPrivateClauseOperands, linearVars,
426-
linearStepVars;
426+
linearStepVars, reductionVars;
427427
mlir::Value scheduleChunkClauseOperand;
428428
mlir::Attribute scheduleClauseOperand, collapseClauseOperand,
429429
noWaitClauseOperand, orderedClauseOperand, orderClauseOperand;
@@ -514,7 +514,7 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
514514
auto wsLoopOp = firOpBuilder.create<mlir::omp::WsLoopOp>(
515515
currentLocation, resultType, lowerBound, upperBound, step,
516516
privateClauseOperands, firstPrivateClauseOperands,
517-
lastPrivateClauseOperands, linearVars, linearStepVars,
517+
lastPrivateClauseOperands, linearVars, linearStepVars, reductionVars,
518518
scheduleClauseOperand.dyn_cast_or_null<StringAttr>(),
519519
scheduleChunkClauseOperand,
520520
collapseClauseOperand.dyn_cast_or_null<IntegerAttr>(),

mlir/include/mlir/Dialect/OpenMP/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ mlir_tablegen(OpenMPOps.h.inc -gen-op-decls)
88
mlir_tablegen(OpenMPOps.cpp.inc -gen-op-defs)
99
mlir_tablegen(OpenMPOpsEnums.h.inc -gen-enum-decls)
1010
mlir_tablegen(OpenMPOpsEnums.cpp.inc -gen-enum-defs)
11+
mlir_tablegen(OpenMPTypeInterfaces.h.inc -gen-type-interface-decls)
12+
mlir_tablegen(OpenMPTypeInterfaces.cpp.inc -gen-type-interface-defs)
1113
add_mlir_doc(OpenMPOps OpenMPDialect Dialects/ -gen-dialect-doc)
1214
add_public_tablegen_target(MLIROpenMPOpsIncGen)
1315
add_dependencies(OpenMPDialectDocGen omp_common_td)

mlir/include/mlir/Dialect/OpenMP/OpenMPDialect.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,17 @@
1313
#ifndef MLIR_DIALECT_OPENMP_OPENMPDIALECT_H_
1414
#define MLIR_DIALECT_OPENMP_OPENMPDIALECT_H_
1515

16-
#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
16+
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
1717
#include "mlir/IR/Dialect.h"
1818
#include "mlir/IR/OpDefinition.h"
19+
#include "mlir/IR/SymbolTable.h"
1920
#include "mlir/Interfaces/ControlFlowInterfaces.h"
2021
#include "mlir/Interfaces/SideEffectInterfaces.h"
2122

2223
#include "mlir/Dialect/OpenMP/OpenMPOpsDialect.h.inc"
2324
#include "mlir/Dialect/OpenMP/OpenMPOpsEnums.h.inc"
2425
#include "mlir/Dialect/OpenMP/OpenMPOpsInterfaces.h.inc"
26+
#include "mlir/Dialect/OpenMP/OpenMPTypeInterfaces.h.inc"
2527

2628
#define GET_OP_CLASSES
2729
#include "mlir/Dialect/OpenMP/OpenMPOps.h.inc"

mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td

Lines changed: 125 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@
1717
include "mlir/IR/OpBase.td"
1818
include "mlir/Interfaces/SideEffectInterfaces.td"
1919
include "mlir/Interfaces/ControlFlowInterfaces.td"
20-
include "mlir/Dialect/LLVMIR/LLVMOpBase.td"
20+
include "mlir/IR/SymbolInterfaces.td"
2121
include "mlir/Dialect/OpenMP/OmpCommon.td"
2222
include "mlir/Dialect/OpenMP/OpenMPOpsInterfaces.td"
23+
include "mlir/Dialect/LLVMIR/LLVMOpBase.td"
2324

2425
def OpenMP_Dialect : Dialect {
2526
let name = "omp";
2627
let cppNamespace = "::mlir::omp";
28+
let dependentDialects = ["::mlir::LLVM::LLVMDialect"];
2729
}
2830

2931
class OpenMP_Op<string mnemonic, list<OpTrait> traits = []> :
@@ -33,6 +35,27 @@ class OpenMP_Op<string mnemonic, list<OpTrait> traits = []> :
3335
// LLVM integer types.
3436
def IntLikeType : AnyTypeOf<[AnyInteger, Index, LLVM_AnyInteger]>;
3537

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+
3659
//===----------------------------------------------------------------------===//
3760
// 2.6 parallel Construct
3861
//===----------------------------------------------------------------------===//
@@ -163,6 +186,18 @@ def WsLoopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments,
163186
that the `linear_vars` and `linear_step_vars` variadic lists should contain
164187
the same number of elements.
165188

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+
166201
The optional `schedule_val` attribute specifies the loop schedule for this
167202
loop, determining how the loop is distributed across the parallel threads.
168203
The optional `schedule_chunk_var` associated with this determines further
@@ -190,6 +225,9 @@ def WsLoopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments,
190225
Variadic<AnyType>:$lastprivate_vars,
191226
Variadic<AnyType>:$linear_vars,
192227
Variadic<AnyType>:$linear_step_vars,
228+
Variadic<OpenMP_PointerLikeType>:$reduction_vars,
229+
OptionalAttr<TypedArrayAttrBase<SymbolRefAttr,
230+
"array of symbol references">>:$reductions,
193231
OptionalAttr<ScheduleKind>:$schedule_val,
194232
Optional<AnyType>:$schedule_chunk_var,
195233
OptionalAttr<ScheduleModifier>:$schedule_modifiers,
@@ -210,11 +248,11 @@ def WsLoopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments,
210248
"ValueRange":$upperBound, "ValueRange":$step,
211249
"ValueRange":$privateVars, "ValueRange":$firstprivateVars,
212250
"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)>,
218256
OpBuilder<(ins "TypeRange":$resultTypes, "ValueRange":$operands,
219257
CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes)>
220258
];
@@ -224,13 +262,18 @@ def WsLoopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments,
224262
let extraClassDeclaration = [{
225263
/// Returns the number of loops in the workshape loop nest.
226264
unsigned getNumLoops() { return lowerBound().size(); }
265+
266+
/// Returns the number of reduction variables.
267+
unsigned getNumReductionVars() { return reduction_vars().size(); }
227268
}];
228269
let parser = [{ return parseWsLoopOp(parser, result); }];
229270
let printer = [{ return printWsLoopOp(p, *this); }];
271+
let verifier = [{ return ::verifyWsLoopOp(*this); }];
230272
}
231273

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"]>]> {
234277
let summary = "loop yield and termination operation";
235278
let description = [{
236279
"omp.yield" yields SSA values from the OpenMP dialect op region and
@@ -319,4 +362,78 @@ def TaskwaitOp : OpenMP_Op<"taskwait"> {
319362
let assemblyFormat = "attr-dict";
320363
}
321364

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+
322439
#endif // OPENMP_OPS

mlir/lib/Dialect/OpenMP/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ add_mlir_dialect_library(MLIROpenMP
1010

1111
LINK_LIBS PUBLIC
1212
MLIRIR
13+
MLIRLLVMIR
1314
)

0 commit comments

Comments
 (0)