| //===-- OpenMPOps.td - OpenMP dialect operation definitions *- tablegen -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines the basic operations for the OpenMP dialect. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| |
| #ifndef OPENMP_OPS |
| #define OPENMP_OPS |
| |
| include "mlir/IR/OpBase.td" |
| include "mlir/Interfaces/SideEffectInterfaces.td" |
| include "mlir/Interfaces/ControlFlowInterfaces.td" |
| include "mlir/IR/SymbolInterfaces.td" |
| include "mlir/Dialect/OpenMP/OmpCommon.td" |
| include "mlir/Dialect/LLVMIR/LLVMOpBase.td" |
| include "mlir/Dialect/OpenMP/OpenMPOpsInterfaces.td" |
| |
| def OpenMP_Dialect : Dialect { |
| let name = "omp"; |
| let cppNamespace = "::mlir::omp"; |
| let dependentDialects = ["::mlir::LLVM::LLVMDialect"]; |
| } |
| |
| class OpenMP_Op<string mnemonic, list<OpTrait> traits = []> : |
| Op<OpenMP_Dialect, mnemonic, traits>; |
| |
| // Type which can be constraint accepting standard integers and indices. |
| def IntLikeType : AnyTypeOf<[AnyInteger, Index]>; |
| |
| def OpenMP_PointerLikeTypeInterface : TypeInterface<"PointerLikeType"> { |
| let cppNamespace = "::mlir::omp"; |
| |
| let description = [{ |
| An interface for pointer-like types suitable to contain a value that OpenMP |
| specification refers to as variable. |
| }]; |
| |
| let methods = [ |
| InterfaceMethod< |
| /*description=*/"Returns the pointee type.", |
| /*retTy=*/"::mlir::Type", |
| /*methodName=*/"getElementType" |
| >, |
| ]; |
| } |
| |
| def OpenMP_PointerLikeType : Type< |
| CPred<"$_self.isa<::mlir::omp::PointerLikeType>()">, |
| "OpenMP-compatible variable type", "::mlir::omp::PointerLikeType">; |
| |
| //===----------------------------------------------------------------------===// |
| // 2.6 parallel Construct |
| //===----------------------------------------------------------------------===// |
| |
| // Possible values for the default clause |
| def ClauseDefaultPrivate : StrEnumAttrCase<"defprivate">; |
| def ClauseDefaultFirstPrivate : StrEnumAttrCase<"deffirstprivate">; |
| def ClauseDefaultShared : StrEnumAttrCase<"defshared">; |
| def ClauseDefaultNone : StrEnumAttrCase<"defnone">; |
| |
| def ClauseDefault : StrEnumAttr< |
| "ClauseDefault", |
| "default clause", |
| [ClauseDefaultPrivate, ClauseDefaultFirstPrivate, ClauseDefaultShared, |
| ClauseDefaultNone]> { |
| let cppNamespace = "::mlir::omp"; |
| } |
| |
| def ParallelOp : OpenMP_Op<"parallel", [AttrSizedOperandSegments, |
| DeclareOpInterfaceMethods<OutlineableOpenMPOpInterface>]> { |
| 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 |
| 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 optional $default_val attribute specifies the default data sharing attribute |
| of values used in the parallel region that are not passed explicitly as parameters |
| to the operation. |
| |
| The $private_vars, $firstprivate_vars, $shared_vars and $copyin_vars parameters |
| are a variadic list of values that specify the data sharing attribute of |
| those values. |
| |
| 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 optional $proc_bind_val attribute controls the thread affinity for the execution |
| of the parallel region. |
| }]; |
| |
| let arguments = (ins Optional<AnyType>:$if_expr_var, |
| Optional<AnyType>:$num_threads_var, |
| OptionalAttr<ClauseDefault>:$default_val, |
| Variadic<AnyType>:$private_vars, |
| Variadic<AnyType>:$firstprivate_vars, |
| Variadic<AnyType>:$shared_vars, |
| Variadic<AnyType>:$copyin_vars, |
| Variadic<AnyType>:$allocate_vars, |
| Variadic<AnyType>:$allocators_vars, |
| OptionalAttr<ProcBindKind>:$proc_bind_val); |
| |
| let regions = (region AnyRegion:$region); |
| |
| let builders = [ |
| OpBuilder<(ins CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes)> |
| ]; |
| let parser = [{ return parseParallelOp(parser, result); }]; |
| let printer = [{ return printParallelOp(p, *this); }]; |
| let verifier = [{ return ::verifyParallelOp(*this); }]; |
| } |
| |
| def TerminatorOp : OpenMP_Op<"terminator", [Terminator]> { |
| let summary = "terminator for OpenMP regions"; |
| let description = [{ |
| A terminator operation for regions that appear in the body of OpenMP |
| operation. These regions are not expected to return any value so the |
| terminator takes no operands. The terminator op returns control to the |
| enclosing op. |
| }]; |
| |
| let assemblyFormat = "attr-dict"; |
| } |
| |
| def OMP_SCHEDULE_MOD_None : StrEnumAttrCase<"none", 0>; |
| def OMP_SCHEDULE_MOD_Monotonic : StrEnumAttrCase<"monotonic", 1>; |
| def OMP_SCHEDULE_MOD_Nonmonotonic : StrEnumAttrCase<"nonmonotonic", 2>; |
| def OMP_SCHEDULE_MOD_SIMD : StrEnumAttrCase<"simd", 3>; |
| |
| def ScheduleModifier : StrEnumAttr<"ScheduleModifier", "OpenMP Schedule Modifier", |
| [OMP_SCHEDULE_MOD_None, |
| OMP_SCHEDULE_MOD_Monotonic, |
| OMP_SCHEDULE_MOD_Nonmonotonic, |
| OMP_SCHEDULE_MOD_SIMD]> |
| { |
| 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 |
| //===----------------------------------------------------------------------===// |
| |
| def WsLoopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments, |
| AllTypesMatch<["lowerBound", "upperBound", "step"]>]> { |
| let summary = "workshare loop construct"; |
| let description = [{ |
| The workshare loop construct specifies that the iterations of the loop(s) |
| will be executed in parallel by threads in the current context. These |
| iterations are spread across threads that already exist in the enclosing |
| parallel region. The lower and upper bounds specify a half-open range: the |
| range includes the lower bound but does not include the upper bound. If the |
| `inclusive` attribute is specified then the upper bound is also included. |
| |
| The body region can contain any number of blocks. The region is terminated |
| by "omp.yield" instruction without operands. |
| |
| ``` |
| omp.wsloop (%i1, %i2) : index = (%c0, %c0) to (%c10, %c10) step (%c1, %c1) { |
| %a = load %arrA[%i1, %i2] : memref<?x?xf32> |
| %b = load %arrB[%i1, %i2] : memref<?x?xf32> |
| %sum = arith.addf %a, %b : f32 |
| store %sum, %arrC[%i1, %i2] : memref<?x?xf32> |
| omp.yield |
| } |
| ``` |
| |
| `private_vars`, `firstprivate_vars`, `lastprivate_vars` and `linear_vars` |
| arguments are variadic list of operands that specify the data sharing |
| attributes of the list of values. 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 workshare loop 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 current loop |
| iteration 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 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. |
| |
| The optional `collapse_val` attribute specifies the number of loops which |
| are collapsed to form the worksharing loop. |
| |
| The `nowait` attribute, when present, signifies that there should be no |
| implicit barrier at the end of the loop. |
| |
| The optional `ordered_val` attribute specifies how many loops are associated |
| with the do loop construct. |
| |
| The optional `order` attribute specifies which order the iterations of the |
| associate loops are executed in. Currently the only option for this |
| attribute is "concurrent". |
| }]; |
| |
| let arguments = (ins Variadic<IntLikeType>:$lowerBound, |
| Variadic<IntLikeType>:$upperBound, |
| Variadic<IntLikeType>:$step, |
| Variadic<AnyType>:$private_vars, |
| Variadic<AnyType>:$firstprivate_vars, |
| Variadic<AnyType>:$lastprivate_vars, |
| Variadic<AnyType>:$linear_vars, |
| Variadic<AnyType>:$linear_step_vars, |
| Variadic<OpenMP_PointerLikeType>:$reduction_vars, |
| OptionalAttr<SymbolRefArrayAttr>:$reductions, |
| OptionalAttr<ScheduleKind>:$schedule_val, |
| Optional<AnyType>:$schedule_chunk_var, |
| OptionalAttr<ScheduleModifier>:$schedule_modifier, |
| UnitAttr:$simd_modifier, |
| Confined<OptionalAttr<I64Attr>, [IntMinValue<0>]>:$collapse_val, |
| UnitAttr:$nowait, |
| Confined<OptionalAttr<I64Attr>, [IntMinValue<0>]>:$ordered_val, |
| OptionalAttr<OrderKind>:$order_val, |
| UnitAttr:$inclusive); |
| |
| let skipDefaultBuilders = 1; |
| |
| let builders = [ |
| OpBuilder<(ins "ValueRange":$lowerBound, "ValueRange":$upperBound, |
| "ValueRange":$step, |
| CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes)>, |
| OpBuilder<(ins "TypeRange":$resultTypes, "ValueRange":$lowerBound, |
| "ValueRange":$upperBound, "ValueRange":$step, |
| "ValueRange":$privateVars, "ValueRange":$firstprivateVars, |
| "ValueRange":$lastprivate_vars, "ValueRange":$linear_vars, |
| "ValueRange":$linear_step_vars, "ValueRange":$reduction_vars, |
| "StringAttr":$schedule_val, "Value":$schedule_chunk_var, |
| "IntegerAttr":$collapse_val, "UnitAttr":$nowait, |
| "IntegerAttr":$ordered_val, "StringAttr":$order_val, |
| "UnitAttr":$inclusive, CArg<"bool", "true">:$buildBody)>, |
| OpBuilder<(ins "TypeRange":$resultTypes, "ValueRange":$operands, |
| CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes)> |
| ]; |
| |
| let regions = (region AnyRegion:$region); |
| |
| let extraClassDeclaration = [{ |
| /// Returns the number of loops in the workshape loop nest. |
| unsigned getNumLoops() { return lowerBound().size(); } |
| |
| /// Returns the number of reduction variables. |
| unsigned getNumReductionVars() { return reduction_vars().size(); } |
| }]; |
| let parser = [{ return parseWsLoopOp(parser, result); }]; |
| let printer = [{ return printWsLoopOp(p, *this); }]; |
| let verifier = [{ return ::verifyWsLoopOp(*this); }]; |
| } |
| |
| def YieldOp : OpenMP_Op<"yield", |
| [NoSideEffect, ReturnLike, Terminator, |
| ParentOneOf<["WsLoopOp", "ReductionDeclareOp"]>]> { |
| let summary = "loop yield and termination operation"; |
| let description = [{ |
| "omp.yield" yields SSA values from the OpenMP dialect op region and |
| terminates the region. The semantics of how the values are yielded is |
| defined by the parent operation. |
| If "omp.yield" has any operands, the operands must match the parent |
| operation's results. |
| }]; |
| |
| let arguments = (ins Variadic<AnyType>:$results); |
| |
| let assemblyFormat = [{ ( `(` $results^ `:` type($results) `)` )? attr-dict}]; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // 2.10.4 taskyield Construct |
| //===----------------------------------------------------------------------===// |
| |
| def TaskyieldOp : OpenMP_Op<"taskyield"> { |
| let summary = "taskyield construct"; |
| let description = [{ |
| The taskyield construct specifies that the current task can be suspended |
| in favor of execution of a different task. |
| }]; |
| |
| let assemblyFormat = "attr-dict"; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // 2.13.7 flush Construct |
| //===----------------------------------------------------------------------===// |
| def FlushOp : OpenMP_Op<"flush"> { |
| let summary = "flush construct"; |
| let description = [{ |
| The flush construct executes the OpenMP flush operation. This operation |
| makes a thread’s temporary view of memory consistent with memory and |
| enforces an order on the memory operations of the variables explicitly |
| specified or implied. |
| }]; |
| |
| let arguments = (ins Variadic<AnyType>:$varList); |
| |
| let assemblyFormat = [{ ( `(` $varList^ `:` type($varList) `)` )? attr-dict}]; |
| } |
| //===----------------------------------------------------------------------===// |
| // 2.14.5 target construct |
| //===----------------------------------------------------------------------===// |
| |
| def TargetOp : OpenMP_Op<"target",[AttrSizedOperandSegments]> { |
| let summary = "target construct"; |
| let description = [{ |
| The target construct includes a region of code which is to be executed |
| on a device. |
| |
| The optional $if_expr parameter specifies a boolean result of a |
| conditional check. If this value is 1 or is not provided then the target |
| region runs on a device, if it is 0 then the target region is executed on the |
| host device. |
| |
| The optional $device parameter specifies the device number for the target region. |
| |
| The optional $thread_limit specifies the limit on the number of threads |
| |
| The optional $nowait elliminates the implicit barrier so the parent task can make progress |
| even if the target task is not yet completed. |
| |
| TODO: private, map, is_device_ptr, firstprivate, depend, defaultmap, in_reduction |
| |
| }]; |
| |
| let arguments = (ins Optional<I1>:$if_expr, |
| Optional<AnyInteger>:$device, |
| Optional<AnyInteger>:$thread_limit, |
| UnitAttr:$nowait); |
| |
| let regions = (region AnyRegion:$region); |
| } |
| |
| |
| //===----------------------------------------------------------------------===// |
| // 2.16 master Construct |
| //===----------------------------------------------------------------------===// |
| def MasterOp : OpenMP_Op<"master"> { |
| let summary = "master construct"; |
| let description = [{ |
| The master construct specifies a structured block that is executed by |
| the master thread of the team. |
| }]; |
| |
| let regions = (region AnyRegion:$region); |
| |
| let assemblyFormat = "$region attr-dict"; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // 2.17.1 critical Construct |
| //===----------------------------------------------------------------------===// |
| def CriticalDeclareOp : OpenMP_Op<"critical.declare", [Symbol]> { |
| let summary = "declares a named critical section."; |
| |
| let description = [{ |
| Declares a named critical section. |
| |
| The name can be used in critical constructs in the dialect. |
| }]; |
| |
| let arguments = (ins SymbolNameAttr:$sym_name, |
| DefaultValuedAttr<I64Attr, "0">:$hint); |
| |
| let assemblyFormat = [{ |
| $sym_name custom<SynchronizationHint>($hint) attr-dict |
| }]; |
| |
| let verifier = "return verifyCriticalDeclareOp(*this);"; |
| } |
| |
| |
| def CriticalOp : OpenMP_Op<"critical"> { |
| let summary = "critical construct"; |
| let description = [{ |
| The critical construct imposes a restriction on the associated structured |
| block (region) to be executed by only a single thread at a time. |
| }]; |
| |
| let arguments = (ins OptionalAttr<FlatSymbolRefAttr>:$name); |
| |
| let regions = (region AnyRegion:$region); |
| |
| let assemblyFormat = [{ |
| (`(` $name^ `)`)? $region attr-dict |
| }]; |
| |
| let verifier = "return ::verifyCriticalOp(*this);"; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // 2.17.2 barrier Construct |
| //===----------------------------------------------------------------------===// |
| |
| def BarrierOp : OpenMP_Op<"barrier"> { |
| let summary = "barrier construct"; |
| let description = [{ |
| The barrier construct specifies an explicit barrier at the point at which |
| the construct appears. |
| }]; |
| |
| let assemblyFormat = "attr-dict"; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // [5.1] 2.19.9 ordered Construct |
| //===----------------------------------------------------------------------===// |
| |
| def ClauseDependSource : StrEnumAttrCase<"dependsource">; |
| def ClauseDependSink : StrEnumAttrCase<"dependsink">; |
| |
| def ClauseDepend : StrEnumAttr< |
| "ClauseDepend", |
| "depend clause", |
| [ClauseDependSource, ClauseDependSink]> { |
| let cppNamespace = "::mlir::omp"; |
| } |
| |
| def OrderedOp : OpenMP_Op<"ordered"> { |
| let summary = "ordered construct without region"; |
| let description = [{ |
| The ordered construct without region is a stand-alone directive that |
| specifies cross-iteration dependences in a doacross loop nest. |
| |
| The `depend_type_val` attribute refers to either the DEPEND(SOURCE) clause |
| or the DEPEND(SINK: vec) clause. |
| |
| The `num_loops_val` attribute specifies the number of loops in the doacross |
| nest. |
| |
| The `depend_vec_vars` is a variadic list of operands that specifies the index |
| of the loop iterator in the doacross nest for the DEPEND(SOURCE) clause or |
| the index of the element of "vec" for the DEPEND(SINK: vec) clause. It |
| contains the operands in multiple "vec" when multiple DEPEND(SINK: vec) |
| clauses exist in one ORDERED directive. |
| }]; |
| |
| let arguments = (ins OptionalAttr<ClauseDepend>:$depend_type_val, |
| Confined<OptionalAttr<I64Attr>, [IntMinValue<0>]>:$num_loops_val, |
| Variadic<AnyType>:$depend_vec_vars); |
| |
| let assemblyFormat = [{ |
| ( `depend_type` `(` $depend_type_val^ `)` )? |
| ( `depend_vec` `(` $depend_vec_vars^ `:` type($depend_vec_vars) `)` )? |
| attr-dict |
| }]; |
| |
| let verifier = "return ::verifyOrderedOp(*this);"; |
| } |
| |
| def OrderedRegionOp : OpenMP_Op<"ordered_region"> { |
| let summary = "ordered construct with region"; |
| let description = [{ |
| The ordered construct with region specifies a structured block in a |
| worksharing-loop, SIMD, or worksharing-loop SIMD region that is executed in |
| the order of the loop iterations. |
| |
| The `simd` attribute corresponds to the SIMD clause specified. If it is not |
| present, it behaves as if the THREADS clause is specified or no clause is |
| specified. |
| }]; |
| |
| let arguments = (ins UnitAttr:$simd); |
| |
| let regions = (region AnyRegion:$region); |
| |
| let assemblyFormat = [{ ( `simd` $simd^ )? $region attr-dict}]; |
| |
| let verifier = "return ::verifyOrderedRegionOp(*this);"; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // 2.17.5 taskwait Construct |
| //===----------------------------------------------------------------------===// |
| |
| def TaskwaitOp : OpenMP_Op<"taskwait"> { |
| let summary = "taskwait construct"; |
| let description = [{ |
| The taskwait construct specifies a wait on the completion of child tasks |
| of the current task. |
| }]; |
| |
| let assemblyFormat = "attr-dict"; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // 2.17.7 atomic construct |
| //===----------------------------------------------------------------------===// |
| |
| // In the OpenMP Specification, atomic construct has an `atomic-clause` which |
| // can take the values `read`, `write`, `update` and `capture`. These four |
| // kinds of atomic constructs are fundamentally independent and are handled |
| // separately while lowering. Having four separate operations (one for each |
| // value of the clause) here decomposes handling of this construct into a |
| // two-step process. |
| |
| def AtomicReadOp : OpenMP_Op<"atomic.read"> { |
| let arguments = (ins OpenMP_PointerLikeType:$address, |
| DefaultValuedAttr<I64Attr, "0">:$hint, |
| OptionalAttr<MemoryOrderKind>:$memory_order); |
| let results = (outs AnyType); |
| let parser = [{ return parseAtomicReadOp(parser, result); }]; |
| let printer = [{ return printAtomicReadOp(p, *this); }]; |
| let verifier = [{ return verifyAtomicReadOp(*this); }]; |
| } |
| |
| def AtomicWriteOp : OpenMP_Op<"atomic.write"> { |
| let arguments = (ins OpenMP_PointerLikeType:$address, |
| AnyType:$value, |
| DefaultValuedAttr<I64Attr, "0">:$hint, |
| OptionalAttr<MemoryOrderKind>:$memory_order); |
| let parser = [{ return parseAtomicWriteOp(parser, result); }]; |
| let printer = [{ return printAtomicWriteOp(p, *this); }]; |
| let verifier = [{ return verifyAtomicWriteOp(*this); }]; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // 2.19.5.7 declare reduction Directive |
| //===----------------------------------------------------------------------===// |
| |
| def ReductionDeclareOp : OpenMP_Op<"reduction.declare", [Symbol]> { |
| let summary = "declares a reduction kind"; |
| |
| let description = [{ |
| Declares an OpenMP reduction kind. This requires two mandatory and one |
| optional region. |
| |
| 1. The initializer region specifies how to initialize the thread-local |
| reduction value. This is usually the neutral element of the reduction. |
| For convenience, the region has an argument that contains the value |
| of the reduction accumulator at the start of the reduction. It is |
| expected to `omp.yield` the new value on all control flow paths. |
| 2. The reduction region specifies how to combine two values into one, i.e. |
| the reduction operator. It accepts the two values as arguments and is |
| expected to `omp.yield` the combined value on all control flow paths. |
| 3. The atomic reduction region is optional and specifies how two values |
| can be combined atomically given local accumulator variables. It is |
| expected to store the combined value in the first accumulator variable. |
| |
| Note that the MLIR type system does not allow for type-polymorphic |
| reductions. Separate reduction declarations should be created for different |
| element and accumulator types. |
| }]; |
| |
| let arguments = (ins SymbolNameAttr:$sym_name, |
| TypeAttr:$type); |
| |
| let regions = (region AnyRegion:$initializerRegion, |
| AnyRegion:$reductionRegion, |
| AnyRegion:$atomicReductionRegion); |
| let verifier = "return ::verifyReductionDeclareOp(*this);"; |
| |
| let assemblyFormat = "$sym_name `:` $type attr-dict-with-keyword " |
| "`init` $initializerRegion " |
| "`combiner` $reductionRegion " |
| "custom<AtomicReductionRegion>($atomicReductionRegion)"; |
| |
| let extraClassDeclaration = [{ |
| PointerLikeType getAccumulatorType() { |
| if (atomicReductionRegion().empty()) |
| return {}; |
| |
| return atomicReductionRegion().front().getArgument(0).getType(); |
| } |
| }]; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // 2.19.5.4 reduction clause |
| //===----------------------------------------------------------------------===// |
| |
| def ReductionOp : OpenMP_Op<"reduction", [ |
| TypesMatchWith<"value types matches accumulator element type", |
| "accumulator", "operand", |
| "$_self.cast<::mlir::omp::PointerLikeType>().getElementType()"> |
| ]> { |
| let summary = "reduction construct"; |
| let description = [{ |
| Indicates the value that is produced by the current reduction-participating |
| entity for a reduction requested in some ancestor. The reduction is |
| identified by the accumulator, but the value of the accumulator may not be |
| updated immediately. |
| }]; |
| |
| let arguments= (ins AnyType:$operand, OpenMP_PointerLikeType:$accumulator); |
| let assemblyFormat = |
| "$operand `,` $accumulator attr-dict `:` type($accumulator)"; |
| let verifier = "return ::verifyReductionOp(*this);"; |
| } |
| |
| #endif // OPENMP_OPS |