[Mlir-commits] [mlir] 19a7e47 - [MLIR][OpenMP] Added omp.sections and omp.section
Shraiysh Vaishay
llvmlistbot at llvm.org
Sat Nov 6 06:57:44 PDT 2021
Author: Shraiysh Vaishay
Date: 2021-11-06T19:27:35+05:30
New Revision: 19a7e4729da58a968e2e5fccfc6fff1ec4dc4a2d
URL: https://github.com/llvm/llvm-project/commit/19a7e4729da58a968e2e5fccfc6fff1ec4dc4a2d
DIFF: https://github.com/llvm/llvm-project/commit/19a7e4729da58a968e2e5fccfc6fff1ec4dc4a2d.diff
LOG: [MLIR][OpenMP] Added omp.sections and omp.section
Added omp.sections and omp.section operation according to the
section 2.8.1 of OpenMP Standard 5.0.
Reviewed By: kiranchandramohan
Differential Revision: https://reviews.llvm.org/D110844
Added:
Modified:
mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
mlir/test/Dialect/OpenMP/invalid.mlir
mlir/test/Dialect/OpenMP/ops.mlir
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
index ed04dc4ca395d..d552132b4d49e 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
@@ -148,6 +148,68 @@ def ScheduleModifier : StrEnumAttr<"ScheduleModifier", "OpenMP Schedule Modifier
let cppNamespace = "::mlir::omp";
}
+//===----------------------------------------------------------------------===//
+// 2.8.1 Sections Construct
+//===----------------------------------------------------------------------===//
+
+def SectionOp : OpenMP_Op<"section", [HasParent<"SectionsOp">]> {
+ let summary = "section directive";
+ let description = [{
+ A section operation encloses a region which represents one section in a
+ sections construct. A section op should always be surrounded by an
+ `omp.sections` operation.
+ }];
+ let regions = (region AnyRegion:$region);
+ let assemblyFormat = "$region attr-dict";
+}
+
+def SectionsOp : OpenMP_Op<"sections", [AttrSizedOperandSegments]> {
+ let summary = "sections construct";
+ let description = [{
+ The sections construct is a non-iterative worksharing construct that
+ contains `omp.section` operations. The `omp.section` operations are to be
+ distributed among and executed by the threads in a team. Each `omp.section`
+ is executed once by one of the threads in the team in the context of its
+ implicit task.
+
+ `private_vars`, `firstprivate_vars` and`lastprivate_vars` arguments are
+ variadic list of operands that specify the data sharing attributes of the
+ list of values. They are optional.
+
+ Reductions can be performed in a sections construct by specifying reduction
+ accumulator variables in `reduction_vars` and symbols referring to reduction
+ declarations in the `reductions` attribute. Each reduction is identified
+ by the accumulator it uses and accumulators must not be repeated in the same
+ reduction. The `omp.reduction` operation accepts the accumulator and a
+ partial value which is considered to be produced by the section for the
+ given reduction. If multiple values are produced for the same accumulator,
+ i.e. there are multiple `omp.reduction`s, the last value is taken. The
+ reduction declaration specifies how to combine the values from each section
+ into the final value, which is available in the accumulator after all the
+ sections complete.
+
+ The $allocators_vars and $allocate_vars parameters are a variadic list of values
+ that specify the memory allocator to be used to obtain storage for private values.
+
+ The `nowait` attribute, when present, signifies that there should be no
+ implicit barrier at the end of the construct.
+ }];
+ let arguments = (ins Variadic<AnyType>:$private_vars,
+ Variadic<AnyType>:$firstprivate_vars,
+ Variadic<AnyType>:$lastprivate_vars,
+ Variadic<OpenMP_PointerLikeType>:$reduction_vars,
+ OptionalAttr<SymbolRefArrayAttr>:$reductions,
+ Variadic<AnyType>:$allocate_vars,
+ Variadic<AnyType>:$allocators_vars,
+ UnitAttr:$nowait);
+
+ let regions = (region SizedRegion<1>:$region);
+
+ let parser = [{ return parseSectionsOp(parser, result); }];
+ let printer = [{ return printSectionsOp(p, *this); }];
+ let verifier = [{ return verifySectionsOp(*this); }];
+}
+
//===----------------------------------------------------------------------===//
// 2.9.2 Workshare Loop Construct
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
index e85a4b722aced..b24fb868dcd4b 100644
--- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
+++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
@@ -152,9 +152,6 @@ static ParseResult parseAllocateAndAllocator(
static void printAllocateAndAllocator(OpAsmPrinter &p,
OperandRange varsAllocate,
OperandRange varsAllocator) {
- if (varsAllocate.empty())
- return;
-
p << "allocate(";
for (unsigned i = 0; i < varsAllocate.size(); ++i) {
std::string separator = i == varsAllocate.size() - 1 ? ") " : ", ";
@@ -182,7 +179,9 @@ static void printParallelOp(OpAsmPrinter &p, ParallelOp op) {
printDataVars(p, op.firstprivate_vars(), "firstprivate");
printDataVars(p, op.shared_vars(), "shared");
printDataVars(p, op.copyin_vars(), "copyin");
- printAllocateAndAllocator(p, op.allocate_vars(), op.allocators_vars());
+
+ if (!op.allocate_vars().empty())
+ printAllocateAndAllocator(p, op.allocate_vars(), op.allocators_vars());
if (auto def = op.default_val())
p << "default(" << def->drop_front(3) << ") ";
@@ -231,7 +230,7 @@ parseLinearClause(OpAsmParser &parser,
static void printLinearClause(OpAsmPrinter &p, OperandRange linearVars,
OperandRange linearStepVars) {
size_t linearVarsSize = linearVars.size();
- p << "(";
+ p << "linear(";
for (unsigned i = 0; i < linearVarsSize; ++i) {
std::string separator = i == linearVarsSize - 1 ? ") " : ", ";
p << linearVars[i];
@@ -296,7 +295,7 @@ static void printScheduleClause(OpAsmPrinter &p, StringRef &sched,
llvm::Optional<StringRef> modifier,
Value scheduleChunkVar) {
std::string schedLower = sched.lower();
- p << "(" << schedLower;
+ p << "schedule(" << schedLower;
if (scheduleChunkVar)
p << " = " << scheduleChunkVar;
if (modifier && modifier.getValue() != "none")
@@ -333,6 +332,7 @@ parseReductionVarList(OpAsmParser &parser,
static void printReductionVarList(OpAsmPrinter &p,
Optional<ArrayAttr> reductions,
OperandRange reduction_vars) {
+ p << "reduction(";
for (unsigned i = 0, e = reductions->size(); i < e; ++i) {
if (i != 0)
p << ", ";
@@ -864,6 +864,83 @@ static ParseResult parseParallelOp(OpAsmParser &parser,
return success();
}
+//===----------------------------------------------------------------------===//
+// Parser, printer and verifier for SectionsOp
+//===----------------------------------------------------------------------===//
+
+/// Parses an OpenMP Sections operation
+///
+/// sections ::= `omp.sections` clause-list
+/// clause-list ::= clause clause-list | empty
+/// clause ::= private | firstprivate | lastprivate | reduction | allocate |
+/// nowait
+static ParseResult parseSectionsOp(OpAsmParser &parser,
+ OperationState &result) {
+
+ SmallVector<ClauseType> clauses = {privateClause, firstprivateClause,
+ lastprivateClause, reductionClause,
+ allocateClause, nowaitClause};
+
+ SmallVector<int> segments;
+
+ if (failed(parseClauses(parser, result, clauses, segments)))
+ return failure();
+
+ result.addAttribute("operand_segment_sizes",
+ parser.getBuilder().getI32VectorAttr(segments));
+
+ // Now parse the body.
+ Region *body = result.addRegion();
+ if (parser.parseRegion(*body))
+ return failure();
+ return success();
+}
+
+static void printSectionsOp(OpAsmPrinter &p, SectionsOp op) {
+ p << " ";
+ printDataVars(p, op.private_vars(), "private");
+ printDataVars(p, op.firstprivate_vars(), "firstprivate");
+ printDataVars(p, op.lastprivate_vars(), "lastprivate");
+
+ if (!op.reduction_vars().empty())
+ printReductionVarList(p, op.reductions(), op.reduction_vars());
+
+ if (!op.allocate_vars().empty())
+ printAllocateAndAllocator(p, op.allocate_vars(), op.allocators_vars());
+
+ if (op.nowait())
+ p << "nowait ";
+
+ p.printRegion(op.region());
+}
+
+static LogicalResult verifySectionsOp(SectionsOp op) {
+
+ // A list item may not appear in more than one clause on the same directive,
+ // except that it may be specified in both firstprivate and lastprivate
+ // clauses.
+ for (auto var : op.private_vars()) {
+ if (llvm::is_contained(op.firstprivate_vars(), var))
+ return op.emitOpError()
+ << "operand used in both private and firstprivate clauses";
+ if (llvm::is_contained(op.lastprivate_vars(), var))
+ return op.emitOpError()
+ << "operand used in both private and lastprivate clauses";
+ }
+
+ if (op.allocate_vars().size() != op.allocators_vars().size())
+ return op.emitError(
+ "expected equal sizes for allocate and allocator variables");
+
+ for (auto &inst : *op.region().begin()) {
+ if (!(isa<SectionOp>(inst) || isa<TerminatorOp>(inst)))
+ op.emitOpError()
+ << "expected omp.section op or terminator op inside region";
+ }
+
+ return verifyReductionVarList(op, op.reductions(), op.reduction_vars());
+}
+
/// Parses an OpenMP Workshare Loop operation
///
/// wsloop ::= `omp.wsloop` loop-control clause-list
@@ -944,16 +1021,12 @@ static void printWsLoopOp(OpAsmPrinter &p, WsLoopOp op) {
printDataVars(p, op.firstprivate_vars(), "firstprivate");
printDataVars(p, op.lastprivate_vars(), "lastprivate");
- if (op.linear_vars().size()) {
- p << "linear";
+ if (op.linear_vars().size())
printLinearClause(p, op.linear_vars(), op.linear_step_vars());
- }
- if (auto sched = op.schedule_val()) {
- p << "schedule";
+ if (auto sched = op.schedule_val())
printScheduleClause(p, sched.getValue(), op.schedule_modifier(),
op.schedule_chunk_var());
- }
if (auto collapse = op.collapse_val())
p << "collapse(" << collapse << ") ";
@@ -967,10 +1040,8 @@ static void printWsLoopOp(OpAsmPrinter &p, WsLoopOp op) {
if (auto order = op.order_val())
p << "order(" << order << ") ";
- if (!op.reduction_vars().empty()) {
- p << "reduction(";
+ if (!op.reduction_vars().empty())
printReductionVarList(p, op.reductions(), op.reduction_vars());
- }
p.printRegion(op.region(), /*printEntryBlockArgs=*/false);
}
diff --git a/mlir/test/Dialect/OpenMP/invalid.mlir b/mlir/test/Dialect/OpenMP/invalid.mlir
index 36eee320af555..d3a78857f6b41 100644
--- a/mlir/test/Dialect/OpenMP/invalid.mlir
+++ b/mlir/test/Dialect/OpenMP/invalid.mlir
@@ -598,3 +598,188 @@ func @omp_atomic_write6(%addr : memref<i32>, %val : i32) {
omp.atomic.write %addr, %val memory_order(xyz) : memref<i32>, i32
return
}
+
+// -----
+
+func @omp_sections(%data_var1 : memref<i32>, %data_var2 : memref<i32>, %data_var3 : memref<i32>) -> () {
+ // expected-error @below {{operand used in both private and firstprivate clauses}}
+ omp.sections private(%data_var1 : memref<i32>) firstprivate(%data_var1 : memref<i32>) {
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+func @omp_sections(%data_var1 : memref<i32>, %data_var2 : memref<i32>, %data_var3 : memref<i32>) -> () {
+ // expected-error @below {{operand used in both private and lastprivate clauses}}
+ omp.sections private(%data_var1 : memref<i32>) lastprivate(%data_var1 : memref<i32>) {
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+func @omp_sections(%data_var1 : memref<i32>, %data_var2 : memref<i32>, %data_var3 : memref<i32>) -> () {
+ // expected-error @below {{operand used in both private and lastprivate clauses}}
+ omp.sections private(%data_var1 : memref<i32>, %data_var2 : memref<i32>) lastprivate(%data_var3 : memref<i32>, %data_var2 : memref<i32>) {
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+func @omp_sections(%data_var : memref<i32>) -> () {
+ // expected-error @below {{expected equal sizes for allocate and allocator variables}}
+ "omp.sections" (%data_var) ({
+ omp.terminator
+ }) {operand_segment_sizes = dense<[0,0,0,0,1,0]> : vector<6xi32>} : (memref<i32>) -> ()
+ return
+}
+
+// -----
+
+func @omp_sections(%data_var : memref<i32>) -> () {
+ // expected-error @below {{expected as many reduction symbol references as reduction variables}}
+ "omp.sections" (%data_var) ({
+ omp.terminator
+ }) {operand_segment_sizes = dense<[0,0,0,1,0,0]> : vector<6xi32>} : (memref<i32>) -> ()
+ return
+}
+
+// -----
+
+func @omp_sections(%data_var : memref<i32>) -> () {
+ // expected-error @below {{expected omp.section op or terminator op inside region}}
+ omp.sections {
+ "test.payload" () : () -> ()
+ }
+ return
+}
+
+// -----
+
+func @omp_sections(%cond : i1) {
+ // expected-error @below {{if is not a valid clause for the omp.sections operation}}
+ omp.sections if(%cond) {
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+func @omp_sections() {
+ // expected-error @below {{num_threads is not a valid clause for the omp.sections operation}}
+ omp.sections num_threads(10) {
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+func @omp_sections(%datavar : memref<i32>) {
+ // expected-error @below {{shared is not a valid clause for the omp.sections operation}}
+ omp.sections shared(%datavar : memref<i32>) {
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+func @omp_sections(%datavar : memref<i32>) {
+ // expected-error @below {{copyin is not a valid clause for the omp.sections operation}}
+ omp.sections copyin(%datavar : memref<i32>) {
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+func @omp_sections() {
+ // expected-error @below {{default is not a valid clause for the omp.sections operation}}
+ omp.sections default(private) {
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+func @omp_sections() {
+ // expected-error @below {{proc_bind is not a valid clause for the omp.sections operation}}
+ omp.sections proc_bind(close) {
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+func @omp_sections(%data_var : memref<i32>, %linear_var : i32) {
+ // expected-error @below {{linear is not a valid clause for the omp.sections operation}}
+ omp.sections linear(%data_var = %linear_var : memref<i32>) {
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+func @omp_sections() {
+ // expected-error @below {{schedule is not a valid clause for the omp.sections operation}}
+ omp.sections schedule(static, none) {
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+func @omp_sections() {
+ // expected-error @below {{collapse is not a valid clause for the omp.sections operation}}
+ omp.sections collapse(3) {
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+func @omp_sections() {
+ // expected-error @below {{ordered is not a valid clause for the omp.sections operation}}
+ omp.sections ordered(2) {
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+func @omp_sections() {
+ // expected-error @below {{order is not a valid clause for the omp.sections operation}}
+ omp.sections order(concurrent) {
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+func @omp_sections() {
+ // expected-error @below {{failed to verify constraint: region with 1 blocks}}
+ omp.sections {
+ omp.section {
+ omp.terminator
+ }
+ omp.terminator
+ ^bb2:
+ omp.terminator
+ }
+ return
+}
diff --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir
index 4d0801de0cd44..522d9b48291d3 100644
--- a/mlir/test/Dialect/OpenMP/ops.mlir
+++ b/mlir/test/Dialect/OpenMP/ops.mlir
@@ -523,3 +523,124 @@ func @omp_atomic_write(%addr : memref<i32>, %val : i32) {
omp.atomic.write %addr, %val hint(speculative, uncontended) : memref<i32>, i32
return
}
+
+// CHECK-LABEL: omp_sectionsop
+func @omp_sectionsop(%data_var1 : memref<i32>, %data_var2 : memref<i32>,
+ %data_var3 : memref<i32>, %redn_var : !llvm.ptr<f32>) {
+
+ // CHECK: omp.sections private(%{{.*}} : memref<i32>) {
+ "omp.sections" (%data_var1) ({
+ // CHECK: omp.terminator
+ omp.terminator
+ }) {operand_segment_sizes = dense<[1,0,0,0,0,0]> : vector<6xi32>} : (memref<i32>) -> ()
+
+ // CHECK: omp.sections firstprivate(%{{.*}} : memref<i32>) {
+ "omp.sections" (%data_var1) ({
+ // CHECK: omp.terminator
+ omp.terminator
+ }) {operand_segment_sizes = dense<[0,1,0,0,0,0]> : vector<6xi32>} : (memref<i32>) -> ()
+
+ // CHECK: omp.sections lastprivate(%{{.*}} : memref<i32>) {
+ "omp.sections" (%data_var1) ({
+ // CHECK: omp.terminator
+ omp.terminator
+ }) {operand_segment_sizes = dense<[0,0,1,0,0,0]> : vector<6xi32>} : (memref<i32>) -> ()
+
+ // CHECK: omp.sections private(%{{.*}} : memref<i32>) firstprivate(%{{.*}} : memref<i32>) lastprivate(%{{.*}} : memref<i32>) {
+ "omp.sections" (%data_var1, %data_var2, %data_var3) ({
+ // CHECK: omp.terminator
+ omp.terminator
+ }) {operand_segment_sizes = dense<[1,1,1,0,0,0]> : vector<6xi32>} : (memref<i32>, memref<i32>, memref<i32>) -> ()
+
+ // CHECK: omp.sections allocate(%{{.*}} : memref<i32> -> %{{.*}} : memref<i32>)
+ "omp.sections" (%data_var1, %data_var1) ({
+ // CHECK: omp.terminator
+ omp.terminator
+ }) {operand_segment_sizes = dense<[0,0,0,0,1,1]> : vector<6xi32>} : (memref<i32>, memref<i32>) -> ()
+
+ // CHECK: omp.sections reduction(@add_f32 -> %{{.*}} : !llvm.ptr<f32>)
+ "omp.sections" (%redn_var) ({
+ // CHECK: omp.terminator
+ omp.terminator
+ }) {operand_segment_sizes = dense<[0,0,0,1,0,0]> : vector<6xi32>, reductions=[@add_f32]} : (!llvm.ptr<f32>) -> ()
+
+ // CHECK: omp.sections private(%{{.*}} : memref<i32>) {
+ omp.sections private(%data_var1 : memref<i32>) {
+ // CHECK: omp.terminator
+ omp.terminator
+ }
+
+ // CHECK: omp.sections firstprivate(%{{.*}} : memref<i32>)
+ omp.sections firstprivate(%data_var1 : memref<i32>) {
+ // CHECK: omp.terminator
+ omp.terminator
+ }
+
+ // CHECK: omp.sections lastprivate(%{{.*}} : memref<i32>)
+ omp.sections lastprivate(%data_var1 : memref<i32>) {
+ // CHECK: omp.terminator
+ omp.terminator
+ }
+
+ // CHECK: omp.sections private(%{{.*}} : memref<i32>) firstprivate(%{{.*}} : memref<i32>) lastprivate(%{{.*}} : memref<i32>) {
+ omp.sections private(%data_var1 : memref<i32>) firstprivate(%data_var2 : memref<i32>) lastprivate(%data_var3 : memref<i32>) {
+ // CHECK: omp.terminator
+ omp.terminator
+ }
+
+ // CHECK: omp.sections private(%{{.*}} : memref<i32>) firstprivate(%{{.*}} : memref<i32>) lastprivate(%{{.*}} : memref<i32>) {
+ omp.sections lastprivate(%data_var1 : memref<i32>) firstprivate(%data_var2 : memref<i32>) private(%data_var3 : memref<i32>) {
+ // CHECK: omp.terminator
+ omp.terminator
+ }
+
+ // CHECK: omp.sections private(%{{.*}} : memref<i32>) nowait {
+ omp.sections nowait private(%data_var1 : memref<i32>) {
+ // CHECK: omp.terminator
+ omp.terminator
+ }
+
+ // CHECK: omp.sections firstprivate(%{{.*}} : memref<i32>, %{{.*}} : memref<i32>) lastprivate(%{{.*}} : memref<i32>) {
+ omp.sections firstprivate(%data_var1 : memref<i32>, %data_var2 : memref<i32>) lastprivate(%data_var1 : memref<i32>) {
+ // CHECK: omp.terminator
+ omp.terminator
+ }
+
+ // CHECK: omp.sections reduction(@add_f32 -> %{{.*}} : !llvm.ptr<f32>) {
+ omp.sections reduction(@add_f32 -> %redn_var : !llvm.ptr<f32>) {
+ // CHECK: omp.terminator
+ omp.terminator
+ }
+
+ // CHECK: omp.sections allocate(%{{.*}} : memref<i32> -> %{{.*}} : memref<i32>)
+ omp.sections allocate(%data_var1 : memref<i32> -> %data_var1 : memref<i32>) {
+ // CHECK: omp.terminator
+ omp.terminator
+ }
+
+ // CHECK: omp.sections nowait
+ omp.sections nowait {
+ // CHECK: omp.section
+ omp.section {
+ // CHECK: %{{.*}} = "test.payload"() : () -> i32
+ %1 = "test.payload"() : () -> i32
+ // CHECK: %{{.*}} = "test.payload"() : () -> i32
+ %2 = "test.payload"() : () -> i32
+ // CHECK: %{{.*}} = "test.payload"(%{{.*}}, %{{.*}}) : (i32, i32) -> i32
+ %3 = "test.payload"(%1, %2) : (i32, i32) -> i32
+ }
+ // CHECK: omp.section
+ omp.section {
+ // CHECK: %{{.*}} = "test.payload"(%{{.*}}) : (!llvm.ptr<f32>) -> i32
+ %1 = "test.payload"(%redn_var) : (!llvm.ptr<f32>) -> i32
+ }
+ // CHECK: omp.section
+ omp.section {
+ // CHECK: "test.payload"(%{{.*}}) : (!llvm.ptr<f32>) -> ()
+ "test.payload"(%redn_var) : (!llvm.ptr<f32>) -> ()
+ }
+ // CHECK: omp.terminator
+ omp.terminator
+ }
+ return
+}
More information about the Mlir-commits
mailing list