xref: /llvm-project/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td (revision e492083f55d98144ba9a049450cb429d7fd52510)
1//===- OpenACCOps.td - OpenACC operation definitions -------*- tablegen -*-===//
2//
3// Part of the MLIR Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7// =============================================================================
8//
9// Defines MLIR OpenACC operations.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef OPENACC_OPS
14#define OPENACC_OPS
15
16include "mlir/Interfaces/ControlFlowInterfaces.td"
17include "mlir/Interfaces/LoopLikeInterface.td"
18include "mlir/Interfaces/SideEffectInterfaces.td"
19include "mlir/IR/BuiltinTypes.td"
20include "mlir/IR/EnumAttr.td"
21include "mlir/IR/OpBase.td"
22include "mlir/IR/SymbolInterfaces.td"
23include "mlir/Dialect/OpenACC/OpenACCBase.td"
24include "mlir/Dialect/OpenACC/OpenACCOpsTypes.td"
25include "mlir/Dialect/OpenACC/OpenACCOpsInterfaces.td"
26include "mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td"
27include "mlir/Dialect/OpenACCMPCommon/Interfaces/AtomicInterfaces.td"
28include "mlir/Dialect/OpenACCMPCommon/Interfaces/OpenACCMPOpsInterfaces.td"
29
30// AccCommon requires definition of OpenACC_Dialect.
31include "mlir/Dialect/OpenACC/AccCommon.td"
32
33// Base class for OpenACC dialect ops.
34class OpenACC_Op<string mnemonic, list<Trait> traits = []> :
35  Op<OpenACC_Dialect, mnemonic, traits>;
36
37// Reduction operation enumeration.
38def OpenACC_ReductionOperatorAdd     : I32EnumAttrCase<"AccAdd", 0, "add">;
39def OpenACC_ReductionOperatorMul     : I32EnumAttrCase<"AccMul", 1, "mul">;
40def OpenACC_ReductionOperatorMax     : I32EnumAttrCase<"AccMax", 2, "max">;
41def OpenACC_ReductionOperatorMin     : I32EnumAttrCase<"AccMin", 3, "min">;
42def OpenACC_ReductionOperatorAnd     : I32EnumAttrCase<"AccIand", 4, "iand">;
43def OpenACC_ReductionOperatorOr      : I32EnumAttrCase<"AccIor", 5, "ior">;
44def OpenACC_ReductionOperatorXor     : I32EnumAttrCase<"AccXor", 6, "xor">;
45def OpenACC_ReductionOperatorLogEqv  : I32EnumAttrCase<"AccEqv", 7, "eqv">;
46def OpenACC_ReductionOperatorLogNeqv : I32EnumAttrCase<"AccNeqv", 8, "neqv">;
47def OpenACC_ReductionOperatorLogAnd  : I32EnumAttrCase<"AccLand", 9, "land">;
48def OpenACC_ReductionOperatorLogOr   : I32EnumAttrCase<"AccLor", 10, "lor">;
49
50def OpenACC_ReductionOperator : I32EnumAttr<"ReductionOperator",
51    "built-in reduction operations supported by OpenACC",
52    [OpenACC_ReductionOperatorAdd, OpenACC_ReductionOperatorMul,
53     OpenACC_ReductionOperatorMax, OpenACC_ReductionOperatorMin,
54     OpenACC_ReductionOperatorAnd, OpenACC_ReductionOperatorOr,
55     OpenACC_ReductionOperatorXor, OpenACC_ReductionOperatorLogEqv,
56     OpenACC_ReductionOperatorLogNeqv, OpenACC_ReductionOperatorLogAnd,
57     OpenACC_ReductionOperatorLogOr
58    ]> {
59  let genSpecializedAttr = 0;
60  let cppNamespace = "::mlir::acc";
61}
62def OpenACC_ReductionOperatorAttr : EnumAttr<OpenACC_Dialect,
63                                             OpenACC_ReductionOperator,
64                                             "reduction_operator"> {
65  let assemblyFormat = [{ ```<` $value `>` }];
66}
67
68// Type used in operation below.
69def IntOrIndex : AnyTypeOf<[AnyInteger, Index]>;
70
71// Simple alias to pointer-like interface to reduce verbosity.
72def OpenACC_PointerLikeType : TypeAlias<OpenACC_PointerLikeTypeInterface,
73    "pointer-like type">;
74def OpenACC_MappableType : TypeAlias<OpenACC_MappableTypeInterface,
75    "mappable type">;
76
77def OpenACC_AnyPointerOrMappableLike : TypeConstraint<Or<[OpenACC_PointerLikeType.predicate,
78    OpenACC_MappableType.predicate]>, "any pointer or mappable">;
79def OpenACC_AnyPointerOrMappableType : Type<OpenACC_AnyPointerOrMappableLike.predicate,
80    "any pointer or mappable">;
81
82// Define the OpenACC data clauses. There are a few cases where a modifier
83// is used, like create(zero), copyin(readonly), and copyout(zero). Since in
84// some cases we decompose the original acc data clauses into multiple acc
85// dialect operations, we need to keep track of original clause. Thus even
86// for the clause with modifier, we create separate operation to make this
87// possible.
88def OpenACC_CopyinClause          : I64EnumAttrCase<"acc_copyin", 1>;
89def OpenACC_CopyinReadonlyClause  : I64EnumAttrCase<"acc_copyin_readonly", 2>;
90def OpenACC_CopyClause            : I64EnumAttrCase<"acc_copy", 3>;
91def OpenACC_CopyoutClause         : I64EnumAttrCase<"acc_copyout", 4>;
92def OpenACC_CopyoutZeroClause     : I64EnumAttrCase<"acc_copyout_zero", 5>;
93def OpenACC_PresentClause         : I64EnumAttrCase<"acc_present", 6>;
94def OpenACC_CreateClause          : I64EnumAttrCase<"acc_create", 7>;
95def OpenACC_CreateZeroClause      : I64EnumAttrCase<"acc_create_zero", 8>;
96def OpenACC_DeleteClause          : I64EnumAttrCase<"acc_delete", 9>;
97def OpenACC_AttachClause          : I64EnumAttrCase<"acc_attach", 10>;
98def OpenACC_DetachClause          : I64EnumAttrCase<"acc_detach", 11>;
99def OpenACC_NoCreateClause        : I64EnumAttrCase<"acc_no_create", 12>;
100def OpenACC_PrivateClause         : I64EnumAttrCase<"acc_private", 13>;
101def OpenACC_FirstPrivateClause    : I64EnumAttrCase<"acc_firstprivate", 14>;
102def OpenACC_IsDevicePtrClause     : I64EnumAttrCase<"acc_deviceptr", 15>;
103def OpenACC_GetDevicePtrClause    : I64EnumAttrCase<"acc_getdeviceptr", 16>;
104def OpenACC_UpdateHost            : I64EnumAttrCase<"acc_update_host", 17>;
105def OpenACC_UpdateSelf            : I64EnumAttrCase<"acc_update_self", 18>;
106def OpenACC_UpdateDevice          : I64EnumAttrCase<"acc_update_device", 19>;
107def OpenACC_UseDevice             : I64EnumAttrCase<"acc_use_device", 20>;
108def OpenACC_Reduction             : I64EnumAttrCase<"acc_reduction", 21>;
109def OpenACC_DeclareDeviceResident : I64EnumAttrCase<"acc_declare_device_resident", 22>;
110def OpenACC_DeclareLink           : I64EnumAttrCase<"acc_declare_link", 23>;
111def OpenACC_Cache                 : I64EnumAttrCase<"acc_cache", 24>;
112def OpenACC_CacheReadonly         : I64EnumAttrCase<"acc_cache_readonly", 25>;
113
114def OpenACC_DataClauseEnum : I64EnumAttr<"DataClause",
115    "data clauses supported by OpenACC",
116    [OpenACC_CopyinClause, OpenACC_CopyinReadonlyClause, OpenACC_CopyClause,
117     OpenACC_CopyoutClause, OpenACC_CopyoutZeroClause, OpenACC_PresentClause,
118     OpenACC_CreateClause, OpenACC_CreateZeroClause, OpenACC_DeleteClause,
119     OpenACC_AttachClause, OpenACC_DetachClause, OpenACC_NoCreateClause,
120     OpenACC_PrivateClause, OpenACC_FirstPrivateClause,
121     OpenACC_IsDevicePtrClause, OpenACC_GetDevicePtrClause, OpenACC_UpdateHost,
122     OpenACC_UpdateSelf, OpenACC_UpdateDevice, OpenACC_UseDevice,
123     OpenACC_Reduction, OpenACC_DeclareDeviceResident, OpenACC_DeclareLink,
124     OpenACC_Cache, OpenACC_CacheReadonly,
125    ]> {
126  let cppNamespace = "::mlir::acc";
127  let genSpecializedAttr = 0;
128}
129
130def OpenACC_DataClauseAttr : EnumAttr<OpenACC_Dialect, OpenACC_DataClauseEnum,
131                                      "data_clause">;
132
133class OpenACC_Attr<string name, string attrMnemonic,
134                   list<Trait> traits = [],
135                   string baseCppClass = "::mlir::Attribute">
136    : AttrDef<OpenACC_Dialect, name, traits, baseCppClass> {
137  let mnemonic = attrMnemonic;
138}
139
140// Attribute to describe the declare data clause used on variable.
141// Intended to be used at the variable creation site (on the global op or the
142// corresponding allocation operation). This is used in conjunction with the
143// declare operations (`acc.declare_enter` and `acc.declare_exit`) since those
144// describe how the data action is performed. The attribute itself makes it
145// easier to find out whether the variable is in a declare clause and what kind
146// of clause it is.
147def DeclareAttr : OpenACC_Attr<"Declare", "declare"> {
148  let parameters = (ins "DataClauseAttr":$dataClause,
149                        DefaultValuedParameter<"bool", "false">:$implicit);
150  let assemblyFormat = "`<` struct(params) `>`";
151  let builders = [AttrBuilder<(ins "DataClauseAttr":$dataClause), [{
152      return $_get($_ctxt, dataClause, /*implicit=*/false);
153    }]>
154  ];
155}
156
157// Attribute to attach functions that perform the pre/post allocation actions or
158// pre/post deallocation actions as described in section 2.13.
159def DeclareActionAttr : OpenACC_Attr<"DeclareAction", "declare_action"> {
160  let parameters = (ins OptionalParameter<"SymbolRefAttr">:$preAlloc,
161                        OptionalParameter<"SymbolRefAttr">:$postAlloc,
162                        OptionalParameter<"SymbolRefAttr">:$preDealloc,
163                        OptionalParameter<"SymbolRefAttr">:$postDealloc);
164  let assemblyFormat = "`<` struct(params) `>`";
165}
166
167// Device type enumeration.
168def OpenACC_DeviceTypeNone      : I32EnumAttrCase<"None", 0, "none">;
169def OpenACC_DeviceTypeStar      : I32EnumAttrCase<"Star", 1, "star">;
170def OpenACC_DeviceTypeDefault   : I32EnumAttrCase<"Default", 2, "default">;
171def OpenACC_DeviceTypeHost      : I32EnumAttrCase<"Host", 3, "host">;
172def OpenACC_DeviceTypeMulticore : I32EnumAttrCase<"Multicore", 4, "multicore">;
173def OpenACC_DeviceTypeNvidia    : I32EnumAttrCase<"Nvidia", 5, "nvidia">;
174def OpenACC_DeviceTypeRadeon    : I32EnumAttrCase<"Radeon", 6, "radeon">;
175
176def OpenACC_DeviceType : I32EnumAttr<"DeviceType",
177    "built-in device type supported by OpenACC",
178    [OpenACC_DeviceTypeNone, OpenACC_DeviceTypeStar, OpenACC_DeviceTypeDefault,
179     OpenACC_DeviceTypeHost, OpenACC_DeviceTypeMulticore,
180     OpenACC_DeviceTypeNvidia, OpenACC_DeviceTypeRadeon
181    ]> {
182  let genSpecializedAttr = 0;
183  let cppNamespace = "::mlir::acc";
184}
185
186// Device type attribute is used to associate a value for for clauses that
187// appear after a device_type clause. The list of clauses allowed after the
188// device_type clause is defined per construct as follows:
189// Loop construct: collapse, gang, worker, vector, seq, independent, auto,
190//                 and tile
191// Compute construct: async, wait, num_gangs, num_workers, and vector_length
192// Data construct: async and wait
193// Routine: gang, worker, vector, seq and bind
194//
195// The `none` means that the value appears before any device_type clause.
196//
197def OpenACC_DeviceTypeAttr : EnumAttr<OpenACC_Dialect,
198                                      OpenACC_DeviceType,
199                                      "device_type"> {
200  let assemblyFormat = [{ ```<` $value `>` }];
201}
202
203def DeviceTypeArrayAttr :
204  TypedArrayAttrBase<OpenACC_DeviceTypeAttr, "device type array attribute"> {
205  let constBuilderCall = ?;
206}
207
208// Gang arg type enumeration
209def OpenACC_GangArgNum      : I32EnumAttrCase<"Num", 0, "Num">;
210def OpenACC_GangArgDim      : I32EnumAttrCase<"Dim", 1, "Dim">;
211def OpenACC_GangArgStatic   : I32EnumAttrCase<"Static", 2, "Static">;
212
213def OpenACC_GangArgType : I32EnumAttr<"GangArgType",
214    "Differentiate the different gang arg values",
215    [OpenACC_GangArgNum, OpenACC_GangArgDim, OpenACC_GangArgStatic]> {
216  let genSpecializedAttr = 0;
217  let cppNamespace = "::mlir::acc";
218}
219def OpenACC_GangArgTypeAttr : EnumAttr<OpenACC_Dialect,
220                                       OpenACC_GangArgType,
221                                       "gang_arg_type"> {
222  let assemblyFormat = [{ ```<` $value `>` }];
223}
224def GangArgTypeArrayAttr :
225  TypedArrayAttrBase<OpenACC_GangArgTypeAttr, "gang arg type array attribute"> {
226  let constBuilderCall = ?;
227}
228
229// Combined constructs enumerations
230def OpenACC_KernelsLoop    : I32EnumAttrCase<"KernelsLoop", 1, "kernels_loop">;
231def OpenACC_ParallelLoop   : I32EnumAttrCase<"ParallelLoop", 2, "parallel_loop">;
232def OpenACC_SerialLoop     : I32EnumAttrCase<"SerialLoop", 3, "serial_loop">;
233
234def OpenACC_CombinedConstructsType : I32EnumAttr<"CombinedConstructsType",
235    "Differentiate between combined constructs",
236    [OpenACC_KernelsLoop, OpenACC_ParallelLoop, OpenACC_SerialLoop]> {
237  let genSpecializedAttr = 0;
238  let cppNamespace = "::mlir::acc";
239}
240
241def OpenACC_CombinedConstructsAttr : EnumAttr<OpenACC_Dialect,
242                                       OpenACC_CombinedConstructsType,
243                                       "combined_constructs"> {
244  let assemblyFormat = [{ ```<` $value `>` }];
245}
246
247def OpenACC_ParallelConstruct : I64EnumAttrCase<"acc_construct_parallel", 0>;
248def OpenACC_KernelsConstruct : I64EnumAttrCase<"acc_construct_kernels", 1>;
249def OpenACC_LoopConstruct : I64EnumAttrCase<"acc_construct_loop", 2>;
250def OpenACC_DataConstruct : I64EnumAttrCase<"acc_construct_data", 3>;
251def OpenACC_EnterDataConstruct : I64EnumAttrCase<"acc_construct_enter_data", 4>;
252def OpenACC_ExitDataConstruct : I64EnumAttrCase<"acc_construct_exit_data", 5>;
253def OpenACC_HostDataConstruct : I64EnumAttrCase<"acc_construct_host_data", 6>;
254def OpenACC_AtomicConstruct : I64EnumAttrCase<"acc_construct_atomic", 7>;
255def OpenACC_DeclareConstruct : I64EnumAttrCase<"acc_construct_declare", 8>;
256def OpenACC_InitConstruct : I64EnumAttrCase<"acc_construct_init", 9>;
257def OpenACC_ShutdownConstruct : I64EnumAttrCase<"acc_construct_shutdown", 10>;
258def OpenACC_SetConstruct : I64EnumAttrCase<"acc_construct_set", 11>;
259def OpenACC_UpdateConstruct : I64EnumAttrCase<"acc_construct_update", 12>;
260def OpenACC_RoutineConstruct : I64EnumAttrCase<"acc_construct_routine", 13>;
261def OpenACC_WaitConstruct : I64EnumAttrCase<"acc_construct_wait", 14>;
262def OpenACC_RuntimeAPIConstruct : I64EnumAttrCase<"acc_construct_runtime_api", 15>;
263def OpenACC_SerialConstruct : I64EnumAttrCase<"acc_construct_serial", 16>;
264
265def OpenACC_ConstructEnum : I64EnumAttr<"Construct",
266    "constructs supported by OpenACC",
267    [OpenACC_ParallelConstruct, OpenACC_KernelsConstruct,
268     OpenACC_LoopConstruct, OpenACC_DataConstruct,
269     OpenACC_EnterDataConstruct, OpenACC_ExitDataConstruct,
270     OpenACC_HostDataConstruct, OpenACC_AtomicConstruct,
271     OpenACC_DeclareConstruct, OpenACC_InitConstruct,
272     OpenACC_ShutdownConstruct, OpenACC_SetConstruct,
273     OpenACC_UpdateConstruct, OpenACC_RoutineConstruct,
274     OpenACC_WaitConstruct, OpenACC_RuntimeAPIConstruct,
275     OpenACC_SerialConstruct
276    ]> {
277  let genSpecializedAttr = 0;
278  let cppNamespace = "::mlir::acc";
279}
280
281def OpenACC_ConstructAttr : EnumAttr<OpenACC_Dialect, OpenACC_ConstructEnum,
282                                     "construct">;
283
284// Define a resource for the OpenACC runtime counters.
285def OpenACC_RuntimeCounters : Resource<"::mlir::acc::RuntimeCounters">;
286
287// Define a resource for the OpenACC constructs.
288// Useful to ensure that the constructs are not removed (even though
289// the data semantics are encoded in the operations linked via their
290// `dataOperands` list).
291def OpenACC_ConstructResource : Resource<"::mlir::acc::ConstructResource">;
292
293// Define a resource for the OpenACC current device setting.
294def OpenACC_CurrentDeviceIdResource : Resource<"::mlir::acc::CurrentDeviceIdResource">;
295
296// Used for data specification in data clauses (2.7.1).
297// Either (or both) extent and upperbound must be specified.
298def OpenACC_DataBoundsOp : OpenACC_Op<"bounds",
299    [AttrSizedOperandSegments, NoMemoryEffect]> {
300  let summary = "Represents normalized bounds information for acc data clause.";
301
302  let description = [{
303    This operation is used to record bounds used in acc data clause in a
304    normalized fashion (zero-based). This works well with the `PointerLikeType`
305    requirement in data clauses - since a `lowerbound` of 0 means looking
306    at data at the zero offset from pointer.
307
308    The operation must have an `upperbound` or `extent` (or both are allowed -
309    but not checked for consistency). When the source language's arrays are
310    not zero-based, the `startIdx` must specify the zero-position index.
311
312    Examples below show copying a slice of 10-element array except first element.
313    Note that the examples use extent in data clause for C++ and upperbound
314    for Fortran (as per 2.7.1). To simplify examples, the constants are used
315    directly in the acc.bounds operands - this is not the syntax of operation.
316
317    C++:
318    ```
319    int array[10];
320    #pragma acc copy(array[1:9])
321    ```
322    =>
323    ```mlir
324    acc.bounds lb(1) ub(9) extent(9) startIdx(0)
325    ```
326
327    Fortran:
328    ```
329    integer :: array(1:10)
330    !$acc copy(array(2:10))
331    ```
332    =>
333    ```mlir
334    acc.bounds lb(1) ub(9) extent(9) startIdx(1)
335    ```
336  }];
337
338  let arguments = (ins Optional<IntOrIndex>:$lowerbound,
339                       Optional<IntOrIndex>:$upperbound,
340                       Optional<IntOrIndex>:$extent,
341                       Optional<IntOrIndex>:$stride,
342                       DefaultValuedAttr<BoolAttr, "false">:$strideInBytes,
343                       Optional<IntOrIndex>:$startIdx);
344  let results = (outs OpenACC_DataBoundsType:$result);
345
346  let assemblyFormat = [{
347    oilist(
348        `lowerbound` `(` $lowerbound `:` type($lowerbound) `)`
349      | `upperbound` `(` $upperbound `:` type($upperbound) `)`
350      | `extent` `(` $extent `:` type($extent) `)`
351      | `stride` `(` $stride `:` type($stride) `)`
352      | `startIdx` `(` $startIdx `:` type($startIdx) `)`
353    ) attr-dict
354  }];
355
356  let hasVerifier = 1;
357
358  let builders = [
359    OpBuilder<(ins "::mlir::Value":$extent), [{
360        build($_builder, $_state,
361          ::mlir::acc::DataBoundsType::get($_builder.getContext()),
362          /*lowerbound=*/{}, /*upperbound=*/{}, extent,
363          /*stride=*/{}, /*strideInBytes=*/$_builder.getBoolAttr(false),
364          /*startIdx=*/{});
365      }]
366    >,
367    OpBuilder<(ins "::mlir::Value":$lowerbound,
368                   "::mlir::Value":$upperbound), [{
369        build($_builder, $_state,
370          ::mlir::acc::DataBoundsType::get($_builder.getContext()),
371          lowerbound, upperbound, /*extent=*/{},
372          /*stride=*/{}, /*strideInBytes=*/$_builder.getBoolAttr(false),
373          /*startIdx=*/{});
374      }]
375    >
376  ];
377}
378
379// Data entry operation does not refer to OpenACC spec terminology, but to
380// terminology used in this dialect. It refers to data operations that will
381// appear before data or compute region. It will be used as the base of acc
382// dialect operations for the following OpenACC data clauses: copyin, create,
383// present, attach, deviceptr.
384//
385// The bounds are represented in rank order. Rank 0 (inner-most dimension) is
386// the first.
387//
388class OpenACC_DataEntryOp<string mnemonic, string clause, string extraDescription,
389                          list<Trait> traits = [], dag additionalArgs = (ins)> :
390    OpenACC_Op<mnemonic, !listconcat(traits,
391        [AttrSizedOperandSegments,
392         MemoryEffects<[MemRead<OpenACC_CurrentDeviceIdResource>]>])> {
393  let arguments = !con(
394      additionalArgs,
395      (ins TypeAttr:$varType,
396          Optional<OpenACC_PointerLikeTypeInterface>:$varPtrPtr,
397          Variadic<OpenACC_DataBoundsType>:$bounds, /* rank-0 to rank-{n-1} */
398          Variadic<IntOrIndex>:$asyncOperands,
399          OptionalAttr<DeviceTypeArrayAttr>:$asyncOperandsDeviceType,
400          OptionalAttr<DeviceTypeArrayAttr>:$asyncOnly,
401          DefaultValuedAttr<OpenACC_DataClauseAttr, clause>:$dataClause,
402          DefaultValuedAttr<BoolAttr, "true">:$structured,
403          DefaultValuedAttr<BoolAttr, "false">:$implicit,
404          OptionalAttr<StrAttr>:$name));
405
406  let description = !strconcat(extraDescription, [{
407    Description of arguments:
408    - `var`: The variable to copy. Must be either `MappableType` or
409    `PointerLikeType`.
410    - `varType`: The type of the variable that is being copied. When `var` is
411    a `MappableType`, this matches the type of `var`. When `var` is a
412    `PointerLikeType`, this type holds information about the target of the
413    pointer.
414    - `varPtrPtr`: Specifies the address of the address of `var` - only used
415    when the variable copied is a field in a struct. This is important for
416    OpenACC due to implicit attach semantics on data clauses (2.6.4).
417    - `bounds`: Used when copying just slice of array or array's bounds are not
418    encoded in type. They are in rank order where rank 0 is inner-most dimension.
419    - `asyncOperands` and `asyncOperandsDeviceType`:
420    pair-wise lists of the async clause values associated with device_type's.
421    - `asyncOnly`: a list of device_type's for which async clause
422    does not specify a value (default is acc_async_noval - OpenACC 3.3 2.16.1).
423    - `dataClause`: Keeps track of the data clause the user used. This is because
424    the acc operations are decomposed. So a 'copy' clause is decomposed to both
425    `acc.copyin` and `acc.copyout` operations, but both have dataClause that
426    specifies `acc_copy` in this field.
427    - `structured`: Flag to note whether this is associated with structured region
428    (parallel, kernels, data) or unstructured (enter data, exit data). This is
429    important due to spec specifically calling out structured and dynamic reference
430    counters (2.6.7).
431    - `implicit`: Whether this is an implicitly generated operation, such as copies
432    done to satisfy "Variables with Implicitly Determined Data Attributes" in 2.6.2.
433    - `name`: Holds the name of variable as specified in user clause (including bounds).
434
435    The async values attached to the data entry operation imply that the data
436    action applies to all device types specified by the device_type clauses
437    using the activity queues on these devices as defined by the async values.
438  }]);
439
440  code extraClassDeclarationBase = [{
441    /// Return true if the op has the async attribute for the
442    /// mlir::acc::DeviceType::None device_type.
443    bool hasAsyncOnly() {
444      return hasAsyncOnly(mlir::acc::DeviceType::None);
445    }
446    /// Return true if the op has the async attribute for the given device_type.
447    bool hasAsyncOnly(mlir::acc::DeviceType deviceType) {
448      mlir::ArrayAttr asyncOnly = getAsyncOnlyAttr();
449      if (!asyncOnly)
450        return false;
451      for (auto attr : asyncOnly) {
452        auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
453        if (deviceTypeAttr.getValue() == deviceType)
454          return true;
455      }
456      return false;
457    }
458    /// Return the value of the async clause if present.
459    mlir::Value getAsyncValue() {
460      return getAsyncValue(mlir::acc::DeviceType::None);
461    }
462    /// Return the value of the async clause for the given device_type if
463    /// present.
464    mlir::Value getAsyncValue(mlir::acc::DeviceType deviceType) {
465      mlir::ArrayAttr deviceTypes = getAsyncOperandsDeviceTypeAttr();
466      if (!deviceTypes)
467        return nullptr;
468      for (auto [attr, asyncValue] :
469          llvm::zip(deviceTypes, getAsyncOperands())) {
470        auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
471        if (deviceTypeAttr.getValue() == deviceType)
472          return asyncValue;
473      }
474      return nullptr;
475    }
476    mlir::TypedValue<mlir::acc::PointerLikeType> getVarPtr() {
477      return mlir::dyn_cast<mlir::TypedValue<mlir::acc::PointerLikeType>>(getVar());
478    }
479    mlir::TypedValue<mlir::acc::PointerLikeType> getAccPtr() {
480      return mlir::dyn_cast<mlir::TypedValue<mlir::acc::PointerLikeType>>(getAccVar());
481    }
482  }];
483
484  let assemblyFormat = [{
485    custom<Var>($var) `:` custom<VarPtrType>(type($var), $varType)
486    oilist(
487        `varPtrPtr` `(` $varPtrPtr `:` type($varPtrPtr) `)`
488      | `bounds` `(` $bounds `)`
489      | `async` `(` custom<DeviceTypeOperands>($asyncOperands,
490            type($asyncOperands), $asyncOperandsDeviceType) `)`
491    ) `->` type($accVar) attr-dict
492  }];
493
494  let hasVerifier = 1;
495
496  let builders = [
497    OpBuilder<(ins "::mlir::TypedValue<::mlir::acc::PointerLikeType>":$varPtr,
498                   "bool":$structured, "bool":$implicit,
499                   CArg<"::mlir::ValueRange", "{}">:$bounds),
500      [{
501        build($_builder, $_state, varPtr.getType(), varPtr,
502          /*varType=*/::mlir::TypeAttr::get(
503            varPtr.getType().getElementType()),
504          /*varPtrPtr=*/{}, bounds, /*asyncOperands=*/{},
505          /*asyncOperandsDeviceType=*/nullptr,
506          /*asyncOnly=*/nullptr, /*dataClause=*/nullptr,
507          /*structured=*/$_builder.getBoolAttr(structured),
508          /*implicit=*/$_builder.getBoolAttr(implicit), /*name=*/nullptr);
509      }]>,
510    OpBuilder<(ins "::mlir::TypedValue<::mlir::acc::PointerLikeType>":$varPtr,
511                   "bool":$structured, "bool":$implicit,
512                   "const ::llvm::Twine &":$name,
513                   CArg<"::mlir::ValueRange", "{}">:$bounds),
514      [{
515        build($_builder, $_state, varPtr.getType(), varPtr,
516          /*varType=*/::mlir::TypeAttr::get(
517            varPtr.getType().getElementType()),
518          /*varPtrPtr=*/{}, bounds, /*asyncOperands=*/{},
519          /*asyncOperandsDeviceType=*/nullptr,
520          /*asyncOnly=*/nullptr, /*dataClause=*/nullptr,
521          /*structured=*/$_builder.getBoolAttr(structured),
522          /*implicit=*/$_builder.getBoolAttr(implicit),
523          /*name=*/$_builder.getStringAttr(name));
524      }]>,
525    OpBuilder<(ins "::mlir::TypedValue<::mlir::acc::MappableType>":$var,
526                   "bool":$structured, "bool":$implicit,
527                   CArg<"::mlir::ValueRange", "{}">:$bounds),
528      [{
529        build($_builder, $_state, var.getType(), var,
530          /*varType=*/::mlir::TypeAttr::get(var.getType()),
531          /*varPtrPtr=*/{}, bounds, /*asyncOperands=*/{},
532          /*asyncOperandsDeviceType=*/nullptr,
533          /*asyncOnly=*/nullptr, /*dataClause=*/nullptr,
534          /*structured=*/$_builder.getBoolAttr(structured),
535          /*implicit=*/$_builder.getBoolAttr(implicit), /*name=*/nullptr);
536      }]>,
537    OpBuilder<(ins "::mlir::TypedValue<::mlir::acc::MappableType>":$var,
538                   "bool":$structured, "bool":$implicit,
539                   "const ::llvm::Twine &":$name,
540                  CArg<"::mlir::ValueRange", "{}">:$bounds),
541      [{
542        build($_builder, $_state, var.getType(), var,
543          /*varType=*/::mlir::TypeAttr::get(var.getType()),
544          /*varPtrPtr=*/{}, bounds, /*asyncOperands=*/{},
545          /*asyncOperandsDeviceType=*/nullptr,
546          /*asyncOnly=*/nullptr, /*dataClause=*/nullptr,
547          /*structured=*/$_builder.getBoolAttr(structured),
548          /*implicit=*/$_builder.getBoolAttr(implicit),
549          /*name=*/$_builder.getStringAttr(name));
550      }]>];
551}
552
553//===----------------------------------------------------------------------===//
554// 2.5.13 private clause
555//===----------------------------------------------------------------------===//
556def OpenACC_PrivateOp : OpenACC_DataEntryOp<"private",
557    "mlir::acc::DataClause::acc_private", "", [],
558    (ins OpenACC_AnyPointerOrMappableType:$var)> {
559  let summary = "Represents private semantics for acc private clause.";
560  let results = (outs Arg<OpenACC_AnyPointerOrMappableType,
561                          "Accelerator mapped variable",[MemWrite]>:$accVar);
562  let extraClassDeclaration = extraClassDeclarationBase;
563}
564
565//===----------------------------------------------------------------------===//
566// 2.5.14 firstprivate clause
567//===----------------------------------------------------------------------===//
568def OpenACC_FirstprivateOp : OpenACC_DataEntryOp<"firstprivate",
569    "mlir::acc::DataClause::acc_firstprivate", "", [],
570    (ins Arg<OpenACC_AnyPointerOrMappableType,"Host variable",[MemRead]>:$var)> {
571  let summary = "Represents firstprivate semantic for the acc firstprivate "
572                "clause.";
573  let results = (outs Arg<OpenACC_AnyPointerOrMappableType,
574                          "Accelerator mapped variable",[MemWrite]>:$accVar);
575  let extraClassDeclaration = extraClassDeclarationBase;
576}
577
578//===----------------------------------------------------------------------===//
579// 2.5.15 reduction clause
580//===----------------------------------------------------------------------===//
581def OpenACC_ReductionOp : OpenACC_DataEntryOp<"reduction",
582    "mlir::acc::DataClause::acc_reduction", "", [],
583    (ins Arg<OpenACC_AnyPointerOrMappableType,"Host variable",[MemRead]>:$var)> {
584  let summary = "Represents reduction semantics for acc reduction clause.";
585  let results = (outs Arg<OpenACC_AnyPointerOrMappableType,
586                          "Accelerator mapped variable",[MemWrite]>:$accVar);
587  let extraClassDeclaration = extraClassDeclarationBase;
588}
589
590//===----------------------------------------------------------------------===//
591// 2.7.4 deviceptr clause
592//===----------------------------------------------------------------------===//
593def OpenACC_DevicePtrOp : OpenACC_DataEntryOp<"deviceptr",
594    "mlir::acc::DataClause::acc_deviceptr", "",
595    [MemoryEffects<[MemRead<OpenACC_RuntimeCounters>]>],
596    (ins OpenACC_AnyPointerOrMappableType:$var)> {
597  let summary = "Specifies that the variable pointer is a device pointer.";
598  let results = (outs OpenACC_AnyPointerOrMappableType:$accVar);
599  let extraClassDeclaration = extraClassDeclarationBase;
600}
601
602//===----------------------------------------------------------------------===//
603// 2.7.5 present clause
604//===----------------------------------------------------------------------===//
605def OpenACC_PresentOp : OpenACC_DataEntryOp<"present",
606    "mlir::acc::DataClause::acc_present", "",
607    [MemoryEffects<[MemRead<OpenACC_RuntimeCounters>,
608                    MemWrite<OpenACC_RuntimeCounters>]>],
609    (ins OpenACC_AnyPointerOrMappableType:$var)> {
610  let summary = "Specifies that the variable is already present on device.";
611  let results = (outs OpenACC_AnyPointerOrMappableType:$accVar);
612  let extraClassDeclaration = extraClassDeclarationBase;
613}
614
615//===----------------------------------------------------------------------===//
616// 2.7.7 copyin clause
617//===----------------------------------------------------------------------===//
618def OpenACC_CopyinOp : OpenACC_DataEntryOp<"copyin",
619    "mlir::acc::DataClause::acc_copyin", "",
620    [MemoryEffects<[MemRead<OpenACC_RuntimeCounters>,
621                    MemWrite<OpenACC_RuntimeCounters>]>],
622    (ins Arg<OpenACC_AnyPointerOrMappableType,"Host variable",[MemRead]>:$var)> {
623  let summary = "Represents copyin semantics for acc data clauses like acc "
624                "copyin and acc copy.";
625  let results = (outs Arg<OpenACC_AnyPointerOrMappableType,
626                          "Accelerator mapped variable",[MemWrite]>:$accVar);
627
628  let extraClassDeclaration = extraClassDeclarationBase # [{
629    /// Check if this is a copyin with readonly modifier.
630    bool isCopyinReadonly();
631  }];
632}
633
634//===----------------------------------------------------------------------===//
635// 2.7.9 create clause
636//===----------------------------------------------------------------------===//
637def OpenACC_CreateOp : OpenACC_DataEntryOp<"create",
638    "mlir::acc::DataClause::acc_create", "",
639    [MemoryEffects<[MemRead<OpenACC_RuntimeCounters>,
640                    MemWrite<OpenACC_RuntimeCounters>]>],
641    (ins OpenACC_AnyPointerOrMappableType:$var)> {
642  let summary = "Represents create semantics for acc data clauses like acc "
643                "create and acc copyout.";
644  let results = (outs Arg<OpenACC_AnyPointerOrMappableType,
645                          "Accelerator mapped variable",[MemWrite]>:$accVar);
646
647  let extraClassDeclaration = extraClassDeclarationBase # [{
648    /// Check if this is a create with zero modifier.
649    bool isCreateZero();
650  }];
651}
652
653//===----------------------------------------------------------------------===//
654// 2.7.10 no_create clause
655//===----------------------------------------------------------------------===//
656def OpenACC_NoCreateOp : OpenACC_DataEntryOp<"nocreate",
657    "mlir::acc::DataClause::acc_no_create", "",
658    [MemoryEffects<[MemRead<OpenACC_RuntimeCounters>,
659                    MemWrite<OpenACC_RuntimeCounters>]>],
660    (ins OpenACC_AnyPointerOrMappableType:$var)> {
661  let summary = "Represents acc no_create semantics.";
662  let results = (outs OpenACC_AnyPointerOrMappableType:$accVar);
663  let extraClassDeclaration = extraClassDeclarationBase;
664}
665
666//===----------------------------------------------------------------------===//
667// 2.7.12 attach clause
668//===----------------------------------------------------------------------===//
669def OpenACC_AttachOp : OpenACC_DataEntryOp<"attach",
670    "mlir::acc::DataClause::acc_attach", "",
671    [MemoryEffects<[MemRead<OpenACC_RuntimeCounters>,
672                    MemWrite<OpenACC_RuntimeCounters>]>],
673    (ins Arg<OpenACC_AnyPointerOrMappableType,"Host variable",[MemRead]>:$var)> {
674  let summary = "Represents acc attach semantics which updates a pointer in "
675                "device memory with the corresponding device address of the "
676                "pointee.";
677  let results = (outs OpenACC_AnyPointerOrMappableType:$accVar);
678  let extraClassDeclaration = extraClassDeclarationBase;
679}
680
681//===----------------------------------------------------------------------===//
682// 3.2.23 acc_deviceptr
683//===----------------------------------------------------------------------===//
684// This is needed to get device address without the additional semantics in
685// acc present. Effectively, it can be used to get "accPtr" for any variable.
686// It is also useful for providing the device address for unstructured construct
687// exit_data since unlike structured constructs, there is no matching data entry
688// operation.
689def OpenACC_GetDevicePtrOp : OpenACC_DataEntryOp<"getdeviceptr",
690    "mlir::acc::DataClause::acc_getdeviceptr", [{
691      This operation is used to get the `accPtr` for a variable. This is often
692      used in conjunction with data exit operations when the data entry
693      operation is not visible. This operation can have a `dataClause` argument
694      that is any of the valid `mlir::acc::DataClause` entries.
695      \
696    }], [MemoryEffects<[MemRead<OpenACC_RuntimeCounters>]>],
697    (ins OpenACC_AnyPointerOrMappableType:$var)> {
698  let summary = "Gets device address if variable exists on device.";
699  let results = (outs OpenACC_AnyPointerOrMappableType:$accVar);
700  let hasVerifier = 0;
701  let extraClassDeclaration = extraClassDeclarationBase;
702}
703
704//===----------------------------------------------------------------------===//
705// 2.14.4 device clause
706//===----------------------------------------------------------------------===//
707def OpenACC_UpdateDeviceOp : OpenACC_DataEntryOp<"update_device",
708    "mlir::acc::DataClause::acc_update_device", "", [],
709    (ins Arg<OpenACC_AnyPointerOrMappableType,"Host variable",[MemRead]>:$var)> {
710  let summary = "Represents acc update device semantics.";
711  let results = (outs Arg<OpenACC_AnyPointerOrMappableType,
712                          "Accelerator mapped variable",[MemWrite]>:$accVar);
713  let extraClassDeclaration = extraClassDeclarationBase;
714}
715
716//===----------------------------------------------------------------------===//
717// 2.8 use_device clause
718//===----------------------------------------------------------------------===//
719def OpenACC_UseDeviceOp : OpenACC_DataEntryOp<"use_device",
720    "mlir::acc::DataClause::acc_use_device", "",
721    [MemoryEffects<[MemRead<OpenACC_RuntimeCounters>]>],
722    (ins OpenACC_AnyPointerOrMappableType:$var)> {
723  let summary = "Represents acc use_device semantics.";
724  let results = (outs OpenACC_AnyPointerOrMappableType:$accVar);
725  let extraClassDeclaration = extraClassDeclarationBase;
726}
727
728//===----------------------------------------------------------------------===//
729// 2.13.1 device_resident clause
730//===----------------------------------------------------------------------===//
731def OpenACC_DeclareDeviceResidentOp : OpenACC_DataEntryOp<"declare_device_resident",
732    "mlir::acc::DataClause::acc_declare_device_resident", "",
733    [MemoryEffects<[MemWrite<OpenACC_RuntimeCounters>]>],
734    (ins Arg<OpenACC_AnyPointerOrMappableType,"Host variable",[MemRead]>:$var)> {
735  let summary = "Represents acc declare device_resident semantics.";
736  let results = (outs OpenACC_AnyPointerOrMappableType:$accVar);
737  let extraClassDeclaration = extraClassDeclarationBase;
738}
739
740//===----------------------------------------------------------------------===//
741// 2.13.3 link clause
742//===----------------------------------------------------------------------===//
743def OpenACC_DeclareLinkOp : OpenACC_DataEntryOp<"declare_link",
744    "mlir::acc::DataClause::acc_declare_link", "",
745    [MemoryEffects<[MemWrite<OpenACC_RuntimeCounters>]>],
746    (ins Arg<OpenACC_AnyPointerOrMappableType,"Host variable",[MemRead]>:$var)> {
747  let summary = "Represents acc declare link semantics.";
748  let results = (outs OpenACC_AnyPointerOrMappableType:$accVar);
749  let extraClassDeclaration = extraClassDeclarationBase;
750}
751
752//===----------------------------------------------------------------------===//
753// 2.10 cache directive
754//===----------------------------------------------------------------------===//
755def OpenACC_CacheOp : OpenACC_DataEntryOp<"cache",
756    "mlir::acc::DataClause::acc_cache", "", [NoMemoryEffect],
757    (ins OpenACC_AnyPointerOrMappableType:$var)> {
758  let summary = "Represents the cache directive that is associated with a "
759                "loop.";
760  let results = (outs OpenACC_AnyPointerOrMappableType:$accVar);
761
762  let extraClassDeclaration = extraClassDeclarationBase # [{
763    /// Check if this is a cache with readonly modifier.
764    bool isCacheReadonly() {
765      return getDataClause() == acc::DataClause::acc_cache_readonly;
766    }
767  }];
768}
769
770// Data exit operation does not refer to OpenACC spec terminology, but to
771// terminology used in this dialect. It refers to data operations that will appear
772// after data or compute region. It will be used as the base of acc dialect
773// operations for the following OpenACC data clauses: copyout, detach, delete.
774class OpenACC_DataExitOp<string mnemonic, string clause, string extraDescription,
775                         list<Trait> traits = [], dag additionalArgs = (ins)> :
776    OpenACC_Op<mnemonic, !listconcat(traits,
777        [AttrSizedOperandSegments,
778         MemoryEffects<[MemRead<OpenACC_CurrentDeviceIdResource>]>])> {
779  let arguments = !con(additionalArgs,
780                      (ins Variadic<OpenACC_DataBoundsType>:$bounds,
781                       Variadic<IntOrIndex>:$asyncOperands,
782                       OptionalAttr<DeviceTypeArrayAttr>:$asyncOperandsDeviceType,
783                       OptionalAttr<DeviceTypeArrayAttr>:$asyncOnly,
784                       DefaultValuedAttr<OpenACC_DataClauseAttr,clause>:$dataClause,
785                       DefaultValuedAttr<BoolAttr, "true">:$structured,
786                       DefaultValuedAttr<BoolAttr, "false">:$implicit,
787                       OptionalAttr<StrAttr>:$name));
788
789  let description = !strconcat(extraDescription, [{
790    - `accVar`: The acc variable. This is the link from the data-entry
791    operation used.
792    - `bounds`: Used when copying just slice of array or array's bounds are not
793    encoded in type. They are in rank order where rank 0 is inner-most dimension.
794    - `asyncOperands` and `asyncOperandsDeviceType`:
795    pair-wise lists of the async clause values associated with device_type's.
796    - `asyncOnly`: a list of device_type's for which async clause
797    does not specify a value (default is acc_async_noval - OpenACC 3.3 2.16.1).
798    - `dataClause`: Keeps track of the data clause the user used. This is because
799    the acc operations are decomposed. So a 'copy' clause is decomposed to both
800    `acc.copyin` and `acc.copyout` operations, but both have dataClause that
801    specifies `acc_copy` in this field.
802    - `structured`: Flag to note whether this is associated with structured region
803    (parallel, kernels, data) or unstructured (enter data, exit data). This is
804    important due to spec specifically calling out structured and dynamic reference
805    counters (2.6.7).
806    - `implicit`: Whether this is an implicitly generated operation, such as copies
807    done to satisfy "Variables with Implicitly Determined Data Attributes" in 2.6.2.
808    - `name`: Holds the name of variable as specified in user clause (including bounds).
809
810    The async values attached to the data exit operation imply that the data
811    action applies to all device types specified by the device_type clauses
812    using the activity queues on these devices as defined by the async values.
813  }]);
814
815  code extraClassDeclarationBase = [{
816    /// Return true if the op has the async attribute for the
817    /// mlir::acc::DeviceType::None device_type.
818    bool hasAsyncOnly() {
819      return hasAsyncOnly(mlir::acc::DeviceType::None);
820    }
821    /// Return true if the op has the async attribute for the given device_type.
822    bool hasAsyncOnly(mlir::acc::DeviceType deviceType) {
823      mlir::ArrayAttr asyncOnly = getAsyncOnlyAttr();
824      if (!asyncOnly)
825        return false;
826      for (auto attr : asyncOnly) {
827        auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
828        if (deviceTypeAttr.getValue() == deviceType)
829          return true;
830      }
831      return false;
832    }
833    /// Return the value of the async clause if present.
834    mlir::Value getAsyncValue() {
835      return getAsyncValue(mlir::acc::DeviceType::None);
836    }
837    /// Return the value of the async clause for the given device_type if
838    /// present.
839    mlir::Value getAsyncValue(mlir::acc::DeviceType deviceType) {
840      mlir::ArrayAttr deviceTypes = getAsyncOperandsDeviceTypeAttr();
841      if (!deviceTypes)
842        return nullptr;
843      for (auto [attr, asyncValue] :
844          llvm::zip(deviceTypes, getAsyncOperands())) {
845        auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
846        if (deviceTypeAttr.getValue() == deviceType)
847          return asyncValue;
848      }
849      return nullptr;
850    }
851  }];
852
853  let hasVerifier = 1;
854}
855
856class OpenACC_DataExitOpWithVarPtr<string mnemonic, string clause>
857    : OpenACC_DataExitOp<
858          mnemonic, clause,
859          "- `varPtr`: The address of variable to copy back to.",
860          [MemoryEffects<[MemRead<OpenACC_RuntimeCounters>,
861                          MemWrite<OpenACC_RuntimeCounters>]>],
862          (ins Arg<OpenACC_PointerLikeTypeInterface,
863                   "Accelerator mapped variable", [MemRead]>:$accVar,
864              Arg<OpenACC_PointerLikeTypeInterface,
865                  "Host variable", [MemWrite]>:$var,
866              TypeAttr:$varType)> {
867  let assemblyFormat = [{
868    custom<AccVar>($accVar, type($accVar))
869    (`bounds` `(` $bounds^ `)` )?
870    (`async` `(` custom<DeviceTypeOperands>($asyncOperands,
871            type($asyncOperands), $asyncOperandsDeviceType)^ `)`)?
872    `to` custom<Var>($var) `:` custom<VarPtrType>(type($var), $varType)
873    attr-dict
874  }];
875
876  let builders = [
877    OpBuilder<(ins "::mlir::TypedValue<::mlir::acc::PointerLikeType>":$accPtr,
878                   "::mlir::TypedValue<::mlir::acc::PointerLikeType>":$varPtr,
879                   "bool":$structured, "bool":$implicit,
880                   CArg<"::mlir::ValueRange", "{}">:$bounds),
881      [{
882        build($_builder, $_state, accPtr, varPtr,
883          /*varType=*/::mlir::TypeAttr::get(
884            varPtr.getType().getElementType()),
885          bounds, /*asyncOperands=*/{}, /*asyncOperandsDeviceType=*/nullptr,
886          /*asyncOnly=*/nullptr, /*dataClause=*/nullptr,
887          /*structured=*/$_builder.getBoolAttr(structured),
888          /*implicit=*/$_builder.getBoolAttr(implicit), /*name=*/nullptr);
889      }]>,
890    OpBuilder<(ins "::mlir::TypedValue<::mlir::acc::PointerLikeType>":$accPtr,
891                   "::mlir::TypedValue<::mlir::acc::PointerLikeType>":$varPtr,
892                   "bool":$structured, "bool":$implicit,
893                   "const ::llvm::Twine &":$name,
894                   CArg<"::mlir::ValueRange", "{}">:$bounds),
895      [{
896        build($_builder, $_state, accPtr, varPtr,
897          /*varType=*/::mlir::TypeAttr::get(
898            varPtr.getType().getElementType()),
899          bounds, /*asyncOperands=*/{}, /*asyncOperandsDeviceType=*/nullptr,
900          /*asyncOnly=*/nullptr, /*dataClause=*/nullptr,
901          /*structured=*/$_builder.getBoolAttr(structured),
902          /*implicit=*/$_builder.getBoolAttr(implicit),
903          /*name=*/$_builder.getStringAttr(name));
904      }]>];
905
906  code extraClassDeclarationDataExit = [{
907    mlir::TypedValue<mlir::acc::PointerLikeType> getVarPtr() {
908      return mlir::dyn_cast<mlir::TypedValue<mlir::acc::PointerLikeType>>(getVar());
909    }
910    mlir::TypedValue<mlir::acc::PointerLikeType> getAccPtr() {
911      return mlir::dyn_cast<mlir::TypedValue<mlir::acc::PointerLikeType>>(getAccVar());
912    }
913  }];
914}
915
916class OpenACC_DataExitOpNoVarPtr<string mnemonic, string clause> :
917    OpenACC_DataExitOp<mnemonic, clause, "",
918      [MemoryEffects<[MemRead<OpenACC_RuntimeCounters>,
919                    MemWrite<OpenACC_RuntimeCounters>]>],
920      (ins Arg<OpenACC_PointerLikeTypeInterface,"Accelerator mapped variable",
921           [MemRead]>:$accVar)> {
922  let assemblyFormat = [{
923    custom<AccVar>($accVar, type($accVar))
924    (`bounds` `(` $bounds^ `)` )?
925    (`async` `(` custom<DeviceTypeOperands>($asyncOperands,
926            type($asyncOperands), $asyncOperandsDeviceType)^ `)`)?
927    attr-dict
928  }];
929
930  let builders = [
931    OpBuilder<(ins "::mlir::TypedValue<::mlir::acc::PointerLikeType>":$accPtr,
932                   "bool":$structured, "bool":$implicit,
933                   CArg<"::mlir::ValueRange", "{}">:$bounds),
934      [{
935        build($_builder, $_state, accPtr,
936          bounds, /*asyncOperands=*/{}, /*asyncOperandsDeviceType=*/nullptr,
937          /*asyncOnly=*/nullptr, /*dataClause=*/nullptr,
938          /*structured=*/$_builder.getBoolAttr(structured),
939          /*implicit=*/$_builder.getBoolAttr(implicit), /*name=*/nullptr);
940      }]>,
941    OpBuilder<(ins "::mlir::TypedValue<::mlir::acc::PointerLikeType>":$accPtr,
942                   "bool":$structured, "bool":$implicit,
943                   "const ::llvm::Twine &":$name,
944                   CArg<"::mlir::ValueRange", "{}">:$bounds),
945      [{
946        build($_builder, $_state, accPtr,
947          bounds, /*asyncOperands=*/{}, /*asyncOperandsDeviceType=*/nullptr,
948          /*asyncOnly=*/nullptr, /*dataClause=*/nullptr,
949          /*structured=*/$_builder.getBoolAttr(structured),
950          /*implicit=*/$_builder.getBoolAttr(implicit),
951          /*name=*/$_builder.getStringAttr(name));
952      }]>
953  ];
954
955  code extraClassDeclarationDataExit = [{
956    mlir::TypedValue<mlir::acc::PointerLikeType> getAccPtr() {
957      return mlir::dyn_cast<mlir::TypedValue<mlir::acc::PointerLikeType>>(getAccVar());
958    }
959  }];
960}
961
962//===----------------------------------------------------------------------===//
963// 2.7.8 copyout clause
964//===----------------------------------------------------------------------===//
965def OpenACC_CopyoutOp : OpenACC_DataExitOpWithVarPtr<"copyout",
966    "mlir::acc::DataClause::acc_copyout"> {
967  let summary = "Represents acc copyout semantics - reverse of copyin.";
968
969  let extraClassDeclaration = extraClassDeclarationBase # extraClassDeclarationDataExit # [{
970    /// Check if this is a copyout with zero modifier.
971    bool isCopyoutZero();
972  }];
973}
974
975//===----------------------------------------------------------------------===//
976// 2.7.11 delete clause
977//===----------------------------------------------------------------------===//
978def OpenACC_DeleteOp : OpenACC_DataExitOpNoVarPtr<"delete",
979    "mlir::acc::DataClause::acc_delete"> {
980  let summary = "Represents acc delete semantics - reverse of create.";
981  let extraClassDeclaration = extraClassDeclarationBase # extraClassDeclarationDataExit;
982}
983
984//===----------------------------------------------------------------------===//
985// 2.7.13 detach clause
986//===----------------------------------------------------------------------===//
987def OpenACC_DetachOp : OpenACC_DataExitOpNoVarPtr<"detach",
988    "mlir::acc::DataClause::acc_detach"> {
989  let summary = "Represents acc detach semantics - reverse of attach.";
990  let extraClassDeclaration = extraClassDeclarationBase # extraClassDeclarationDataExit;
991}
992
993//===----------------------------------------------------------------------===//
994// 2.14.4 host clause
995//===----------------------------------------------------------------------===//
996def OpenACC_UpdateHostOp : OpenACC_DataExitOpWithVarPtr<"update_host",
997    "mlir::acc::DataClause::acc_update_host"> {
998  let summary = "Represents acc update host semantics.";
999  let extraClassDeclaration = extraClassDeclarationBase # extraClassDeclarationDataExit # [{
1000    /// Check if this is an acc update self.
1001    bool isSelf() {
1002      return getDataClause() == acc::DataClause::acc_update_self;
1003    }
1004  }];
1005}
1006
1007//===----------------------------------------------------------------------===//
1008// 2.5.13 private clause
1009//===----------------------------------------------------------------------===//
1010
1011def OpenACC_PrivateRecipeOp
1012    : OpenACC_Op<"private.recipe", [IsolatedFromAbove, Symbol, RecipeInterface,
1013                                    AutomaticAllocationScope]> {
1014  let summary = "privatization recipe";
1015
1016  let description = [{
1017    Declares an OpenACC privatization recipe. The operation requires one
1018    mandatory and one optional region.
1019
1020      1. The initializer region specifies how to allocate and initialize a new
1021         private value. For example in Fortran, a derived-type might have a
1022         default initialization. The region has an argument that contains the
1023         value that need to be privatized. This is useful if the type is not
1024         known at compile time and the private value is needed to create its
1025         copy.
1026      2. The destroy region specifies how to destruct the value when it reaches
1027         its end of life. It takes the privatized value as argument.
1028
1029    A single privatization recipe can be used for multiple operand if they have
1030    the same type and do not require a specific default initialization.
1031
1032    Example:
1033
1034    ```mlir
1035    acc.private.recipe @privatization_f32 : f32 init {
1036    ^bb0(%0: f32):
1037      // init region contains a sequence of operations to create and
1038      // initialize the copy if needed. It yields the create copy.
1039    } destroy {
1040    ^bb0(%0: f32)
1041      // destroy region contains a sequences of operations to destruct the
1042      // created copy.
1043    }
1044
1045    // The privatization symbol is then used in the corresponding operation.
1046    acc.parallel private(@privatization_f32 -> %a : f32) {
1047    }
1048    ```
1049  }];
1050
1051  let arguments = (ins SymbolNameAttr:$sym_name,
1052                       TypeAttr:$type);
1053
1054  let regions = (region AnyRegion:$initRegion,
1055                        AnyRegion:$destroyRegion);
1056
1057  let assemblyFormat = [{
1058    $sym_name `:` $type attr-dict-with-keyword `init` $initRegion
1059    (`destroy` $destroyRegion^)?
1060  }];
1061
1062  let hasRegionVerifier = 1;
1063}
1064
1065//===----------------------------------------------------------------------===//
1066// 2.5.14 firstprivate clause
1067//===----------------------------------------------------------------------===//
1068
1069def OpenACC_FirstprivateRecipeOp
1070    : OpenACC_Op<"firstprivate.recipe", [IsolatedFromAbove, Symbol,
1071                                         RecipeInterface,
1072                                         AutomaticAllocationScope]> {
1073  let summary = "privatization recipe";
1074
1075  let description = [{
1076    Declares an OpenACC privatization recipe with copy of the initial value.
1077    The operation requires two mandatory regions and one optional.
1078
1079      1. The initializer region specifies how to allocate and initialize a new
1080         private value. For example in Fortran, a derived-type might have a
1081         default initialization. The region has an argument that contains the
1082         value that need to be privatized. This is useful if the type is not
1083         known at compile time and the private value is needed to create its
1084         copy.
1085      2. The copy region specifies how to copy the initial value to the newly
1086         created private value. It takes the initial value and the privatized
1087         value as arguments.
1088      3. The destroy region specifies how to destruct the value when it reaches
1089         its end of life. It takes the privatized value as argument. It is
1090         optional.
1091
1092    A single privatization recipe can be used for multiple operand if they have
1093    the same type and do not require a specific default initialization.
1094
1095    Example:
1096
1097    ```mlir
1098    acc.firstprivate.recipe @privatization_f32 : f32 init {
1099    ^bb0(%0: f32):
1100      // init region contains a sequence of operations to create and
1101      // initialize the copy if needed. It yields the create copy.
1102    } copy {
1103    ^bb0(%0: f32, %1: !llvm.ptr):
1104      // copy region contains a sequence of operations to copy the initial value
1105      // of the firstprivate value to the newly created value.
1106    } destroy {
1107    ^bb0(%0: f32)
1108      // destroy region contains a sequences of operations to destruct the
1109      // created copy.
1110    }
1111
1112    // The privatization symbol is then used in the corresponding operation.
1113    acc.parallel firstprivate(@privatization_f32 -> %a : f32) {
1114    }
1115    ```
1116  }];
1117
1118  let arguments = (ins SymbolNameAttr:$sym_name,
1119                       TypeAttr:$type);
1120
1121  let regions = (region AnyRegion:$initRegion, AnyRegion:$copyRegion,
1122                        AnyRegion:$destroyRegion);
1123
1124  let assemblyFormat = [{
1125    $sym_name `:` $type attr-dict-with-keyword `init` $initRegion
1126    `copy` $copyRegion
1127    (`destroy` $destroyRegion^)?
1128  }];
1129
1130  let hasRegionVerifier = 1;
1131}
1132
1133//===----------------------------------------------------------------------===//
1134// 2.5.15 reduction clause
1135//===----------------------------------------------------------------------===//
1136
1137def OpenACC_ReductionRecipeOp
1138    : OpenACC_Op<"reduction.recipe", [IsolatedFromAbove, Symbol,
1139                                      RecipeInterface,
1140                                      AutomaticAllocationScope]> {
1141  let summary = "reduction recipe";
1142
1143  let description = [{
1144    Declares an OpenACC reduction recipe. The operation requires two
1145    mandatory regions.
1146
1147      1. The initializer region specifies how to initialize the local reduction
1148         value. The region has a first argument that contains the value of the
1149         reduction accumulator at the start of the reduction. It is expected to
1150         `acc.yield` the new value. Extra arguments can be added to deal with
1151         dynamic arrays.
1152      2. The reduction region contains a sequences of operations to combine two
1153         values of the reduction type into one. It has at least two arguments
1154         and it is expected to `acc.yield` the combined value. Extra arguments
1155         can be added to deal with dynamic arrays.
1156
1157    Example:
1158
1159    ```mlir
1160    acc.reduction.recipe @reduction_add_i64 : i64 reduction_operator<add> init {
1161    ^bb0(%0: i64):
1162      // init region contains a sequence of operations to initialize the local
1163      // reduction value as specified in 2.5.15
1164      %c0 = arith.constant 0 : i64
1165      acc.yield %c0 : i64
1166    } combiner {
1167    ^bb0(%0: i64, %1: i64)
1168      // combiner region contains a sequence of operations to combine
1169      // two values into one.
1170      %2 = arith.addi %0, %1 : i64
1171      acc.yield %2 : i64
1172    }
1173
1174    // The reduction symbol is then used in the corresponding operation.
1175    acc.parallel reduction(@reduction_add_i64 -> %a : i64) {
1176    }
1177    ```
1178
1179    The following table lists the valid operators and the initialization values
1180    according to OpenACC 3.3:
1181
1182    |------------------------------------------------|
1183    |        C/C++          |        Fortran         |
1184    |-----------------------|------------------------|
1185    | operator | init value | operator | init value  |
1186    |     +    |      0     |     +    |      0      |
1187    |     *    |      1     |     *    |      1      |
1188    |    max   |    least   |    max   |    least    |
1189    |    min   |   largest  |    min   |   largest   |
1190    |     &    |     ~0     |   iand   | all bits on |
1191    |     |    |      0     |    ior   |      0      |
1192    |     ^    |      0     |   ieor   |      0      |
1193    |    &&    |      1     |   .and.  |    .true.   |
1194    |    ||    |      0     |    .or.  |   .false.   |
1195    |          |            |   .eqv.  |    .true.   |
1196    |          |            |  .neqv.  |   .false.   |
1197    -------------------------------------------------|
1198  }];
1199
1200  let arguments = (ins SymbolNameAttr:$sym_name,
1201                       TypeAttr:$type,
1202                       OpenACC_ReductionOperatorAttr:$reductionOperator);
1203
1204  let regions = (region AnyRegion:$initRegion,
1205                        AnyRegion:$combinerRegion);
1206
1207  let assemblyFormat = [{
1208    $sym_name `:` $type attr-dict-with-keyword
1209    `reduction_operator` $reductionOperator
1210    `init` $initRegion `combiner` $combinerRegion
1211  }];
1212
1213  let hasRegionVerifier = 1;
1214}
1215
1216//===----------------------------------------------------------------------===//
1217// 2.5.1 parallel Construct
1218//===----------------------------------------------------------------------===//
1219
1220def OpenACC_ParallelOp : OpenACC_Op<"parallel",
1221    [AttrSizedOperandSegments, AutomaticAllocationScope,
1222     RecursiveMemoryEffects,
1223     DeclareOpInterfaceMethods<ComputeRegionOpInterface>,
1224     MemoryEffects<[MemWrite<OpenACC_ConstructResource>,
1225                    MemRead<OpenACC_CurrentDeviceIdResource>]>]> {
1226  let summary = "parallel construct";
1227  let description = [{
1228    The "acc.parallel" operation represents a parallel construct block. It has
1229    one region to be executed in parallel on the current device.
1230
1231    Example:
1232
1233    ```mlir
1234    acc.parallel num_gangs(%c10) num_workers(%c10)
1235        private(%c : memref<10xf32>) {
1236      // parallel region
1237    }
1238    ```
1239
1240    `async`, `wait`, `num_gangs`, `num_workers` and `vector_length` operands are
1241    supported with `device_type` information. They should only be accessed by
1242    the extra provided getters. If modified, the corresponding `device_type`
1243    attributes must be modified as well.
1244  }];
1245
1246  let arguments = (ins
1247      Variadic<IntOrIndex>:$asyncOperands,
1248      OptionalAttr<DeviceTypeArrayAttr>:$asyncOperandsDeviceType,
1249      OptionalAttr<DeviceTypeArrayAttr>:$asyncOnly,
1250      Variadic<IntOrIndex>:$waitOperands,
1251      OptionalAttr<DenseI32ArrayAttr>:$waitOperandsSegments,
1252      OptionalAttr<DeviceTypeArrayAttr>:$waitOperandsDeviceType,
1253      OptionalAttr<BoolArrayAttr>:$hasWaitDevnum,
1254      OptionalAttr<DeviceTypeArrayAttr>:$waitOnly,
1255      Variadic<IntOrIndex>:$numGangs,
1256      OptionalAttr<DenseI32ArrayAttr>:$numGangsSegments,
1257      OptionalAttr<DeviceTypeArrayAttr>:$numGangsDeviceType,
1258      Variadic<IntOrIndex>:$numWorkers,
1259      OptionalAttr<DeviceTypeArrayAttr>:$numWorkersDeviceType,
1260      Variadic<IntOrIndex>:$vectorLength,
1261      OptionalAttr<DeviceTypeArrayAttr>:$vectorLengthDeviceType,
1262      Optional<I1>:$ifCond,
1263      Optional<I1>:$selfCond,
1264      UnitAttr:$selfAttr,
1265      Variadic<AnyType>:$reductionOperands,
1266      OptionalAttr<SymbolRefArrayAttr>:$reductionRecipes,
1267      Variadic<OpenACC_AnyPointerOrMappableType>:$privateOperands,
1268      OptionalAttr<SymbolRefArrayAttr>:$privatizations,
1269      Variadic<OpenACC_AnyPointerOrMappableType>:$firstprivateOperands,
1270      OptionalAttr<SymbolRefArrayAttr>:$firstprivatizations,
1271      Variadic<OpenACC_AnyPointerOrMappableType>:$dataClauseOperands,
1272      OptionalAttr<DefaultValueAttr>:$defaultAttr,
1273      UnitAttr:$combined);
1274
1275  let regions = (region AnyRegion:$region);
1276
1277  let builders = [
1278    OpBuilder<(ins
1279      CArg<"mlir::ValueRange", "{}">:$numGangs,
1280      CArg<"mlir::ValueRange", "{}">:$numWorkers,
1281      CArg<"mlir::ValueRange", "{}">:$vectorLength,
1282      CArg<"mlir::ValueRange", "{}">:$asyncOperands,
1283      CArg<"mlir::ValueRange", "{}">:$waitOperands,
1284      CArg<"mlir::Value", "{}">:$ifCond,
1285      CArg<"mlir::Value", "{}">:$selfCond,
1286      CArg<"mlir::ValueRange", "{}">:$reductionOperands,
1287      CArg<"mlir::ValueRange", "{}">:$privateOperands,
1288      CArg<"mlir::ValueRange", "{}">:$firstprivateOperands,
1289      CArg<"mlir::ValueRange", "{}">:$dataClauseOperands)>];
1290
1291  let extraClassDeclaration = [{
1292    /// The number of data operands.
1293    unsigned getNumDataOperands();
1294
1295    /// The i-th data operand passed.
1296    Value getDataOperand(unsigned i);
1297
1298    /// Used to retrieve the block inside the op's region.
1299    Block &getBody() { return getRegion().front(); }
1300
1301    /// Return true if the op has the async attribute for the
1302    /// mlir::acc::DeviceType::None device_type.
1303    bool hasAsyncOnly();
1304    /// Return true if the op has the async attribute for the given device_type.
1305    bool hasAsyncOnly(mlir::acc::DeviceType deviceType);
1306    /// Return the value of the async clause if present.
1307    mlir::Value getAsyncValue();
1308    /// Return the value of the async clause for the given device_type if
1309    /// present.
1310    mlir::Value getAsyncValue(mlir::acc::DeviceType deviceType);
1311
1312    /// Return the value of the num_workers clause if present.
1313    mlir::Value getNumWorkersValue();
1314    /// Return the value of the num_workers clause for the given device_type if
1315    /// present.
1316    mlir::Value getNumWorkersValue(mlir::acc::DeviceType deviceType);
1317
1318    /// Return the value of the vector_length clause if present.
1319    mlir::Value getVectorLengthValue();
1320    /// Return the value of the vector_length clause for the given device_type
1321    /// if present.
1322    mlir::Value getVectorLengthValue(mlir::acc::DeviceType deviceType);
1323
1324    /// Return the values of the num_gangs clause if present.
1325    mlir::Operation::operand_range getNumGangsValues();
1326    /// Return the values of the num_gangs clause for the given device_type if
1327    /// present.
1328    mlir::Operation::operand_range
1329    getNumGangsValues(mlir::acc::DeviceType deviceType);
1330
1331    /// Return true if the op has the wait attribute for the
1332    /// mlir::acc::DeviceType::None device_type.
1333    bool hasWaitOnly();
1334    /// Return true if the op has the wait attribute for the given device_type.
1335    bool hasWaitOnly(mlir::acc::DeviceType deviceType);
1336    /// Return the values of the wait clause if present.
1337    mlir::Operation::operand_range getWaitValues();
1338    /// Return the values of the wait clause for the given device_type if
1339    /// present.
1340    mlir::Operation::operand_range
1341    getWaitValues(mlir::acc::DeviceType deviceType);
1342    /// Return the wait devnum value clause if present;
1343    mlir::Value getWaitDevnum();
1344    /// Return the wait devnum value clause for the given device_type if
1345    /// present.
1346    mlir::Value getWaitDevnum(mlir::acc::DeviceType deviceType);
1347    static mlir::acc::Construct getConstructId() {
1348      return mlir::acc::Construct::acc_construct_parallel;
1349    }
1350  }];
1351
1352  let assemblyFormat = [{
1353    ( `combined` `(` `loop` `)` $combined^)?
1354    oilist(
1355        `dataOperands` `(` $dataClauseOperands `:` type($dataClauseOperands) `)`
1356      | `async` `(` custom<DeviceTypeOperands>($asyncOperands,
1357            type($asyncOperands), $asyncOperandsDeviceType) `)`
1358      | `firstprivate` `(` custom<SymOperandList>($firstprivateOperands,
1359            type($firstprivateOperands), $firstprivatizations)
1360        `)`
1361      | `num_gangs` `(` custom<NumGangs>($numGangs,
1362            type($numGangs), $numGangsDeviceType, $numGangsSegments) `)`
1363      | `num_workers` `(` custom<DeviceTypeOperands>($numWorkers,
1364            type($numWorkers), $numWorkersDeviceType) `)`
1365      | `private` `(` custom<SymOperandList>(
1366            $privateOperands, type($privateOperands), $privatizations)
1367        `)`
1368      | `vector_length` `(` custom<DeviceTypeOperands>($vectorLength,
1369            type($vectorLength), $vectorLengthDeviceType) `)`
1370      | `wait` `` custom<WaitClause>($waitOperands, type($waitOperands),
1371          $waitOperandsDeviceType, $waitOperandsSegments, $hasWaitDevnum,
1372          $waitOnly)
1373      | `self` `(` $selfCond `)`
1374      | `if` `(` $ifCond `)`
1375      | `reduction` `(` custom<SymOperandList>(
1376            $reductionOperands, type($reductionOperands), $reductionRecipes)
1377        `)`
1378    )
1379    $region attr-dict-with-keyword
1380  }];
1381
1382  let hasVerifier = 1;
1383}
1384
1385//===----------------------------------------------------------------------===//
1386// 2.5.2 serial Construct
1387//===----------------------------------------------------------------------===//
1388
1389def OpenACC_SerialOp : OpenACC_Op<"serial",
1390    [AttrSizedOperandSegments, AutomaticAllocationScope,
1391     RecursiveMemoryEffects,
1392     DeclareOpInterfaceMethods<ComputeRegionOpInterface>,
1393     MemoryEffects<[MemWrite<OpenACC_ConstructResource>,
1394                    MemRead<OpenACC_CurrentDeviceIdResource>]>]> {
1395  let summary = "serial construct";
1396  let description = [{
1397    The "acc.serial" operation represents a serial construct block. It has
1398    one region to be executed in serial on the current device.
1399
1400    Example:
1401
1402    ```mlir
1403    acc.serial private(%c : memref<10xf32>) {
1404      // serial region
1405    }
1406    ```
1407
1408    `async` and `wait` operands are supported with `device_type` information.
1409    They should only be accessed by the extra provided getters. If modified,
1410    the corresponding `device_type` attributes must be modified as well.
1411  }];
1412
1413  let arguments = (ins
1414      Variadic<IntOrIndex>:$asyncOperands,
1415      OptionalAttr<DeviceTypeArrayAttr>:$asyncOperandsDeviceType,
1416      OptionalAttr<DeviceTypeArrayAttr>:$asyncOnly,
1417      Variadic<IntOrIndex>:$waitOperands,
1418      OptionalAttr<DenseI32ArrayAttr>:$waitOperandsSegments,
1419      OptionalAttr<DeviceTypeArrayAttr>:$waitOperandsDeviceType,
1420      OptionalAttr<BoolArrayAttr>:$hasWaitDevnum,
1421      OptionalAttr<DeviceTypeArrayAttr>:$waitOnly,
1422      Optional<I1>:$ifCond,
1423      Optional<I1>:$selfCond,
1424      UnitAttr:$selfAttr,
1425      Variadic<AnyType>:$reductionOperands,
1426      OptionalAttr<SymbolRefArrayAttr>:$reductionRecipes,
1427      Variadic<OpenACC_AnyPointerOrMappableType>:$privateOperands,
1428      OptionalAttr<SymbolRefArrayAttr>:$privatizations,
1429      Variadic<OpenACC_AnyPointerOrMappableType>:$firstprivateOperands,
1430      OptionalAttr<SymbolRefArrayAttr>:$firstprivatizations,
1431      Variadic<OpenACC_AnyPointerOrMappableType>:$dataClauseOperands,
1432      OptionalAttr<DefaultValueAttr>:$defaultAttr,
1433      UnitAttr:$combined);
1434
1435  let regions = (region AnyRegion:$region);
1436
1437  let extraClassDeclaration = [{
1438    /// The number of data operands.
1439    unsigned getNumDataOperands();
1440
1441    /// The i-th data operand passed.
1442    Value getDataOperand(unsigned i);
1443
1444    /// Used to retrieve the block inside the op's region.
1445    Block &getBody() { return getRegion().front(); }
1446
1447    /// Return true if the op has the async attribute for the
1448    /// mlir::acc::DeviceType::None device_type.
1449    bool hasAsyncOnly();
1450    /// Return true if the op has the async attribute for the given device_type.
1451    bool hasAsyncOnly(mlir::acc::DeviceType deviceType);
1452    /// Return the value of the async clause if present.
1453    mlir::Value getAsyncValue();
1454    /// Return the value of the async clause for the given device_type if
1455    /// present.
1456    mlir::Value getAsyncValue(mlir::acc::DeviceType deviceType);
1457
1458    /// Return true if the op has the wait attribute for the
1459    /// mlir::acc::DeviceType::None device_type.
1460    bool hasWaitOnly();
1461    /// Return true if the op has the wait attribute for the given device_type.
1462    bool hasWaitOnly(mlir::acc::DeviceType deviceType);
1463    /// Return the values of the wait clause if present.
1464    mlir::Operation::operand_range getWaitValues();
1465    /// Return the values of the wait clause for the given device_type if
1466    /// present.
1467    mlir::Operation::operand_range
1468    getWaitValues(mlir::acc::DeviceType deviceType);
1469    /// Return the wait devnum value clause if present;
1470    mlir::Value getWaitDevnum();
1471    /// Return the wait devnum value clause for the given device_type if
1472    /// present.
1473    mlir::Value getWaitDevnum(mlir::acc::DeviceType deviceType);
1474    static mlir::acc::Construct getConstructId() {
1475      return mlir::acc::Construct::acc_construct_serial;
1476    }
1477  }];
1478
1479  let assemblyFormat = [{
1480    ( `combined` `(` `loop` `)` $combined^)?
1481    oilist(
1482        `dataOperands` `(` $dataClauseOperands `:` type($dataClauseOperands) `)`
1483      | `async` `(` custom<DeviceTypeOperands>($asyncOperands,
1484            type($asyncOperands), $asyncOperandsDeviceType) `)`
1485      | `firstprivate` `(` custom<SymOperandList>($firstprivateOperands,
1486            type($firstprivateOperands), $firstprivatizations)
1487        `)`
1488      | `private` `(` custom<SymOperandList>(
1489            $privateOperands, type($privateOperands), $privatizations)
1490        `)`
1491      | `wait` `` custom<WaitClause>($waitOperands, type($waitOperands),
1492          $waitOperandsDeviceType, $waitOperandsSegments, $hasWaitDevnum,
1493          $waitOnly)
1494      | `self` `(` $selfCond `)`
1495      | `if` `(` $ifCond `)`
1496      | `reduction` `(` custom<SymOperandList>(
1497            $reductionOperands, type($reductionOperands), $reductionRecipes)
1498        `)`
1499    )
1500    $region attr-dict-with-keyword
1501  }];
1502
1503  let hasVerifier = 1;
1504}
1505
1506//===----------------------------------------------------------------------===//
1507// 2.5.1 kernels Construct
1508//===----------------------------------------------------------------------===//
1509
1510def OpenACC_KernelsOp : OpenACC_Op<"kernels",
1511    [AttrSizedOperandSegments, AutomaticAllocationScope,
1512     RecursiveMemoryEffects,
1513     DeclareOpInterfaceMethods<ComputeRegionOpInterface>,
1514     MemoryEffects<[MemWrite<OpenACC_ConstructResource>,
1515                    MemRead<OpenACC_CurrentDeviceIdResource>]>]> {
1516  let summary = "kernels construct";
1517  let description = [{
1518    The "acc.kernels" operation represents a kernels construct block. It has
1519    one region to be compiled into a sequence of kernels for execution on the
1520    current device.
1521
1522    Example:
1523
1524    ```mlir
1525    acc.kernels num_gangs(%c10) num_workers(%c10)
1526        private(%c : memref<10xf32>) {
1527      // kernels region
1528    }
1529    ```
1530
1531    `collapse`, `gang`, `worker`, `vector`, `seq`, `independent`, `auto` and
1532    `tile` operands are supported with `device_type` information. They should
1533    only be accessed by the extra provided getters. If modified, the
1534    corresponding `device_type` attributes must be modified as well.
1535  }];
1536
1537  let arguments = (ins
1538      Variadic<IntOrIndex>:$asyncOperands,
1539      OptionalAttr<DeviceTypeArrayAttr>:$asyncOperandsDeviceType,
1540      OptionalAttr<DeviceTypeArrayAttr>:$asyncOnly,
1541      Variadic<IntOrIndex>:$waitOperands,
1542      OptionalAttr<DenseI32ArrayAttr>:$waitOperandsSegments,
1543      OptionalAttr<DeviceTypeArrayAttr>:$waitOperandsDeviceType,
1544      OptionalAttr<BoolArrayAttr>:$hasWaitDevnum,
1545      OptionalAttr<DeviceTypeArrayAttr>:$waitOnly,
1546      Variadic<IntOrIndex>:$numGangs,
1547      OptionalAttr<DenseI32ArrayAttr>:$numGangsSegments,
1548      OptionalAttr<DeviceTypeArrayAttr>:$numGangsDeviceType,
1549      Variadic<IntOrIndex>:$numWorkers,
1550      OptionalAttr<DeviceTypeArrayAttr>:$numWorkersDeviceType,
1551      Variadic<IntOrIndex>:$vectorLength,
1552      OptionalAttr<DeviceTypeArrayAttr>:$vectorLengthDeviceType,
1553      Optional<I1>:$ifCond,
1554      Optional<I1>:$selfCond,
1555      UnitAttr:$selfAttr,
1556      Variadic<OpenACC_AnyPointerOrMappableType>:$dataClauseOperands,
1557      OptionalAttr<DefaultValueAttr>:$defaultAttr,
1558      UnitAttr:$combined);
1559
1560  let regions = (region AnyRegion:$region);
1561
1562  let extraClassDeclaration = [{
1563    /// The number of data operands.
1564    unsigned getNumDataOperands();
1565
1566    /// The i-th data operand passed.
1567    Value getDataOperand(unsigned i);
1568
1569    /// Used to retrieve the block inside the op's region.
1570    Block &getBody() { return getRegion().front(); }
1571
1572    /// Return true if the op has the async attribute for the
1573    /// mlir::acc::DeviceType::None device_type.
1574    bool hasAsyncOnly();
1575    /// Return true if the op has the async attribute for the given device_type.
1576    bool hasAsyncOnly(mlir::acc::DeviceType deviceType);
1577    /// Return the value of the async clause if present.
1578    mlir::Value getAsyncValue();
1579    /// Return the value of the async clause for the given device_type if
1580    /// present.
1581    mlir::Value getAsyncValue(mlir::acc::DeviceType deviceType);
1582
1583    /// Return the value of the num_workers clause if present.
1584    mlir::Value getNumWorkersValue();
1585    /// Return the value of the num_workers clause for the given device_type if
1586    /// present.
1587    mlir::Value getNumWorkersValue(mlir::acc::DeviceType deviceType);
1588
1589    /// Return the value of the vector_length clause if present.
1590    mlir::Value getVectorLengthValue();
1591    /// Return the value of the vector_length clause for the given device_type
1592    /// if present.
1593    mlir::Value getVectorLengthValue(mlir::acc::DeviceType deviceType);
1594
1595    /// Return the values of the num_gangs clause if present.
1596    mlir::Operation::operand_range getNumGangsValues();
1597    /// Return the values of the num_gangs clause for the given device_type if
1598    /// present.
1599    mlir::Operation::operand_range
1600    getNumGangsValues(mlir::acc::DeviceType deviceType);
1601
1602    /// Return true if the op has the wait attribute for the
1603    /// mlir::acc::DeviceType::None device_type.
1604    bool hasWaitOnly();
1605    /// Return true if the op has the wait attribute for the given device_type.
1606    bool hasWaitOnly(mlir::acc::DeviceType deviceType);
1607    /// Return the values of the wait clause if present.
1608    mlir::Operation::operand_range getWaitValues();
1609    /// Return the values of the wait clause for the given device_type if
1610    /// present.
1611    mlir::Operation::operand_range
1612    getWaitValues(mlir::acc::DeviceType deviceType);
1613    /// Return the wait devnum value clause if present;
1614    mlir::Value getWaitDevnum();
1615    /// Return the wait devnum value clause for the given device_type if
1616    /// present.
1617    mlir::Value getWaitDevnum(mlir::acc::DeviceType deviceType);
1618    static mlir::acc::Construct getConstructId() {
1619      return mlir::acc::Construct::acc_construct_kernels;
1620    }
1621  }];
1622
1623  let assemblyFormat = [{
1624    ( `combined` `(` `loop` `)` $combined^)?
1625    oilist(
1626        `dataOperands` `(` $dataClauseOperands `:` type($dataClauseOperands) `)`
1627      | `async` `(` custom<DeviceTypeOperands>($asyncOperands,
1628            type($asyncOperands), $asyncOperandsDeviceType) `)`
1629      | `num_gangs` `(` custom<NumGangs>($numGangs,
1630            type($numGangs), $numGangsDeviceType, $numGangsSegments) `)`
1631      | `num_workers` `(` custom<DeviceTypeOperands>($numWorkers,
1632            type($numWorkers), $numWorkersDeviceType) `)`
1633      | `vector_length` `(` custom<DeviceTypeOperands>($vectorLength,
1634            type($vectorLength), $vectorLengthDeviceType) `)`
1635      | `wait` `` custom<WaitClause>($waitOperands, type($waitOperands),
1636          $waitOperandsDeviceType, $waitOperandsSegments, $hasWaitDevnum,
1637          $waitOnly)
1638      | `self` `(` $selfCond `)`
1639      | `if` `(` $ifCond `)`
1640    )
1641    $region attr-dict-with-keyword
1642  }];
1643
1644  let hasVerifier = 1;
1645}
1646
1647//===----------------------------------------------------------------------===//
1648// 2.6.5 data Construct
1649//===----------------------------------------------------------------------===//
1650
1651def OpenACC_DataOp : OpenACC_Op<"data",
1652    [AttrSizedOperandSegments, RecursiveMemoryEffects,
1653     MemoryEffects<[MemWrite<OpenACC_ConstructResource>,
1654                    MemRead<OpenACC_CurrentDeviceIdResource>]>]> {
1655  let summary = "data construct";
1656
1657  let description = [{
1658    The "acc.data" operation represents a data construct. It defines vars to
1659    be allocated in the current device memory for the duration of the region,
1660    whether data should be copied from local memory to the current device
1661    memory upon region entry , and copied from device memory to local memory
1662    upon region exit.
1663
1664    Example:
1665
1666    ```mlir
1667    acc.data present(%a: memref<10x10xf32>, %b: memref<10x10xf32>,
1668        %c: memref<10xf32>, %d: memref<10xf32>) {
1669      // data region
1670    }
1671    ```
1672
1673    `async` and `wait` operands are supported with `device_type` information.
1674    They should only be accessed by the extra provided getters. If modified,
1675    the corresponding `device_type` attributes must be modified as well.
1676  }];
1677
1678
1679  let arguments = (ins Optional<I1>:$ifCond,
1680      Variadic<IntOrIndex>:$asyncOperands,
1681      OptionalAttr<DeviceTypeArrayAttr>:$asyncOperandsDeviceType,
1682      OptionalAttr<DeviceTypeArrayAttr>:$asyncOnly,
1683      Variadic<IntOrIndex>:$waitOperands,
1684      OptionalAttr<DenseI32ArrayAttr>:$waitOperandsSegments,
1685      OptionalAttr<DeviceTypeArrayAttr>:$waitOperandsDeviceType,
1686      OptionalAttr<BoolArrayAttr>:$hasWaitDevnum,
1687      OptionalAttr<DeviceTypeArrayAttr>:$waitOnly,
1688      Variadic<OpenACC_AnyPointerOrMappableType>:$dataClauseOperands,
1689      OptionalAttr<DefaultValueAttr>:$defaultAttr);
1690
1691  let regions = (region AnyRegion:$region);
1692
1693  let extraClassDeclaration = [{
1694    /// The number of data operands.
1695    unsigned getNumDataOperands();
1696
1697    /// The i-th data operand passed.
1698    Value getDataOperand(unsigned i);
1699
1700    /// Return true if the op has the async attribute for the
1701    /// mlir::acc::DeviceType::None device_type.
1702    bool hasAsyncOnly();
1703    /// Return true if the op has the async attribute for the given device_type.
1704    bool hasAsyncOnly(mlir::acc::DeviceType deviceType);
1705    /// Return the value of the async clause if present.
1706    mlir::Value getAsyncValue();
1707    /// Return the value of the async clause for the given device_type if
1708    /// present.
1709    mlir::Value getAsyncValue(mlir::acc::DeviceType deviceType);
1710
1711    /// Return true if the op has the wait attribute for the
1712    /// mlir::acc::DeviceType::None device_type.
1713    bool hasWaitOnly();
1714    /// Return true if the op has the wait attribute for the given device_type.
1715    bool hasWaitOnly(mlir::acc::DeviceType deviceType);
1716    /// Return the values of the wait clause if present.
1717    mlir::Operation::operand_range getWaitValues();
1718    /// Return the values of the wait clause for the given device_type if
1719    /// present.
1720    mlir::Operation::operand_range
1721    getWaitValues(mlir::acc::DeviceType deviceType);
1722    /// Return the wait devnum value clause if present;
1723    mlir::Value getWaitDevnum();
1724    /// Return the wait devnum value clause for the given device_type if
1725    /// present.
1726    mlir::Value getWaitDevnum(mlir::acc::DeviceType deviceType);
1727  }];
1728
1729  let assemblyFormat = [{
1730    oilist(
1731        `if` `(` $ifCond `)`
1732      | `async` `(` custom<DeviceTypeOperands>($asyncOperands,
1733            type($asyncOperands), $asyncOperandsDeviceType) `)`
1734      | `dataOperands` `(` $dataClauseOperands `:` type($dataClauseOperands) `)`
1735      | `wait` `` custom<WaitClause>($waitOperands, type($waitOperands),
1736          $waitOperandsDeviceType, $waitOperandsSegments, $hasWaitDevnum,
1737          $waitOnly)
1738    )
1739    $region attr-dict-with-keyword
1740  }];
1741  let hasVerifier = 1;
1742}
1743
1744def OpenACC_TerminatorOp : OpenACC_Op<"terminator", [Pure, Terminator]> {
1745  let summary = "Generic terminator for OpenACC regions";
1746
1747  let description = [{
1748    A terminator operation for regions that appear in the body of OpenACC
1749    operation. Generic OpenACC construct regions are not expected to return any
1750    value so the terminator takes no operands. The terminator op returns control
1751    to the enclosing op.
1752  }];
1753
1754  let assemblyFormat = "attr-dict";
1755}
1756
1757//===----------------------------------------------------------------------===//
1758// 2.6.6 Enter Data Directive
1759//===----------------------------------------------------------------------===//
1760
1761def OpenACC_EnterDataOp : OpenACC_Op<"enter_data",
1762    [AttrSizedOperandSegments,
1763     MemoryEffects<[MemWrite<OpenACC_ConstructResource>,
1764                    MemRead<OpenACC_CurrentDeviceIdResource>]>]> {
1765  let summary = "enter data operation";
1766
1767  let description = [{
1768    The "acc.enter_data" operation represents the OpenACC enter data directive.
1769
1770    Example:
1771
1772    ```mlir
1773    acc.enter_data create(%d1 : memref<10xf32>) attributes {async}
1774    ```
1775  }];
1776
1777  let arguments = (ins Optional<I1>:$ifCond,
1778                       Optional<IntOrIndex>:$asyncOperand,
1779                       UnitAttr:$async,
1780                       Optional<IntOrIndex>:$waitDevnum,
1781                       Variadic<IntOrIndex>:$waitOperands,
1782                       UnitAttr:$wait,
1783                       Variadic<OpenACC_AnyPointerOrMappableType>:$dataClauseOperands);
1784
1785  let extraClassDeclaration = [{
1786    /// The number of data operands.
1787    unsigned getNumDataOperands();
1788
1789    /// The i-th data operand passed.
1790    Value getDataOperand(unsigned i);
1791  }];
1792
1793  let assemblyFormat = [{
1794    oilist(
1795        `if` `(` $ifCond `)`
1796      | `async` `(` $asyncOperand `:` type($asyncOperand) `)`
1797      | `wait_devnum` `(` $waitDevnum `:` type($waitDevnum) `)`
1798      | `wait` `(` $waitOperands `:` type($waitOperands) `)`
1799      | `dataOperands` `(` $dataClauseOperands `:` type($dataClauseOperands) `)`
1800    )
1801    attr-dict-with-keyword
1802  }];
1803
1804  let hasCanonicalizer = 1;
1805  let hasVerifier = 1;
1806}
1807
1808//===----------------------------------------------------------------------===//
1809// 2.6.6 Exit Data Directive
1810//===----------------------------------------------------------------------===//
1811
1812def OpenACC_ExitDataOp : OpenACC_Op<"exit_data",
1813    [AttrSizedOperandSegments,
1814     MemoryEffects<[MemWrite<OpenACC_ConstructResource>,
1815                    MemRead<OpenACC_CurrentDeviceIdResource>]>]> {
1816  let summary = "exit data operation";
1817
1818  let description = [{
1819    The "acc.exit_data" operation represents the OpenACC exit data directive.
1820
1821    Example:
1822
1823    ```mlir
1824    acc.exit_data delete(%d1 : memref<10xf32>) attributes {async}
1825    ```
1826  }];
1827
1828  let arguments = (ins Optional<I1>:$ifCond,
1829                       Optional<IntOrIndex>:$asyncOperand,
1830                       UnitAttr:$async,
1831                       Optional<IntOrIndex>:$waitDevnum,
1832                       Variadic<IntOrIndex>:$waitOperands,
1833                       UnitAttr:$wait,
1834                       Variadic<OpenACC_AnyPointerOrMappableType>:$dataClauseOperands,
1835                       UnitAttr:$finalize);
1836
1837  let extraClassDeclaration = [{
1838    /// The number of data operands.
1839    unsigned getNumDataOperands();
1840
1841    /// The i-th data operand passed.
1842    Value getDataOperand(unsigned i);
1843  }];
1844
1845  let assemblyFormat = [{
1846    oilist(
1847        `if` `(` $ifCond `)`
1848      | `async` `(` $asyncOperand `:` type($asyncOperand) `)`
1849      | `wait_devnum` `(` $waitDevnum `:` type($waitDevnum) `)`
1850      | `wait` `(` $waitOperands `:` type($waitOperands) `)`
1851      | `dataOperands` `(` $dataClauseOperands `:` type($dataClauseOperands) `)`
1852    )
1853    attr-dict-with-keyword
1854  }];
1855
1856  let hasCanonicalizer = 1;
1857  let hasVerifier = 1;
1858}
1859
1860//===----------------------------------------------------------------------===//
1861// 2.8 Host_Data Construct
1862//===----------------------------------------------------------------------===//
1863
1864def OpenACC_HostDataOp : OpenACC_Op<"host_data",
1865    [AttrSizedOperandSegments,
1866     MemoryEffects<[MemWrite<OpenACC_ConstructResource>,
1867                    MemRead<OpenACC_CurrentDeviceIdResource>]>]> {
1868  let summary = "host_data construct";
1869
1870  let description = [{
1871    The "acc.host_data" operation represents the OpenACC host_data construct.
1872
1873    Example:
1874
1875    ```mlir
1876    %0 = acc.use_device varPtr(%a : !llvm.ptr) -> !llvm.ptr
1877    acc.host_data dataOperands(%0 : !llvm.ptr) {
1878
1879    }
1880    ```
1881  }];
1882
1883  let arguments = (ins Optional<I1>:$ifCond,
1884                       Variadic<OpenACC_AnyPointerOrMappableType>:$dataClauseOperands,
1885                       UnitAttr:$ifPresent);
1886
1887  let regions = (region AnyRegion:$region);
1888
1889  let assemblyFormat = [{
1890    oilist(
1891        `if` `(` $ifCond `)`
1892      | `dataOperands` `(` $dataClauseOperands `:` type($dataClauseOperands) `)`
1893    )
1894    $region attr-dict-with-keyword
1895  }];
1896
1897  let hasVerifier = 1;
1898  let hasCanonicalizer = 1;
1899}
1900
1901//===----------------------------------------------------------------------===//
1902// 2.9 loop Construct
1903//===----------------------------------------------------------------------===//
1904
1905def OpenACC_LoopOp : OpenACC_Op<"loop",
1906    [AttrSizedOperandSegments, AutomaticAllocationScope,
1907     RecursiveMemoryEffects,
1908     DeclareOpInterfaceMethods<ComputeRegionOpInterface>,
1909     DeclareOpInterfaceMethods<LoopLikeOpInterface>,
1910     MemoryEffects<[MemWrite<OpenACC_ConstructResource>]>]> {
1911  let summary = "loop construct";
1912
1913  let description = [{
1914    The "acc.loop" operation represents the OpenACC loop construct. The lower
1915    and upper bounds specify a half-open range: the range includes the lower
1916    bound but does not include the upper bound. If the `inclusive` attribute is
1917    set then the upper bound is included.
1918
1919    Example:
1920
1921    ```mlir
1922    acc.loop gang() vector() (%arg3 : index, %arg4 : index, %arg5 : index) =
1923        (%c0, %c0, %c0 : index, index, index) to
1924        (%c10, %c10, %c10 : index, index, index) step
1925        (%c1, %c1, %c1 : index, index, index) {
1926      // Loop body
1927      acc.yield
1928    } attributes { collapse = [3] }
1929    ```
1930
1931    `collapse`, `gang`, `worker`, `vector`, `seq`, `independent`, `auto` and
1932    `tile` operands are supported with `device_type` information. They should
1933    only be accessed by the extra provided getters. If modified, the
1934    corresponding `device_type` attributes must be modified as well.
1935  }];
1936
1937  let arguments = (ins
1938      Variadic<IntOrIndex>:$lowerbound,
1939      Variadic<IntOrIndex>:$upperbound,
1940      Variadic<IntOrIndex>:$step,
1941      OptionalAttr<DenseBoolArrayAttr>:$inclusiveUpperbound,
1942      OptionalAttr<I64ArrayAttr>:$collapse,
1943      OptionalAttr<DeviceTypeArrayAttr>:$collapseDeviceType,
1944      Variadic<IntOrIndex>:$gangOperands,
1945      OptionalAttr<GangArgTypeArrayAttr>:$gangOperandsArgType,
1946      OptionalAttr<DenseI32ArrayAttr>:$gangOperandsSegments,
1947      OptionalAttr<DeviceTypeArrayAttr>:$gangOperandsDeviceType,
1948      Variadic<IntOrIndex>:$workerNumOperands,
1949      OptionalAttr<DeviceTypeArrayAttr>:$workerNumOperandsDeviceType,
1950      Variadic<IntOrIndex>:$vectorOperands,
1951      OptionalAttr<DeviceTypeArrayAttr>:$vectorOperandsDeviceType,
1952      OptionalAttr<DeviceTypeArrayAttr>:$seq,
1953      OptionalAttr<DeviceTypeArrayAttr>:$independent,
1954      OptionalAttr<DeviceTypeArrayAttr>:$auto_,
1955      OptionalAttr<DeviceTypeArrayAttr>:$gang,
1956      OptionalAttr<DeviceTypeArrayAttr>:$worker,
1957      OptionalAttr<DeviceTypeArrayAttr>:$vector,
1958      Variadic<IntOrIndex>:$tileOperands,
1959      OptionalAttr<DenseI32ArrayAttr>:$tileOperandsSegments,
1960      OptionalAttr<DeviceTypeArrayAttr>:$tileOperandsDeviceType,
1961      Variadic<OpenACC_AnyPointerOrMappableType>:$cacheOperands,
1962      Variadic<OpenACC_AnyPointerOrMappableType>:$privateOperands,
1963      OptionalAttr<SymbolRefArrayAttr>:$privatizations,
1964      Variadic<AnyType>:$reductionOperands,
1965      OptionalAttr<SymbolRefArrayAttr>:$reductionRecipes,
1966      OptionalAttr<OpenACC_CombinedConstructsAttr>:$combined
1967  );
1968
1969  let results = (outs Variadic<AnyType>:$results);
1970
1971  let regions = (region AnyRegion:$region);
1972
1973  let extraClassDeclaration = [{
1974    static StringRef getAutoAttrStrName() { return "auto"; }
1975    static StringRef getGangNumKeyword() { return "num"; }
1976    static StringRef getGangDimKeyword() { return "dim"; }
1977    static StringRef getGangStaticKeyword() { return "static"; }
1978    static StringRef getControlKeyword() { return "control"; }
1979
1980    /// The number of private and reduction operands.
1981    unsigned getNumDataOperands();
1982
1983    /// The i-th data operand passed.
1984    Value getDataOperand(unsigned i);
1985
1986    /// Used to retrieve the block inside the op's region.
1987    Block &getBody() { return getLoopRegions().front()->front(); }
1988
1989    /// Return true if the op has the auto attribute for the
1990    /// mlir::acc::DeviceType::None device_type.
1991    bool hasAuto();
1992    /// Return true if the op has the auto attribute for the given device_type.
1993    bool hasAuto(mlir::acc::DeviceType deviceType);
1994    /// Return true if the op has the independent attribute for the
1995    /// mlir::acc::DeviceType::None device_type.
1996    bool hasIndependent();
1997    /// Return true if the op has the independent attribute for the given
1998    /// device_type.
1999    bool hasIndependent(mlir::acc::DeviceType deviceType);
2000    /// Return true if the op has the seq attribute for the
2001    /// mlir::acc::DeviceType::None device_type.
2002    bool hasSeq();
2003    /// Return true if the op has the seq attribute for the given device_type.
2004    bool hasSeq(mlir::acc::DeviceType deviceType);
2005
2006    /// Return the value of the vector clause if present.
2007    mlir::Value getVectorValue();
2008    /// Return the value of the vector clause for the given device_type
2009    /// if present.
2010    mlir::Value getVectorValue(mlir::acc::DeviceType deviceType);
2011    /// Return true if the op has the vector attribute for the
2012    /// mlir::acc::DeviceType::None device_type.
2013    bool hasVector();
2014    /// Return true if the op has the vector attribute for the given
2015    /// device_type.
2016    bool hasVector(mlir::acc::DeviceType deviceType);
2017
2018    /// Return the value of the worker clause if present.
2019    mlir::Value getWorkerValue();
2020    /// Return the value of the worker clause for the given device_type
2021    /// if present.
2022    mlir::Value getWorkerValue(mlir::acc::DeviceType deviceType);
2023    /// Return true if the op has the worker attribute for the
2024    /// mlir::acc::DeviceType::None device_type.
2025    bool hasWorker();
2026    /// Return true if the op has the worker attribute for the given
2027    /// device_type.
2028    bool hasWorker(mlir::acc::DeviceType deviceType);
2029
2030    /// Return the values of the tile clause if present.
2031    mlir::Operation::operand_range getTileValues();
2032    /// Return the values of the tile clause for the given device_type if
2033    /// present.
2034    mlir::Operation::operand_range
2035    getTileValues(mlir::acc::DeviceType deviceType);
2036
2037    /// Return the value of the collapse clause if present.
2038    std::optional<int64_t> getCollapseValue();
2039    /// Return the value of the collapse clause for the given device_type
2040    /// if present.
2041    std::optional<int64_t> getCollapseValue(mlir::acc::DeviceType deviceType);
2042
2043    /// Return true if the op has the gang attribute for the
2044    /// mlir::acc::DeviceType::None device_type.
2045    bool hasGang();
2046    /// Return true if the op has the gang attribute for the given
2047    /// device_type.
2048    bool hasGang(mlir::acc::DeviceType deviceType);
2049
2050    /// Return the value of the worker clause if present.
2051    mlir::Value getGangValue(mlir::acc::GangArgType gangArgType);
2052    /// Return the value of the worker clause for the given device_type
2053    /// if present.
2054    mlir::Value getGangValue(mlir::acc::GangArgType gangArgType, mlir::acc::DeviceType deviceType);
2055  }];
2056
2057  let hasCustomAssemblyFormat = 1;
2058  let assemblyFormat = [{
2059    custom<CombinedConstructsLoop>($combined)
2060    oilist(
2061        `gang` `` custom<GangClause>($gangOperands, type($gangOperands),
2062            $gangOperandsArgType, $gangOperandsDeviceType,
2063            $gangOperandsSegments, $gang)
2064      | `worker` `` custom<DeviceTypeOperandsWithKeywordOnly>(
2065            $workerNumOperands, type($workerNumOperands),
2066            $workerNumOperandsDeviceType, $worker)
2067      | `vector` `` custom<DeviceTypeOperandsWithKeywordOnly>($vectorOperands,
2068            type($vectorOperands), $vectorOperandsDeviceType, $vector)
2069      | `private` `(` custom<SymOperandList>(
2070            $privateOperands, type($privateOperands), $privatizations) `)`
2071      | `tile` `(` custom<DeviceTypeOperandsWithSegment>($tileOperands,
2072            type($tileOperands), $tileOperandsDeviceType, $tileOperandsSegments)
2073        `)`
2074      | `reduction` `(` custom<SymOperandList>(
2075            $reductionOperands, type($reductionOperands), $reductionRecipes)
2076        `)`
2077      | `cache` `(` $cacheOperands `:` type($cacheOperands) `)`
2078    )
2079    custom<LoopControl>($region, $lowerbound, type($lowerbound), $upperbound,
2080        type($upperbound), $step, type($step))
2081    ( `(` type($results)^ `)` )?
2082    attr-dict-with-keyword
2083  }];
2084
2085  let hasVerifier = 1;
2086}
2087
2088// Yield operation for the acc.loop and acc.parallel operations.
2089def OpenACC_YieldOp : OpenACC_Op<"yield", [Pure, ReturnLike, Terminator,
2090    ParentOneOf<["FirstprivateRecipeOp, LoopOp, ParallelOp, PrivateRecipeOp,"
2091                 "ReductionRecipeOp, SerialOp, AtomicUpdateOp"]>]> {
2092  let summary = "Acc yield and termination operation";
2093
2094  let description = [{
2095    `acc.yield` is a special terminator operation for block inside regions in
2096    various acc ops (including parallel, loop, atomic.update). It returns values
2097    to the immediately enclosing acc op.
2098  }];
2099
2100  let arguments = (ins Variadic<AnyType>:$operands);
2101
2102  let builders = [OpBuilder<(ins), [{ /* nothing to do */ }]>];
2103
2104  let assemblyFormat = "attr-dict ($operands^ `:` type($operands))?";
2105}
2106
2107//===----------------------------------------------------------------------===//
2108// 2.12 atomic construct
2109//===----------------------------------------------------------------------===//
2110
2111def AtomicReadOp : OpenACC_Op<"atomic.read", [AtomicReadOpInterface]> {
2112
2113  let summary = "performs an atomic read";
2114
2115  let description = [{
2116    This operation performs an atomic read.
2117
2118    The operand `x` is the address from where the value is atomically read.
2119    The operand `v` is the address where the value is stored after reading.
2120  }];
2121
2122  let arguments = (ins OpenACC_PointerLikeType:$x,
2123                       OpenACC_PointerLikeType:$v,
2124                       TypeAttr:$element_type);
2125  let assemblyFormat = [{
2126    $v `=` $x
2127    `:` type($v) `,` type($x) `,` $element_type attr-dict
2128  }];
2129  let hasVerifier = 1;
2130}
2131
2132def AtomicWriteOp : OpenACC_Op<"atomic.write",[AtomicWriteOpInterface]> {
2133
2134  let summary = "performs an atomic write";
2135
2136  let description = [{
2137    This operation performs an atomic write.
2138
2139    The operand `x` is the address to where the `expr` is atomically
2140    written w.r.t. multiple threads. The evaluation of `expr` need not be
2141    atomic w.r.t. the write to address. In general, the type(x) must
2142    dereference to type(expr).
2143  }];
2144
2145  let arguments = (ins OpenACC_PointerLikeType:$x,
2146                       AnyType:$expr);
2147  let assemblyFormat = [{
2148    $x `=` $expr
2149    `:` type($x) `,` type($expr)
2150    attr-dict
2151  }];
2152  let hasVerifier = 1;
2153}
2154
2155def AtomicUpdateOp : OpenACC_Op<"atomic.update",
2156                               [SingleBlockImplicitTerminator<"YieldOp">,
2157                                RecursiveMemoryEffects,
2158                                AtomicUpdateOpInterface]> {
2159
2160  let summary = "performs an atomic update";
2161
2162  let description = [{
2163    This operation performs an atomic update.
2164
2165    The operand `x` is exactly the same as the operand `x` in the OpenACC
2166    Standard (OpenACC 3.3, section 2.12). It is the address of the variable
2167    that is being updated. `x` is atomically read/written.
2168
2169    The region describes how to update the value of `x`. It takes the value at
2170    `x` as an input and must yield the updated value. Only the update to `x` is
2171    atomic. Generally the region must have only one instruction, but can
2172    potentially have more than one instructions too. The update is sematically
2173    similar to a compare-exchange loop based atomic update.
2174
2175    The syntax of atomic update operation is different from atomic read and
2176    atomic write operations. This is because only the host dialect knows how to
2177    appropriately update a value. For example, while generating LLVM IR, if
2178    there are no special `atomicrmw` instructions for the operation-type
2179    combination in atomic update, a compare-exchange loop is generated, where
2180    the core update operation is directly translated like regular operations by
2181    the host dialect. The front-end must handle semantic checks for allowed
2182    operations.
2183  }];
2184
2185  let arguments = (ins Arg<OpenACC_PointerLikeType,
2186                           "Address of variable to be updated",
2187                           [MemRead, MemWrite]>:$x);
2188  let regions = (region SizedRegion<1>:$region);
2189  let assemblyFormat = [{
2190    $x `:` type($x) $region attr-dict
2191  }];
2192  let hasVerifier = 1;
2193  let hasRegionVerifier = 1;
2194  let hasCanonicalizeMethod = 1;
2195  let extraClassDeclaration = [{
2196    Operation* getFirstOp() {
2197      return &getRegion().front().getOperations().front();
2198    }
2199  }];
2200}
2201
2202def AtomicCaptureOp : OpenACC_Op<"atomic.capture",
2203    [SingleBlockImplicitTerminator<"TerminatorOp">,
2204     RecursiveMemoryEffects, AtomicCaptureOpInterface]> {
2205  let summary = "performs an atomic capture";
2206  let description = [{
2207    This operation performs an atomic capture.
2208
2209    The region has the following allowed forms:
2210
2211    ```
2212      acc.atomic.capture {
2213        acc.atomic.update ...
2214        acc.atomic.read ...
2215        acc.terminator
2216      }
2217
2218      acc.atomic.capture {
2219        acc.atomic.read ...
2220        acc.atomic.update ...
2221        acc.terminator
2222      }
2223
2224      acc.atomic.capture {
2225        acc.atomic.read ...
2226        acc.atomic.write ...
2227        acc.terminator
2228      }
2229    ```
2230
2231  }];
2232
2233  let regions = (region SizedRegion<1>:$region);
2234  let assemblyFormat = [{
2235    $region attr-dict
2236  }];
2237  let hasRegionVerifier = 1;
2238  let extraClassDeclaration = [{
2239    /// Returns the `atomic.read` operation inside the region, if any.
2240    /// Otherwise, it returns nullptr.
2241    AtomicReadOp getAtomicReadOp();
2242
2243    /// Returns the `atomic.write` operation inside the region, if any.
2244    /// Otherwise, it returns nullptr.
2245    AtomicWriteOp getAtomicWriteOp();
2246
2247    /// Returns the `atomic.update` operation inside the region, if any.
2248    /// Otherwise, it returns nullptr.
2249    AtomicUpdateOp getAtomicUpdateOp();
2250  }];
2251}
2252
2253//===----------------------------------------------------------------------===//
2254// 2.13 Declare Directive
2255//===----------------------------------------------------------------------===//
2256
2257def OpenACC_DeclareEnterOp : OpenACC_Op<"declare_enter",
2258    [MemoryEffects<[MemWrite<OpenACC_ConstructResource>,
2259                    MemRead<OpenACC_CurrentDeviceIdResource>]>]> {
2260  let summary = "declare directive - entry to implicit data region";
2261
2262  let description = [{
2263    The "acc.declare_enter" operation represents the OpenACC declare directive
2264    and captures the entry semantics to the implicit data region.
2265    This operation is modeled similarly to "acc.enter_data".
2266
2267    Example showing `acc declare create(a)`:
2268
2269    ```mlir
2270    %0 = acc.create varPtr(%a : !llvm.ptr) -> !llvm.ptr
2271    acc.declare_enter dataOperands(%0 : !llvm.ptr)
2272    ```
2273  }];
2274
2275  let arguments = (ins Variadic<OpenACC_AnyPointerOrMappableType>:$dataClauseOperands);
2276  let results = (outs OpenACC_DeclareTokenType:$token);
2277
2278  let assemblyFormat = [{
2279    oilist(
2280        `dataOperands` `(` $dataClauseOperands `:` type($dataClauseOperands) `)`
2281    )
2282    attr-dict-with-keyword
2283  }];
2284
2285  let hasVerifier = 1;
2286}
2287
2288def OpenACC_DeclareExitOp : OpenACC_Op<"declare_exit",
2289    [AttrSizedOperandSegments,
2290     MemoryEffects<[MemWrite<OpenACC_ConstructResource>,
2291                    MemRead<OpenACC_CurrentDeviceIdResource>]>]> {
2292  let summary = "declare directive - exit from implicit data region";
2293
2294  let description = [{
2295    The "acc.declare_exit" operation represents the OpenACC declare directive
2296    and captures the exit semantics from the implicit data region.
2297    This operation is modeled similarly to "acc.exit_data".
2298
2299    Example showing `acc declare device_resident(a)`:
2300
2301    ```mlir
2302    %0 = acc.getdeviceptr varPtr(%a : !llvm.ptr) -> !llvm.ptr {dataClause = #acc<data_clause declare_device_resident>}
2303    acc.declare_exit dataOperands(%0 : !llvm.ptr)
2304    acc.delete accPtr(%0 : !llvm.ptr) {dataClause = #acc<data_clause declare_device_resident>}
2305    ```
2306  }];
2307
2308  let arguments = (ins
2309      Optional<OpenACC_DeclareTokenType>:$token,
2310      Variadic<OpenACC_AnyPointerOrMappableType>:$dataClauseOperands);
2311
2312  let assemblyFormat = [{
2313    oilist(
2314        `token` `(` $token `)` |
2315        `dataOperands` `(` $dataClauseOperands `:` type($dataClauseOperands) `)`
2316    )
2317    attr-dict-with-keyword
2318  }];
2319
2320  let hasVerifier = 1;
2321}
2322
2323def OpenACC_GlobalConstructorOp : OpenACC_Op<"global_ctor",
2324                                             [IsolatedFromAbove, Symbol]> {
2325  let summary = "Used to hold construction operations associated with globals such as declare";
2326
2327  let description = [{
2328    The "acc.global_ctor" operation is used to capture OpenACC actions to apply
2329    on globals (such as `acc declare`) at the entry to the implicit data region.
2330    This operation is isolated and intended to be used in a module.
2331
2332    Example showing `declare create` of global:
2333
2334    ```mlir
2335    llvm.mlir.global external @globalvar() : i32 {
2336      %0 = llvm.mlir.constant(0 : i32) : i32
2337      llvm.return %0 : i32
2338    }
2339    acc.global_ctor @acc_constructor {
2340      %0 = llvm.mlir.addressof @globalvar : !llvm.ptr
2341      %1 = acc.create varPtr(%0 : !llvm.ptr) -> !llvm.ptr
2342      acc.declare_enter dataOperands(%1 : !llvm.ptr)
2343    }
2344    ```
2345  }];
2346
2347  let arguments = (ins SymbolNameAttr:$sym_name);
2348  let regions = (region AnyRegion:$region);
2349
2350  let assemblyFormat = [{
2351    $sym_name $region attr-dict-with-keyword
2352  }];
2353
2354  let hasVerifier = 0;
2355}
2356
2357def OpenACC_GlobalDestructorOp : OpenACC_Op<"global_dtor",
2358                                            [IsolatedFromAbove, Symbol]> {
2359  let summary = "Used to hold destruction operations associated with globals such as declare";
2360
2361  let description = [{
2362    The "acc.global_dtor" operation is used to capture OpenACC actions to apply
2363    on globals (such as `acc declare`) at the exit from the implicit data
2364    region. This operation is isolated and intended to be used in a module.
2365
2366    Example showing delete associated with `declare create` of global:
2367
2368    ```mlir
2369    llvm.mlir.global external @globalvar() : i32 {
2370      %0 = llvm.mlir.constant(0 : i32) : i32
2371      llvm.return %0 : i32
2372    }
2373    acc.global_dtor @acc_destructor {
2374      %0 = llvm.mlir.addressof @globalvar : !llvm.ptr
2375      %1 = acc.getdeviceptr varPtr(%0 : !llvm.ptr) -> !llvm.ptr {dataClause = #acc<data_clause create>}
2376      acc.declare_exit dataOperands(%1 : !llvm.ptr)
2377      acc.delete accPtr(%1 : !llvm.ptr) {dataClause = #acc<data_clause create>}
2378    }
2379    ```
2380  }];
2381
2382  let arguments = (ins SymbolNameAttr:$sym_name);
2383  let regions = (region AnyRegion:$region);
2384
2385  let assemblyFormat = [{
2386    $sym_name $region attr-dict-with-keyword
2387  }];
2388
2389  let hasVerifier = 0;
2390}
2391
2392def OpenACC_DeclareOp : OpenACC_Op<"declare",
2393    [RecursiveMemoryEffects,
2394     MemoryEffects<[MemWrite<OpenACC_ConstructResource>]>]> {
2395  let summary = "declare implicit region";
2396
2397  let description = [{
2398    The "acc.declare" operation represents an implicit declare region in
2399    function (and subroutine in Fortran).
2400
2401    Example:
2402
2403    ```mlir
2404    %pa = acc.present varPtr(%a : memref<10x10xf32>) -> memref<10x10xf32>
2405    acc.declare dataOperands(%pa: memref<10x10xf32>) {
2406      // implicit region
2407    }
2408    ```
2409  }];
2410
2411  let arguments = (ins
2412      Variadic<OpenACC_AnyPointerOrMappableType>:$dataClauseOperands);
2413
2414  let regions = (region AnyRegion:$region);
2415
2416  let assemblyFormat = [{
2417      `dataOperands` `(` $dataClauseOperands `:` type($dataClauseOperands) `)`
2418    $region attr-dict-with-keyword
2419  }];
2420
2421  let hasVerifier = 1;
2422}
2423
2424//===----------------------------------------------------------------------===//
2425// 2.15.1 Routine Directive
2426//===----------------------------------------------------------------------===//
2427
2428def OpenACC_RoutineOp : OpenACC_Op<"routine", [IsolatedFromAbove]> {
2429  let summary = "acc routine operation";
2430
2431  let description = [{
2432    The `acc.routine` operation is used to capture the clauses of acc
2433    routine directive, including the associated function name. The associated
2434    function keeps track of its corresponding routine declaration through
2435    the `RoutineInfoAttr`.
2436
2437    Example:
2438
2439    ```mlir
2440    func.func @acc_func(%a : i64) -> () attributes
2441        {acc.routine_info = #acc.routine_info<[@acc_func_rout1]>} {
2442      return
2443    }
2444    acc.routine @acc_func_rout1 func(@acc_func) gang
2445    ```
2446
2447    `bind`, `gang`, `worker`, `vector` and `seq` operands are supported with
2448    `device_type` information. They should only be accessed by the extra
2449    provided getters. If modified, the corresponding `device_type` attributes
2450    must be modified as well.
2451  }];
2452
2453  let arguments = (ins SymbolNameAttr:$sym_name,
2454                       SymbolNameAttr:$func_name,
2455                       OptionalAttr<StrArrayAttr>:$bindName,
2456                       OptionalAttr<DeviceTypeArrayAttr>:$bindNameDeviceType,
2457                       OptionalAttr<DeviceTypeArrayAttr>:$worker,
2458                       OptionalAttr<DeviceTypeArrayAttr>:$vector,
2459                       OptionalAttr<DeviceTypeArrayAttr>:$seq,
2460                       UnitAttr:$nohost,
2461                       UnitAttr:$implicit,
2462                       OptionalAttr<DeviceTypeArrayAttr>:$gang,
2463                       OptionalAttr<I64ArrayAttr>:$gangDim,
2464                       OptionalAttr<DeviceTypeArrayAttr>:$gangDimDeviceType);
2465
2466  let extraClassDeclaration = [{
2467    static StringRef getGangDimKeyword() { return "dim"; }
2468
2469    /// Return true if the op has the worker attribute for the
2470    /// mlir::acc::DeviceType::None device_type.
2471    bool hasWorker();
2472    /// Return true if the op has the worker attribute for the given
2473    /// device_type.
2474    bool hasWorker(mlir::acc::DeviceType deviceType);
2475
2476    /// Return true if the op has the vector attribute for the
2477    /// mlir::acc::DeviceType::None device_type.
2478    bool hasVector();
2479    /// Return true if the op has the vector attribute for the given
2480    /// device_type.
2481    bool hasVector(mlir::acc::DeviceType deviceType);
2482
2483    /// Return true if the op has the seq attribute for the
2484    /// mlir::acc::DeviceType::None device_type.
2485    bool hasSeq();
2486    /// Return true if the op has the seq attribute for the given
2487    /// device_type.
2488    bool hasSeq(mlir::acc::DeviceType deviceType);
2489
2490    /// Return true if the op has the gang attribute for the
2491    /// mlir::acc::DeviceType::None device_type.
2492    bool hasGang();
2493    /// Return true if the op has the gang attribute for the given
2494    /// device_type.
2495    bool hasGang(mlir::acc::DeviceType deviceType);
2496
2497    std::optional<int64_t> getGangDimValue();
2498    std::optional<int64_t> getGangDimValue(mlir::acc::DeviceType deviceType);
2499
2500    std::optional<llvm::StringRef> getBindNameValue();
2501    std::optional<llvm::StringRef> getBindNameValue(mlir::acc::DeviceType deviceType);
2502  }];
2503
2504  let assemblyFormat = [{
2505    $sym_name `func` `(` $func_name `)`
2506    oilist (
2507        `bind` `(` custom<BindName>($bindName, $bindNameDeviceType) `)`
2508      | `gang` `` custom<RoutineGangClause>($gang, $gangDim, $gangDimDeviceType)
2509      | `worker` custom<DeviceTypeArrayAttr>($worker)
2510      | `vector` custom<DeviceTypeArrayAttr>($vector)
2511      | `seq` custom<DeviceTypeArrayAttr>($seq)
2512      | `nohost` $nohost
2513      | `implicit` $implicit
2514    ) attr-dict-with-keyword
2515  }];
2516
2517  let hasVerifier = 1;
2518}
2519
2520def RoutineInfoAttr : OpenACC_Attr<"RoutineInfo", "routine_info"> {
2521  let summary = "Keeps track of associated acc routine information";
2522
2523  let description = [{
2524    This attribute is used to create the association between a function and
2525    its `acc.routine` operation. A `func.func` uses this if its name
2526    was referenced in an `acc routine` directive.
2527  }];
2528
2529  let parameters = (ins ArrayRefParameter<"SymbolRefAttr", "">:$accRoutines);
2530  let assemblyFormat = "`<` `[` `` $accRoutines `]` `>`";
2531}
2532
2533//===----------------------------------------------------------------------===//
2534// 2.14.1. Init Directive
2535//===----------------------------------------------------------------------===//
2536
2537def OpenACC_InitOp : OpenACC_Op<"init", [AttrSizedOperandSegments]> {
2538  let summary = "init operation";
2539
2540  let description = [{
2541    The "acc.init" operation represents the OpenACC init executable
2542    directive.
2543
2544    Example:
2545
2546    ```mlir
2547    acc.init
2548    acc.init device_num(%dev1 : i32)
2549    ```
2550  }];
2551
2552  let arguments = (ins OptionalAttr<TypedArrayAttrBase<OpenACC_DeviceTypeAttr, "Device type attributes">>:$device_types,
2553                       Optional<IntOrIndex>:$deviceNumOperand,
2554                       Optional<I1>:$ifCond);
2555
2556  let assemblyFormat = [{
2557    oilist(`device_num` `(` $deviceNumOperand `:` type($deviceNumOperand) `)`
2558      | `if` `(` $ifCond `)`
2559    ) attr-dict-with-keyword
2560  }];
2561  let hasVerifier = 1;
2562}
2563
2564//===----------------------------------------------------------------------===//
2565// 2.14.2. Shutdown
2566//===----------------------------------------------------------------------===//
2567
2568def OpenACC_ShutdownOp : OpenACC_Op<"shutdown", [AttrSizedOperandSegments]> {
2569  let summary = "shutdown operation";
2570
2571  let description = [{
2572    The "acc.shutdown" operation represents the OpenACC shutdown executable
2573    directive.
2574
2575    Example:
2576
2577    ```mlir
2578    acc.shutdown
2579    acc.shutdown device_num(%dev1 : i32)
2580    ```
2581  }];
2582
2583  let arguments = (ins OptionalAttr<TypedArrayAttrBase<OpenACC_DeviceTypeAttr, "Device type attributes">>:$device_types,
2584                       Optional<IntOrIndex>:$deviceNumOperand,
2585                       Optional<I1>:$ifCond);
2586
2587  let assemblyFormat = [{
2588    oilist(`device_num` `(` $deviceNumOperand `:` type($deviceNumOperand) `)`
2589    |`if` `(` $ifCond `)`
2590    ) attr-dict-with-keyword
2591  }];
2592  let hasVerifier = 1;
2593}
2594
2595//===----------------------------------------------------------------------===//
2596// 2.14.3. Set
2597//===----------------------------------------------------------------------===//
2598
2599def OpenACC_SetOp : OpenACC_Op<"set", [AttrSizedOperandSegments,
2600    MemoryEffects<[MemWrite<OpenACC_CurrentDeviceIdResource>]>]> {
2601  let summary = "set operation";
2602
2603  let description = [{
2604    The "acc.set" operation represents the OpenACC set directive.
2605
2606    Example:
2607
2608    ```mlir
2609    acc.set device_num(%dev1 : i32)
2610    ```
2611  }];
2612
2613  let arguments = (ins OptionalAttr<OpenACC_DeviceTypeAttr>:$device_type,
2614                       Optional<IntOrIndex>:$defaultAsync,
2615                       Optional<IntOrIndex>:$deviceNum,
2616                       Optional<I1>:$ifCond);
2617
2618  let assemblyFormat = [{
2619    oilist(`default_async` `(` $defaultAsync `:` type($defaultAsync) `)`
2620    | `device_num` `(` $deviceNum `:` type($deviceNum) `)`
2621    | `if` `(` $ifCond `)`
2622    ) attr-dict-with-keyword
2623  }];
2624  let hasVerifier = 1;
2625}
2626
2627//===----------------------------------------------------------------------===//
2628// 2.14.4. Update Directive
2629//===----------------------------------------------------------------------===//
2630
2631def OpenACC_UpdateOp : OpenACC_Op<"update",
2632    [AttrSizedOperandSegments,
2633     MemoryEffects<[MemWrite<OpenACC_ConstructResource>,
2634                    MemRead<OpenACC_CurrentDeviceIdResource>]>]> {
2635  let summary = "update operation";
2636
2637  let description = [{
2638    The `acc.update` operation represents the OpenACC update executable
2639    directive.
2640    As host and self clauses are synonyms, any operands for host and self are
2641    add to $hostOperands.
2642
2643    Example:
2644
2645    ```mlir
2646    acc.update device(%d1 : memref<10xf32>) attributes {async}
2647    ```
2648
2649    `async` and `wait` operands are supported with `device_type` information.
2650    They should only be accessed by the extra provided getters. If modified,
2651    the corresponding `device_type` attributes must be modified as well.
2652  }];
2653
2654  let arguments = (ins Optional<I1>:$ifCond,
2655      Variadic<IntOrIndex>:$asyncOperands,
2656      OptionalAttr<DeviceTypeArrayAttr>:$asyncOperandsDeviceType,
2657      OptionalAttr<DeviceTypeArrayAttr>:$async,
2658      Variadic<IntOrIndex>:$waitOperands,
2659      OptionalAttr<DenseI32ArrayAttr>:$waitOperandsSegments,
2660      OptionalAttr<DeviceTypeArrayAttr>:$waitOperandsDeviceType,
2661      OptionalAttr<BoolArrayAttr>:$hasWaitDevnum,
2662      OptionalAttr<DeviceTypeArrayAttr>:$waitOnly,
2663      Variadic<OpenACC_AnyPointerOrMappableType>:$dataClauseOperands,
2664      UnitAttr:$ifPresent);
2665
2666  let extraClassDeclaration = [{
2667    /// The number of data operands.
2668    unsigned getNumDataOperands();
2669
2670    /// The i-th data operand passed.
2671    Value getDataOperand(unsigned i);
2672
2673    /// Return true if the op has the async attribute for the
2674    /// mlir::acc::DeviceType::None device_type.
2675    bool hasAsyncOnly();
2676    /// Return true if the op has the async attribute for the given device_type.
2677    bool hasAsyncOnly(mlir::acc::DeviceType deviceType);
2678    /// Return the value of the async clause if present.
2679    mlir::Value getAsyncValue();
2680    /// Return the value of the async clause for the given device_type if
2681    /// present.
2682    mlir::Value getAsyncValue(mlir::acc::DeviceType deviceType);
2683
2684    /// Return true if the op has the wait attribute for the
2685    /// mlir::acc::DeviceType::None device_type.
2686    bool hasWaitOnly();
2687    /// Return true if the op has the wait attribute for the given device_type.
2688    bool hasWaitOnly(mlir::acc::DeviceType deviceType);
2689    /// Return the values of the wait clause if present.
2690    mlir::Operation::operand_range getWaitValues();
2691    /// Return the values of the wait clause for the given device_type if
2692    /// present.
2693    mlir::Operation::operand_range
2694    getWaitValues(mlir::acc::DeviceType deviceType);
2695    /// Return the wait devnum value clause if present;
2696    mlir::Value getWaitDevnum();
2697    /// Return the wait devnum value clause for the given device_type if
2698    /// present.
2699    mlir::Value getWaitDevnum(mlir::acc::DeviceType deviceType);
2700  }];
2701
2702  let assemblyFormat = [{
2703    oilist(
2704        `if` `(` $ifCond `)`
2705      | `async` `` custom<DeviceTypeOperandsWithKeywordOnly>(
2706            $asyncOperands, type($asyncOperands),
2707            $asyncOperandsDeviceType, $async)
2708      | `wait` `` custom<WaitClause>($waitOperands, type($waitOperands),
2709          $waitOperandsDeviceType, $waitOperandsSegments, $hasWaitDevnum,
2710          $waitOnly)
2711      | `dataOperands` `(` $dataClauseOperands `:` type($dataClauseOperands) `)`
2712    )
2713    attr-dict-with-keyword
2714  }];
2715
2716  let hasCanonicalizer = 1;
2717  let hasVerifier = 1;
2718}
2719
2720//===----------------------------------------------------------------------===//
2721// 2.16.3. Wait Directive
2722//===----------------------------------------------------------------------===//
2723
2724def OpenACC_WaitOp : OpenACC_Op<"wait", [AttrSizedOperandSegments]> {
2725  let summary = "wait operation";
2726
2727  let description = [{
2728    The "acc.wait" operation represents the OpenACC wait executable
2729    directive.
2730
2731    Example:
2732
2733    ```mlir
2734    acc.wait(%value1: index)
2735    acc.wait() async(%async1: i32)
2736    ```
2737
2738    acc.wait does not implement MemoryEffects interface,
2739    so it affects all the resources. This is conservatively
2740    correct. More precise modelling of the memory effects
2741    seems to be impossible without the whole program analysis.
2742  }];
2743
2744  let arguments = (ins Variadic<IntOrIndex>:$waitOperands,
2745                       Optional<IntOrIndex>:$asyncOperand,
2746                       Optional<IntOrIndex>:$waitDevnum,
2747                       UnitAttr:$async,
2748                       Optional<I1>:$ifCond);
2749
2750  let assemblyFormat = [{
2751    ( `(` $waitOperands^ `:` type($waitOperands) `)` )?
2752    oilist(`async` `(` $asyncOperand `:` type($asyncOperand) `)`
2753      |`wait_devnum` `(` $waitDevnum `:` type($waitDevnum) `)`
2754      |`if` `(` $ifCond `)`
2755    ) attr-dict-with-keyword
2756  }];
2757  let hasVerifier = 1;
2758}
2759
2760#endif // OPENACC_OPS
2761