Skip to content

[MLIR][OpenMP] Clause-based OpenMP operation definition #92523

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 1, 2024

Conversation

skatrak
Copy link
Member

@skatrak skatrak commented May 17, 2024

This patch updates OpenMP_Op definitions to be based on the new set of OpenMP_Clause definitions, and to take advantage of clause-based automatically-generated argument lists, descriptions, assembly format and class declarations.

There are also changes introduced to the clause operands structures to match the current set of tablegen clause definitions. These two are very closely linked and should be kept in sync. It would probably be a good idea to try generating clause operands structures from the tablegen OpenMP_Clause definitions in the future.

As a result of this change, arguments for some operations have been reordered. This patch also addresses this by updating affected operation build calls and unit tests. Some other updates to tests related to the order of arguments in the resulting assembly format and others due to certain previous inconsistencies in the printing/parsing of clauses are addressed.

The printer and parser functions for the map clause are updated, so that they are able to handle map clauses linked to entry block arguments as well as those which aren't.

@llvmbot
Copy link
Member

llvmbot commented May 17, 2024

@llvm/pr-subscribers-mlir-openmp

@llvm/pr-subscribers-flang-openmp

Author: Sergio Afonso (skatrak)

Changes

This patch updates OpenMP_Op definitions to be based on the new set of OpenMP_Clause definitions, and to take advantage of clause-based automatically-generated argument lists, descriptions, assembly format and class declarations.

There are also changes introduced to the clause operands structures to match the current set of tablegen clause definitions. These two are very closely linked and should be kept in sync. It would probably be a good idea to try generating clause operands structures from the tablegen OpenMP_Clause definitions in the future.

As a result of this change, arguments for some operations have been reordered. This patch also addresses this by updating affected operation build calls and unit tests. Some other updates to tests related to the order of arguments in the resulting assembly format and others due to certain previous inconsistencies in the printing/parsing of clauses are addressed.

The printer and parser functions for the map clause are updated, so that they are able to handle map clauses linked to entry block arguments as well as those which aren't.


Patch is 106.52 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/92523.diff

11 Files Affected:

  • (modified) mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h (+26-10)
  • (modified) mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td (+298-846)
  • (modified) mlir/lib/Conversion/SCFToOpenMP/SCFToOpenMP.cpp (+2-1)
  • (modified) mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp (+50-28)
  • (modified) mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp (+1-1)
  • (modified) mlir/test/Dialect/OpenMP/invalid.mlir (+10-10)
  • (modified) mlir/test/Dialect/OpenMP/ops.mlir (+25-26)
  • (modified) mlir/test/Target/LLVMIR/omptarget-llvm.mlir (+3-3)
  • (modified) mlir/test/Target/LLVMIR/omptarget-nowait-llvm.mlir (+1-1)
  • (modified) mlir/test/Target/LLVMIR/omptarget-parallel-llvm.mlir (+2-2)
  • (modified) mlir/test/Target/LLVMIR/openmp-llvm.mlir (+1-1)
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h
index 244cee1dd635b..bd0d44f932981 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h
@@ -39,6 +39,10 @@ struct AllocateClauseOps {
   llvm::SmallVector<Value> allocatorVars, allocateVars;
 };
 
+struct CancelDirectiveNameClauseOps {
+  ClauseCancellationConstructTypeAttr cancelDirectiveNameAttr;
+};
+
 struct CollapseClauseOps {
   llvm::SmallVector<Value> loopLBVar, loopUBVar, loopStepVar;
 };
@@ -48,6 +52,10 @@ struct CopyprivateClauseOps {
   llvm::SmallVector<Attribute> copyprivateFuncs;
 };
 
+struct CriticalNameClauseOps {
+  StringAttr criticalNameAttr;
+};
+
 struct DependClauseOps {
   llvm::SmallVector<Attribute> dependTypeAttrs;
   llvm::SmallVector<Value> dependVars;
@@ -84,6 +92,7 @@ struct GrainsizeClauseOps {
 struct HasDeviceAddrClauseOps {
   llvm::SmallVector<Value> hasDeviceAddrVars;
 };
+
 struct HintClauseOps {
   IntegerAttr hintAttr;
 };
@@ -117,10 +126,6 @@ struct MergeableClauseOps {
   UnitAttr mergeableAttr;
 };
 
-struct NameClauseOps {
-  StringAttr nameAttr;
-};
-
 struct NogroupClauseOps {
   UnitAttr nogroupAttr;
 };
@@ -209,8 +214,12 @@ struct UntiedClauseOps {
   UnitAttr untiedAttr;
 };
 
-struct UseDeviceClauseOps {
-  llvm::SmallVector<Value> useDevicePtrVars, useDeviceAddrVars;
+struct UseDeviceAddrClauseOps {
+  llvm::SmallVector<Value> useDeviceAddrVars;
+};
+
+struct UseDevicePtrClauseOps {
+  llvm::SmallVector<Value> useDevicePtrVars;
 };
 
 //===----------------------------------------------------------------------===//
@@ -225,7 +234,13 @@ template <typename... Mixins>
 struct Clauses : public Mixins... {};
 } // namespace detail
 
-using CriticalClauseOps = detail::Clauses<HintClauseOps, NameClauseOps>;
+using CancelClauseOps =
+    detail::Clauses<CancelDirectiveNameClauseOps, IfClauseOps>;
+
+using CancellationPointClauseOps =
+    detail::Clauses<CancelDirectiveNameClauseOps>;
+
+using CriticalClauseOps = detail::Clauses<CriticalNameClauseOps, HintClauseOps>;
 
 // TODO `indirect` clause.
 using DeclareTargetClauseOps = detail::Clauses<DeviceTypeClauseOps>;
@@ -264,10 +279,11 @@ using TargetClauseOps =
     detail::Clauses<AllocateClauseOps, DependClauseOps, DeviceClauseOps,
                     HasDeviceAddrClauseOps, IfClauseOps, InReductionClauseOps,
                     IsDevicePtrClauseOps, MapClauseOps, NowaitClauseOps,
-                    PrivateClauseOps, ReductionClauseOps, ThreadLimitClauseOps>;
+                    PrivateClauseOps, ThreadLimitClauseOps>;
 
-using TargetDataClauseOps = detail::Clauses<DeviceClauseOps, IfClauseOps,
-                                            MapClauseOps, UseDeviceClauseOps>;
+using TargetDataClauseOps =
+    detail::Clauses<DeviceClauseOps, IfClauseOps, MapClauseOps,
+                    UseDeviceAddrClauseOps, UseDevicePtrClauseOps>;
 
 using TargetEnterExitUpdateDataClauseOps =
     detail::Clauses<DependClauseOps, DeviceClauseOps, IfClauseOps, MapClauseOps,
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
index 0a688635e69da..49eedfeba2ee0 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
@@ -16,7 +16,7 @@
 
 include "mlir/Dialect/LLVMIR/LLVMOpBase.td"
 include "mlir/Dialect/OpenACCMPCommon/Interfaces/AtomicInterfaces.td"
-include "mlir/Dialect/OpenMP/OpenMPAttrDefs.td"
+include "mlir/Dialect/OpenMP/OpenMPClauses.td"
 include "mlir/Dialect/OpenMP/OpenMPOpBase.td"
 include "mlir/Interfaces/ControlFlowInterfaces.td"
 include "mlir/Interfaces/SideEffectInterfaces.td"
@@ -126,26 +126,25 @@ def PrivateClauseOp : OpenMP_Op<"private", [IsolatedFromAbove]> {
 //===----------------------------------------------------------------------===//
 
 def ParallelOp : OpenMP_Op<"parallel", [
-                 AutomaticAllocationScope, AttrSizedOperandSegments,
-                 DeclareOpInterfaceMethods<LoopWrapperInterface>,
-                 DeclareOpInterfaceMethods<OutlineableOpenMPOpInterface>,
-                 RecursiveMemoryEffects, ReductionClauseInterface]> {
+    AttrSizedOperandSegments, AutomaticAllocationScope,
+    DeclareOpInterfaceMethods<LoopWrapperInterface>,
+    DeclareOpInterfaceMethods<OutlineableOpenMPOpInterface>,
+    RecursiveMemoryEffects
+  ], [
+    // TODO: Sort clauses alphabetically.
+    OpenMP_IfClause, OpenMP_NumThreadsClause, OpenMP_AllocateClause,
+    OpenMP_ReductionClause, OpenMP_ProcBindClause, OpenMP_PrivateClause
+  ], singleRegion = true> {
   let summary = "parallel construct";
   let description = [{
     The parallel construct includes a region of code which is to be executed
     by a team of threads.
 
-    The optional $if_expr_var parameter specifies a boolean result of a
+    The optional `if_expr` parameter specifies a boolean result of a
     conditional check. If this value is 1 or is not provided then the parallel
     region runs as normal, if it is 0 then the parallel region is executed with
     one thread.
 
-    The optional $num_threads_var parameter specifies the number of threads which
-    should be used to execute the parallel region.
-
-    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.
-
     Reductions can be performed in a parallel construct by specifying reduction
     accumulator variables in `reduction_vars` and symbols referring to reduction
     declarations in the `reductions` attribute. Each reduction is identified
@@ -158,37 +157,21 @@ def ParallelOp : OpenMP_Op<"parallel", [
     into the final value, which is available in the accumulator after all the
     threads complete.
 
-    The optional $proc_bind_val attribute controls the thread affinity for the execution
-    of the parallel region.
-
-    The optional byref attribute controls whether reduction arguments are passed by
-    reference or by value.
-  }];
-
-  let arguments = (ins Optional<I1>:$if_expr_var,
-             Optional<IntLikeType>:$num_threads_var,
-             Variadic<AnyType>:$allocate_vars,
-             Variadic<AnyType>:$allocators_vars,
-             Variadic<OpenMP_PointerLikeType>:$reduction_vars,
-             OptionalAttr<SymbolRefArrayAttr>:$reductions,
-             OptionalAttr<ProcBindKindAttr>:$proc_bind_val,
-             Variadic<AnyType>:$private_vars,
-             OptionalAttr<SymbolRefArrayAttr>:$privatizers,
-             UnitAttr:$byref);
-
-  let regions = (region AnyRegion:$region);
+    The optional `byref` attribute controls whether reduction arguments are
+    passed by reference or by value.
+  }] # clausesDescription;
 
   let builders = [
     OpBuilder<(ins CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes)>,
     OpBuilder<(ins CArg<"const ParallelClauseOps &">:$clauses)>
   ];
-  let extraClassDeclaration = [{
-    /// Returns the number of reduction variables.
-    unsigned getNumReductionVars() { return getReductionVars().size(); }
-  }];
+
+  // TODO: Use default assembly format inherited from OpenMP_Op after printing
+  // and parsing of the parallel region is not intermingled with printing and
+  // parsing of reduction and private clauses.
   let assemblyFormat = [{
     oilist(
-          `if` `(` $if_expr_var `:` type($if_expr_var) `)`
+          `if` `(` $if_expr `)`
           | `num_threads` `(` $num_threads_var `:` type($num_threads_var) `)`
           | `allocate` `(`
               custom<AllocateAndAllocator>(
@@ -201,6 +184,7 @@ def ParallelOp : OpenMP_Op<"parallel", [
                              $reductions, $private_vars, type($private_vars),
                              $privatizers) attr-dict
   }];
+
   let hasVerifier = 1;
 }
 
@@ -220,63 +204,27 @@ def TerminatorOp : OpenMP_Op<"terminator", [Terminator, Pure]> {
 // 2.7 teams Construct
 //===----------------------------------------------------------------------===//
 def TeamsOp : OpenMP_Op<"teams", [
-              AttrSizedOperandSegments, RecursiveMemoryEffects,
-              ReductionClauseInterface]> {
+    AttrSizedOperandSegments, RecursiveMemoryEffects
+  ], [
+    // TODO: Complete clause list (private).
+    // TODO: Sort clauses alphabetically.
+    OpenMP_NumTeamsClause, OpenMP_IfClause, OpenMP_ThreadLimitClause,
+    OpenMP_AllocateClause, OpenMP_ReductionClause
+  ], singleRegion = true> {
   let summary = "teams construct";
   let description = [{
     The teams construct defines a region of code that triggers the creation of a
     league of teams. Once created, the number of teams remains constant for the
     duration of its code region.
 
-    The optional $num_teams_upper and $num_teams_lower specify the limit on the
-    number of teams to be created. If only the upper bound is specified, it acts
-    as if the lower bound was set to the same value. It is not supported to set
-    $num_teams_lower if $num_teams_upper is not specified. They define a closed
-    range, where both the lower and upper bounds are included.
-
-    If the $if_expr is present and it evaluates to `false`, the number of teams
+    If the `if_expr` is present and it evaluates to `false`, the number of teams
     created is one.
-
-    The optional $thread_limit specifies the limit on the number of threads.
-
-    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.
-  }];
-
-  let arguments = (ins Optional<AnyInteger>:$num_teams_lower,
-                       Optional<AnyInteger>:$num_teams_upper,
-                       Optional<I1>:$if_expr,
-                       Optional<AnyInteger>:$thread_limit,
-                       Variadic<AnyType>:$allocate_vars,
-                       Variadic<AnyType>:$allocators_vars,
-                       Variadic<OpenMP_PointerLikeType>:$reduction_vars,
-                       OptionalAttr<SymbolRefArrayAttr>:$reductions);
-
-  let regions = (region AnyRegion:$region);
+  }] # clausesDescription;
 
   let builders = [
     OpBuilder<(ins CArg<"const TeamsClauseOps &">:$clauses)>
   ];
 
-  let assemblyFormat = [{
-    oilist(
-      `num_teams` `(` ( $num_teams_lower^ `:` type($num_teams_lower) )? `to`
-                        $num_teams_upper `:` type($num_teams_upper) `)`
-    | `if` `(` $if_expr `)`
-    | `thread_limit` `(` $thread_limit `:` type($thread_limit) `)`
-    | `reduction` `(`
-        custom<ReductionVarList>(
-          $reduction_vars, type($reduction_vars), $reductions
-        ) `)`
-    | `allocate` `(`
-        custom<AllocateAndAllocator>(
-          $allocate_vars, type($allocate_vars),
-          $allocators_vars, type($allocators_vars)
-        ) `)`
-    ) $region attr-dict
-  }];
-
   let hasVerifier = 1;
 }
 
@@ -284,19 +232,22 @@ def TeamsOp : OpenMP_Op<"teams", [
 // 2.8.1 Sections Construct
 //===----------------------------------------------------------------------===//
 
-def SectionOp : OpenMP_Op<"section", [HasParent<"SectionsOp">]> {
+def SectionOp : OpenMP_Op<"section", [HasParent<"SectionsOp">],
+                          singleRegion = true> {
   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,
-                           ReductionClauseInterface]> {
+def SectionsOp : OpenMP_Op<"sections", [AttrSizedOperandSegments], [
+    // TODO: Complete clause list (private).
+    // TODO: Sort clauses alphabetically.
+    OpenMP_ReductionClause, OpenMP_AllocateClause, OpenMP_NowaitClause
+  ], singleRegion = true> {
   let summary = "sections construct";
   let description = [{
     The sections construct is a non-iterative worksharing construct that
@@ -317,38 +268,17 @@ def SectionsOp : OpenMP_Op<"sections", [AttrSizedOperandSegments,
     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<OpenMP_PointerLikeType>:$reduction_vars,
-                       OptionalAttr<SymbolRefArrayAttr>:$reductions,
-                       Variadic<AnyType>:$allocate_vars,
-                       Variadic<AnyType>:$allocators_vars,
-                       UnitAttr:$nowait);
+    The optional `byref` attribute controls whether reduction arguments are
+    passed by reference or by value.
+  }] # clausesDescription;
 
+  // Override region definition.
   let regions = (region SizedRegion<1>:$region);
 
   let builders = [
     OpBuilder<(ins CArg<"const SectionsClauseOps &">:$clauses)>
   ];
 
-  let assemblyFormat = [{
-    oilist( `reduction` `(`
-              custom<ReductionVarList>(
-                $reduction_vars, type($reduction_vars), $reductions
-              ) `)`
-          | `allocate` `(`
-              custom<AllocateAndAllocator>(
-                $allocate_vars, type($allocate_vars),
-                $allocators_vars, type($allocators_vars)
-              ) `)`
-          | `nowait` $nowait
-    ) $region attr-dict
-  }];
-
   let hasVerifier = 1;
   let hasRegionVerifier = 1;
 }
@@ -357,45 +287,23 @@ def SectionsOp : OpenMP_Op<"sections", [AttrSizedOperandSegments,
 // 2.8.2 Single Construct
 //===----------------------------------------------------------------------===//
 
-def SingleOp : OpenMP_Op<"single", [AttrSizedOperandSegments]> {
+def SingleOp : OpenMP_Op<"single", [AttrSizedOperandSegments], [
+    // TODO: Complete clause list (private).
+    OpenMP_AllocateClause, OpenMP_CopyprivateClause, OpenMP_NowaitClause
+  ], singleRegion = true> {
   let summary = "single directive";
   let description = [{
     The single construct specifies that the associated structured block is
     executed by only one of the threads in the team (not necessarily the
     master thread), in the context of its implicit task. The other threads
     in the team, which do not execute the block, wait at an implicit barrier
-    at the end of the single construct unless a nowait clause is specified.
-
-    If copyprivate variables and functions are specified, then each thread
-    variable is updated with the variable value of the thread that executed
-    the single region, using the specified copy functions.
-  }];
-
-  let arguments = (ins Variadic<AnyType>:$allocate_vars,
-                       Variadic<AnyType>:$allocators_vars,
-                       Variadic<OpenMP_PointerLikeType>:$copyprivate_vars,
-                       OptionalAttr<SymbolRefArrayAttr>:$copyprivate_funcs,
-                       UnitAttr:$nowait);
-
-  let regions = (region AnyRegion:$region);
+    at the end of the single construct.
+  }] # clausesDescription;
 
   let builders = [
     OpBuilder<(ins CArg<"const SingleClauseOps &">:$clauses)>
   ];
 
-  let assemblyFormat = [{
-    oilist(`allocate` `(`
-              custom<AllocateAndAllocator>(
-                $allocate_vars, type($allocate_vars),
-                $allocators_vars, type($allocators_vars)
-              ) `)`
-          |`nowait` $nowait
-          |`copyprivate` `(`
-              custom<CopyPrivateVarList>(
-                $copyprivate_vars, type($copyprivate_vars), $copyprivate_funcs
-              ) `)`
-    ) $region attr-dict
-  }];
   let hasVerifier = 1;
 }
 
@@ -403,9 +311,11 @@ def SingleOp : OpenMP_Op<"single", [AttrSizedOperandSegments]> {
 // Loop Nest
 //===----------------------------------------------------------------------===//
 
-def LoopNestOp : OpenMP_Op<"loop_nest", [SameVariadicOperandSize,
-                        AllTypesMatch<["lowerBound", "upperBound", "step"]>,
-                        RecursiveMemoryEffects]> {
+def LoopNestOp : OpenMP_Op<"loop_nest", [
+    RecursiveMemoryEffects, SameVariadicOperandSize
+  ], [
+    OpenMP_CollapseClause
+  ], singleRegion = true> {
   let summary = "rectangular loop nest";
   let description = [{
     This operation represents a collapsed rectangular loop nest. For each
@@ -442,29 +352,24 @@ def LoopNestOp : OpenMP_Op<"loop_nest", [SameVariadicOperandSize,
     non-perfectly nested loops.
   }];
 
-  let arguments = (ins Variadic<IntLikeType>:$lowerBound,
-                       Variadic<IntLikeType>:$upperBound,
-                       Variadic<IntLikeType>:$step,
-                       UnitAttr:$inclusive);
+  let arguments = !con(clausesArgs, (ins UnitAttr:$inclusive));
 
   let builders = [
     OpBuilder<(ins CArg<"const LoopNestClauseOps &">:$clauses)>
   ];
 
-  let regions = (region AnyRegion:$region);
-
   let extraClassDeclaration = [{
-    /// Returns the number of loops in the loop nest.
-    unsigned getNumLoops() { return getLowerBound().size(); }
-
     /// Returns the induction variables of the loop nest.
     ArrayRef<BlockArgument> getIVs() { return getRegion().getArguments(); }
 
     /// Fills a list of wrapper operations around this loop nest. Wrappers
     /// in the resulting vector will be sorted from innermost to outermost.
     void gatherWrappers(SmallVectorImpl<LoopWrapperInterface> &wrappers);
-  }];
+  }] # clausesExtraClassDeclaration;
 
+  // Disable inherited clause-based declarative assembly format and instead
+  // enable using the custom parser-printer implemented in C++.
+  let assemblyFormat = ?;
   let hasCustomAssemblyFormat = 1;
   let hasVerifier = 1;
 }
@@ -473,10 +378,15 @@ def LoopNestOp : OpenMP_Op<"loop_nest", [SameVariadicOperandSize,
 // 2.9.2 Workshare Loop Construct
 //===----------------------------------------------------------------------===//
 
-def WsloopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments,
-                         DeclareOpInterfaceMethods<LoopWrapperInterface>,
-                         RecursiveMemoryEffects, ReductionClauseInterface,
-                         SingleBlockImplicitTerminator<"TerminatorOp">]> {
+def WsloopOp : OpenMP_Op<"wsloop", [
+    AttrSizedOperandSegments, DeclareOpInterfaceMethods<LoopWrapperInterface>,
+    RecursiveMemoryEffects, SingleBlockImplicitTerminator<"TerminatorOp">
+  ], [
+    // TODO: Complete clause list (allocate, private).
+    // TODO: Sort clauses alphabetically.
+    OpenMP_LinearClause, OpenMP_ReductionClause, OpenMP_ScheduleClause,
+    OpenMP_NowaitClause, OpenMP_OrderedClause, OpenMP_OrderClause
+  ], singleRegion = true> {
   let summary = "worksharing-loop construct";
   let description = [{
     The worksharing-loop construct specifies that the iterations of the loop(s)
@@ -501,11 +411,6 @@ def WsloopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments,
     }
     ```
 
-    The `linear_step_vars` operand additionally specifies the step for each
-    associated linear operand. Note that the `linear_vars` and
-    `linear_step_vars` variadic lists should contain the same number of
-    elements.
-
     Reductions can be performed in a worksharing-loop by specifying reduction
     accumulator variables in `reduction_vars` and symbols referring to reduction
     declarations in the `reductions` attribute. Each reduction is identified
@@ -516,55 +421,18 @@ def WsloopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments,
     iteration into the final value, which is available in the accumulator after
     the loop completes.
 
-    The optional `schedule_val` attribute specifies the loop schedule for this
-    loop, determining how the loop is distributed across the parallel threads.
-    The optional `schedule_chunk_var` associated with this determines further
-    controls this distribution.
-
-    Collapsed loops are represented by the worksharing-loop having a list of
-    indices, bounds and steps where the size of the list is equal to the
-    collapse value.
-
-    The `nowait` attribute, when present, signifies that there should be no
-    implicit barrier at the e...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented May 17, 2024

@llvm/pr-subscribers-mlir-llvm

Author: Sergio Afonso (skatrak)

Changes

This patch updates OpenMP_Op definitions to be based on the new set of OpenMP_Clause definitions, and to take advantage of clause-based automatically-generated argument lists, descriptions, assembly format and class declarations.

There are also changes introduced to the clause operands structures to match the current set of tablegen clause definitions. These two are very closely linked and should be kept in sync. It would probably be a good idea to try generating clause operands structures from the tablegen OpenMP_Clause definitions in the future.

As a result of this change, arguments for some operations have been reordered. This patch also addresses this by updating affected operation build calls and unit tests. Some other updates to tests related to the order of arguments in the resulting assembly format and others due to certain previous inconsistencies in the printing/parsing of clauses are addressed.

The printer and parser functions for the map clause are updated, so that they are able to handle map clauses linked to entry block arguments as well as those which aren't.


Patch is 106.52 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/92523.diff

11 Files Affected:

  • (modified) mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h (+26-10)
  • (modified) mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td (+298-846)
  • (modified) mlir/lib/Conversion/SCFToOpenMP/SCFToOpenMP.cpp (+2-1)
  • (modified) mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp (+50-28)
  • (modified) mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp (+1-1)
  • (modified) mlir/test/Dialect/OpenMP/invalid.mlir (+10-10)
  • (modified) mlir/test/Dialect/OpenMP/ops.mlir (+25-26)
  • (modified) mlir/test/Target/LLVMIR/omptarget-llvm.mlir (+3-3)
  • (modified) mlir/test/Target/LLVMIR/omptarget-nowait-llvm.mlir (+1-1)
  • (modified) mlir/test/Target/LLVMIR/omptarget-parallel-llvm.mlir (+2-2)
  • (modified) mlir/test/Target/LLVMIR/openmp-llvm.mlir (+1-1)
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h
index 244cee1dd635b..bd0d44f932981 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h
@@ -39,6 +39,10 @@ struct AllocateClauseOps {
   llvm::SmallVector<Value> allocatorVars, allocateVars;
 };
 
+struct CancelDirectiveNameClauseOps {
+  ClauseCancellationConstructTypeAttr cancelDirectiveNameAttr;
+};
+
 struct CollapseClauseOps {
   llvm::SmallVector<Value> loopLBVar, loopUBVar, loopStepVar;
 };
@@ -48,6 +52,10 @@ struct CopyprivateClauseOps {
   llvm::SmallVector<Attribute> copyprivateFuncs;
 };
 
+struct CriticalNameClauseOps {
+  StringAttr criticalNameAttr;
+};
+
 struct DependClauseOps {
   llvm::SmallVector<Attribute> dependTypeAttrs;
   llvm::SmallVector<Value> dependVars;
@@ -84,6 +92,7 @@ struct GrainsizeClauseOps {
 struct HasDeviceAddrClauseOps {
   llvm::SmallVector<Value> hasDeviceAddrVars;
 };
+
 struct HintClauseOps {
   IntegerAttr hintAttr;
 };
@@ -117,10 +126,6 @@ struct MergeableClauseOps {
   UnitAttr mergeableAttr;
 };
 
-struct NameClauseOps {
-  StringAttr nameAttr;
-};
-
 struct NogroupClauseOps {
   UnitAttr nogroupAttr;
 };
@@ -209,8 +214,12 @@ struct UntiedClauseOps {
   UnitAttr untiedAttr;
 };
 
-struct UseDeviceClauseOps {
-  llvm::SmallVector<Value> useDevicePtrVars, useDeviceAddrVars;
+struct UseDeviceAddrClauseOps {
+  llvm::SmallVector<Value> useDeviceAddrVars;
+};
+
+struct UseDevicePtrClauseOps {
+  llvm::SmallVector<Value> useDevicePtrVars;
 };
 
 //===----------------------------------------------------------------------===//
@@ -225,7 +234,13 @@ template <typename... Mixins>
 struct Clauses : public Mixins... {};
 } // namespace detail
 
-using CriticalClauseOps = detail::Clauses<HintClauseOps, NameClauseOps>;
+using CancelClauseOps =
+    detail::Clauses<CancelDirectiveNameClauseOps, IfClauseOps>;
+
+using CancellationPointClauseOps =
+    detail::Clauses<CancelDirectiveNameClauseOps>;
+
+using CriticalClauseOps = detail::Clauses<CriticalNameClauseOps, HintClauseOps>;
 
 // TODO `indirect` clause.
 using DeclareTargetClauseOps = detail::Clauses<DeviceTypeClauseOps>;
@@ -264,10 +279,11 @@ using TargetClauseOps =
     detail::Clauses<AllocateClauseOps, DependClauseOps, DeviceClauseOps,
                     HasDeviceAddrClauseOps, IfClauseOps, InReductionClauseOps,
                     IsDevicePtrClauseOps, MapClauseOps, NowaitClauseOps,
-                    PrivateClauseOps, ReductionClauseOps, ThreadLimitClauseOps>;
+                    PrivateClauseOps, ThreadLimitClauseOps>;
 
-using TargetDataClauseOps = detail::Clauses<DeviceClauseOps, IfClauseOps,
-                                            MapClauseOps, UseDeviceClauseOps>;
+using TargetDataClauseOps =
+    detail::Clauses<DeviceClauseOps, IfClauseOps, MapClauseOps,
+                    UseDeviceAddrClauseOps, UseDevicePtrClauseOps>;
 
 using TargetEnterExitUpdateDataClauseOps =
     detail::Clauses<DependClauseOps, DeviceClauseOps, IfClauseOps, MapClauseOps,
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
index 0a688635e69da..49eedfeba2ee0 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
@@ -16,7 +16,7 @@
 
 include "mlir/Dialect/LLVMIR/LLVMOpBase.td"
 include "mlir/Dialect/OpenACCMPCommon/Interfaces/AtomicInterfaces.td"
-include "mlir/Dialect/OpenMP/OpenMPAttrDefs.td"
+include "mlir/Dialect/OpenMP/OpenMPClauses.td"
 include "mlir/Dialect/OpenMP/OpenMPOpBase.td"
 include "mlir/Interfaces/ControlFlowInterfaces.td"
 include "mlir/Interfaces/SideEffectInterfaces.td"
@@ -126,26 +126,25 @@ def PrivateClauseOp : OpenMP_Op<"private", [IsolatedFromAbove]> {
 //===----------------------------------------------------------------------===//
 
 def ParallelOp : OpenMP_Op<"parallel", [
-                 AutomaticAllocationScope, AttrSizedOperandSegments,
-                 DeclareOpInterfaceMethods<LoopWrapperInterface>,
-                 DeclareOpInterfaceMethods<OutlineableOpenMPOpInterface>,
-                 RecursiveMemoryEffects, ReductionClauseInterface]> {
+    AttrSizedOperandSegments, AutomaticAllocationScope,
+    DeclareOpInterfaceMethods<LoopWrapperInterface>,
+    DeclareOpInterfaceMethods<OutlineableOpenMPOpInterface>,
+    RecursiveMemoryEffects
+  ], [
+    // TODO: Sort clauses alphabetically.
+    OpenMP_IfClause, OpenMP_NumThreadsClause, OpenMP_AllocateClause,
+    OpenMP_ReductionClause, OpenMP_ProcBindClause, OpenMP_PrivateClause
+  ], singleRegion = true> {
   let summary = "parallel construct";
   let description = [{
     The parallel construct includes a region of code which is to be executed
     by a team of threads.
 
-    The optional $if_expr_var parameter specifies a boolean result of a
+    The optional `if_expr` parameter specifies a boolean result of a
     conditional check. If this value is 1 or is not provided then the parallel
     region runs as normal, if it is 0 then the parallel region is executed with
     one thread.
 
-    The optional $num_threads_var parameter specifies the number of threads which
-    should be used to execute the parallel region.
-
-    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.
-
     Reductions can be performed in a parallel construct by specifying reduction
     accumulator variables in `reduction_vars` and symbols referring to reduction
     declarations in the `reductions` attribute. Each reduction is identified
@@ -158,37 +157,21 @@ def ParallelOp : OpenMP_Op<"parallel", [
     into the final value, which is available in the accumulator after all the
     threads complete.
 
-    The optional $proc_bind_val attribute controls the thread affinity for the execution
-    of the parallel region.
-
-    The optional byref attribute controls whether reduction arguments are passed by
-    reference or by value.
-  }];
-
-  let arguments = (ins Optional<I1>:$if_expr_var,
-             Optional<IntLikeType>:$num_threads_var,
-             Variadic<AnyType>:$allocate_vars,
-             Variadic<AnyType>:$allocators_vars,
-             Variadic<OpenMP_PointerLikeType>:$reduction_vars,
-             OptionalAttr<SymbolRefArrayAttr>:$reductions,
-             OptionalAttr<ProcBindKindAttr>:$proc_bind_val,
-             Variadic<AnyType>:$private_vars,
-             OptionalAttr<SymbolRefArrayAttr>:$privatizers,
-             UnitAttr:$byref);
-
-  let regions = (region AnyRegion:$region);
+    The optional `byref` attribute controls whether reduction arguments are
+    passed by reference or by value.
+  }] # clausesDescription;
 
   let builders = [
     OpBuilder<(ins CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes)>,
     OpBuilder<(ins CArg<"const ParallelClauseOps &">:$clauses)>
   ];
-  let extraClassDeclaration = [{
-    /// Returns the number of reduction variables.
-    unsigned getNumReductionVars() { return getReductionVars().size(); }
-  }];
+
+  // TODO: Use default assembly format inherited from OpenMP_Op after printing
+  // and parsing of the parallel region is not intermingled with printing and
+  // parsing of reduction and private clauses.
   let assemblyFormat = [{
     oilist(
-          `if` `(` $if_expr_var `:` type($if_expr_var) `)`
+          `if` `(` $if_expr `)`
           | `num_threads` `(` $num_threads_var `:` type($num_threads_var) `)`
           | `allocate` `(`
               custom<AllocateAndAllocator>(
@@ -201,6 +184,7 @@ def ParallelOp : OpenMP_Op<"parallel", [
                              $reductions, $private_vars, type($private_vars),
                              $privatizers) attr-dict
   }];
+
   let hasVerifier = 1;
 }
 
@@ -220,63 +204,27 @@ def TerminatorOp : OpenMP_Op<"terminator", [Terminator, Pure]> {
 // 2.7 teams Construct
 //===----------------------------------------------------------------------===//
 def TeamsOp : OpenMP_Op<"teams", [
-              AttrSizedOperandSegments, RecursiveMemoryEffects,
-              ReductionClauseInterface]> {
+    AttrSizedOperandSegments, RecursiveMemoryEffects
+  ], [
+    // TODO: Complete clause list (private).
+    // TODO: Sort clauses alphabetically.
+    OpenMP_NumTeamsClause, OpenMP_IfClause, OpenMP_ThreadLimitClause,
+    OpenMP_AllocateClause, OpenMP_ReductionClause
+  ], singleRegion = true> {
   let summary = "teams construct";
   let description = [{
     The teams construct defines a region of code that triggers the creation of a
     league of teams. Once created, the number of teams remains constant for the
     duration of its code region.
 
-    The optional $num_teams_upper and $num_teams_lower specify the limit on the
-    number of teams to be created. If only the upper bound is specified, it acts
-    as if the lower bound was set to the same value. It is not supported to set
-    $num_teams_lower if $num_teams_upper is not specified. They define a closed
-    range, where both the lower and upper bounds are included.
-
-    If the $if_expr is present and it evaluates to `false`, the number of teams
+    If the `if_expr` is present and it evaluates to `false`, the number of teams
     created is one.
-
-    The optional $thread_limit specifies the limit on the number of threads.
-
-    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.
-  }];
-
-  let arguments = (ins Optional<AnyInteger>:$num_teams_lower,
-                       Optional<AnyInteger>:$num_teams_upper,
-                       Optional<I1>:$if_expr,
-                       Optional<AnyInteger>:$thread_limit,
-                       Variadic<AnyType>:$allocate_vars,
-                       Variadic<AnyType>:$allocators_vars,
-                       Variadic<OpenMP_PointerLikeType>:$reduction_vars,
-                       OptionalAttr<SymbolRefArrayAttr>:$reductions);
-
-  let regions = (region AnyRegion:$region);
+  }] # clausesDescription;
 
   let builders = [
     OpBuilder<(ins CArg<"const TeamsClauseOps &">:$clauses)>
   ];
 
-  let assemblyFormat = [{
-    oilist(
-      `num_teams` `(` ( $num_teams_lower^ `:` type($num_teams_lower) )? `to`
-                        $num_teams_upper `:` type($num_teams_upper) `)`
-    | `if` `(` $if_expr `)`
-    | `thread_limit` `(` $thread_limit `:` type($thread_limit) `)`
-    | `reduction` `(`
-        custom<ReductionVarList>(
-          $reduction_vars, type($reduction_vars), $reductions
-        ) `)`
-    | `allocate` `(`
-        custom<AllocateAndAllocator>(
-          $allocate_vars, type($allocate_vars),
-          $allocators_vars, type($allocators_vars)
-        ) `)`
-    ) $region attr-dict
-  }];
-
   let hasVerifier = 1;
 }
 
@@ -284,19 +232,22 @@ def TeamsOp : OpenMP_Op<"teams", [
 // 2.8.1 Sections Construct
 //===----------------------------------------------------------------------===//
 
-def SectionOp : OpenMP_Op<"section", [HasParent<"SectionsOp">]> {
+def SectionOp : OpenMP_Op<"section", [HasParent<"SectionsOp">],
+                          singleRegion = true> {
   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,
-                           ReductionClauseInterface]> {
+def SectionsOp : OpenMP_Op<"sections", [AttrSizedOperandSegments], [
+    // TODO: Complete clause list (private).
+    // TODO: Sort clauses alphabetically.
+    OpenMP_ReductionClause, OpenMP_AllocateClause, OpenMP_NowaitClause
+  ], singleRegion = true> {
   let summary = "sections construct";
   let description = [{
     The sections construct is a non-iterative worksharing construct that
@@ -317,38 +268,17 @@ def SectionsOp : OpenMP_Op<"sections", [AttrSizedOperandSegments,
     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<OpenMP_PointerLikeType>:$reduction_vars,
-                       OptionalAttr<SymbolRefArrayAttr>:$reductions,
-                       Variadic<AnyType>:$allocate_vars,
-                       Variadic<AnyType>:$allocators_vars,
-                       UnitAttr:$nowait);
+    The optional `byref` attribute controls whether reduction arguments are
+    passed by reference or by value.
+  }] # clausesDescription;
 
+  // Override region definition.
   let regions = (region SizedRegion<1>:$region);
 
   let builders = [
     OpBuilder<(ins CArg<"const SectionsClauseOps &">:$clauses)>
   ];
 
-  let assemblyFormat = [{
-    oilist( `reduction` `(`
-              custom<ReductionVarList>(
-                $reduction_vars, type($reduction_vars), $reductions
-              ) `)`
-          | `allocate` `(`
-              custom<AllocateAndAllocator>(
-                $allocate_vars, type($allocate_vars),
-                $allocators_vars, type($allocators_vars)
-              ) `)`
-          | `nowait` $nowait
-    ) $region attr-dict
-  }];
-
   let hasVerifier = 1;
   let hasRegionVerifier = 1;
 }
@@ -357,45 +287,23 @@ def SectionsOp : OpenMP_Op<"sections", [AttrSizedOperandSegments,
 // 2.8.2 Single Construct
 //===----------------------------------------------------------------------===//
 
-def SingleOp : OpenMP_Op<"single", [AttrSizedOperandSegments]> {
+def SingleOp : OpenMP_Op<"single", [AttrSizedOperandSegments], [
+    // TODO: Complete clause list (private).
+    OpenMP_AllocateClause, OpenMP_CopyprivateClause, OpenMP_NowaitClause
+  ], singleRegion = true> {
   let summary = "single directive";
   let description = [{
     The single construct specifies that the associated structured block is
     executed by only one of the threads in the team (not necessarily the
     master thread), in the context of its implicit task. The other threads
     in the team, which do not execute the block, wait at an implicit barrier
-    at the end of the single construct unless a nowait clause is specified.
-
-    If copyprivate variables and functions are specified, then each thread
-    variable is updated with the variable value of the thread that executed
-    the single region, using the specified copy functions.
-  }];
-
-  let arguments = (ins Variadic<AnyType>:$allocate_vars,
-                       Variadic<AnyType>:$allocators_vars,
-                       Variadic<OpenMP_PointerLikeType>:$copyprivate_vars,
-                       OptionalAttr<SymbolRefArrayAttr>:$copyprivate_funcs,
-                       UnitAttr:$nowait);
-
-  let regions = (region AnyRegion:$region);
+    at the end of the single construct.
+  }] # clausesDescription;
 
   let builders = [
     OpBuilder<(ins CArg<"const SingleClauseOps &">:$clauses)>
   ];
 
-  let assemblyFormat = [{
-    oilist(`allocate` `(`
-              custom<AllocateAndAllocator>(
-                $allocate_vars, type($allocate_vars),
-                $allocators_vars, type($allocators_vars)
-              ) `)`
-          |`nowait` $nowait
-          |`copyprivate` `(`
-              custom<CopyPrivateVarList>(
-                $copyprivate_vars, type($copyprivate_vars), $copyprivate_funcs
-              ) `)`
-    ) $region attr-dict
-  }];
   let hasVerifier = 1;
 }
 
@@ -403,9 +311,11 @@ def SingleOp : OpenMP_Op<"single", [AttrSizedOperandSegments]> {
 // Loop Nest
 //===----------------------------------------------------------------------===//
 
-def LoopNestOp : OpenMP_Op<"loop_nest", [SameVariadicOperandSize,
-                        AllTypesMatch<["lowerBound", "upperBound", "step"]>,
-                        RecursiveMemoryEffects]> {
+def LoopNestOp : OpenMP_Op<"loop_nest", [
+    RecursiveMemoryEffects, SameVariadicOperandSize
+  ], [
+    OpenMP_CollapseClause
+  ], singleRegion = true> {
   let summary = "rectangular loop nest";
   let description = [{
     This operation represents a collapsed rectangular loop nest. For each
@@ -442,29 +352,24 @@ def LoopNestOp : OpenMP_Op<"loop_nest", [SameVariadicOperandSize,
     non-perfectly nested loops.
   }];
 
-  let arguments = (ins Variadic<IntLikeType>:$lowerBound,
-                       Variadic<IntLikeType>:$upperBound,
-                       Variadic<IntLikeType>:$step,
-                       UnitAttr:$inclusive);
+  let arguments = !con(clausesArgs, (ins UnitAttr:$inclusive));
 
   let builders = [
     OpBuilder<(ins CArg<"const LoopNestClauseOps &">:$clauses)>
   ];
 
-  let regions = (region AnyRegion:$region);
-
   let extraClassDeclaration = [{
-    /// Returns the number of loops in the loop nest.
-    unsigned getNumLoops() { return getLowerBound().size(); }
-
     /// Returns the induction variables of the loop nest.
     ArrayRef<BlockArgument> getIVs() { return getRegion().getArguments(); }
 
     /// Fills a list of wrapper operations around this loop nest. Wrappers
     /// in the resulting vector will be sorted from innermost to outermost.
     void gatherWrappers(SmallVectorImpl<LoopWrapperInterface> &wrappers);
-  }];
+  }] # clausesExtraClassDeclaration;
 
+  // Disable inherited clause-based declarative assembly format and instead
+  // enable using the custom parser-printer implemented in C++.
+  let assemblyFormat = ?;
   let hasCustomAssemblyFormat = 1;
   let hasVerifier = 1;
 }
@@ -473,10 +378,15 @@ def LoopNestOp : OpenMP_Op<"loop_nest", [SameVariadicOperandSize,
 // 2.9.2 Workshare Loop Construct
 //===----------------------------------------------------------------------===//
 
-def WsloopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments,
-                         DeclareOpInterfaceMethods<LoopWrapperInterface>,
-                         RecursiveMemoryEffects, ReductionClauseInterface,
-                         SingleBlockImplicitTerminator<"TerminatorOp">]> {
+def WsloopOp : OpenMP_Op<"wsloop", [
+    AttrSizedOperandSegments, DeclareOpInterfaceMethods<LoopWrapperInterface>,
+    RecursiveMemoryEffects, SingleBlockImplicitTerminator<"TerminatorOp">
+  ], [
+    // TODO: Complete clause list (allocate, private).
+    // TODO: Sort clauses alphabetically.
+    OpenMP_LinearClause, OpenMP_ReductionClause, OpenMP_ScheduleClause,
+    OpenMP_NowaitClause, OpenMP_OrderedClause, OpenMP_OrderClause
+  ], singleRegion = true> {
   let summary = "worksharing-loop construct";
   let description = [{
     The worksharing-loop construct specifies that the iterations of the loop(s)
@@ -501,11 +411,6 @@ def WsloopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments,
     }
     ```
 
-    The `linear_step_vars` operand additionally specifies the step for each
-    associated linear operand. Note that the `linear_vars` and
-    `linear_step_vars` variadic lists should contain the same number of
-    elements.
-
     Reductions can be performed in a worksharing-loop by specifying reduction
     accumulator variables in `reduction_vars` and symbols referring to reduction
     declarations in the `reductions` attribute. Each reduction is identified
@@ -516,55 +421,18 @@ def WsloopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments,
     iteration into the final value, which is available in the accumulator after
     the loop completes.
 
-    The optional `schedule_val` attribute specifies the loop schedule for this
-    loop, determining how the loop is distributed across the parallel threads.
-    The optional `schedule_chunk_var` associated with this determines further
-    controls this distribution.
-
-    Collapsed loops are represented by the worksharing-loop having a list of
-    indices, bounds and steps where the size of the list is equal to the
-    collapse value.
-
-    The `nowait` attribute, when present, signifies that there should be no
-    implicit barrier at the e...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented May 17, 2024

@llvm/pr-subscribers-mlir

Author: Sergio Afonso (skatrak)

Changes

This patch updates OpenMP_Op definitions to be based on the new set of OpenMP_Clause definitions, and to take advantage of clause-based automatically-generated argument lists, descriptions, assembly format and class declarations.

There are also changes introduced to the clause operands structures to match the current set of tablegen clause definitions. These two are very closely linked and should be kept in sync. It would probably be a good idea to try generating clause operands structures from the tablegen OpenMP_Clause definitions in the future.

As a result of this change, arguments for some operations have been reordered. This patch also addresses this by updating affected operation build calls and unit tests. Some other updates to tests related to the order of arguments in the resulting assembly format and others due to certain previous inconsistencies in the printing/parsing of clauses are addressed.

The printer and parser functions for the map clause are updated, so that they are able to handle map clauses linked to entry block arguments as well as those which aren't.


Patch is 106.52 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/92523.diff

11 Files Affected:

  • (modified) mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h (+26-10)
  • (modified) mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td (+298-846)
  • (modified) mlir/lib/Conversion/SCFToOpenMP/SCFToOpenMP.cpp (+2-1)
  • (modified) mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp (+50-28)
  • (modified) mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp (+1-1)
  • (modified) mlir/test/Dialect/OpenMP/invalid.mlir (+10-10)
  • (modified) mlir/test/Dialect/OpenMP/ops.mlir (+25-26)
  • (modified) mlir/test/Target/LLVMIR/omptarget-llvm.mlir (+3-3)
  • (modified) mlir/test/Target/LLVMIR/omptarget-nowait-llvm.mlir (+1-1)
  • (modified) mlir/test/Target/LLVMIR/omptarget-parallel-llvm.mlir (+2-2)
  • (modified) mlir/test/Target/LLVMIR/openmp-llvm.mlir (+1-1)
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h
index 244cee1dd635b..bd0d44f932981 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h
@@ -39,6 +39,10 @@ struct AllocateClauseOps {
   llvm::SmallVector<Value> allocatorVars, allocateVars;
 };
 
+struct CancelDirectiveNameClauseOps {
+  ClauseCancellationConstructTypeAttr cancelDirectiveNameAttr;
+};
+
 struct CollapseClauseOps {
   llvm::SmallVector<Value> loopLBVar, loopUBVar, loopStepVar;
 };
@@ -48,6 +52,10 @@ struct CopyprivateClauseOps {
   llvm::SmallVector<Attribute> copyprivateFuncs;
 };
 
+struct CriticalNameClauseOps {
+  StringAttr criticalNameAttr;
+};
+
 struct DependClauseOps {
   llvm::SmallVector<Attribute> dependTypeAttrs;
   llvm::SmallVector<Value> dependVars;
@@ -84,6 +92,7 @@ struct GrainsizeClauseOps {
 struct HasDeviceAddrClauseOps {
   llvm::SmallVector<Value> hasDeviceAddrVars;
 };
+
 struct HintClauseOps {
   IntegerAttr hintAttr;
 };
@@ -117,10 +126,6 @@ struct MergeableClauseOps {
   UnitAttr mergeableAttr;
 };
 
-struct NameClauseOps {
-  StringAttr nameAttr;
-};
-
 struct NogroupClauseOps {
   UnitAttr nogroupAttr;
 };
@@ -209,8 +214,12 @@ struct UntiedClauseOps {
   UnitAttr untiedAttr;
 };
 
-struct UseDeviceClauseOps {
-  llvm::SmallVector<Value> useDevicePtrVars, useDeviceAddrVars;
+struct UseDeviceAddrClauseOps {
+  llvm::SmallVector<Value> useDeviceAddrVars;
+};
+
+struct UseDevicePtrClauseOps {
+  llvm::SmallVector<Value> useDevicePtrVars;
 };
 
 //===----------------------------------------------------------------------===//
@@ -225,7 +234,13 @@ template <typename... Mixins>
 struct Clauses : public Mixins... {};
 } // namespace detail
 
-using CriticalClauseOps = detail::Clauses<HintClauseOps, NameClauseOps>;
+using CancelClauseOps =
+    detail::Clauses<CancelDirectiveNameClauseOps, IfClauseOps>;
+
+using CancellationPointClauseOps =
+    detail::Clauses<CancelDirectiveNameClauseOps>;
+
+using CriticalClauseOps = detail::Clauses<CriticalNameClauseOps, HintClauseOps>;
 
 // TODO `indirect` clause.
 using DeclareTargetClauseOps = detail::Clauses<DeviceTypeClauseOps>;
@@ -264,10 +279,11 @@ using TargetClauseOps =
     detail::Clauses<AllocateClauseOps, DependClauseOps, DeviceClauseOps,
                     HasDeviceAddrClauseOps, IfClauseOps, InReductionClauseOps,
                     IsDevicePtrClauseOps, MapClauseOps, NowaitClauseOps,
-                    PrivateClauseOps, ReductionClauseOps, ThreadLimitClauseOps>;
+                    PrivateClauseOps, ThreadLimitClauseOps>;
 
-using TargetDataClauseOps = detail::Clauses<DeviceClauseOps, IfClauseOps,
-                                            MapClauseOps, UseDeviceClauseOps>;
+using TargetDataClauseOps =
+    detail::Clauses<DeviceClauseOps, IfClauseOps, MapClauseOps,
+                    UseDeviceAddrClauseOps, UseDevicePtrClauseOps>;
 
 using TargetEnterExitUpdateDataClauseOps =
     detail::Clauses<DependClauseOps, DeviceClauseOps, IfClauseOps, MapClauseOps,
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
index 0a688635e69da..49eedfeba2ee0 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
@@ -16,7 +16,7 @@
 
 include "mlir/Dialect/LLVMIR/LLVMOpBase.td"
 include "mlir/Dialect/OpenACCMPCommon/Interfaces/AtomicInterfaces.td"
-include "mlir/Dialect/OpenMP/OpenMPAttrDefs.td"
+include "mlir/Dialect/OpenMP/OpenMPClauses.td"
 include "mlir/Dialect/OpenMP/OpenMPOpBase.td"
 include "mlir/Interfaces/ControlFlowInterfaces.td"
 include "mlir/Interfaces/SideEffectInterfaces.td"
@@ -126,26 +126,25 @@ def PrivateClauseOp : OpenMP_Op<"private", [IsolatedFromAbove]> {
 //===----------------------------------------------------------------------===//
 
 def ParallelOp : OpenMP_Op<"parallel", [
-                 AutomaticAllocationScope, AttrSizedOperandSegments,
-                 DeclareOpInterfaceMethods<LoopWrapperInterface>,
-                 DeclareOpInterfaceMethods<OutlineableOpenMPOpInterface>,
-                 RecursiveMemoryEffects, ReductionClauseInterface]> {
+    AttrSizedOperandSegments, AutomaticAllocationScope,
+    DeclareOpInterfaceMethods<LoopWrapperInterface>,
+    DeclareOpInterfaceMethods<OutlineableOpenMPOpInterface>,
+    RecursiveMemoryEffects
+  ], [
+    // TODO: Sort clauses alphabetically.
+    OpenMP_IfClause, OpenMP_NumThreadsClause, OpenMP_AllocateClause,
+    OpenMP_ReductionClause, OpenMP_ProcBindClause, OpenMP_PrivateClause
+  ], singleRegion = true> {
   let summary = "parallel construct";
   let description = [{
     The parallel construct includes a region of code which is to be executed
     by a team of threads.
 
-    The optional $if_expr_var parameter specifies a boolean result of a
+    The optional `if_expr` parameter specifies a boolean result of a
     conditional check. If this value is 1 or is not provided then the parallel
     region runs as normal, if it is 0 then the parallel region is executed with
     one thread.
 
-    The optional $num_threads_var parameter specifies the number of threads which
-    should be used to execute the parallel region.
-
-    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.
-
     Reductions can be performed in a parallel construct by specifying reduction
     accumulator variables in `reduction_vars` and symbols referring to reduction
     declarations in the `reductions` attribute. Each reduction is identified
@@ -158,37 +157,21 @@ def ParallelOp : OpenMP_Op<"parallel", [
     into the final value, which is available in the accumulator after all the
     threads complete.
 
-    The optional $proc_bind_val attribute controls the thread affinity for the execution
-    of the parallel region.
-
-    The optional byref attribute controls whether reduction arguments are passed by
-    reference or by value.
-  }];
-
-  let arguments = (ins Optional<I1>:$if_expr_var,
-             Optional<IntLikeType>:$num_threads_var,
-             Variadic<AnyType>:$allocate_vars,
-             Variadic<AnyType>:$allocators_vars,
-             Variadic<OpenMP_PointerLikeType>:$reduction_vars,
-             OptionalAttr<SymbolRefArrayAttr>:$reductions,
-             OptionalAttr<ProcBindKindAttr>:$proc_bind_val,
-             Variadic<AnyType>:$private_vars,
-             OptionalAttr<SymbolRefArrayAttr>:$privatizers,
-             UnitAttr:$byref);
-
-  let regions = (region AnyRegion:$region);
+    The optional `byref` attribute controls whether reduction arguments are
+    passed by reference or by value.
+  }] # clausesDescription;
 
   let builders = [
     OpBuilder<(ins CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes)>,
     OpBuilder<(ins CArg<"const ParallelClauseOps &">:$clauses)>
   ];
-  let extraClassDeclaration = [{
-    /// Returns the number of reduction variables.
-    unsigned getNumReductionVars() { return getReductionVars().size(); }
-  }];
+
+  // TODO: Use default assembly format inherited from OpenMP_Op after printing
+  // and parsing of the parallel region is not intermingled with printing and
+  // parsing of reduction and private clauses.
   let assemblyFormat = [{
     oilist(
-          `if` `(` $if_expr_var `:` type($if_expr_var) `)`
+          `if` `(` $if_expr `)`
           | `num_threads` `(` $num_threads_var `:` type($num_threads_var) `)`
           | `allocate` `(`
               custom<AllocateAndAllocator>(
@@ -201,6 +184,7 @@ def ParallelOp : OpenMP_Op<"parallel", [
                              $reductions, $private_vars, type($private_vars),
                              $privatizers) attr-dict
   }];
+
   let hasVerifier = 1;
 }
 
@@ -220,63 +204,27 @@ def TerminatorOp : OpenMP_Op<"terminator", [Terminator, Pure]> {
 // 2.7 teams Construct
 //===----------------------------------------------------------------------===//
 def TeamsOp : OpenMP_Op<"teams", [
-              AttrSizedOperandSegments, RecursiveMemoryEffects,
-              ReductionClauseInterface]> {
+    AttrSizedOperandSegments, RecursiveMemoryEffects
+  ], [
+    // TODO: Complete clause list (private).
+    // TODO: Sort clauses alphabetically.
+    OpenMP_NumTeamsClause, OpenMP_IfClause, OpenMP_ThreadLimitClause,
+    OpenMP_AllocateClause, OpenMP_ReductionClause
+  ], singleRegion = true> {
   let summary = "teams construct";
   let description = [{
     The teams construct defines a region of code that triggers the creation of a
     league of teams. Once created, the number of teams remains constant for the
     duration of its code region.
 
-    The optional $num_teams_upper and $num_teams_lower specify the limit on the
-    number of teams to be created. If only the upper bound is specified, it acts
-    as if the lower bound was set to the same value. It is not supported to set
-    $num_teams_lower if $num_teams_upper is not specified. They define a closed
-    range, where both the lower and upper bounds are included.
-
-    If the $if_expr is present and it evaluates to `false`, the number of teams
+    If the `if_expr` is present and it evaluates to `false`, the number of teams
     created is one.
-
-    The optional $thread_limit specifies the limit on the number of threads.
-
-    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.
-  }];
-
-  let arguments = (ins Optional<AnyInteger>:$num_teams_lower,
-                       Optional<AnyInteger>:$num_teams_upper,
-                       Optional<I1>:$if_expr,
-                       Optional<AnyInteger>:$thread_limit,
-                       Variadic<AnyType>:$allocate_vars,
-                       Variadic<AnyType>:$allocators_vars,
-                       Variadic<OpenMP_PointerLikeType>:$reduction_vars,
-                       OptionalAttr<SymbolRefArrayAttr>:$reductions);
-
-  let regions = (region AnyRegion:$region);
+  }] # clausesDescription;
 
   let builders = [
     OpBuilder<(ins CArg<"const TeamsClauseOps &">:$clauses)>
   ];
 
-  let assemblyFormat = [{
-    oilist(
-      `num_teams` `(` ( $num_teams_lower^ `:` type($num_teams_lower) )? `to`
-                        $num_teams_upper `:` type($num_teams_upper) `)`
-    | `if` `(` $if_expr `)`
-    | `thread_limit` `(` $thread_limit `:` type($thread_limit) `)`
-    | `reduction` `(`
-        custom<ReductionVarList>(
-          $reduction_vars, type($reduction_vars), $reductions
-        ) `)`
-    | `allocate` `(`
-        custom<AllocateAndAllocator>(
-          $allocate_vars, type($allocate_vars),
-          $allocators_vars, type($allocators_vars)
-        ) `)`
-    ) $region attr-dict
-  }];
-
   let hasVerifier = 1;
 }
 
@@ -284,19 +232,22 @@ def TeamsOp : OpenMP_Op<"teams", [
 // 2.8.1 Sections Construct
 //===----------------------------------------------------------------------===//
 
-def SectionOp : OpenMP_Op<"section", [HasParent<"SectionsOp">]> {
+def SectionOp : OpenMP_Op<"section", [HasParent<"SectionsOp">],
+                          singleRegion = true> {
   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,
-                           ReductionClauseInterface]> {
+def SectionsOp : OpenMP_Op<"sections", [AttrSizedOperandSegments], [
+    // TODO: Complete clause list (private).
+    // TODO: Sort clauses alphabetically.
+    OpenMP_ReductionClause, OpenMP_AllocateClause, OpenMP_NowaitClause
+  ], singleRegion = true> {
   let summary = "sections construct";
   let description = [{
     The sections construct is a non-iterative worksharing construct that
@@ -317,38 +268,17 @@ def SectionsOp : OpenMP_Op<"sections", [AttrSizedOperandSegments,
     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<OpenMP_PointerLikeType>:$reduction_vars,
-                       OptionalAttr<SymbolRefArrayAttr>:$reductions,
-                       Variadic<AnyType>:$allocate_vars,
-                       Variadic<AnyType>:$allocators_vars,
-                       UnitAttr:$nowait);
+    The optional `byref` attribute controls whether reduction arguments are
+    passed by reference or by value.
+  }] # clausesDescription;
 
+  // Override region definition.
   let regions = (region SizedRegion<1>:$region);
 
   let builders = [
     OpBuilder<(ins CArg<"const SectionsClauseOps &">:$clauses)>
   ];
 
-  let assemblyFormat = [{
-    oilist( `reduction` `(`
-              custom<ReductionVarList>(
-                $reduction_vars, type($reduction_vars), $reductions
-              ) `)`
-          | `allocate` `(`
-              custom<AllocateAndAllocator>(
-                $allocate_vars, type($allocate_vars),
-                $allocators_vars, type($allocators_vars)
-              ) `)`
-          | `nowait` $nowait
-    ) $region attr-dict
-  }];
-
   let hasVerifier = 1;
   let hasRegionVerifier = 1;
 }
@@ -357,45 +287,23 @@ def SectionsOp : OpenMP_Op<"sections", [AttrSizedOperandSegments,
 // 2.8.2 Single Construct
 //===----------------------------------------------------------------------===//
 
-def SingleOp : OpenMP_Op<"single", [AttrSizedOperandSegments]> {
+def SingleOp : OpenMP_Op<"single", [AttrSizedOperandSegments], [
+    // TODO: Complete clause list (private).
+    OpenMP_AllocateClause, OpenMP_CopyprivateClause, OpenMP_NowaitClause
+  ], singleRegion = true> {
   let summary = "single directive";
   let description = [{
     The single construct specifies that the associated structured block is
     executed by only one of the threads in the team (not necessarily the
     master thread), in the context of its implicit task. The other threads
     in the team, which do not execute the block, wait at an implicit barrier
-    at the end of the single construct unless a nowait clause is specified.
-
-    If copyprivate variables and functions are specified, then each thread
-    variable is updated with the variable value of the thread that executed
-    the single region, using the specified copy functions.
-  }];
-
-  let arguments = (ins Variadic<AnyType>:$allocate_vars,
-                       Variadic<AnyType>:$allocators_vars,
-                       Variadic<OpenMP_PointerLikeType>:$copyprivate_vars,
-                       OptionalAttr<SymbolRefArrayAttr>:$copyprivate_funcs,
-                       UnitAttr:$nowait);
-
-  let regions = (region AnyRegion:$region);
+    at the end of the single construct.
+  }] # clausesDescription;
 
   let builders = [
     OpBuilder<(ins CArg<"const SingleClauseOps &">:$clauses)>
   ];
 
-  let assemblyFormat = [{
-    oilist(`allocate` `(`
-              custom<AllocateAndAllocator>(
-                $allocate_vars, type($allocate_vars),
-                $allocators_vars, type($allocators_vars)
-              ) `)`
-          |`nowait` $nowait
-          |`copyprivate` `(`
-              custom<CopyPrivateVarList>(
-                $copyprivate_vars, type($copyprivate_vars), $copyprivate_funcs
-              ) `)`
-    ) $region attr-dict
-  }];
   let hasVerifier = 1;
 }
 
@@ -403,9 +311,11 @@ def SingleOp : OpenMP_Op<"single", [AttrSizedOperandSegments]> {
 // Loop Nest
 //===----------------------------------------------------------------------===//
 
-def LoopNestOp : OpenMP_Op<"loop_nest", [SameVariadicOperandSize,
-                        AllTypesMatch<["lowerBound", "upperBound", "step"]>,
-                        RecursiveMemoryEffects]> {
+def LoopNestOp : OpenMP_Op<"loop_nest", [
+    RecursiveMemoryEffects, SameVariadicOperandSize
+  ], [
+    OpenMP_CollapseClause
+  ], singleRegion = true> {
   let summary = "rectangular loop nest";
   let description = [{
     This operation represents a collapsed rectangular loop nest. For each
@@ -442,29 +352,24 @@ def LoopNestOp : OpenMP_Op<"loop_nest", [SameVariadicOperandSize,
     non-perfectly nested loops.
   }];
 
-  let arguments = (ins Variadic<IntLikeType>:$lowerBound,
-                       Variadic<IntLikeType>:$upperBound,
-                       Variadic<IntLikeType>:$step,
-                       UnitAttr:$inclusive);
+  let arguments = !con(clausesArgs, (ins UnitAttr:$inclusive));
 
   let builders = [
     OpBuilder<(ins CArg<"const LoopNestClauseOps &">:$clauses)>
   ];
 
-  let regions = (region AnyRegion:$region);
-
   let extraClassDeclaration = [{
-    /// Returns the number of loops in the loop nest.
-    unsigned getNumLoops() { return getLowerBound().size(); }
-
     /// Returns the induction variables of the loop nest.
     ArrayRef<BlockArgument> getIVs() { return getRegion().getArguments(); }
 
     /// Fills a list of wrapper operations around this loop nest. Wrappers
     /// in the resulting vector will be sorted from innermost to outermost.
     void gatherWrappers(SmallVectorImpl<LoopWrapperInterface> &wrappers);
-  }];
+  }] # clausesExtraClassDeclaration;
 
+  // Disable inherited clause-based declarative assembly format and instead
+  // enable using the custom parser-printer implemented in C++.
+  let assemblyFormat = ?;
   let hasCustomAssemblyFormat = 1;
   let hasVerifier = 1;
 }
@@ -473,10 +378,15 @@ def LoopNestOp : OpenMP_Op<"loop_nest", [SameVariadicOperandSize,
 // 2.9.2 Workshare Loop Construct
 //===----------------------------------------------------------------------===//
 
-def WsloopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments,
-                         DeclareOpInterfaceMethods<LoopWrapperInterface>,
-                         RecursiveMemoryEffects, ReductionClauseInterface,
-                         SingleBlockImplicitTerminator<"TerminatorOp">]> {
+def WsloopOp : OpenMP_Op<"wsloop", [
+    AttrSizedOperandSegments, DeclareOpInterfaceMethods<LoopWrapperInterface>,
+    RecursiveMemoryEffects, SingleBlockImplicitTerminator<"TerminatorOp">
+  ], [
+    // TODO: Complete clause list (allocate, private).
+    // TODO: Sort clauses alphabetically.
+    OpenMP_LinearClause, OpenMP_ReductionClause, OpenMP_ScheduleClause,
+    OpenMP_NowaitClause, OpenMP_OrderedClause, OpenMP_OrderClause
+  ], singleRegion = true> {
   let summary = "worksharing-loop construct";
   let description = [{
     The worksharing-loop construct specifies that the iterations of the loop(s)
@@ -501,11 +411,6 @@ def WsloopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments,
     }
     ```
 
-    The `linear_step_vars` operand additionally specifies the step for each
-    associated linear operand. Note that the `linear_vars` and
-    `linear_step_vars` variadic lists should contain the same number of
-    elements.
-
     Reductions can be performed in a worksharing-loop by specifying reduction
     accumulator variables in `reduction_vars` and symbols referring to reduction
     declarations in the `reductions` attribute. Each reduction is identified
@@ -516,55 +421,18 @@ def WsloopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments,
     iteration into the final value, which is available in the accumulator after
     the loop completes.
 
-    The optional `schedule_val` attribute specifies the loop schedule for this
-    loop, determining how the loop is distributed across the parallel threads.
-    The optional `schedule_chunk_var` associated with this determines further
-    controls this distribution.
-
-    Collapsed loops are represented by the worksharing-loop having a list of
-    indices, bounds and steps where the size of the list is equal to the
-    collapse value.
-
-    The `nowait` attribute, when present, signifies that there should be no
-    implicit barrier at the e...
[truncated]

@skatrak skatrak force-pushed the users/skatrak/mlir-clauses-03-clausedefs branch from e1aa6cb to 7466061 Compare May 20, 2024 13:40
@skatrak skatrak force-pushed the users/skatrak/mlir-clauses-04-ops branch from 6fb9989 to b43c823 Compare May 20, 2024 13:40
@skatrak
Copy link
Member Author

skatrak commented Jun 6, 2024

@tblah thanks for giving this a look. Basically the issue here with the reduction clause is that its description is currently different for each operation that accepts it. They are generally quite similar, just not the same. I think the clause is already consistent in terms of how it's represented but what it means is slightly different depending on the operation, hence the variations in their way of describing it. If you look at the OpenMP_ReductionClause definition in OpenMPClauses.td, you'll see that I added a comment to it saying basically that no description is defined for it because it's different on each operation (same thing I did for the if and in_reduction clauses).

It would be great to agree on a generic description for that clause that would work for all ops, so that it makes sense while reading the generated documentation and also being centralized into the clause definition rather than each operation. I created a gist here with the whole list of descriptions that currently exist for reduction, in case that helps with figuring out a shared description. Another option would be to provide a generic description for that clause used by most operations and then override it for one or two if they need to be more specific about something.

@tblah
Copy link
Contributor

tblah commented Jun 7, 2024

@tblah thanks for giving this a look. Basically the issue here with the reduction clause is that its description is currently different for each operation that accepts it.

It would be great to agree on a generic description for that clause that would work for all ops, so that it makes sense while reading the generated documentation and also being centralized into the clause definition rather than each operation. I created a gist here with the whole list of descriptions that currently exist for reduction, in case that helps with figuring out a shared description.

Thanks for taking the time to create the gist. Some thoughts

I guess fixing byref is on me (#92244). Unfortunately I can't work on this immediately so I won't hold up this PR for it.

Copy link
Contributor

@tblah tblah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but please wait for another reviewer

Edit: and CI is red

@skatrak skatrak force-pushed the users/skatrak/mlir-clauses-03-clausedefs branch from 7466061 to 1496299 Compare June 12, 2024 13:17
@skatrak skatrak force-pushed the users/skatrak/mlir-clauses-04-ops branch from b43c823 to 2a089ad Compare June 12, 2024 13:41
@skatrak
Copy link
Member Author

skatrak commented Jun 12, 2024

Quick update about reduction clause descriptions @tblah: I updated the previous PR on the stack (#92521) to add a shared description that basically incorporates all of the information that was spread across the various operations using it. I updated the description of omp.taskloop in this PR as well to keep the additional related information it previously had while still inheriting the base description for the clause.

Also, it's expected that this PR breaks buildbots because of some small reordering of operation arguments and assembly format normalization. The next PR in the stack (#92524) addresses this.

@tblah
Copy link
Contributor

tblah commented Jun 20, 2024

I guess fixing byref is on me (#92244). Unfortunately I can't work on this immediately so I won't hold up this PR for it.

@skatrak does #96215 cover everything you need?

@skatrak
Copy link
Member Author

skatrak commented Jun 26, 2024

I guess fixing byref is on me (#92244). Unfortunately I can't work on this immediately so I won't hold up this PR for it.

@skatrak does #96215 cover everything you need?

Thank you for the heads-up, that certainly helps. My plan is to update the PR stack after yours and one or two other PRs that conflict with this change land and hopefully by then all patches in this stack should be reviewed/approved to be merged.

Copy link
Member

@TIFitis TIFitis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy with the patch. Thanks for the good work :)

@skatrak skatrak force-pushed the users/skatrak/mlir-clauses-03-clausedefs branch from 1496299 to 0e0d66e Compare June 28, 2024 14:55
@skatrak skatrak force-pushed the users/skatrak/mlir-clauses-04-ops branch from 2a089ad to b0c7acd Compare June 28, 2024 14:55
This patch adds a new tablegen file for the OpenMP dialect containing the list
of clauses currently supported.
@skatrak skatrak force-pushed the users/skatrak/mlir-clauses-03-clausedefs branch from 0e0d66e to bd17957 Compare July 1, 2024 09:26
This patch updates `OpenMP_Op` definitions to be based on the new set of
`OpenMP_Clause` definitions, and to take advantage of clause-based
automatically-generated argument lists, descriptions, assembly format and class
declarations.

There are also changes introduced to the clause operands structures to match
the current set of tablegen clause definitions. These two are very closely
linked and should be kept in sync. It would probably be a good idea to try
generating clause operands structures from the tablegen `OpenMP_Clause`
definitions in the future.

As a result of this change, arguments for some operations have been reordered.
This patch also addresses this by updating affected operation build calls and
unit tests. Some other updates to tests related to the order of arguments in
the resulting assembly format and others due to certain previous
inconsistencies in the printing/parsing of clauses are addressed.

The printer and parser functions for the `map` clause are updated, so that they
are able to handle `map` clauses linked to entry block arguments as well as
those which aren't. Printer and parser of reduction-related clauses are updated
as well to add support for `byref` information to all operations, unifying the
representation of reductions for all operations.
@skatrak skatrak force-pushed the users/skatrak/mlir-clauses-04-ops branch from b0c7acd to f66b88b Compare July 1, 2024 09:27
Base automatically changed from users/skatrak/mlir-clauses-03-clausedefs to main July 1, 2024 10:06
@skatrak skatrak merged commit d1fcfce into main Jul 1, 2024
4 of 6 checks passed
@skatrak skatrak deleted the users/skatrak/mlir-clauses-04-ops branch July 1, 2024 10:08
@llvm-ci
Copy link
Collaborator

llvm-ci commented Jul 1, 2024

LLVM Buildbot has detected a new failure on builder ppc64le-flang-rhel-clang running on ppc64le-flang-rhel-test while building mlir at step 5 "build-unified-tree".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/157/builds/1431

Here is the relevant piece of the build log for the reference:

Step 5 (build-unified-tree) failure: build (failure)
...
66.925 [18/16/6436] Linking CXX executable bin/mlir-lsp-server
66.977 [18/15/6437] Linking CXX executable bin/mlir-reduce
67.262 [18/14/6438] Linking CXX executable bin/mlir-capi-pass-test
67.293 [18/13/6439] Linking CXX executable bin/mlir-capi-translation-test
67.391 [18/12/6440] Linking CXX executable bin/mlir-query
67.532 [18/11/6441] Linking CXX executable bin/mlir-capi-execution-engine-test
67.730 [18/10/6442] Linking CXX executable bin/mlir-opt
72.649 [18/9/6443] Building CXX object tools/flang/tools/bbc/CMakeFiles/bbc.dir/bbc.cpp.o
83.638 [18/8/6444] Building CXX object tools/flang/lib/Lower/CMakeFiles/obj.FortranLower.dir/OpenMP/Utils.cpp.o
85.920 [18/7/6445] Building CXX object tools/flang/lib/Lower/CMakeFiles/obj.FortranLower.dir/OpenMP/OpenMP.cpp.o
FAILED: tools/flang/lib/Lower/CMakeFiles/obj.FortranLower.dir/OpenMP/OpenMP.cpp.o 
ccache /home/buildbots/llvm-external-buildbots/clang.16.0.1/bin/clang++ -DFLANG_INCLUDE_TESTS=1 -DFLANG_LITTLE_ENDIAN=1 -DGTEST_HAS_RTTI=0 -D_DEBUG -D_GLIBCXX_ASSERTIONS -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/build/tools/flang/lib/Lower -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Lower -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/include -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/build/tools/flang/include -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/build/include -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/llvm/include -isystem /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/llvm/../mlir/include -isystem /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/build/tools/mlir/include -isystem /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/build/tools/clang/include -isystem /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/llvm/../clang/include -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -Werror -Wno-deprecated-copy -Wno-string-conversion -Wno-ctad-maybe-unsupported -Wno-unused-command-line-argument -Wstring-conversion           -Wcovered-switch-default -Wno-nested-anon-types -O3 -DNDEBUG -std=c++17  -fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -MD -MT tools/flang/lib/Lower/CMakeFiles/obj.FortranLower.dir/OpenMP/OpenMP.cpp.o -MF tools/flang/lib/Lower/CMakeFiles/obj.FortranLower.dir/OpenMP/OpenMP.cpp.o.d -o tools/flang/lib/Lower/CMakeFiles/obj.FortranLower.dir/OpenMP/OpenMP.cpp.o -c /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Lower/OpenMP/OpenMP.cpp
In file included from /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Lower/OpenMP/OpenMP.cpp:15:
/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Lower/OpenMP/ClauseProcessor.h:132:18: error: no type named 'UseDeviceClauseOps' in namespace 'mlir::omp'
      mlir::omp::UseDeviceClauseOps &result,
      ~~~~~~~~~~~^
/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Lower/OpenMP/ClauseProcessor.h:137:18: error: no type named 'UseDeviceClauseOps' in namespace 'mlir::omp'
      mlir::omp::UseDeviceClauseOps &result,
      ~~~~~~~~~~~^
/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Lower/OpenMP/OpenMP.cpp:247:16: error: no type named 'UseDeviceClauseOps' in namespace 'mlir::omp'
    mlir::omp::UseDeviceClauseOps &clauseOps,
    ~~~~~~~~~~~^
/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Lower/OpenMP/OpenMP.cpp:1027:13: error: no member named 'nameAttr' in 'mlir::omp::detail::Clauses<mlir::omp::CriticalNameClauseOps, mlir::omp::HintClauseOps>'
  clauseOps.nameAttr =
  ~~~~~~~~~ ^
/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Lower/OpenMP/OpenMP.cpp:1199:3: error: no matching function for call to 'promoteNonCPtrUseDevicePtrArgsToUseDeviceAddr'
  promoteNonCPtrUseDevicePtrArgsToUseDeviceAddr(clauseOps, useDeviceTypes,
  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Lower/OpenMP/OpenMP.cpp:246:13: note: candidate function not viable: no known conversion from 'mlir::omp::TargetDataClauseOps' (aka 'Clauses<DeviceClauseOps, IfClauseOps, MapClauseOps, UseDeviceAddrClauseOps, UseDevicePtrClauseOps>') to 'int &' for 1st argument
static void promoteNonCPtrUseDevicePtrArgsToUseDeviceAddr(
            ^
5 errors generated.
88.250 [18/6/6446] Building CXX object tools/flang/lib/Lower/CMakeFiles/obj.FortranLower.dir/OpenMP/ClauseProcessor.cpp.o
FAILED: tools/flang/lib/Lower/CMakeFiles/obj.FortranLower.dir/OpenMP/ClauseProcessor.cpp.o 
ccache /home/buildbots/llvm-external-buildbots/clang.16.0.1/bin/clang++ -DFLANG_INCLUDE_TESTS=1 -DFLANG_LITTLE_ENDIAN=1 -DGTEST_HAS_RTTI=0 -D_DEBUG -D_GLIBCXX_ASSERTIONS -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/build/tools/flang/lib/Lower -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Lower -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/include -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/build/tools/flang/include -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/build/include -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/llvm/include -isystem /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/llvm/../mlir/include -isystem /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/build/tools/mlir/include -isystem /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/build/tools/clang/include -isystem /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/llvm/../clang/include -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -Werror -Wno-deprecated-copy -Wno-string-conversion -Wno-ctad-maybe-unsupported -Wno-unused-command-line-argument -Wstring-conversion           -Wcovered-switch-default -Wno-nested-anon-types -O3 -DNDEBUG -std=c++17  -fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -MD -MT tools/flang/lib/Lower/CMakeFiles/obj.FortranLower.dir/OpenMP/ClauseProcessor.cpp.o -MF tools/flang/lib/Lower/CMakeFiles/obj.FortranLower.dir/OpenMP/ClauseProcessor.cpp.o.d -o tools/flang/lib/Lower/CMakeFiles/obj.FortranLower.dir/OpenMP/ClauseProcessor.cpp.o -c /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
In file included from /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Lower/OpenMP/ClauseProcessor.cpp:13:
/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Lower/OpenMP/ClauseProcessor.h:132:18: error: no type named 'UseDeviceClauseOps' in namespace 'mlir::omp'
      mlir::omp::UseDeviceClauseOps &result,
      ~~~~~~~~~~~^
/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Lower/OpenMP/ClauseProcessor.h:137:18: error: no type named 'UseDeviceClauseOps' in namespace 'mlir::omp'
      mlir::omp::UseDeviceClauseOps &result,
      ~~~~~~~~~~~^
/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Lower/OpenMP/ClauseProcessor.cpp:1076:16: error: no type named 'UseDeviceClauseOps' in namespace 'mlir::omp'
    mlir::omp::UseDeviceClauseOps &result,
    ~~~~~~~~~~~^
/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Lower/OpenMP/ClauseProcessor.cpp:1088:16: error: no type named 'UseDeviceClauseOps' in namespace 'mlir::omp'
    mlir::omp::UseDeviceClauseOps &result,
    ~~~~~~~~~~~^
4 errors generated.

lravenclaw pushed a commit to lravenclaw/llvm-project that referenced this pull request Jul 3, 2024
This patch updates `OpenMP_Op` definitions to be based on the new set of
`OpenMP_Clause` definitions, and to take advantage of clause-based
automatically-generated argument lists, descriptions, assembly format
and class declarations.

There are also changes introduced to the clause operands structures to
match the current set of tablegen clause definitions. These two are very
closely linked and should be kept in sync. It would probably be a good
idea to try generating clause operands structures from the tablegen
`OpenMP_Clause` definitions in the future.

As a result of this change, arguments for some operations have been
reordered. This patch also addresses this by updating affected operation
build calls and unit tests. Some other updates to tests related to the
order of arguments in the resulting assembly format and others due to
certain previous inconsistencies in the printing/parsing of clauses are
addressed.

The printer and parser functions for the `map` clause are updated, so
that they are able to handle `map` clauses linked to entry block
arguments as well as those which aren't.

This PR causes a build failure in the flang subproject. This is addressed
by the next PR in the stack.
kbluck pushed a commit to kbluck/llvm-project that referenced this pull request Jul 6, 2024
This patch updates `OpenMP_Op` definitions to be based on the new set of
`OpenMP_Clause` definitions, and to take advantage of clause-based
automatically-generated argument lists, descriptions, assembly format
and class declarations.

There are also changes introduced to the clause operands structures to
match the current set of tablegen clause definitions. These two are very
closely linked and should be kept in sync. It would probably be a good
idea to try generating clause operands structures from the tablegen
`OpenMP_Clause` definitions in the future.

As a result of this change, arguments for some operations have been
reordered. This patch also addresses this by updating affected operation
build calls and unit tests. Some other updates to tests related to the
order of arguments in the resulting assembly format and others due to
certain previous inconsistencies in the printing/parsing of clauses are
addressed.

The printer and parser functions for the `map` clause are updated, so
that they are able to handle `map` clauses linked to entry block
arguments as well as those which aren't.

This PR causes a build failure in the flang subproject. This is addressed
by the next PR in the stack.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants