[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