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