1//===-- OpenMPOps.td - OpenMP dialect operation definitions *- tablegen -*-===// 2// 3// Part of the LLVM 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// This file defines the basic operations for the OpenMP dialect. 10// 11//===----------------------------------------------------------------------===// 12 13 14#ifndef OPENMP_OPS 15#define OPENMP_OPS 16 17include "mlir/Dialect/LLVMIR/LLVMOpBase.td" 18include "mlir/Dialect/OpenACCMPCommon/Interfaces/AtomicInterfaces.td" 19include "mlir/Dialect/OpenACCMPCommon/Interfaces/OpenACCMPOpsInterfaces.td" 20include "mlir/Dialect/OpenMP/OpenMPClauses.td" 21include "mlir/Dialect/OpenMP/OpenMPOpBase.td" 22include "mlir/Interfaces/ControlFlowInterfaces.td" 23include "mlir/Interfaces/SideEffectInterfaces.td" 24include "mlir/IR/EnumAttr.td" 25include "mlir/IR/OpBase.td" 26include "mlir/IR/SymbolInterfaces.td" 27 28//===----------------------------------------------------------------------===// 29// 2.19.4 Data-Sharing Attribute Clauses 30//===----------------------------------------------------------------------===// 31 32def PrivateClauseOp : OpenMP_Op<"private", [IsolatedFromAbove, RecipeInterface]> { 33 let summary = "Provides declaration of [first]private logic."; 34 let description = [{ 35 This operation provides a declaration of how to implement the 36 [first]privatization of a variable. The dialect users should provide 37 information about how to create an instance of the type in the alloc region, 38 how to initialize the copy from the original item in the copy region, and if 39 needed, how to deallocate allocated memory in the dealloc region. 40 41 Examples: 42 43 * `private(x)` would be emitted as: 44 ```mlir 45 omp.private {type = private} @x.privatizer : !fir.ref<i32> alloc { 46 ^bb0(%arg0: !fir.ref<i32>): 47 %0 = ... allocate proper memory for the private clone ... 48 omp.yield(%0 : !fir.ref<i32>) 49 } 50 ``` 51 52 * `firstprivate(x)` would be emitted as: 53 ```mlir 54 omp.private {type = firstprivate} @x.privatizer : !fir.ref<i32> alloc { 55 ^bb0(%arg0: !fir.ref<i32>): 56 %0 = ... allocate proper memory for the private clone ... 57 omp.yield(%0 : !fir.ref<i32>) 58 } copy { 59 ^bb0(%arg0: !fir.ref<i32>, %arg1: !fir.ref<i32>): 60 // %arg0 is the original host variable. Same as for `alloc`. 61 // %arg1 represents the memory allocated in `alloc`. 62 ... copy from host to the privatized clone .... 63 omp.yield(%arg1 : !fir.ref<i32>) 64 } 65 ``` 66 67 * `private(x)` for "allocatables" would be emitted as: 68 ```mlir 69 omp.private {type = private} @x.privatizer : !some.type alloc { 70 ^bb0(%arg0: !some.type): 71 %0 = ... allocate proper memory for the private clone ... 72 omp.yield(%0 : !fir.ref<i32>) 73 } dealloc { 74 ^bb0(%arg0: !some.type): 75 ... deallocate allocated memory ... 76 omp.yield 77 } 78 ``` 79 80 There are no restrictions on the body except for: 81 - The `alloc` & `dealloc` regions have a single argument. 82 - The `copy` region has 2 arguments. 83 - All three regions are terminated by `omp.yield` ops. 84 The above restrictions and other obvious restrictions (e.g. verifying the 85 type of yielded values) are verified by the custom op verifier. The actual 86 contents of the blocks inside all regions are not verified. 87 88 Instances of this op would then be used by ops that model directives that 89 accept data-sharing attribute clauses. 90 91 The $sym_name attribute provides a symbol by which the privatizer op can be 92 referenced by other dialect ops. 93 94 The $type attribute is the type of the value being privatized. 95 96 The $data_sharing_type attribute specifies whether privatizer corresponds 97 to a `private` or a `firstprivate` clause. 98 }]; 99 100 let arguments = (ins SymbolNameAttr:$sym_name, 101 TypeAttrOf<AnyType>:$type, 102 DataSharingClauseTypeAttr:$data_sharing_type); 103 104 let regions = (region MinSizedRegion<1>:$alloc_region, 105 AnyRegion:$copy_region, 106 AnyRegion:$dealloc_region); 107 108 let assemblyFormat = [{ 109 $data_sharing_type $sym_name `:` $type 110 `alloc` $alloc_region 111 (`copy` $copy_region^)? 112 (`dealloc` $dealloc_region^)? 113 attr-dict 114 }]; 115 116 let builders = [ 117 OpBuilder<(ins CArg<"TypeRange">:$result, 118 CArg<"StringAttr">:$sym_name, 119 CArg<"TypeAttr">:$type)> 120 ]; 121 122 let extraClassDeclaration = [{ 123 BlockArgument getAllocMoldArg() { 124 return getAllocRegion().getArgument(0); 125 } 126 BlockArgument getCopyMoldArg() { 127 auto ®ion = getCopyRegion(); 128 return region.empty() ? nullptr : region.getArgument(0); 129 } 130 BlockArgument getCopyPrivateArg() { 131 auto ®ion = getCopyRegion(); 132 return region.empty() ? nullptr : region.getArgument(1); 133 } 134 BlockArgument getDeallocMoldArg() { 135 auto ®ion = getDeallocRegion(); 136 return region.empty() ? nullptr : region.getArgument(0); 137 } 138 139 /// needsMap returns true if the value being privatized should additionally 140 /// be mapped to the target region using a MapInfoOp. This is most common 141 /// when an allocatable is privatized. In such cases, the descriptor is used 142 /// in privatization and needs to be mapped on to the device. 143 bool needsMap() { 144 return !getAllocMoldArg().use_empty(); 145 } 146 }]; 147 148 let hasRegionVerifier = 1; 149} 150 151//===----------------------------------------------------------------------===// 152// 2.6 parallel Construct 153//===----------------------------------------------------------------------===// 154 155def ParallelOp : OpenMP_Op<"parallel", traits = [ 156 AttrSizedOperandSegments, AutomaticAllocationScope, 157 DeclareOpInterfaceMethods<ComposableOpInterface>, 158 DeclareOpInterfaceMethods<OutlineableOpenMPOpInterface>, 159 RecursiveMemoryEffects 160 ], clauses = [ 161 OpenMP_AllocateClause, OpenMP_IfClause, OpenMP_NumThreadsClause, 162 OpenMP_PrivateClause, OpenMP_ProcBindClause, OpenMP_ReductionClause 163 ], singleRegion = true> { 164 let summary = "parallel construct"; 165 let description = [{ 166 The parallel construct includes a region of code which is to be executed 167 by a team of threads. 168 169 The optional `if_expr` parameter specifies a boolean result of a conditional 170 check. If this value is 1 or is not provided then the parallel region runs 171 as normal, if it is 0 then the parallel region is executed with one thread. 172 }] # clausesDescription; 173 174 let builders = [ 175 OpBuilder<(ins CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes)>, 176 OpBuilder<(ins CArg<"const ParallelOperands &">:$clauses)> 177 ]; 178 179 let assemblyFormat = clausesAssemblyFormat # [{ 180 custom<PrivateReductionRegion>($region, $private_vars, type($private_vars), 181 $private_syms, $reduction_mod, $reduction_vars, type($reduction_vars), $reduction_byref, 182 $reduction_syms) attr-dict 183 }]; 184 185 let hasVerifier = 1; 186 let hasRegionVerifier = 1; 187} 188 189def TerminatorOp : OpenMP_Op<"terminator", [Terminator, Pure]> { 190 let summary = "terminator for OpenMP regions"; 191 let description = [{ 192 A terminator operation for regions that appear in the body of OpenMP 193 operation. These regions are not expected to return any value so the 194 terminator takes no operands. The terminator op returns control to the 195 enclosing op. 196 }]; 197 198 let assemblyFormat = "attr-dict"; 199} 200 201//===----------------------------------------------------------------------===// 202// 2.7 teams Construct 203//===----------------------------------------------------------------------===// 204def TeamsOp : OpenMP_Op<"teams", traits = [ 205 AttrSizedOperandSegments, RecursiveMemoryEffects 206 ], clauses = [ 207 OpenMP_AllocateClause, OpenMP_IfClause, OpenMP_NumTeamsClause, 208 OpenMP_PrivateClause, OpenMP_ReductionClause, OpenMP_ThreadLimitClause 209 ], singleRegion = true> { 210 let summary = "teams construct"; 211 let description = [{ 212 The teams construct defines a region of code that triggers the creation of a 213 league of teams. Once created, the number of teams remains constant for the 214 duration of its code region. 215 216 If the `if_expr` is present and it evaluates to `false`, the number of teams 217 created is one. 218 }] # clausesDescription; 219 220 let builders = [ 221 OpBuilder<(ins CArg<"const TeamsOperands &">:$clauses)> 222 ]; 223 224 let assemblyFormat = clausesAssemblyFormat # [{ 225 custom<PrivateReductionRegion>($region, $private_vars, type($private_vars), 226 $private_syms, $reduction_mod, $reduction_vars, type($reduction_vars), $reduction_byref, 227 $reduction_syms) attr-dict 228 }]; 229 230 let hasVerifier = 1; 231} 232 233//===----------------------------------------------------------------------===// 234// 2.8.1 Sections Construct 235//===----------------------------------------------------------------------===// 236 237def SectionOp : OpenMP_Op<"section", traits = [ 238 BlockArgOpenMPOpInterface, HasParent<"SectionsOp"> 239 ], singleRegion = true> { 240 let summary = "section directive"; 241 let description = [{ 242 A section operation encloses a region which represents one section in a 243 sections construct. A section op should always be surrounded by an 244 `omp.sections` operation. The section operation may have block args 245 which corespond to the block arguments of the surrounding `omp.sections` 246 operation. This is done to reflect situations where these block arguments 247 represent variables private to each section. 248 }]; 249 let extraClassDeclaration = [{ 250 // Override BlockArgOpenMPOpInterface methods based on the parent 251 // omp.sections operation. Only forward-declare here because SectionsOp is 252 // not completely defined at this point. 253 unsigned numPrivateBlockArgs(); 254 unsigned numReductionBlockArgs(); 255 }] # clausesExtraClassDeclaration; 256 let assemblyFormat = "$region attr-dict"; 257} 258 259def SectionsOp : OpenMP_Op<"sections", traits = [ 260 AttrSizedOperandSegments 261 ], clauses = [ 262 OpenMP_AllocateClause, OpenMP_NowaitClause, OpenMP_PrivateClause, 263 OpenMP_ReductionClause 264 ], singleRegion = true> { 265 let summary = "sections construct"; 266 let description = [{ 267 The sections construct is a non-iterative worksharing construct that 268 contains `omp.section` operations. The `omp.section` operations are to be 269 distributed among and executed by the threads in a team. Each `omp.section` 270 is executed once by one of the threads in the team in the context of its 271 implicit task. 272 Block arguments for reduction variables should be mirrored in enclosed 273 `omp.section` operations. 274 }] # clausesDescription; 275 276 // Override region definition. 277 let regions = (region SizedRegion<1>:$region); 278 279 let builders = [ 280 OpBuilder<(ins CArg<"const SectionsOperands &">:$clauses)> 281 ]; 282 283 let assemblyFormat = clausesAssemblyFormat # [{ 284 custom<PrivateReductionRegion>($region, $private_vars, type($private_vars), 285 $private_syms, $reduction_mod, $reduction_vars, type($reduction_vars), $reduction_byref, 286 $reduction_syms) attr-dict 287 }]; 288 289 let hasVerifier = 1; 290 let hasRegionVerifier = 1; 291} 292 293//===----------------------------------------------------------------------===// 294// 2.8.2 Single Construct 295//===----------------------------------------------------------------------===// 296 297def SingleOp : OpenMP_Op<"single", traits = [ 298 AttrSizedOperandSegments 299 ], clauses = [ 300 OpenMP_AllocateClause, OpenMP_CopyprivateClause, OpenMP_NowaitClause, 301 OpenMP_PrivateClause 302 ], singleRegion = true> { 303 let summary = "single directive"; 304 let description = [{ 305 The single construct specifies that the associated structured block is 306 executed by only one of the threads in the team (not necessarily the 307 master thread), in the context of its implicit task. The other threads 308 in the team, which do not execute the block, wait at an implicit barrier 309 at the end of the single construct. 310 }] # clausesDescription; 311 312 let builders = [ 313 OpBuilder<(ins CArg<"const SingleOperands &">:$clauses)> 314 ]; 315 316 let assemblyFormat = clausesAssemblyFormat # [{ 317 custom<PrivateRegion>($region, $private_vars, type($private_vars), 318 $private_syms) attr-dict 319 }]; 320 321 let hasVerifier = 1; 322} 323 324//===----------------------------------------------------------------------===// 325// 2.8.3 Workshare Construct 326//===----------------------------------------------------------------------===// 327 328def WorkshareOp : OpenMP_Op<"workshare", traits = [ 329 RecursiveMemoryEffects, 330 ], clauses = [ 331 OpenMP_NowaitClause, 332 ], singleRegion = true> { 333 let summary = "workshare directive"; 334 let description = [{ 335 The workshare construct divides the execution of the enclosed structured 336 block into separate units of work, and causes the threads of the team to 337 share the work such that each unit is executed only once by one thread, in 338 the context of its implicit task 339 340 This operation is used for the intermediate representation of the workshare 341 block before the work gets divided between the threads. See the flang 342 LowerWorkshare pass for details. 343 }] # clausesDescription; 344 345 let builders = [ 346 OpBuilder<(ins CArg<"const WorkshareOperands &">:$clauses)> 347 ]; 348} 349 350def WorkshareLoopWrapperOp : OpenMP_Op<"workshare.loop_wrapper", traits = [ 351 DeclareOpInterfaceMethods<LoopWrapperInterface>, NoTerminator, 352 RecursiveMemoryEffects, SingleBlock 353 ], singleRegion = true> { 354 let summary = "contains loop nests to be parallelized by workshare"; 355 let description = [{ 356 This operation wraps a loop nest that is marked for dividing into units of 357 work by an encompassing omp.workshare operation. 358 }]; 359 360 let builders = [ 361 OpBuilder<(ins), [{ build($_builder, $_state, {}); }]> 362 ]; 363 let assemblyFormat = "$region attr-dict"; 364 let hasVerifier = 1; 365} 366 367//===----------------------------------------------------------------------===// 368// Loop Nest 369//===----------------------------------------------------------------------===// 370 371def LoopNestOp : OpenMP_Op<"loop_nest", traits = [ 372 RecursiveMemoryEffects, SameVariadicOperandSize 373 ], clauses = [ 374 OpenMP_LoopRelatedClause 375 ], singleRegion = true> { 376 let summary = "rectangular loop nest"; 377 let description = [{ 378 This operation represents a collapsed rectangular loop nest. For each 379 rectangular loop of the nest represented by an instance of this operation, 380 lower and upper bounds, as well as a step variable, must be defined. 381 382 The lower and upper bounds specify a half-open range: the range includes the 383 lower bound but does not include the upper bound. If the `loop_inclusive` 384 attribute is specified then the upper bound is also included. 385 386 The body region can contain any number of blocks. The region is terminated 387 by an `omp.yield` instruction without operands. The induction variables, 388 represented as entry block arguments to the loop nest operation's single 389 region, match the types of the `loop_lower_bounds`, `loop_upper_bounds` and 390 `loop_steps` arguments. 391 392 ```mlir 393 omp.loop_nest (%i1, %i2) : i32 = (%c0, %c0) to (%c10, %c10) step (%c1, %c1) { 394 %a = load %arrA[%i1, %i2] : memref<?x?xf32> 395 %b = load %arrB[%i1, %i2] : memref<?x?xf32> 396 %sum = arith.addf %a, %b : f32 397 store %sum, %arrC[%i1, %i2] : memref<?x?xf32> 398 omp.yield 399 } 400 ``` 401 402 This is a temporary simplified definition of a loop based on existing OpenMP 403 loop operations intended to serve as a stopgap solution until the long-term 404 representation of canonical loops is defined. Specifically, this operation 405 is intended to serve as a unique source for loop information during the 406 transition to making `omp.distribute`, `omp.simd`, `omp.taskloop` and 407 `omp.wsloop` wrapper operations. It is not intended to help with the 408 addition of support for loop transformations, non-rectangular loops and 409 non-perfectly nested loops. 410 }]; 411 412 let builders = [ 413 OpBuilder<(ins CArg<"const LoopNestOperands &">:$clauses)> 414 ]; 415 416 let extraClassDeclaration = [{ 417 /// Returns the induction variables of the loop nest. 418 ArrayRef<BlockArgument> getIVs() { return getRegion().getArguments(); } 419 420 /// Fills a list of wrapper operations around this loop nest. Wrappers 421 /// in the resulting vector will be sorted from innermost to outermost. 422 void gatherWrappers(SmallVectorImpl<LoopWrapperInterface> &wrappers); 423 }] # clausesExtraClassDeclaration; 424 425 // Disable inherited clause-based declarative assembly format and instead 426 // enable using the custom parser-printer implemented in C++. 427 let assemblyFormat = ?; 428 let hasCustomAssemblyFormat = 1; 429 let hasVerifier = 1; 430} 431 432//===----------------------------------------------------------------------===// 433// 2.9.2 Workshare Loop Construct 434//===----------------------------------------------------------------------===// 435 436def LoopOp : OpenMP_Op<"loop", traits = [ 437 AttrSizedOperandSegments, DeclareOpInterfaceMethods<LoopWrapperInterface>, 438 NoTerminator, SingleBlock 439 ], clauses = [ 440 OpenMP_BindClause, OpenMP_PrivateClause, OpenMP_OrderClause, 441 OpenMP_ReductionClause 442 ], singleRegion = true> { 443 let summary = "loop construct"; 444 let description = [{ 445 A loop construct specifies that the logical iterations of the associated loops 446 may execute concurrently and permits the encountering threads to execute the 447 loop accordingly. A loop construct can have 3 different types of binding: 448 1. teams: in which case the binding region is the innermost enclosing `teams` 449 region. 450 2. parallel: in which case the binding region is the innermost enclosing `parallel` 451 region. 452 3. thread: in which case the binding region is not defined. 453 454 The body region can only contain a single block which must contain a single 455 operation, this operation must be an `omp.loop_nest`. 456 457 ``` 458 omp.loop <clauses> { 459 omp.loop_nest (%i1, %i2) : index = (%c0, %c0) to (%c10, %c10) step (%c1, %c1) { 460 %a = load %arrA[%i1, %i2] : memref<?x?xf32> 461 %b = load %arrB[%i1, %i2] : memref<?x?xf32> 462 %sum = arith.addf %a, %b : f32 463 store %sum, %arrC[%i1, %i2] : memref<?x?xf32> 464 omp.yield 465 } 466 } 467 ``` 468 }] # clausesDescription; 469 470 let assemblyFormat = clausesAssemblyFormat # [{ 471 custom<PrivateReductionRegion>($region, $private_vars, type($private_vars), 472 $private_syms, $reduction_mod, $reduction_vars, type($reduction_vars), $reduction_byref, 473 $reduction_syms) attr-dict 474 }]; 475 476 let builders = [ 477 OpBuilder<(ins CArg<"const LoopOperands &">:$clauses)> 478 ]; 479 480 let hasVerifier = 1; 481 let hasRegionVerifier = 1; 482} 483 484def WsloopOp : OpenMP_Op<"wsloop", traits = [ 485 AttrSizedOperandSegments, DeclareOpInterfaceMethods<ComposableOpInterface>, 486 DeclareOpInterfaceMethods<LoopWrapperInterface>, NoTerminator, 487 RecursiveMemoryEffects, SingleBlock 488 ], clauses = [ 489 OpenMP_AllocateClause, OpenMP_LinearClause, OpenMP_NowaitClause, 490 OpenMP_OrderClause, OpenMP_OrderedClause, OpenMP_PrivateClause, 491 OpenMP_ReductionClause, OpenMP_ScheduleClause 492 ], singleRegion = true> { 493 let summary = "worksharing-loop construct"; 494 let description = [{ 495 The worksharing-loop construct specifies that the iterations of the loop(s) 496 will be executed in parallel by threads in the current context. These 497 iterations are spread across threads that already exist in the enclosing 498 parallel region. 499 500 The body region can only contain a single block which must contain a single 501 operation. This operation must be another compatible loop wrapper or an 502 `omp.loop_nest`. 503 504 ``` 505 omp.wsloop <clauses> { 506 omp.loop_nest (%i1, %i2) : index = (%c0, %c0) to (%c10, %c10) step (%c1, %c1) { 507 %a = load %arrA[%i1, %i2] : memref<?x?xf32> 508 %b = load %arrB[%i1, %i2] : memref<?x?xf32> 509 %sum = arith.addf %a, %b : f32 510 store %sum, %arrC[%i1, %i2] : memref<?x?xf32> 511 omp.yield 512 } 513 } 514 ``` 515 }] # clausesDescription; 516 517 let builders = [ 518 OpBuilder<(ins CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes)>, 519 OpBuilder<(ins CArg<"const WsloopOperands &">:$clauses)> 520 ]; 521 522 let assemblyFormat = clausesAssemblyFormat # [{ 523 custom<PrivateReductionRegion>($region, $private_vars, type($private_vars), 524 $private_syms, $reduction_mod, $reduction_vars, type($reduction_vars), $reduction_byref, 525 $reduction_syms) attr-dict 526 }]; 527 528 let hasVerifier = 1; 529 let hasRegionVerifier = 1; 530} 531 532//===----------------------------------------------------------------------===// 533// Simd construct [2.9.3.1] 534//===----------------------------------------------------------------------===// 535 536def SimdOp : OpenMP_Op<"simd", traits = [ 537 AttrSizedOperandSegments, DeclareOpInterfaceMethods<ComposableOpInterface>, 538 DeclareOpInterfaceMethods<LoopWrapperInterface>, NoTerminator, 539 RecursiveMemoryEffects, SingleBlock 540 ], clauses = [ 541 OpenMP_AlignedClause, OpenMP_IfClause, OpenMP_LinearClause, 542 OpenMP_NontemporalClause, OpenMP_OrderClause, OpenMP_PrivateClause, 543 OpenMP_ReductionClause, OpenMP_SafelenClause, OpenMP_SimdlenClause 544 ], singleRegion = true> { 545 let summary = "simd construct"; 546 let description = [{ 547 The simd construct can be applied to a loop to indicate that the loop can be 548 transformed into a SIMD loop (that is, multiple iterations of the loop can 549 be executed concurrently using SIMD instructions). 550 551 The body region can only contain a single block which must contain a single 552 operation. This operation must be another compatible loop wrapper or an 553 `omp.loop_nest`. 554 555 ``` 556 omp.simd <clauses> { 557 omp.loop_nest (%i1, %i2) : index = (%c0, %c0) to (%c10, %c10) step (%c1, %c1) { 558 %a = load %arrA[%i1, %i2] : memref<?x?xf32> 559 %b = load %arrB[%i1, %i2] : memref<?x?xf32> 560 %sum = arith.addf %a, %b : f32 561 store %sum, %arrC[%i1, %i2] : memref<?x?xf32> 562 omp.yield 563 } 564 } 565 ``` 566 567 When an if clause is present and evaluates to false, the preferred number of 568 iterations to be executed concurrently is one, regardless of whether 569 a simdlen clause is specified. 570 }] # clausesDescription; 571 572 let builders = [ 573 OpBuilder<(ins CArg<"const SimdOperands &">:$clauses)> 574 ]; 575 576 let assemblyFormat = clausesAssemblyFormat # [{ 577 custom<PrivateReductionRegion>($region, $private_vars, type($private_vars), 578 $private_syms, $reduction_mod, $reduction_vars, type($reduction_vars), $reduction_byref, 579 $reduction_syms) attr-dict 580 }]; 581 582 let hasVerifier = 1; 583 let hasRegionVerifier = 1; 584} 585 586 587def YieldOp : OpenMP_Op<"yield", 588 [Pure, ReturnLike, Terminator, 589 ParentOneOf<["AtomicUpdateOp", "DeclareReductionOp", "LoopNestOp", 590 "PrivateClauseOp"]>]> { 591 let summary = "loop yield and termination operation"; 592 let description = [{ 593 "omp.yield" yields SSA values from the OpenMP dialect op region and 594 terminates the region. The semantics of how the values are yielded is 595 defined by the parent operation. 596 }]; 597 598 let arguments = (ins Variadic<AnyType>:$results); 599 600 let builders = [ 601 OpBuilder<(ins), [{ build($_builder, $_state, {}); }]> 602 ]; 603 604 let assemblyFormat = "( `(` $results^ `:` type($results) `)` )? attr-dict"; 605} 606 607//===----------------------------------------------------------------------===// 608// Distribute construct [2.9.4.1] 609//===----------------------------------------------------------------------===// 610def DistributeOp : OpenMP_Op<"distribute", traits = [ 611 AttrSizedOperandSegments, DeclareOpInterfaceMethods<ComposableOpInterface>, 612 DeclareOpInterfaceMethods<LoopWrapperInterface>, NoTerminator, 613 RecursiveMemoryEffects, SingleBlock 614 ], clauses = [ 615 OpenMP_AllocateClause, OpenMP_DistScheduleClause, OpenMP_OrderClause, 616 OpenMP_PrivateClause 617 ], singleRegion = true> { 618 let summary = "distribute construct"; 619 let description = [{ 620 The distribute construct specifies that the iterations of one or more loops 621 (optionally specified using collapse clause) will be executed by the 622 initial teams in the context of their implicit tasks. The loops that the 623 distribute op is associated with starts with the outermost loop enclosed by 624 the distribute op region and going down the loop nest toward the innermost 625 loop. The iterations are distributed across the initial threads of all 626 initial teams that execute the teams region to which the distribute region 627 binds. 628 629 The distribute loop construct specifies that the iterations of the loop(s) 630 will be executed in parallel by threads in the current context. These 631 iterations are spread across threads that already exist in the enclosing 632 region. 633 634 The body region can only contain a single block which must contain a single 635 operation. This operation must be another compatible loop wrapper or an 636 `omp.loop_nest`. 637 638 ```mlir 639 omp.distribute <clauses> { 640 omp.loop_nest (%i1, %i2) : index = (%c0, %c0) to (%c10, %c10) step (%c1, %c1) { 641 %a = load %arrA[%i1, %i2] : memref<?x?xf32> 642 %b = load %arrB[%i1, %i2] : memref<?x?xf32> 643 %sum = arith.addf %a, %b : f32 644 store %sum, %arrC[%i1, %i2] : memref<?x?xf32> 645 omp.yield 646 } 647 } 648 ``` 649 }] # clausesDescription; 650 651 let builders = [ 652 OpBuilder<(ins CArg<"const DistributeOperands &">:$clauses)> 653 ]; 654 655 let assemblyFormat = clausesAssemblyFormat # [{ 656 custom<PrivateRegion>($region, $private_vars, type($private_vars), 657 $private_syms) attr-dict 658 }]; 659 660 let hasVerifier = 1; 661 let hasRegionVerifier = 1; 662} 663 664//===----------------------------------------------------------------------===// 665// 2.10.1 task Construct 666//===----------------------------------------------------------------------===// 667 668def TaskOp 669 : OpenMP_Op<"task", 670 traits = [AttrSizedOperandSegments, AutomaticAllocationScope, 671 OutlineableOpenMPOpInterface], 672 clauses = [ 673 // TODO: Complete clause list (affinity, detach). 674 OpenMP_AllocateClause, OpenMP_DependClause, 675 OpenMP_FinalClause, OpenMP_IfClause, 676 OpenMP_InReductionClause, OpenMP_MergeableClause, 677 OpenMP_PriorityClause, OpenMP_PrivateClause, 678 OpenMP_UntiedClause, OpenMP_DetachClause], 679 singleRegion = true> { 680 let summary = "task construct"; 681 let description = [{ 682 The task construct defines an explicit task. 683 684 For definitions of "undeferred task", "included task", "final task" and 685 "mergeable task", please check OpenMP Specification. 686 687 When an `if` clause is present on a task construct, and the value of 688 `if_expr` evaluates to `false`, an "undeferred task" is generated, and the 689 encountering thread must suspend the current task region, for which 690 execution cannot be resumed until execution of the structured block that is 691 associated with the generated task is completed. 692 693 The `in_reduction` clause specifies that this particular task (among all the 694 tasks in current taskgroup, if any) participates in a reduction. 695 `in_reduction_byref` indicates whether each reduction variable should 696 be passed by value or by reference. 697 }] # clausesDescription; 698 699 let builders = [ 700 OpBuilder<(ins CArg<"const TaskOperands &">:$clauses)> 701 ]; 702 703 let assemblyFormat = clausesAssemblyFormat # [{ 704 custom<InReductionPrivateRegion>( 705 $region, $in_reduction_vars, type($in_reduction_vars), 706 $in_reduction_byref, $in_reduction_syms, $private_vars, 707 type($private_vars), $private_syms) attr-dict 708 }]; 709 710 let hasVerifier = 1; 711} 712 713def TaskloopOp : OpenMP_Op<"taskloop", traits = [ 714 AttrSizedOperandSegments, AutomaticAllocationScope, 715 DeclareOpInterfaceMethods<ComposableOpInterface>, 716 DeclareOpInterfaceMethods<LoopWrapperInterface>, NoTerminator, 717 RecursiveMemoryEffects, SingleBlock 718 ], clauses = [ 719 OpenMP_AllocateClause, OpenMP_FinalClause, OpenMP_GrainsizeClause, 720 OpenMP_IfClause, OpenMP_InReductionClauseSkip<extraClassDeclaration = true>, 721 OpenMP_MergeableClause, OpenMP_NogroupClause, OpenMP_NumTasksClause, 722 OpenMP_PriorityClause, OpenMP_PrivateClause, 723 OpenMP_ReductionClauseSkip<extraClassDeclaration = true>, 724 OpenMP_UntiedClause 725 ], singleRegion = true> { 726 let summary = "taskloop construct"; 727 let description = [{ 728 The taskloop construct specifies that the iterations of one or more 729 associated loops will be executed in parallel using explicit tasks. The 730 iterations are distributed across tasks generated by the construct and 731 scheduled to be executed. 732 733 The body region can only contain a single block which must contain a single 734 operation. This operation must be another compatible loop wrapper or an 735 `omp.loop_nest`. 736 737 ``` 738 omp.taskloop <clauses> { 739 omp.loop_nest (%i1, %i2) : index = (%c0, %c0) to (%c10, %c10) step (%c1, %c1) { 740 %a = load %arrA[%i1, %i2] : memref<?x?xf32> 741 %b = load %arrB[%i1, %i2] : memref<?x?xf32> 742 %sum = arith.addf %a, %b : f32 743 store %sum, %arrC[%i1, %i2] : memref<?x?xf32> 744 omp.yield 745 } 746 } 747 ``` 748 749 For definitions of "undeferred task", "included task", "final task" and 750 "mergeable task", please check OpenMP Specification. 751 752 When an `if` clause is present on a taskloop construct, and if the `if` 753 clause expression evaluates to `false`, undeferred tasks are generated. The 754 use of a variable in an `if` clause expression of a taskloop construct 755 causes an implicit reference to the variable in all enclosing constructs. 756 }] # clausesDescription # [{ 757 If an `in_reduction` clause is present on the taskloop construct, the 758 behavior is as if each generated task was defined by a task construct on 759 which an `in_reduction` clause with the same reduction operator and list 760 items is present. Thus, the generated tasks are participants of a reduction 761 previously defined by a reduction scoping clause. In this case, accumulator 762 variables are specified in `in_reduction_vars`, symbols referring to 763 reduction declarations in `in_reduction_syms` and `in_reduction_byref` 764 indicate for each reduction variable whether it should be passed by value or 765 by reference. 766 767 If a `reduction` clause is present on the taskloop construct, the behavior 768 is as if a `task_reduction` clause with the same reduction operator and list 769 items was applied to the implicit taskgroup construct enclosing the taskloop 770 construct. The taskloop construct executes as if each generated task was 771 defined by a task construct on which an `in_reduction` clause with the same 772 reduction operator and list items is present. Thus, the generated tasks are 773 participants of the reduction defined by the `task_reduction` clause that 774 was applied to the implicit taskgroup construct. 775 }]; 776 777 let builders = [ 778 OpBuilder<(ins CArg<"const TaskloopOperands &">:$clauses)> 779 ]; 780 781 let assemblyFormat = clausesAssemblyFormat # [{ 782 custom<InReductionPrivateReductionRegion>( 783 $region, $in_reduction_vars, type($in_reduction_vars), 784 $in_reduction_byref, $in_reduction_syms, $private_vars, 785 type($private_vars), $private_syms, $reduction_mod, $reduction_vars, 786 type($reduction_vars), $reduction_byref, $reduction_syms) attr-dict 787 }]; 788 789 let extraClassDeclaration = [{ 790 /// Returns the reduction variables 791 SmallVector<Value> getAllReductionVars(); 792 793 // Define BlockArgOpenMPOpInterface methods here because they are not 794 // inherited from the respective clauses. 795 unsigned numInReductionBlockArgs() { return getInReductionVars().size(); } 796 unsigned numReductionBlockArgs() { return getReductionVars().size(); } 797 798 void getEffects(SmallVectorImpl<MemoryEffects::EffectInstance> &effects); 799 }] # clausesExtraClassDeclaration; 800 801 let hasVerifier = 1; 802 let hasRegionVerifier = 1; 803} 804 805def TaskgroupOp : OpenMP_Op<"taskgroup", traits = [ 806 AttrSizedOperandSegments, AutomaticAllocationScope 807 ], clauses = [ 808 OpenMP_AllocateClause, OpenMP_TaskReductionClause 809 ], singleRegion = true> { 810 let summary = "taskgroup construct"; 811 let description = [{ 812 The taskgroup construct specifies a wait on completion of child tasks of the 813 current task and their descendent tasks. 814 815 When a thread encounters a taskgroup construct, it starts executing the 816 region. All child tasks generated in the taskgroup region and all of their 817 descendants that bind to the same parallel region as the taskgroup region 818 are part of the taskgroup set associated with the taskgroup region. There is 819 an implicit task scheduling point at the end of the taskgroup region. The 820 current task is suspended at the task scheduling point until all tasks in 821 the taskgroup set complete execution. 822 }] # clausesDescription; 823 824 let builders = [ 825 OpBuilder<(ins CArg<"const TaskgroupOperands &">:$clauses)> 826 ]; 827 828 let assemblyFormat = clausesAssemblyFormat # [{ 829 custom<TaskReductionRegion>( 830 $region, $task_reduction_vars, type($task_reduction_vars), 831 $task_reduction_byref, $task_reduction_syms) attr-dict 832 }]; 833 834 let hasVerifier = 1; 835} 836 837//===----------------------------------------------------------------------===// 838// 2.10.4 taskyield Construct 839//===----------------------------------------------------------------------===// 840 841def TaskyieldOp : OpenMP_Op<"taskyield"> { 842 let summary = "taskyield construct"; 843 let description = [{ 844 The taskyield construct specifies that the current task can be suspended 845 in favor of execution of a different task. 846 }]; 847 848 let assemblyFormat = "attr-dict"; 849} 850 851//===----------------------------------------------------------------------===// 852// 2.13.7 flush Construct 853//===----------------------------------------------------------------------===// 854def FlushOp : OpenMP_Op<"flush", clauses = [ 855 // TODO: Complete clause list (memory_order). 856 ]> { 857 let summary = "flush construct"; 858 let description = [{ 859 The flush construct executes the OpenMP flush operation. This operation 860 makes a thread's temporary view of memory consistent with memory and 861 enforces an order on the memory operations of the variables explicitly 862 specified or implied. 863 }] # clausesDescription; 864 865 let arguments = !con((ins Variadic<OpenMP_PointerLikeType>:$varList), 866 clausesArgs); 867 868 // Override inherited assembly format to include `varList`. 869 let assemblyFormat = "( `(` $varList^ `:` type($varList) `)` )? attr-dict"; 870 871 let extraClassDeclaration = [{ 872 /// The number of variable operands. 873 unsigned getNumVariableOperands() { 874 return getOperation()->getNumOperands(); 875 } 876 /// The i-th variable operand passed. 877 Value getVariableOperand(unsigned i) { 878 return getOperand(i); 879 } 880 }] # clausesExtraClassDeclaration; 881} 882 883//===----------------------------------------------------------------------===// 884// Map related constructs 885//===----------------------------------------------------------------------===// 886 887def MapBoundsOp : OpenMP_Op<"map.bounds", 888 [AttrSizedOperandSegments, NoMemoryEffect]> { 889 let summary = "Represents normalized bounds information for map clauses."; 890 891 let description = [{ 892 This operation is a variation on the OpenACC dialects DataBoundsOp. Within 893 the OpenMP dialect it stores the bounds/range of data to be mapped to a 894 device specified by map clauses on target directives. Within 895 the OpenMP dialect, the MapBoundsOp is associated with MapInfoOp, 896 helping to store bounds information for the mapped variable. 897 898 It is used to support OpenMP array sectioning, Fortran pointer and 899 allocatable mapping and pointer/allocatable member of derived types. 900 In all cases the MapBoundsOp holds information on the section of 901 data to be mapped. Such as the upper bound and lower bound of the 902 section of data to be mapped. This information is currently 903 utilised by the LLVM-IR lowering to help generate instructions to 904 copy data to and from the device when processing target operations. 905 906 The example below copys a section of a 10-element array; all except the 907 first element, utilising OpenMP array sectioning syntax where array 908 subscripts are provided to specify the bounds to be mapped to device. 909 To simplify the examples, the constants are used directly, in reality 910 they will be MLIR SSA values. 911 912 C++: 913 ``` 914 int array[10]; 915 #pragma target map(array[1:9]) 916 ``` 917 => 918 ```mlir 919 omp.map.bounds lower_bound(1) upper_bound(9) extent(9) start_idx(0) 920 ``` 921 922 Fortran: 923 ``` 924 integer :: array(1:10) 925 !$target map(array(2:10)) 926 ``` 927 => 928 ```mlir 929 omp.map.bounds lower_bound(1) upper_bound(9) extent(9) start_idx(1) 930 ``` 931 932 For Fortran pointers and allocatables (as well as those that are 933 members of derived types) the bounds information is provided by 934 the Fortran compiler and runtime through descriptor information. 935 936 A basic pointer example can be found below (constants again 937 provided for simplicity, where in reality SSA values will be 938 used, in this case that point to data yielded by Fortran's 939 descriptors): 940 941 Fortran: 942 ``` 943 integer, pointer :: ptr(:) 944 allocate(ptr(10)) 945 !$target map(ptr) 946 ``` 947 => 948 ```mlir 949 omp.map.bounds lower_bound(0) upper_bound(9) extent(10) start_idx(1) 950 ``` 951 952 This operation records the bounds information in a normalized fashion 953 (zero-based). This works well with the `PointerLikeType` 954 requirement in data clauses - since a `lower_bound` of 0 means looking 955 at data at the zero offset from pointer. 956 957 This operation must have an `upper_bound` or `extent` (or both are allowed - 958 but not checked for consistency). When the source language's arrays are 959 not zero-based, the `start_idx` must specify the zero-position index. 960 }]; 961 962 let arguments = (ins Optional<IntLikeType>:$lower_bound, 963 Optional<IntLikeType>:$upper_bound, 964 Optional<IntLikeType>:$extent, 965 Optional<IntLikeType>:$stride, 966 DefaultValuedAttr<BoolAttr, "false">:$stride_in_bytes, 967 Optional<IntLikeType>:$start_idx); 968 let results = (outs OpenMP_MapBoundsType:$result); 969 970 let assemblyFormat = [{ 971 oilist( 972 `lower_bound` `(` $lower_bound `:` type($lower_bound) `)` 973 | `upper_bound` `(` $upper_bound `:` type($upper_bound) `)` 974 | `extent` `(` $extent `:` type($extent) `)` 975 | `stride` `(` $stride `:` type($stride) `)` 976 | `start_idx` `(` $start_idx `:` type($start_idx) `)` 977 ) attr-dict 978 }]; 979 980 let extraClassDeclaration = [{ 981 /// The number of variable operands. 982 unsigned getNumVariableOperands() { 983 return getNumOperands(); 984 } 985 986 /// The i-th variable operand passed. 987 Value getVariableOperand(unsigned i) { 988 return getOperands()[i]; 989 } 990 }]; 991 992 let hasVerifier = 1; 993} 994 995def MapInfoOp : OpenMP_Op<"map.info", [AttrSizedOperandSegments]> { 996 let arguments = (ins OpenMP_PointerLikeType:$var_ptr, 997 TypeAttr:$var_type, 998 Optional<OpenMP_PointerLikeType>:$var_ptr_ptr, 999 Variadic<OpenMP_PointerLikeType>:$members, 1000 OptionalAttr<IndexListArrayAttr>:$members_index, 1001 Variadic<OpenMP_MapBoundsType>:$bounds, /* rank-0 to rank-{n-1} */ 1002 OptionalAttr<UI64Attr>:$map_type, 1003 OptionalAttr<VariableCaptureKindAttr>:$map_capture_type, 1004 OptionalAttr<StrAttr>:$name, 1005 DefaultValuedAttr<BoolAttr, "false">:$partial_map); 1006 let results = (outs OpenMP_PointerLikeType:$omp_ptr); 1007 1008 let description = [{ 1009 The MapInfoOp captures information relating to individual OpenMP map clauses 1010 that are applied to certain OpenMP directives such as Target and Target Data. 1011 1012 For example, the map type modifier; such as from, tofrom and to, the variable 1013 being captured or the bounds of an array section being mapped. 1014 1015 It can be used to capture both implicit and explicit map information, where 1016 explicit is an argument directly specified to an OpenMP map clause or implicit 1017 where a variable is utilised in a target region but is defined externally to 1018 the target region. 1019 1020 This map information is later used to aid the lowering of the target operations 1021 they are attached to providing argument input and output context for kernels 1022 generated or the target data mapping environment. 1023 1024 Example (Fortran): 1025 1026 ``` 1027 integer :: index 1028 !$target map(to: index) 1029 ``` 1030 => 1031 ```mlir 1032 omp.map.info var_ptr(%index_ssa) map_type(to) map_capture_type(ByRef) 1033 name(index) 1034 ``` 1035 1036 Description of arguments: 1037 - `var_ptr`: The address of variable to copy. 1038 - `var_type`: The type of the variable to copy. 1039 - `var_ptr_ptr`: Used when the variable copied is a member of a class, structure 1040 or derived type and refers to the originating struct. 1041 - `members`: Used to indicate mapped child members for the current MapInfoOp, 1042 represented as other MapInfoOp's, utilised in cases where a parent structure 1043 type and members of the structure type are being mapped at the same time. 1044 For example: map(to: parent, parent->member, parent->member2[:10]) 1045 - `members_index`: Used to indicate the ordering of members within the containing 1046 parent (generally a record type such as a structure, class or derived type), 1047 e.g. struct {int x, float y, double z}, x would be 0, y would be 1, and z 1048 would be 2. This aids the mapping. 1049 - `bounds`: Used when copying slices of array's, pointers or pointer members of 1050 objects (e.g. derived types or classes), indicates the bounds to be copied 1051 of the variable. When it's an array slice it is in rank order where rank 0 1052 is the inner-most dimension. 1053 - 'map_type': OpenMP map type for this map capture, for example: from, to and 1054 always. It's a bitfield composed of the OpenMP runtime flags stored in 1055 OpenMPOffloadMappingFlags. 1056 - 'map_capture_type': Capture type for the variable e.g. this, byref, byvalue, byvla 1057 this can affect how the variable is lowered. 1058 - `name`: Holds the name of variable as specified in user clause (including bounds). 1059 - `partial_map`: The record type being mapped will not be mapped in its entirety, 1060 it may be used however, in a mapping to bind it's mapped components together. 1061 }]; 1062 1063 let assemblyFormat = [{ 1064 `var_ptr` `(` $var_ptr `:` type($var_ptr) `,` $var_type `)` 1065 oilist( 1066 `var_ptr_ptr` `(` $var_ptr_ptr `:` type($var_ptr_ptr) `)` 1067 | `map_clauses` `(` custom<MapClause>($map_type) `)` 1068 | `capture` `(` custom<CaptureType>($map_capture_type) `)` 1069 | `members` `(` $members `:` custom<MembersIndex>($members_index) `:` type($members) `)` 1070 | `bounds` `(` $bounds `)` 1071 ) `->` type($omp_ptr) attr-dict 1072 }]; 1073 1074 let extraClassDeclaration = [{ 1075 /// The number of variable operands. 1076 unsigned getNumVariableOperands() { 1077 return getNumOperands(); 1078 } 1079 1080 /// The i-th variable operand passed. 1081 Value getVariableOperand(unsigned i) { 1082 return getOperands()[i]; 1083 } 1084 }]; 1085} 1086 1087//===---------------------------------------------------------------------===// 1088// 2.14.2 target data Construct 1089//===---------------------------------------------------------------------===// 1090 1091def TargetDataOp: OpenMP_Op<"target_data", traits = [ 1092 AttrSizedOperandSegments 1093 ], clauses = [ 1094 OpenMP_DeviceClause, OpenMP_IfClause, OpenMP_MapClause, 1095 OpenMP_UseDeviceAddrClause, OpenMP_UseDevicePtrClause 1096 ], singleRegion = true> { 1097 let summary = "target data construct"; 1098 let description = [{ 1099 Map variables to a device data environment for the extent of the region. 1100 1101 The omp target data directive maps variables to a device data 1102 environment, and defines the lexical scope of the data environment 1103 that is created. The omp target data directive can reduce data copies 1104 to and from the offloading device when multiple target regions are using 1105 the same data. 1106 1107 The optional `if_expr` parameter specifies a boolean result of a conditional 1108 check. If this value is 1 or is not provided then the target region runs on 1109 a device, if it is 0 then the target region is executed on the host device. 1110 }] # clausesDescription; 1111 1112 let builders = [ 1113 OpBuilder<(ins CArg<"const TargetDataOperands &">:$clauses)> 1114 ]; 1115 1116 let assemblyFormat = clausesAssemblyFormat # [{ 1117 custom<UseDeviceAddrUseDevicePtrRegion>( 1118 $region, $use_device_addr_vars, type($use_device_addr_vars), 1119 $use_device_ptr_vars, type($use_device_ptr_vars)) attr-dict 1120 }]; 1121 1122 let hasVerifier = 1; 1123} 1124 1125//===---------------------------------------------------------------------===// 1126// 2.14.3 target enter data Construct 1127//===---------------------------------------------------------------------===// 1128 1129def TargetEnterDataOp: OpenMP_Op<"target_enter_data", traits = [ 1130 AttrSizedOperandSegments 1131 ], clauses = [ 1132 OpenMP_DependClause, OpenMP_DeviceClause, OpenMP_IfClause, OpenMP_MapClause, 1133 OpenMP_NowaitClause 1134 ]> { 1135 let summary = "target enter data construct"; 1136 let description = [{ 1137 The target enter data directive specifies that variables are mapped to 1138 a device data environment. The target enter data directive is a 1139 stand-alone directive. 1140 1141 The optional `if_expr` parameter specifies a boolean result of a conditional 1142 check. If this value is 1 or is not provided then the target region runs on 1143 a device, if it is 0 then the target region is executed on the host device. 1144 }] # clausesDescription; 1145 1146 let builders = [ 1147 OpBuilder<(ins CArg<"const TargetEnterExitUpdateDataOperands &">:$clauses)> 1148 ]; 1149 1150 let hasVerifier = 1; 1151} 1152 1153//===---------------------------------------------------------------------===// 1154// 2.14.4 target exit data Construct 1155//===---------------------------------------------------------------------===// 1156 1157def TargetExitDataOp: OpenMP_Op<"target_exit_data", traits = [ 1158 AttrSizedOperandSegments 1159 ], clauses = [ 1160 OpenMP_DependClause, OpenMP_DeviceClause, OpenMP_IfClause, OpenMP_MapClause, 1161 OpenMP_NowaitClause 1162 ]> { 1163 let summary = "target exit data construct"; 1164 let description = [{ 1165 The target exit data directive specifies that variables are mapped to a 1166 device data environment. The target exit data directive is 1167 a stand-alone directive. 1168 1169 The optional `if_expr` parameter specifies a boolean result of a conditional 1170 check. If this value is 1 or is not provided then the target region runs on 1171 a device, if it is 0 then the target region is executed on the host device. 1172 }] # clausesDescription; 1173 1174 let builders = [ 1175 OpBuilder<(ins CArg<"const TargetEnterExitUpdateDataOperands &">:$clauses)> 1176 ]; 1177 1178 let hasVerifier = 1; 1179} 1180 1181//===---------------------------------------------------------------------===// 1182// 2.14.6 target update Construct 1183//===---------------------------------------------------------------------===// 1184 1185def TargetUpdateOp: OpenMP_Op<"target_update", traits = [ 1186 AttrSizedOperandSegments 1187 ], clauses = [ 1188 OpenMP_DependClause, OpenMP_DeviceClause, OpenMP_IfClause, OpenMP_MapClause, 1189 OpenMP_NowaitClause 1190 ]> { 1191 let summary = "target update construct"; 1192 let description = [{ 1193 The target update directive makes the corresponding list items in the device 1194 data environment consistent with their original list items, according to the 1195 specified motion clauses. The target update construct is a stand-alone 1196 directive. 1197 1198 The optional `if_expr` parameter specifies a boolean result of a conditional 1199 check. If this value is 1 or is not provided then the target region runs on 1200 a device, if it is 0 then the target region is executed on the host device. 1201 1202 We use `MapInfoOp` to model the motion clauses and their modifiers. Even 1203 though the spec differentiates between map-types & map-type-modifiers vs. 1204 motion-clauses & motion-modifiers, the motion clauses and their modifiers 1205 are a subset of map types and their modifiers. The subset relation is 1206 handled in during verification to make sure the restrictions for target 1207 update are respected. 1208 }] # clausesDescription; 1209 1210 let builders = [ 1211 OpBuilder<(ins CArg<"const TargetEnterExitUpdateDataOperands &">:$clauses)> 1212 ]; 1213 1214 let hasVerifier = 1; 1215} 1216 1217//===----------------------------------------------------------------------===// 1218// 2.14.5 target construct 1219//===----------------------------------------------------------------------===// 1220 1221def TargetOp : OpenMP_Op<"target", traits = [ 1222 AttrSizedOperandSegments, BlockArgOpenMPOpInterface, IsolatedFromAbove, 1223 OutlineableOpenMPOpInterface 1224 ], clauses = [ 1225 // TODO: Complete clause list (defaultmap, uses_allocators). 1226 OpenMP_AllocateClause, OpenMP_BareClause, OpenMP_DependClause, 1227 OpenMP_DeviceClause, OpenMP_HasDeviceAddrClause, OpenMP_HostEvalClause, 1228 OpenMP_IfClause, OpenMP_InReductionClause, OpenMP_IsDevicePtrClause, 1229 OpenMP_MapClauseSkip<assemblyFormat = true>, OpenMP_NowaitClause, 1230 OpenMP_PrivateClause, OpenMP_ThreadLimitClause 1231 ], singleRegion = true> { 1232 let summary = "target construct"; 1233 let description = [{ 1234 The target construct includes a region of code which is to be executed 1235 on a device. 1236 1237 The optional `if_expr` parameter specifies a boolean result of a conditional 1238 check. If this value is 1 or is not provided then the target region runs on 1239 a device, if it is 0 then the target region is executed on the host device. 1240 1241 The `private_maps` attribute connects `private` operands to their corresponding 1242 `map` operands. For `private` operands that require a map, the value of the 1243 corresponding element in the attribute is the index of the `map` operand 1244 (relative to other `map` operands not the whole operands of the operation). For 1245 `private` opernads that do not require a map, this value is -1 (which is omitted 1246 from the assembly foramt printing). 1247 }] # clausesDescription; 1248 1249 let arguments = !con(clausesArgs, 1250 (ins OptionalAttr<DenseI64ArrayAttr>:$private_maps)); 1251 1252 let builders = [ 1253 OpBuilder<(ins CArg<"const TargetOperands &">:$clauses)> 1254 ]; 1255 1256 let extraClassDeclaration = [{ 1257 unsigned numMapBlockArgs() { return getMapVars().size(); } 1258 1259 mlir::Value getMappedValueForPrivateVar(unsigned privVarIdx) { 1260 std::optional<DenseI64ArrayAttr> privateMapIdices = getPrivateMapsAttr(); 1261 1262 if (!privateMapIdices.has_value()) 1263 return {}; 1264 1265 int64_t mapInfoOpIdx = (*privateMapIdices)[privVarIdx]; 1266 1267 if (mapInfoOpIdx == -1) 1268 return {}; 1269 1270 return getMapVars()[mapInfoOpIdx]; 1271 } 1272 1273 /// Returns the innermost OpenMP dialect operation captured by this target 1274 /// construct. For an operation to be detected as captured, it must be 1275 /// inside a (possibly multi-level) nest of OpenMP dialect operation's 1276 /// regions where none of these levels contain other operations considered 1277 /// not-allowed for these purposes (i.e. only terminator operations are 1278 /// allowed from the OpenMP dialect, and other dialect's operations are 1279 /// allowed as long as they don't have a memory write effect). 1280 /// 1281 /// If there are omp.loop_nest operations in the sequence of nested 1282 /// operations, the top level one will be the one captured. 1283 Operation *getInnermostCapturedOmpOp(); 1284 1285 /// Infers the kernel type (Generic, SPMD or Generic-SPMD) based on the 1286 /// contents of the target region. 1287 llvm::omp::OMPTgtExecModeFlags getKernelExecFlags(); 1288 }] # clausesExtraClassDeclaration; 1289 1290 let assemblyFormat = clausesAssemblyFormat # [{ 1291 custom<HostEvalInReductionMapPrivateRegion>( 1292 $region, $host_eval_vars, type($host_eval_vars), $in_reduction_vars, 1293 type($in_reduction_vars), $in_reduction_byref, $in_reduction_syms, 1294 $map_vars, type($map_vars), $private_vars, type($private_vars), 1295 $private_syms, $private_maps) attr-dict 1296 }]; 1297 1298 let hasVerifier = 1; 1299 let hasRegionVerifier = 1; 1300} 1301 1302 1303//===----------------------------------------------------------------------===// 1304// 2.16 master Construct 1305//===----------------------------------------------------------------------===// 1306def MasterOp : OpenMP_Op<"master", singleRegion = true> { 1307 let summary = "master construct"; 1308 let description = [{ 1309 The master construct specifies a structured block that is executed by 1310 the master thread of the team. 1311 }]; 1312 1313 let assemblyFormat = "$region attr-dict"; 1314} 1315 1316//===----------------------------------------------------------------------===// 1317// 2.17.1 critical Construct 1318//===----------------------------------------------------------------------===// 1319def CriticalDeclareOp : OpenMP_Op<"critical.declare", clauses = [ 1320 OpenMP_CriticalNameClause, OpenMP_HintClause 1321 ]> { 1322 let summary = "declares a named critical section."; 1323 let description = [{ 1324 Declares a named critical section. 1325 }] # clausesDescription; 1326 1327 let builders = [ 1328 OpBuilder<(ins CArg<"const CriticalDeclareOperands &">:$clauses)> 1329 ]; 1330 1331 let hasVerifier = 1; 1332} 1333 1334 1335def CriticalOp : OpenMP_Op<"critical", [ 1336 DeclareOpInterfaceMethods<SymbolUserOpInterface> 1337 ], singleRegion = 1> { 1338 let summary = "critical construct"; 1339 let description = [{ 1340 The critical construct imposes a restriction on the associated structured 1341 block (region) to be executed by only a single thread at a time. 1342 1343 The optional `name` argument of critical constructs is used to identify 1344 them. Unnamed critical constructs behave as though an identical name was 1345 specified. 1346 }]; 1347 1348 let arguments = (ins OptionalAttr<FlatSymbolRefAttr>:$name); 1349 1350 let assemblyFormat = [{ 1351 (`(` $name^ `)`)? $region attr-dict 1352 }]; 1353} 1354 1355//===----------------------------------------------------------------------===// 1356// 2.17.2 barrier Construct 1357//===----------------------------------------------------------------------===// 1358 1359def BarrierOp : OpenMP_Op<"barrier"> { 1360 let summary = "barrier construct"; 1361 let description = [{ 1362 The barrier construct specifies an explicit barrier at the point at which 1363 the construct appears. 1364 }]; 1365 1366 let assemblyFormat = "attr-dict"; 1367} 1368 1369//===----------------------------------------------------------------------===// 1370// [5.1] 2.19.9 ordered Construct 1371//===----------------------------------------------------------------------===// 1372 1373def OrderedOp : OpenMP_Op<"ordered", clauses = [OpenMP_DoacrossClause]> { 1374 let summary = "ordered construct without region"; 1375 let description = [{ 1376 The ordered construct without region is a stand-alone directive that 1377 specifies cross-iteration dependencies in a doacross loop nest. 1378 }] # clausesDescription; 1379 1380 let builders = [ 1381 OpBuilder<(ins CArg<"const OrderedOperands &">:$clauses)> 1382 ]; 1383 1384 let hasVerifier = 1; 1385} 1386 1387def OrderedRegionOp : OpenMP_Op<"ordered.region", clauses = [ 1388 OpenMP_ParallelizationLevelClause 1389 ], singleRegion = true> { 1390 let summary = "ordered construct with region"; 1391 let description = [{ 1392 The ordered construct with region specifies a structured block in a 1393 worksharing-loop, SIMD, or worksharing-loop SIMD region that is executed in 1394 the order of the loop iterations. 1395 }] # clausesDescription; 1396 1397 let builders = [ 1398 OpBuilder<(ins CArg<"const OrderedRegionOperands &">:$clauses)> 1399 ]; 1400 1401 let hasVerifier = 1; 1402} 1403 1404//===----------------------------------------------------------------------===// 1405// 2.17.5 taskwait Construct 1406//===----------------------------------------------------------------------===// 1407 1408def TaskwaitOp : OpenMP_Op<"taskwait", clauses = [ 1409 OpenMP_DependClause, OpenMP_NowaitClause 1410 ]> { 1411 let summary = "taskwait construct"; 1412 let description = [{ 1413 The taskwait construct specifies a wait on the completion of child tasks 1414 of the current task. 1415 }] # clausesDescription; 1416 1417 let builders = [ 1418 OpBuilder<(ins CArg<"const TaskwaitOperands &">:$clauses)> 1419 ]; 1420} 1421 1422//===----------------------------------------------------------------------===// 1423// 2.17.7 atomic construct 1424//===----------------------------------------------------------------------===// 1425 1426// In the OpenMP Specification, atomic construct has an `atomic-clause` which 1427// can take the values `read`, `write`, `update` and `capture`. These four 1428// kinds of atomic constructs are fundamentally independent and are handled 1429// separately while lowering. Having four separate operations (one for each 1430// value of the clause) here decomposes handling of this construct into a 1431// two-step process. 1432 1433def AtomicReadOp : OpenMP_Op<"atomic.read", traits = [ 1434 AtomicReadOpInterface 1435 ], clauses = [ 1436 OpenMP_HintClause, OpenMP_MemoryOrderClause 1437 ]> { 1438 let summary = "performs an atomic read"; 1439 let description = [{ 1440 This operation performs an atomic read. 1441 1442 The operand `x` is the address from where the value is atomically read. 1443 The operand `v` is the address where the value is stored after reading. 1444 }] # clausesDescription; 1445 1446 let arguments = !con((ins OpenMP_PointerLikeType:$x, 1447 OpenMP_PointerLikeType:$v, 1448 TypeAttr:$element_type), clausesArgs); 1449 1450 // Override clause-based assemblyFormat. 1451 let assemblyFormat = "$v `=` $x" # clausesReqAssemblyFormat # " oilist(" # 1452 clausesOptAssemblyFormat # 1453 ") `:` type($v) `,` type($x) `,` $element_type attr-dict"; 1454 1455 let extraClassDeclaration = [{ 1456 /// The number of variable operands. 1457 unsigned getNumVariableOperands() { 1458 assert(getX() && "expected 'x' operand"); 1459 assert(getV() && "expected 'v' operand"); 1460 return 2; 1461 } 1462 1463 /// The i-th variable operand passed. 1464 Value getVariableOperand(unsigned i) { 1465 assert(i < 2 && "invalid index position for an operand"); 1466 return i == 0 ? getX() : getV(); 1467 } 1468 }] # clausesExtraClassDeclaration; 1469 1470 let hasVerifier = 1; 1471} 1472 1473def AtomicWriteOp : OpenMP_Op<"atomic.write", traits = [ 1474 AtomicWriteOpInterface 1475 ], clauses = [ 1476 OpenMP_HintClause, OpenMP_MemoryOrderClause 1477 ]> { 1478 let summary = "performs an atomic write"; 1479 let description = [{ 1480 This operation performs an atomic write. 1481 1482 The operand `x` is the address to where the `expr` is atomically 1483 written w.r.t. multiple threads. The evaluation of `expr` need not be 1484 atomic w.r.t. the write to address. In general, the type(x) must 1485 dereference to type(expr). 1486 }] # clausesDescription; 1487 1488 let arguments = !con((ins OpenMP_PointerLikeType:$x, 1489 AnyType:$expr), clausesArgs); 1490 1491 // Override clause-based assemblyFormat. 1492 let assemblyFormat = "$x `=` $expr" # clausesReqAssemblyFormat # " oilist(" # 1493 clausesOptAssemblyFormat # ") `:` type($x) `,` type($expr) attr-dict"; 1494 1495 let extraClassDeclaration = [{ 1496 /// The number of variable operands. 1497 unsigned getNumVariableOperands() { 1498 assert(getX() && "expected address operand"); 1499 assert(getExpr() && "expected value operand"); 1500 return 2; 1501 } 1502 1503 /// The i-th variable operand passed. 1504 Value getVariableOperand(unsigned i) { 1505 assert(i < 2 && "invalid index position for an operand"); 1506 return i == 0 ? getX() : getExpr(); 1507 } 1508 }] # clausesExtraClassDeclaration; 1509 1510 let hasVerifier = 1; 1511} 1512 1513def AtomicUpdateOp : OpenMP_Op<"atomic.update", traits = [ 1514 AtomicUpdateOpInterface, RecursiveMemoryEffects, 1515 SingleBlockImplicitTerminator<"YieldOp"> 1516 ], clauses = [ 1517 OpenMP_HintClause, OpenMP_MemoryOrderClause 1518 ], singleRegion = 1> { 1519 let summary = "performs an atomic update"; 1520 let description = [{ 1521 This operation performs an atomic update. 1522 1523 The operand `x` is exactly the same as the operand `x` in the OpenMP 1524 Standard (OpenMP 5.0, section 2.17.7). It is the address of the variable 1525 that is being updated. `x` is atomically read/written. 1526 1527 The region describes how to update the value of `x`. It takes the value at 1528 `x` as an input and must yield the updated value. Only the update to `x` is 1529 atomic. Generally the region must have only one instruction, but can 1530 potentially have more than one instructions too. The update is sematically 1531 similar to a compare-exchange loop based atomic update. 1532 1533 The syntax of atomic update operation is different from atomic read and 1534 atomic write operations. This is because only the host dialect knows how to 1535 appropriately update a value. For example, while generating LLVM IR, if 1536 there are no special `atomicrmw` instructions for the operation-type 1537 combination in atomic update, a compare-exchange loop is generated, where 1538 the core update operation is directly translated like regular operations by 1539 the host dialect. The front-end must handle semantic checks for allowed 1540 operations. 1541 }] # clausesDescription; 1542 1543 let arguments = !con((ins Arg<OpenMP_PointerLikeType, 1544 "Address of variable to be updated", 1545 [MemRead, MemWrite]>:$x), clausesArgs); 1546 1547 // Override region definition. 1548 let regions = (region SizedRegion<1>:$region); 1549 1550 // Override clause-based assemblyFormat. 1551 let assemblyFormat = clausesAssemblyFormat # 1552 "$x `:` type($x) $region attr-dict"; 1553 1554 let extraClassDeclaration = [{ 1555 /// The number of variable operands. 1556 unsigned getNumVariableOperands() { 1557 assert(getX() && "expected 'x' operand"); 1558 return 1; 1559 } 1560 1561 /// The i-th variable operand passed. 1562 Value getVariableOperand(unsigned i) { 1563 assert(i == 0 && "invalid index position for an operand"); 1564 return getX(); 1565 } 1566 }] # clausesExtraClassDeclaration; 1567 1568 let hasVerifier = 1; 1569 let hasRegionVerifier = 1; 1570 let hasCanonicalizeMethod = 1; 1571} 1572 1573def AtomicCaptureOp : OpenMP_Op<"atomic.capture", traits = [ 1574 AtomicCaptureOpInterface, RecursiveMemoryEffects, 1575 SingleBlockImplicitTerminator<"TerminatorOp"> 1576 ], clauses = [ 1577 OpenMP_HintClause, OpenMP_MemoryOrderClause 1578 ], singleRegion = 1> { 1579 let summary = "performs an atomic capture"; 1580 let description = [{ 1581 This operation performs an atomic capture. 1582 1583 The region has the following allowed forms: 1584 ``` 1585 omp.atomic.capture { 1586 omp.atomic.update ... 1587 omp.atomic.read ... 1588 omp.terminator 1589 } 1590 1591 omp.atomic.capture { 1592 omp.atomic.read ... 1593 omp.atomic.update ... 1594 omp.terminator 1595 } 1596 1597 omp.atomic.capture { 1598 omp.atomic.read ... 1599 omp.atomic.write ... 1600 omp.terminator 1601 } 1602 ``` 1603 }] # clausesDescription; 1604 1605 // Override region definition. 1606 let regions = (region SizedRegion<1>:$region); 1607 1608 let extraClassDeclaration = [{ 1609 /// Returns the `atomic.read` operation inside the region, if any. 1610 /// Otherwise, it returns nullptr. 1611 AtomicReadOp getAtomicReadOp(); 1612 1613 /// Returns the `atomic.write` operation inside the region, if any. 1614 /// Otherwise, it returns nullptr. 1615 AtomicWriteOp getAtomicWriteOp(); 1616 1617 /// Returns the `atomic.update` operation inside the region, if any. 1618 /// Otherwise, it returns nullptr. 1619 AtomicUpdateOp getAtomicUpdateOp(); 1620 }] # clausesExtraClassDeclaration; 1621 1622 let hasRegionVerifier = 1; 1623 let hasVerifier = 1; 1624} 1625 1626//===----------------------------------------------------------------------===// 1627// [5.1] 2.21.2 threadprivate Directive 1628//===----------------------------------------------------------------------===// 1629 1630def ThreadprivateOp : OpenMP_Op<"threadprivate", 1631 [AllTypesMatch<["sym_addr", "tls_addr"]>]> { 1632 let summary = "threadprivate directive"; 1633 let description = [{ 1634 The threadprivate directive specifies that variables are replicated, with 1635 each thread having its own copy. 1636 1637 The current implementation uses the OpenMP runtime to provide thread-local 1638 storage (TLS). Using the TLS feature of the LLVM IR will be supported in 1639 future. 1640 1641 This operation takes in the address of a symbol that represents the original 1642 variable and returns the address of its TLS. All occurrences of 1643 threadprivate variables in a parallel region should use the TLS returned by 1644 this operation. 1645 1646 The `sym_addr` refers to the address of the symbol, which is a pointer to 1647 the original variable. 1648 }]; 1649 1650 let arguments = (ins OpenMP_PointerLikeType:$sym_addr); 1651 let results = (outs OpenMP_PointerLikeType:$tls_addr); 1652 let assemblyFormat = [{ 1653 $sym_addr `:` type($sym_addr) `->` type($tls_addr) attr-dict 1654 }]; 1655 let extraClassDeclaration = [{ 1656 /// The number of variable operands. 1657 unsigned getNumVariableOperands() { 1658 assert(getSymAddr() && "expected one variable operand"); 1659 return 1; 1660 } 1661 1662 /// The i-th variable operand passed. 1663 Value getVariableOperand(unsigned i) { 1664 assert(i == 0 && "invalid index position for an operand"); 1665 return getSymAddr(); 1666 } 1667 }]; 1668} 1669 1670//===----------------------------------------------------------------------===// 1671// 2.18.1 Cancel Construct 1672//===----------------------------------------------------------------------===// 1673def CancelOp : OpenMP_Op<"cancel", clauses = [ 1674 OpenMP_CancelDirectiveNameClause, OpenMP_IfClause 1675 ]> { 1676 let summary = "cancel directive"; 1677 let description = [{ 1678 The cancel construct activates cancellation of the innermost enclosing 1679 region of the type specified. 1680 }] # clausesDescription; 1681 1682 let builders = [ 1683 OpBuilder<(ins CArg<"const CancelOperands &">:$clauses)> 1684 ]; 1685 1686 let hasVerifier = 1; 1687} 1688 1689//===----------------------------------------------------------------------===// 1690// 2.18.2 Cancellation Point Construct 1691//===----------------------------------------------------------------------===// 1692def CancellationPointOp : OpenMP_Op<"cancellation_point", clauses = [ 1693 OpenMP_CancelDirectiveNameClause 1694 ]> { 1695 let summary = "cancellation point directive"; 1696 let description = [{ 1697 The cancellation point construct introduces a user-defined cancellation 1698 point at which implicit or explicit tasks check if cancellation of the 1699 innermost enclosing region of the type specified has been activated. 1700 }] # clausesDescription; 1701 1702 let builders = [ 1703 OpBuilder<(ins CArg<"const CancellationPointOperands &">:$clauses)> 1704 ]; 1705 1706 let hasVerifier = 1; 1707} 1708 1709def ScanOp : OpenMP_Op<"scan", [ 1710 AttrSizedOperandSegments, MemoryEffects<[MemWrite]> 1711 ], clauses = [ 1712 OpenMP_InclusiveClause, OpenMP_ExclusiveClause]> { 1713 let summary = "scan directive"; 1714 let description = [{ 1715 The scan directive allows to specify scan reductions. It should be 1716 enclosed within a parent directive along with which a reduction clause 1717 with `inscan` modifier must be specified. The scan directive allows to 1718 split code blocks into input phase and scan phase in the region 1719 enclosed by the parent. 1720 }] # clausesDescription; 1721 1722 let builders = [ 1723 OpBuilder<(ins CArg<"const ScanOperands &">:$clauses)> 1724 ]; 1725 1726 let hasVerifier = 1; 1727} 1728 1729//===----------------------------------------------------------------------===// 1730// 2.19.5.7 declare reduction Directive 1731//===----------------------------------------------------------------------===// 1732 1733def DeclareReductionOp : OpenMP_Op<"declare_reduction", [IsolatedFromAbove, 1734 RecipeInterface, 1735 Symbol]> { 1736 let summary = "declares a reduction kind"; 1737 let description = [{ 1738 Declares an OpenMP reduction kind. This requires two mandatory and three 1739 optional regions. 1740 1741 1. The optional alloc region specifies how to allocate the thread-local 1742 reduction value. This region should not contain control flow and all 1743 IR should be suitable for inlining straight into an entry block. In 1744 the common case this is expected to contain only allocas. It is 1745 expected to `omp.yield` the allocated value on all control paths. 1746 If allocation is conditional (e.g. only allocate if the mold is 1747 allocated), this should be done in the initilizer region and this 1748 region not included. The alloc region is not used for by-value 1749 reductions (where allocation is implicit). 1750 2. The initializer region specifies how to initialize the thread-local 1751 reduction value. This is usually the neutral element of the reduction. 1752 For convenience, the region has an argument that contains the value 1753 of the reduction accumulator at the start of the reduction. If an alloc 1754 region is specified, there is a second block argument containing the 1755 address of the allocated memory. The initializer region is expected to 1756 `omp.yield` the new value on all control flow paths. 1757 3. The reduction region specifies how to combine two values into one, i.e. 1758 the reduction operator. It accepts the two values as arguments and is 1759 expected to `omp.yield` the combined value on all control flow paths. 1760 4. The atomic reduction region is optional and specifies how two values 1761 can be combined atomically given local accumulator variables. It is 1762 expected to store the combined value in the first accumulator variable. 1763 5. The cleanup region is optional and specifies how to clean up any memory 1764 allocated by the initializer region. The region has an argument that 1765 contains the value of the thread-local reduction accumulator. This will 1766 be executed after the reduction has completed. 1767 1768 Note that the MLIR type system does not allow for type-polymorphic 1769 reductions. Separate reduction declarations should be created for different 1770 element and accumulator types. 1771 1772 For initializer and reduction regions, the operand to `omp.yield` must 1773 match the parent operation's results. 1774 }]; 1775 1776 let arguments = (ins SymbolNameAttr:$sym_name, 1777 TypeAttr:$type); 1778 1779 let regions = (region MaxSizedRegion<1>:$allocRegion, 1780 AnyRegion:$initializerRegion, 1781 AnyRegion:$reductionRegion, 1782 AnyRegion:$atomicReductionRegion, 1783 AnyRegion:$cleanupRegion); 1784 1785 let assemblyFormat = "$sym_name `:` $type attr-dict-with-keyword " 1786 "( `alloc` $allocRegion^ )? " 1787 "`init` $initializerRegion " 1788 "`combiner` $reductionRegion " 1789 "( `atomic` $atomicReductionRegion^ )? " 1790 "( `cleanup` $cleanupRegion^ )? "; 1791 1792 let extraClassDeclaration = [{ 1793 BlockArgument getAllocMoldArg() { 1794 auto ®ion = getAllocRegion(); 1795 return region.empty() ? nullptr : region.getArgument(0); 1796 } 1797 BlockArgument getInitializerMoldArg() { 1798 return getInitializerRegion().getArgument(0); 1799 } 1800 BlockArgument getInitializerAllocArg() { 1801 return getAllocRegion().empty() ? 1802 nullptr : getInitializerRegion().getArgument(1); 1803 } 1804 BlockArgument getReductionLhsArg() { 1805 return getReductionRegion().getArgument(0); 1806 } 1807 BlockArgument getReductionRhsArg() { 1808 return getReductionRegion().getArgument(1); 1809 } 1810 BlockArgument getAtomicReductionLhsArg() { 1811 auto ®ion = getAtomicReductionRegion(); 1812 return region.empty() ? nullptr : region.getArgument(0); 1813 } 1814 BlockArgument getAtomicReductionRhsArg() { 1815 auto ®ion = getAtomicReductionRegion(); 1816 return region.empty() ? nullptr : region.getArgument(1); 1817 } 1818 BlockArgument getCleanupAllocArg() { 1819 auto ®ion = getCleanupRegion(); 1820 return region.empty() ? nullptr : region.getArgument(0); 1821 } 1822 1823 PointerLikeType getAccumulatorType() { 1824 if (getAtomicReductionRegion().empty()) 1825 return {}; 1826 1827 return cast<PointerLikeType>(getAtomicReductionLhsArg().getType()); 1828 } 1829 }]; 1830 let hasRegionVerifier = 1; 1831} 1832 1833//===----------------------------------------------------------------------===// 1834// [Spec 5.2] 10.5 masked Construct 1835//===----------------------------------------------------------------------===// 1836def MaskedOp : OpenMP_Op<"masked", clauses = [ 1837 OpenMP_FilterClause 1838 ], singleRegion = 1> { 1839 let summary = "masked construct"; 1840 let description = [{ 1841 Masked construct allows to specify a structured block to be executed by a subset of 1842 threads of the current team. 1843 }] # clausesDescription; 1844 1845 let builders = [ 1846 OpBuilder<(ins CArg<"const MaskedOperands &">:$clauses)> 1847 ]; 1848} 1849 1850#endif // OPENMP_OPS 1851