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/IR/EnumAttr.td" 18include "mlir/IR/OpBase.td" 19include "mlir/Interfaces/SideEffectInterfaces.td" 20include "mlir/Interfaces/ControlFlowInterfaces.td" 21include "mlir/IR/SymbolInterfaces.td" 22include "mlir/Dialect/LLVMIR/LLVMOpBase.td" 23include "mlir/Dialect/OpenMP/OpenMPOpsInterfaces.td" 24include "mlir/Dialect/OpenMP/OpenMPTypeInterfaces.td" 25 26def OpenMP_Dialect : Dialect { 27 let name = "omp"; 28 let cppNamespace = "::mlir::omp"; 29 let dependentDialects = ["::mlir::LLVM::LLVMDialect"]; 30 let useDefaultAttributePrinterParser = 1; 31 32 // TODO: Flip to _Prefixed. 33 let emitAccessorPrefix = kEmitAccessorPrefix_Raw; 34} 35 36// OmpCommon requires definition of OpenACC_Dialect. 37include "mlir/Dialect/OpenMP/OmpCommon.td" 38 39class OpenMP_Op<string mnemonic, list<Trait> traits = []> : 40 Op<OpenMP_Dialect, mnemonic, traits>; 41 42// Type which can be constraint accepting standard integers and indices. 43def IntLikeType : AnyTypeOf<[AnyInteger, Index]>; 44 45def OpenMP_PointerLikeType : TypeAlias<OpenMP_PointerLikeTypeInterface, 46 "OpenMP-compatible variable type">; 47 48//===----------------------------------------------------------------------===// 49// 2.6 parallel Construct 50//===----------------------------------------------------------------------===// 51 52def ParallelOp : OpenMP_Op<"parallel", [ 53 AutomaticAllocationScope, AttrSizedOperandSegments, 54 DeclareOpInterfaceMethods<OutlineableOpenMPOpInterface>, 55 RecursiveSideEffects, ReductionClauseInterface]> { 56 let summary = "parallel construct"; 57 let description = [{ 58 The parallel construct includes a region of code which is to be executed 59 by a team of threads. 60 61 The optional $if_expr_var parameter specifies a boolean result of a 62 conditional check. If this value is 1 or is not provided then the parallel 63 region runs as normal, if it is 0 then the parallel region is executed with 64 one thread. 65 66 The optional $num_threads_var parameter specifies the number of threads which 67 should be used to execute the parallel region. 68 69 The $allocators_vars and $allocate_vars parameters are a variadic list of values 70 that specify the memory allocator to be used to obtain storage for private values. 71 72 Reductions can be performed in a parallel construct by specifying reduction 73 accumulator variables in `reduction_vars` and symbols referring to reduction 74 declarations in the `reductions` attribute. Each reduction is identified 75 by the accumulator it uses and accumulators must not be repeated in the same 76 reduction. The `omp.reduction` operation accepts the accumulator and a 77 partial value which is considered to be produced by the thread for the 78 given reduction. If multiple values are produced for the same accumulator, 79 i.e. there are multiple `omp.reduction`s, the last value is taken. The 80 reduction declaration specifies how to combine the values from each thread 81 into the final value, which is available in the accumulator after all the 82 threads complete. 83 84 The optional $proc_bind_val attribute controls the thread affinity for the execution 85 of the parallel region. 86 }]; 87 88 let arguments = (ins Optional<I1>:$if_expr_var, 89 Optional<IntLikeType>:$num_threads_var, 90 Variadic<AnyType>:$allocate_vars, 91 Variadic<AnyType>:$allocators_vars, 92 Variadic<OpenMP_PointerLikeType>:$reduction_vars, 93 OptionalAttr<SymbolRefArrayAttr>:$reductions, 94 OptionalAttr<ProcBindKindAttr>:$proc_bind_val); 95 96 let regions = (region AnyRegion:$region); 97 98 let builders = [ 99 OpBuilder<(ins CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes)> 100 ]; 101 let assemblyFormat = [{ 102 oilist( `reduction` `(` 103 custom<ReductionVarList>( 104 $reduction_vars, type($reduction_vars), $reductions 105 ) `)` 106 | `if` `(` $if_expr_var `:` type($if_expr_var) `)` 107 | `num_threads` `(` $num_threads_var `:` type($num_threads_var) `)` 108 | `allocate` `(` 109 custom<AllocateAndAllocator>( 110 $allocate_vars, type($allocate_vars), 111 $allocators_vars, type($allocators_vars) 112 ) `)` 113 | `proc_bind` `(` custom<ClauseAttr>($proc_bind_val) `)` 114 ) $region attr-dict 115 }]; 116 let hasVerifier = 1; 117 let extraClassDeclaration = [{ 118 // TODO: remove this once emitAccessorPrefix is set to 119 // kEmitAccessorPrefix_Prefixed for the dialect. 120 /// Returns the reduction variables 121 SmallVector<Value> getReductionVars() { 122 return SmallVector<Value>(reduction_vars().begin(), 123 reduction_vars().end()); 124 } 125 }]; 126} 127 128def TerminatorOp : OpenMP_Op<"terminator", [Terminator]> { 129 let summary = "terminator for OpenMP regions"; 130 let description = [{ 131 A terminator operation for regions that appear in the body of OpenMP 132 operation. These regions are not expected to return any value so the 133 terminator takes no operands. The terminator op returns control to the 134 enclosing op. 135 }]; 136 137 let assemblyFormat = "attr-dict"; 138} 139 140def OMP_ScheduleModNone : I32EnumAttrCase<"none", 0>; 141def OMP_ScheduleModMonotonic : I32EnumAttrCase<"monotonic", 1>; 142def OMP_ScheduleModNonmonotonic : I32EnumAttrCase<"nonmonotonic", 2>; 143// FIXME: remove this value for the modifier because this is handled using a 144// separate attribute 145def OMP_ScheduleModSIMD : I32EnumAttrCase<"simd", 3>; 146 147def ScheduleModifier 148 : I32EnumAttr<"ScheduleModifier", "OpenMP Schedule Modifier", 149 [OMP_ScheduleModNone, OMP_ScheduleModMonotonic, 150 OMP_ScheduleModNonmonotonic, OMP_ScheduleModSIMD]> { 151 let genSpecializedAttr = 0; 152 let cppNamespace = "::mlir::omp"; 153} 154def ScheduleModifierAttr : EnumAttr<OpenMP_Dialect, ScheduleModifier, 155 "sched_mod">; 156 157//===----------------------------------------------------------------------===// 158// 2.8.1 Sections Construct 159//===----------------------------------------------------------------------===// 160 161def SectionOp : OpenMP_Op<"section", [HasParent<"SectionsOp">]> { 162 let summary = "section directive"; 163 let description = [{ 164 A section operation encloses a region which represents one section in a 165 sections construct. A section op should always be surrounded by an 166 `omp.sections` operation. 167 }]; 168 let regions = (region AnyRegion:$region); 169 let assemblyFormat = "$region attr-dict"; 170} 171 172def SectionsOp : OpenMP_Op<"sections", [AttrSizedOperandSegments, 173 ReductionClauseInterface]> { 174 let summary = "sections construct"; 175 let description = [{ 176 The sections construct is a non-iterative worksharing construct that 177 contains `omp.section` operations. The `omp.section` operations are to be 178 distributed among and executed by the threads in a team. Each `omp.section` 179 is executed once by one of the threads in the team in the context of its 180 implicit task. 181 182 Reductions can be performed in a sections construct by specifying reduction 183 accumulator variables in `reduction_vars` and symbols referring to reduction 184 declarations in the `reductions` attribute. Each reduction is identified 185 by the accumulator it uses and accumulators must not be repeated in the same 186 reduction. The `omp.reduction` operation accepts the accumulator and a 187 partial value which is considered to be produced by the section for the 188 given reduction. If multiple values are produced for the same accumulator, 189 i.e. there are multiple `omp.reduction`s, the last value is taken. The 190 reduction declaration specifies how to combine the values from each section 191 into the final value, which is available in the accumulator after all the 192 sections complete. 193 194 The $allocators_vars and $allocate_vars parameters are a variadic list of values 195 that specify the memory allocator to be used to obtain storage for private values. 196 197 The `nowait` attribute, when present, signifies that there should be no 198 implicit barrier at the end of the construct. 199 }]; 200 let arguments = (ins Variadic<OpenMP_PointerLikeType>:$reduction_vars, 201 OptionalAttr<SymbolRefArrayAttr>:$reductions, 202 Variadic<AnyType>:$allocate_vars, 203 Variadic<AnyType>:$allocators_vars, 204 UnitAttr:$nowait); 205 206 let regions = (region SizedRegion<1>:$region); 207 208 let assemblyFormat = [{ 209 oilist( `reduction` `(` 210 custom<ReductionVarList>( 211 $reduction_vars, type($reduction_vars), $reductions 212 ) `)` 213 | `allocate` `(` 214 custom<AllocateAndAllocator>( 215 $allocate_vars, type($allocate_vars), 216 $allocators_vars, type($allocators_vars) 217 ) `)` 218 | `nowait` $nowait 219 ) $region attr-dict 220 }]; 221 222 let hasVerifier = 1; 223 let hasRegionVerifier = 1; 224 225 let extraClassDeclaration = [{ 226 // TODO: remove this once emitAccessorPrefix is set to 227 // kEmitAccessorPrefix_Prefixed for the dialect. 228 /// Returns the reduction variables 229 SmallVector<Value> getReductionVars() { 230 return SmallVector<Value>(reduction_vars().begin(), 231 reduction_vars().end()); 232 } 233 }]; 234} 235 236//===----------------------------------------------------------------------===// 237// 2.8.2 Single Construct 238//===----------------------------------------------------------------------===// 239 240def SingleOp : OpenMP_Op<"single", [AttrSizedOperandSegments]> { 241 let summary = "single directive"; 242 let description = [{ 243 The single construct specifies that the associated structured block is 244 executed by only one of the threads in the team (not necessarily the 245 master thread), in the context of its implicit task. The other threads 246 in the team, which do not execute the block, wait at an implicit barrier 247 at the end of the single construct unless a nowait clause is specified. 248 }]; 249 250 let arguments = (ins Variadic<AnyType>:$allocate_vars, 251 Variadic<AnyType>:$allocators_vars, 252 UnitAttr:$nowait); 253 254 let regions = (region SizedRegion<1>:$region); 255 256 let assemblyFormat = [{ 257 oilist(`allocate` `(` 258 custom<AllocateAndAllocator>( 259 $allocate_vars, type($allocate_vars), 260 $allocators_vars, type($allocators_vars) 261 ) `)` 262 |`nowait` $nowait 263 ) $region attr-dict 264 }]; 265 let hasVerifier = 1; 266} 267 268//===----------------------------------------------------------------------===// 269// 2.9.2 Workshare Loop Construct 270//===----------------------------------------------------------------------===// 271 272def WsLoopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments, 273 AllTypesMatch<["lowerBound", "upperBound", "step"]>, 274 RecursiveSideEffects, ReductionClauseInterface]> { 275 let summary = "worksharing-loop construct"; 276 let description = [{ 277 The worksharing-loop construct specifies that the iterations of the loop(s) 278 will be executed in parallel by threads in the current context. These 279 iterations are spread across threads that already exist in the enclosing 280 parallel region. The lower and upper bounds specify a half-open range: the 281 range includes the lower bound but does not include the upper bound. If the 282 `inclusive` attribute is specified then the upper bound is also included. 283 284 The body region can contain any number of blocks. The region is terminated 285 by "omp.yield" instruction without operands. 286 287 ``` 288 omp.wsloop <clauses> 289 for (%i1, %i2) : index = (%c0, %c0) to (%c10, %c10) step (%c1, %c1) { 290 %a = load %arrA[%i1, %i2] : memref<?x?xf32> 291 %b = load %arrB[%i1, %i2] : memref<?x?xf32> 292 %sum = arith.addf %a, %b : f32 293 store %sum, %arrC[%i1, %i2] : memref<?x?xf32> 294 omp.yield 295 } 296 ``` 297 298 The `linear_step_vars` operand additionally specifies the step for each 299 associated linear operand. Note that the `linear_vars` and 300 `linear_step_vars` variadic lists should contain the same number of 301 elements. 302 303 Reductions can be performed in a worksharing-loop by specifying reduction 304 accumulator variables in `reduction_vars` and symbols referring to reduction 305 declarations in the `reductions` attribute. Each reduction is identified 306 by the accumulator it uses and accumulators must not be repeated in the same 307 reduction. The `omp.reduction` operation accepts the accumulator and a 308 partial value which is considered to be produced by the current loop 309 iteration for the given reduction. If multiple values are produced for the 310 same accumulator, i.e. there are multiple `omp.reduction`s, the last value 311 is taken. The reduction declaration specifies how to combine the values from 312 each iteration into the final value, which is available in the accumulator 313 after the loop completes. 314 315 The optional `schedule_val` attribute specifies the loop schedule for this 316 loop, determining how the loop is distributed across the parallel threads. 317 The optional `schedule_chunk_var` associated with this determines further 318 controls this distribution. 319 320 Collapsed loops are represented by the worksharing-loop having a list of 321 indices, bounds and steps where the size of the list is equal to the 322 collapse value. 323 324 The `nowait` attribute, when present, signifies that there should be no 325 implicit barrier at the end of the loop. 326 327 The optional `ordered_val` attribute specifies how many loops are associated 328 with the worksharing-loop construct. The value of zero refers to the ordered 329 clause specified without parameter. 330 331 The optional `order` attribute specifies which order the iterations of the 332 associate loops are executed in. Currently the only option for this 333 attribute is "concurrent". 334 }]; 335 336 let arguments = (ins Variadic<IntLikeType>:$lowerBound, 337 Variadic<IntLikeType>:$upperBound, 338 Variadic<IntLikeType>:$step, 339 Variadic<AnyType>:$linear_vars, 340 Variadic<I32>:$linear_step_vars, 341 Variadic<OpenMP_PointerLikeType>:$reduction_vars, 342 OptionalAttr<SymbolRefArrayAttr>:$reductions, 343 OptionalAttr<ScheduleKindAttr>:$schedule_val, 344 Optional<AnyType>:$schedule_chunk_var, 345 OptionalAttr<ScheduleModifierAttr>:$schedule_modifier, 346 UnitAttr:$simd_modifier, 347 UnitAttr:$nowait, 348 Confined<OptionalAttr<I64Attr>, [IntMinValue<0>]>:$ordered_val, 349 OptionalAttr<OrderKindAttr>:$order_val, 350 UnitAttr:$inclusive); 351 352 let builders = [ 353 OpBuilder<(ins "ValueRange":$lowerBound, "ValueRange":$upperBound, 354 "ValueRange":$step, 355 CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes)>, 356 ]; 357 358 let regions = (region AnyRegion:$region); 359 360 let extraClassDeclaration = [{ 361 /// Returns the number of loops in the worksharing-loop nest. 362 unsigned getNumLoops() { return lowerBound().size(); } 363 364 /// Returns the number of reduction variables. 365 unsigned getNumReductionVars() { return reduction_vars().size(); } 366 367 // TODO: remove this once emitAccessorPrefix is set to 368 // kEmitAccessorPrefix_Prefixed for the dialect. 369 /// Returns the reduction variables 370 SmallVector<Value> getReductionVars() { 371 return SmallVector<Value>(reduction_vars().begin(), 372 reduction_vars().end()); 373 } 374 }]; 375 let hasCustomAssemblyFormat = 1; 376 let assemblyFormat = [{ 377 oilist(`linear` `(` 378 custom<LinearClause>($linear_vars, type($linear_vars), 379 $linear_step_vars) `)` 380 |`schedule` `(` 381 custom<ScheduleClause>( 382 $schedule_val, $schedule_modifier, $simd_modifier, 383 $schedule_chunk_var, type($schedule_chunk_var)) `)` 384 |`nowait` $nowait 385 |`ordered` `(` $ordered_val `)` 386 |`order` `(` custom<ClauseAttr>($order_val) `)` 387 |`reduction` `(` 388 custom<ReductionVarList>( 389 $reduction_vars, type($reduction_vars), $reductions 390 ) `)` 391 ) `for` custom<LoopControl>($region, $lowerBound, $upperBound, $step, 392 type($step), $inclusive) attr-dict 393 }]; 394 let hasVerifier = 1; 395} 396 397//===----------------------------------------------------------------------===// 398// Simd construct [2.9.3.1] 399//===----------------------------------------------------------------------===// 400 401def SimdLoopOp : OpenMP_Op<"simdloop", [AttrSizedOperandSegments, 402 AllTypesMatch<["lowerBound", "upperBound", "step"]>]> { 403 let summary = "simd loop construct"; 404 let description = [{ 405 The simd construct can be applied to a loop to indicate that the loop can be 406 transformed into a SIMD loop (that is, multiple iterations of the loop can 407 be executed concurrently using SIMD instructions).. The lower and upper 408 bounds specify a half-open range: the range includes the lower bound but 409 does not include the upper bound. If the `inclusive` attribute is specified 410 then the upper bound is also included. 411 412 The body region can contain any number of blocks. The region is terminated 413 by "omp.yield" instruction without operands. 414 415 When an if clause is present and evaluates to false, the preferred number of 416 iterations to be executed concurrently is one, regardless of whether 417 a simdlen clause is specified. 418 ``` 419 omp.simdloop <clauses> 420 for (%i1, %i2) : index = (%c0, %c0) to (%c10, %c10) step (%c1, %c1) { 421 // block operations 422 omp.yield 423 } 424 ``` 425 }]; 426 427 // TODO: Add other clauses 428 let arguments = (ins Variadic<IntLikeType>:$lowerBound, 429 Variadic<IntLikeType>:$upperBound, 430 Variadic<IntLikeType>:$step, 431 Optional<I1>:$if_expr, 432 UnitAttr:$inclusive 433 ); 434 435 let regions = (region AnyRegion:$region); 436 let assemblyFormat = [{ 437 oilist(`if` `(` $if_expr `)` 438 ) `for` custom<LoopControl>($region, $lowerBound, $upperBound, $step, 439 type($step), $inclusive) attr-dict 440 }]; 441 442 let extraClassDeclaration = [{ 443 /// Returns the number of loops in the simd loop nest. 444 unsigned getNumLoops() { return lowerBound().size(); } 445 446 }]; 447 448 let hasCustomAssemblyFormat = 1; 449 let hasVerifier = 1; 450} 451 452 453def YieldOp : OpenMP_Op<"yield", 454 [NoSideEffect, ReturnLike, Terminator, 455 ParentOneOf<["WsLoopOp", "ReductionDeclareOp", 456 "AtomicUpdateOp", "SimdLoopOp"]>]> { 457 let summary = "loop yield and termination operation"; 458 let description = [{ 459 "omp.yield" yields SSA values from the OpenMP dialect op region and 460 terminates the region. The semantics of how the values are yielded is 461 defined by the parent operation. 462 }]; 463 464 let arguments = (ins Variadic<AnyType>:$results); 465 466 let builders = [ 467 OpBuilder<(ins), [{ build($_builder, $_state, {}); }]> 468 ]; 469 470 let assemblyFormat = [{ ( `(` $results^ `:` type($results) `)` )? attr-dict}]; 471} 472 473//===----------------------------------------------------------------------===// 474// 2.10.1 task Construct 475//===----------------------------------------------------------------------===// 476 477def TaskOp : OpenMP_Op<"task", [AttrSizedOperandSegments, 478 OutlineableOpenMPOpInterface, AutomaticAllocationScope, 479 ReductionClauseInterface]> { 480 let summary = "task construct"; 481 let description = [{ 482 The task construct defines an explicit task. 483 484 For definitions of "undeferred task", "included task", "final task" and 485 "mergeable task", please check OpenMP Specification. 486 487 When an `if` clause is present on a task construct, and the value of 488 `if_expr` evaluates to `false`, an "undeferred task" is generated, and the 489 encountering thread must suspend the current task region, for which 490 execution cannot be resumed until execution of the structured block that is 491 associated with the generated task is completed. 492 493 When a `final` clause is present on a task construct and the `final_expr` 494 evaluates to `true`, the generated task will be a "final task". All task 495 constructs encountered during execution of a final task will generate final 496 and included tasks. 497 498 If the `untied` clause is present on a task construct, any thread in the 499 team can resume the task region after a suspension. The `untied` clause is 500 ignored if a `final` clause is present on the same task construct and the 501 `final_expr` evaluates to `true`, or if a task is an included task. 502 503 When the `mergeable` clause is present on a task construct, the generated 504 task is a "mergeable task". 505 506 The `in_reduction` clause specifies that this particular task (among all the 507 tasks in current taskgroup, if any) participates in a reduction. 508 509 The `priority` clause is a hint for the priority of the generated task. 510 The `priority` is a non-negative integer expression that provides a hint for 511 task execution order. Among all tasks ready to be executed, higher priority 512 tasks (those with a higher numerical value in the priority clause 513 expression) are recommended to execute before lower priority ones. The 514 default priority-value when no priority clause is specified should be 515 assumed to be zero (the lowest priority). 516 517 The `allocators_vars` and `allocate_vars` arguments are a variadic list of 518 values that specify the memory allocator to be used to obtain storage for 519 private values. 520 521 }]; 522 523 // TODO: depend, affinity and detach clauses 524 let arguments = (ins Optional<I1>:$if_expr, 525 Optional<I1>:$final_expr, 526 UnitAttr:$untied, 527 UnitAttr:$mergeable, 528 Variadic<OpenMP_PointerLikeType>:$in_reduction_vars, 529 OptionalAttr<SymbolRefArrayAttr>:$in_reductions, 530 Optional<I32>:$priority, 531 Variadic<AnyType>:$allocate_vars, 532 Variadic<AnyType>:$allocators_vars); 533 let regions = (region AnyRegion:$region); 534 let assemblyFormat = [{ 535 oilist(`if` `(` $if_expr `)` 536 |`final` `(` $final_expr `)` 537 |`untied` $untied 538 |`mergeable` $mergeable 539 |`in_reduction` `(` 540 custom<ReductionVarList>( 541 $in_reduction_vars, type($in_reduction_vars), $in_reductions 542 ) `)` 543 |`priority` `(` $priority `)` 544 |`allocate` `(` 545 custom<AllocateAndAllocator>( 546 $allocate_vars, type($allocate_vars), 547 $allocators_vars, type($allocators_vars) 548 ) `)` 549 ) $region attr-dict 550 }]; 551 let extraClassDeclaration = [{ 552 /// Returns the reduction variables 553 SmallVector<Value> getReductionVars() { 554 return SmallVector<Value>(in_reduction_vars().begin(), 555 in_reduction_vars().end()); 556 } 557 }]; 558 let hasVerifier = 1; 559} 560 561def TaskLoopOp : OpenMP_Op<"taskloop", [AttrSizedOperandSegments, 562 AutomaticAllocationScope, RecursiveSideEffects, 563 AllTypesMatch<["lowerBound", "upperBound", "step"]>, 564 ReductionClauseInterface]> { 565 let summary = "taskloop construct"; 566 let description = [{ 567 The taskloop construct specifies that the iterations of one or more 568 associated loops will be executed in parallel using explicit tasks. The 569 iterations are distributed across tasks generated by the construct and 570 scheduled to be executed. 571 572 The `lowerBound` and `upperBound` specify a half-open range: the range 573 includes the lower bound but does not include the upper bound. If the 574 `inclusive` attribute is specified then the upper bound is also included. 575 The `step` specifies the loop step. 576 577 The body region can contain any number of blocks. 578 579 ``` 580 omp.taskloop <clauses> 581 for (%i1, %i2) : index = (%c0, %c0) to (%c10, %c10) step (%c1, %c1) { 582 %a = load %arrA[%i1, %i2] : memref<?x?xf32> 583 %b = load %arrB[%i1, %i2] : memref<?x?xf32> 584 %sum = arith.addf %a, %b : f32 585 store %sum, %arrC[%i1, %i2] : memref<?x?xf32> 586 omp.terminator 587 } 588 ``` 589 590 For definitions of "undeferred task", "included task", "final task" and 591 "mergeable task", please check OpenMP Specification. 592 593 When an `if` clause is present on a taskloop construct, and if the `if` 594 clause expression evaluates to `false`, undeferred tasks are generated. The 595 use of a variable in an `if` clause expression of a taskloop construct 596 causes an implicit reference to the variable in all enclosing constructs. 597 598 When a `final` clause is present on a taskloop construct and the `final` 599 clause expression evaluates to `true`, the generated tasks will be final 600 tasks. The use of a variable in a `final` clause expression of a taskloop 601 construct causes an implicit reference to the variable in all enclosing 602 constructs. 603 604 If the `untied` clause is specified, all tasks generated by the taskloop 605 construct are untied tasks. 606 607 When the `mergeable` clause is present on a taskloop construct, each 608 generated task is a mergeable task. 609 610 Reductions can be performed in a loop by specifying reduction accumulator 611 variables in `reduction_vars` or `in_reduction_vars` and symbols referring 612 to reduction declarations in the `reductions` or `in_reductions` attribute. 613 Each reduction is identified by the accumulator it uses and accumulators 614 must not be repeated in the same reduction. The `omp.reduction` operation 615 accepts the accumulator and a partial value which is considered to be 616 produced by the current loop iteration for the given reduction. If multiple 617 values are produced for the same accumulator, i.e. there are multiple 618 `omp.reduction`s, the last value is taken. The reduction declaration 619 specifies how to combine the values from each iteration into the final 620 value, which is available in the accumulator after the loop completes. 621 622 If an `in_reduction` clause is present on the taskloop construct, the 623 behavior is as if each generated task was defined by a task construct on 624 which an `in_reduction` clause with the same reduction operator and list 625 items is present. Thus, the generated tasks are participants of a reduction 626 previously defined by a reduction scoping clause. 627 628 If a `reduction` clause is present on the taskloop construct, the behavior 629 is as if a `task_reduction` clause with the same reduction operator and list 630 items was applied to the implicit taskgroup construct enclosing the taskloop 631 construct. The taskloop construct executes as if each generated task was 632 defined by a task construct on which an `in_reduction` clause with the same 633 reduction operator and list items is present. Thus, the generated tasks are 634 participants of the reduction defined by the `task_reduction` clause that 635 was applied to the implicit taskgroup construct. 636 637 When a `priority` clause is present on a taskloop construct, the generated 638 tasks use the `priority-value` as if it was specified for each individual 639 task. If the `priority` clause is not specified, tasks generated by the 640 taskloop construct have the default task priority (zero). 641 642 The `allocators_vars` and `allocate_vars` arguments are a variadic list of 643 values that specify the memory allocator to be used to obtain storage for 644 private values. 645 646 If a `grainsize` clause is present on the taskloop construct, the number of 647 logical loop iterations assigned to each generated task is greater than or 648 equal to the minimum of the value of the grain-size expression and the 649 number of logical loop iterations, but less than two times the value of the 650 grain-size expression. 651 652 If `num_tasks` is specified, the taskloop construct creates as many tasks as 653 the minimum of the num-tasks expression and the number of logical loop 654 iterations. Each task must have at least one logical loop iteration. 655 656 By default, the taskloop construct executes as if it was enclosed in a 657 taskgroup construct with no statements or directives outside of the taskloop 658 construct. Thus, the taskloop construct creates an implicit taskgroup 659 region. If the `nogroup` clause is present, no implicit taskgroup region is 660 created. 661 }]; 662 663 let arguments = (ins Variadic<IntLikeType>:$lowerBound, 664 Variadic<IntLikeType>:$upperBound, 665 Variadic<IntLikeType>:$step, 666 UnitAttr:$inclusive, 667 Optional<I1>:$if_expr, 668 Optional<I1>:$final_expr, 669 UnitAttr:$untied, 670 UnitAttr:$mergeable, 671 Variadic<OpenMP_PointerLikeType>:$in_reduction_vars, 672 OptionalAttr<SymbolRefArrayAttr>:$in_reductions, 673 Variadic<OpenMP_PointerLikeType>:$reduction_vars, 674 OptionalAttr<SymbolRefArrayAttr>:$reductions, 675 Optional<IntLikeType>:$priority, 676 Variadic<AnyType>:$allocate_vars, 677 Variadic<AnyType>:$allocators_vars, 678 Optional<IntLikeType>: $grain_size, 679 Optional<IntLikeType>: $num_tasks, 680 UnitAttr: $nogroup); 681 682 let regions = (region AnyRegion:$region); 683 684 let assemblyFormat = [{ 685 oilist(`if` `(` $if_expr `)` 686 |`final` `(` $final_expr `)` 687 |`untied` $untied 688 |`mergeable` $mergeable 689 |`in_reduction` `(` 690 custom<ReductionVarList>( 691 $in_reduction_vars, type($in_reduction_vars), $in_reductions 692 ) `)` 693 |`reduction` `(` 694 custom<ReductionVarList>( 695 $reduction_vars, type($reduction_vars), $reductions 696 ) `)` 697 |`priority` `(` $priority `:` type($priority) `)` 698 |`allocate` `(` 699 custom<AllocateAndAllocator>( 700 $allocate_vars, type($allocate_vars), 701 $allocators_vars, type($allocators_vars) 702 ) `)` 703 |`grain_size` `(` $grain_size `:` type($grain_size) `)` 704 |`num_tasks` `(` $num_tasks `:` type($num_tasks) `)` 705 |`nogroup` $nogroup 706 ) `for` custom<LoopControl>($region, $lowerBound, $upperBound, $step, 707 type($step), $inclusive) attr-dict 708 }]; 709 710 let extraClassDeclaration = [{ 711 /// Returns the reduction variables 712 SmallVector<Value> getReductionVars(); 713 void getEffects(SmallVectorImpl<MemoryEffects::EffectInstance> &effects); 714 }]; 715 716 let hasVerifier = 1; 717} 718 719def TaskGroupOp : OpenMP_Op<"taskgroup", [AttrSizedOperandSegments, 720 ReductionClauseInterface, 721 AutomaticAllocationScope]> { 722 let summary = "taskgroup construct"; 723 let description = [{ 724 The taskgroup construct specifies a wait on completion of child tasks of the 725 current task and their descendent tasks. 726 727 When a thread encounters a taskgroup construct, it starts executing the 728 region. All child tasks generated in the taskgroup region and all of their 729 descendants that bind to the same parallel region as the taskgroup region 730 are part of the taskgroup set associated with the taskgroup region. There is 731 an implicit task scheduling point at the end of the taskgroup region. The 732 current task is suspended at the task scheduling point until all tasks in 733 the taskgroup set complete execution. 734 735 The `task_reduction` clause specifies a reduction among tasks. For each list 736 item, the number of copies is unspecified. Any copies associated with the 737 reduction are initialized before they are accessed by the tasks 738 participating in the reduction. After the end of the region, the original 739 list item contains the result of the reduction. 740 741 The `allocators_vars` and `allocate_vars` arguments are a variadic list of 742 values that specify the memory allocator to be used to obtain storage for 743 private values. 744 }]; 745 746 let arguments = (ins Variadic<OpenMP_PointerLikeType>:$task_reduction_vars, 747 OptionalAttr<SymbolRefArrayAttr>:$task_reductions, 748 Variadic<AnyType>:$allocate_vars, 749 Variadic<AnyType>:$allocators_vars); 750 751 let regions = (region AnyRegion:$region); 752 753 let assemblyFormat = [{ 754 oilist(`task_reduction` `(` 755 custom<ReductionVarList>( 756 $task_reduction_vars, type($task_reduction_vars), $task_reductions 757 ) `)` 758 |`allocate` `(` 759 custom<AllocateAndAllocator>( 760 $allocate_vars, type($allocate_vars), 761 $allocators_vars, type($allocators_vars) 762 ) `)` 763 ) $region attr-dict 764 }]; 765 766 let extraClassDeclaration = [{ 767 /// Returns the reduction variables 768 operand_range getReductionVars() { return task_reduction_vars(); } 769 }]; 770 771 let hasVerifier = 1; 772 773} 774 775//===----------------------------------------------------------------------===// 776// 2.10.4 taskyield Construct 777//===----------------------------------------------------------------------===// 778 779def TaskyieldOp : OpenMP_Op<"taskyield"> { 780 let summary = "taskyield construct"; 781 let description = [{ 782 The taskyield construct specifies that the current task can be suspended 783 in favor of execution of a different task. 784 }]; 785 786 let assemblyFormat = "attr-dict"; 787} 788 789//===----------------------------------------------------------------------===// 790// 2.13.7 flush Construct 791//===----------------------------------------------------------------------===// 792def FlushOp : OpenMP_Op<"flush"> { 793 let summary = "flush construct"; 794 let description = [{ 795 The flush construct executes the OpenMP flush operation. This operation 796 makes a thread’s temporary view of memory consistent with memory and 797 enforces an order on the memory operations of the variables explicitly 798 specified or implied. 799 }]; 800 801 let arguments = (ins Variadic<OpenMP_PointerLikeType>:$varList); 802 803 let assemblyFormat = [{ ( `(` $varList^ `:` type($varList) `)` )? attr-dict}]; 804 let extraClassDeclaration = [{ 805 /// The number of variable operands. 806 unsigned getNumVariableOperands() { 807 return getOperation()->getNumOperands(); 808 } 809 /// The i-th variable operand passed. 810 Value getVariableOperand(unsigned i) { 811 return getOperand(i); 812 } 813 }]; 814} 815//===----------------------------------------------------------------------===// 816// 2.14.5 target construct 817//===----------------------------------------------------------------------===// 818 819def TargetOp : OpenMP_Op<"target",[AttrSizedOperandSegments]> { 820 let summary = "target construct"; 821 let description = [{ 822 The target construct includes a region of code which is to be executed 823 on a device. 824 825 The optional $if_expr parameter specifies a boolean result of a 826 conditional check. If this value is 1 or is not provided then the target 827 region runs on a device, if it is 0 then the target region is executed on the 828 host device. 829 830 The optional $device parameter specifies the device number for the target region. 831 832 The optional $thread_limit specifies the limit on the number of threads 833 834 The optional $nowait elliminates the implicit barrier so the parent task can make progress 835 even if the target task is not yet completed. 836 837 TODO: map, is_device_ptr, depend, defaultmap, in_reduction 838 839 }]; 840 841 let arguments = (ins Optional<I1>:$if_expr, 842 Optional<AnyInteger>:$device, 843 Optional<AnyInteger>:$thread_limit, 844 UnitAttr:$nowait); 845 846 let regions = (region AnyRegion:$region); 847 848 let assemblyFormat = [{ 849 oilist( `if` `(` $if_expr `)` 850 | `device` `(` $device `:` type($device) `)` 851 | `thread_limit` `(` $thread_limit `:` type($thread_limit) `)` 852 | `nowait` $nowait 853 ) $region attr-dict 854 }]; 855} 856 857 858//===----------------------------------------------------------------------===// 859// 2.16 master Construct 860//===----------------------------------------------------------------------===// 861def MasterOp : OpenMP_Op<"master"> { 862 let summary = "master construct"; 863 let description = [{ 864 The master construct specifies a structured block that is executed by 865 the master thread of the team. 866 }]; 867 868 let regions = (region AnyRegion:$region); 869 870 let assemblyFormat = "$region attr-dict"; 871} 872 873//===----------------------------------------------------------------------===// 874// 2.17.1 critical Construct 875//===----------------------------------------------------------------------===// 876def CriticalDeclareOp : OpenMP_Op<"critical.declare", [Symbol]> { 877 let summary = "declares a named critical section."; 878 879 let description = [{ 880 Declares a named critical section. 881 882 The name can be used in critical constructs in the dialect. 883 }]; 884 885 let arguments = (ins SymbolNameAttr:$sym_name, 886 DefaultValuedAttr<I64Attr, "0">:$hint_val); 887 888 let assemblyFormat = [{ 889 $sym_name oilist(`hint` `(` custom<SynchronizationHint>($hint_val) `)`) 890 attr-dict 891 }]; 892 let hasVerifier = 1; 893} 894 895 896def CriticalOp : OpenMP_Op<"critical", 897 [DeclareOpInterfaceMethods<SymbolUserOpInterface>]> { 898 let summary = "critical construct"; 899 let description = [{ 900 The critical construct imposes a restriction on the associated structured 901 block (region) to be executed by only a single thread at a time. 902 }]; 903 904 let arguments = (ins OptionalAttr<FlatSymbolRefAttr>:$name); 905 906 let regions = (region AnyRegion:$region); 907 908 let assemblyFormat = [{ 909 (`(` $name^ `)`)? $region attr-dict 910 }]; 911} 912 913//===----------------------------------------------------------------------===// 914// 2.17.2 barrier Construct 915//===----------------------------------------------------------------------===// 916 917def BarrierOp : OpenMP_Op<"barrier"> { 918 let summary = "barrier construct"; 919 let description = [{ 920 The barrier construct specifies an explicit barrier at the point at which 921 the construct appears. 922 }]; 923 924 let assemblyFormat = "attr-dict"; 925} 926 927//===----------------------------------------------------------------------===// 928// [5.1] 2.19.9 ordered Construct 929//===----------------------------------------------------------------------===// 930 931def ClauseDependSource : I32EnumAttrCase<"dependsource", 0>; 932def ClauseDependSink : I32EnumAttrCase<"dependsink", 1>; 933 934def ClauseDepend : I32EnumAttr< 935 "ClauseDepend", 936 "depend clause", 937 [ClauseDependSource, ClauseDependSink]> { 938 let genSpecializedAttr = 0; 939 let cppNamespace = "::mlir::omp"; 940} 941def ClauseDependAttr : EnumAttr<OpenMP_Dialect, ClauseDepend, "clause_depend"> { 942 let assemblyFormat = "`(` $value `)`"; 943} 944 945def OrderedOp : OpenMP_Op<"ordered"> { 946 let summary = "ordered construct without region"; 947 let description = [{ 948 The ordered construct without region is a stand-alone directive that 949 specifies cross-iteration dependences in a doacross loop nest. 950 951 The `depend_type_val` attribute refers to either the DEPEND(SOURCE) clause 952 or the DEPEND(SINK: vec) clause. 953 954 The `num_loops_val` attribute specifies the number of loops in the doacross 955 nest. 956 957 The `depend_vec_vars` is a variadic list of operands that specifies the index 958 of the loop iterator in the doacross nest for the DEPEND(SOURCE) clause or 959 the index of the element of "vec" for the DEPEND(SINK: vec) clause. It 960 contains the operands in multiple "vec" when multiple DEPEND(SINK: vec) 961 clauses exist in one ORDERED directive. 962 }]; 963 964 let arguments = (ins OptionalAttr<ClauseDependAttr>:$depend_type_val, 965 Confined<OptionalAttr<I64Attr>, [IntMinValue<0>]>:$num_loops_val, 966 Variadic<AnyType>:$depend_vec_vars); 967 968 let assemblyFormat = [{ 969 ( `depend_type` `` $depend_type_val^ )? 970 ( `depend_vec` `(` $depend_vec_vars^ `:` type($depend_vec_vars) `)` )? 971 attr-dict 972 }]; 973 let hasVerifier = 1; 974} 975 976def OrderedRegionOp : OpenMP_Op<"ordered_region"> { 977 let summary = "ordered construct with region"; 978 let description = [{ 979 The ordered construct with region specifies a structured block in a 980 worksharing-loop, SIMD, or worksharing-loop SIMD region that is executed in 981 the order of the loop iterations. 982 983 The `simd` attribute corresponds to the SIMD clause specified. If it is not 984 present, it behaves as if the THREADS clause is specified or no clause is 985 specified. 986 }]; 987 988 let arguments = (ins UnitAttr:$simd); 989 990 let regions = (region AnyRegion:$region); 991 992 let assemblyFormat = [{ ( `simd` $simd^ )? $region attr-dict}]; 993 let hasVerifier = 1; 994} 995 996//===----------------------------------------------------------------------===// 997// 2.17.5 taskwait Construct 998//===----------------------------------------------------------------------===// 999 1000def TaskwaitOp : OpenMP_Op<"taskwait"> { 1001 let summary = "taskwait construct"; 1002 let description = [{ 1003 The taskwait construct specifies a wait on the completion of child tasks 1004 of the current task. 1005 }]; 1006 1007 let assemblyFormat = "attr-dict"; 1008} 1009 1010//===----------------------------------------------------------------------===// 1011// 2.17.7 atomic construct 1012//===----------------------------------------------------------------------===// 1013 1014// In the OpenMP Specification, atomic construct has an `atomic-clause` which 1015// can take the values `read`, `write`, `update` and `capture`. These four 1016// kinds of atomic constructs are fundamentally independent and are handled 1017// separately while lowering. Having four separate operations (one for each 1018// value of the clause) here decomposes handling of this construct into a 1019// two-step process. 1020 1021def AtomicReadOp : OpenMP_Op<"atomic.read", [AllTypesMatch<["x", "v"]>]> { 1022 1023 let summary = "performs an atomic read"; 1024 1025 let description = [{ 1026 This operation performs an atomic read. 1027 1028 The operand `x` is the address from where the value is atomically read. 1029 The operand `v` is the address where the value is stored after reading. 1030 1031 `hint` is the value of hint (as specified in the hint clause). It is a 1032 compile time constant. As the name suggests, this is just a hint for 1033 optimization. 1034 1035 `memory_order` indicates the memory ordering behavior of the construct. It 1036 can be one of `seq_cst`, `acquire` or `relaxed`. 1037 }]; 1038 1039 let arguments = (ins OpenMP_PointerLikeType:$x, 1040 OpenMP_PointerLikeType:$v, 1041 DefaultValuedAttr<I64Attr, "0">:$hint_val, 1042 OptionalAttr<MemoryOrderKindAttr>:$memory_order_val); 1043 let assemblyFormat = [{ 1044 $v `=` $x 1045 oilist( `memory_order` `(` custom<ClauseAttr>($memory_order_val) `)` 1046 | `hint` `(` custom<SynchronizationHint>($hint_val) `)`) 1047 `:` type($x) attr-dict 1048 }]; 1049 let hasVerifier = 1; 1050 let extraClassDeclaration = [{ 1051 /// The number of variable operands. 1052 unsigned getNumVariableOperands() { 1053 assert(x() && "expected 'x' operand"); 1054 assert(v() && "expected 'v' operand"); 1055 return 2; 1056 } 1057 1058 /// The i-th variable operand passed. 1059 Value getVariableOperand(unsigned i) { 1060 assert(i < 2 && "invalid index position for an operand"); 1061 return i == 0 ? x() : v(); 1062 } 1063 }]; 1064} 1065 1066def AtomicWriteOp : OpenMP_Op<"atomic.write"> { 1067 1068 let summary = "performs an atomic write"; 1069 1070 let description = [{ 1071 This operation performs an atomic write. 1072 1073 The operand `address` is the address to where the `value` is atomically 1074 written w.r.t. multiple threads. The evaluation of `value` need not be 1075 atomic w.r.t. the write to address. In general, the type(address) must 1076 dereference to type(value). 1077 1078 `hint` is the value of hint (as specified in the hint clause). It is a 1079 compile time constant. As the name suggests, this is just a hint for 1080 optimization. 1081 1082 `memory_order` indicates the memory ordering behavior of the construct. It 1083 can be one of `seq_cst`, `release` or `relaxed`. 1084 }]; 1085 1086 let arguments = (ins OpenMP_PointerLikeType:$address, 1087 AnyType:$value, 1088 DefaultValuedAttr<I64Attr, "0">:$hint_val, 1089 OptionalAttr<MemoryOrderKindAttr>:$memory_order_val); 1090 let assemblyFormat = [{ 1091 $address `=` $value 1092 oilist( `hint` `(` custom<SynchronizationHint>($hint_val) `)` 1093 | `memory_order` `(` custom<ClauseAttr>($memory_order_val) `)`) 1094 `:` type($address) `,` type($value) 1095 attr-dict 1096 }]; 1097 let hasVerifier = 1; 1098 let extraClassDeclaration = [{ 1099 /// The number of variable operands. 1100 unsigned getNumVariableOperands() { 1101 assert(address() && "expected address operand"); 1102 assert(value() && "expected value operand"); 1103 return 2; 1104 } 1105 1106 /// The i-th variable operand passed. 1107 Value getVariableOperand(unsigned i) { 1108 assert(i < 2 && "invalid index position for an operand"); 1109 return i == 0 ? address() : value(); 1110 } 1111 }]; 1112} 1113 1114def AtomicUpdateOp : OpenMP_Op<"atomic.update", 1115 [SingleBlockImplicitTerminator<"YieldOp">]> { 1116 1117 let summary = "performs an atomic update"; 1118 1119 let description = [{ 1120 This operation performs an atomic update. 1121 1122 The operand `x` is exactly the same as the operand `x` in the OpenMP 1123 Standard (OpenMP 5.0, section 2.17.7). It is the address of the variable 1124 that is being updated. `x` is atomically read/written. 1125 1126 `hint` is the value of hint (as used in the hint clause). It is a compile 1127 time constant. As the name suggests, this is just a hint for optimization. 1128 1129 `memory_order` indicates the memory ordering behavior of the construct. It 1130 can be one of `seq_cst`, `release` or `relaxed`. 1131 1132 The region describes how to update the value of `x`. It takes the value at 1133 `x` as an input and must yield the updated value. Only the update to `x` is 1134 atomic. Generally the region must have only one instruction, but can 1135 potentially have more than one instructions too. The update is sematically 1136 similar to a compare-exchange loop based atomic update. 1137 1138 The syntax of atomic update operation is different from atomic read and 1139 atomic write operations. This is because only the host dialect knows how to 1140 appropriately update a value. For example, while generating LLVM IR, if 1141 there are no special `atomicrmw` instructions for the operation-type 1142 combination in atomic update, a compare-exchange loop is generated, where 1143 the core update operation is directly translated like regular operations by 1144 the host dialect. The front-end must handle semantic checks for allowed 1145 operations. 1146 }]; 1147 1148 let arguments = (ins OpenMP_PointerLikeType:$x, 1149 DefaultValuedAttr<I64Attr, "0">:$hint_val, 1150 OptionalAttr<MemoryOrderKindAttr>:$memory_order_val); 1151 let regions = (region SizedRegion<1>:$region); 1152 let assemblyFormat = [{ 1153 oilist( `memory_order` `(` custom<ClauseAttr>($memory_order_val) `)` 1154 | `hint` `(` custom<SynchronizationHint>($hint_val) `)`) 1155 $x `:` type($x) $region attr-dict 1156 }]; 1157 let hasVerifier = 1; 1158 let hasRegionVerifier = 1; 1159 let extraClassDeclaration = [{ 1160 Operation* getFirstOp() { 1161 return &getRegion().front().getOperations().front(); 1162 } 1163 }]; 1164} 1165 1166def AtomicCaptureOp : OpenMP_Op<"atomic.capture", 1167 [SingleBlockImplicitTerminator<"TerminatorOp">]> { 1168 let summary = "performs an atomic capture"; 1169 let description = [{ 1170 This operation performs an atomic capture. 1171 1172 `hint` is the value of hint (as used in the hint clause). It is a compile 1173 time constant. As the name suggests, this is just a hint for optimization. 1174 1175 `memory_order` indicates the memory ordering behavior of the construct. It 1176 can be one of `seq_cst`, `acq_rel`, `release`, `acquire` or `relaxed`. 1177 1178 The region has the following allowed forms: 1179 1180 ``` 1181 omp.atomic.capture { 1182 omp.atomic.update ... 1183 omp.atomic.read ... 1184 omp.terminator 1185 } 1186 1187 omp.atomic.capture { 1188 omp.atomic.read ... 1189 omp.atomic.update ... 1190 omp.terminator 1191 } 1192 1193 omp.atomic.capture { 1194 omp.atomic.read ... 1195 omp.atomic.write ... 1196 omp.terminator 1197 } 1198 ``` 1199 1200 }]; 1201 1202 let arguments = (ins DefaultValuedAttr<I64Attr, "0">:$hint_val, 1203 OptionalAttr<MemoryOrderKindAttr>:$memory_order_val); 1204 let regions = (region SizedRegion<1>:$region); 1205 let assemblyFormat = [{ 1206 oilist(`memory_order` `(` custom<ClauseAttr>($memory_order_val) `)` 1207 |`hint` `(` custom<SynchronizationHint>($hint_val) `)`) 1208 $region attr-dict 1209 }]; 1210 let hasRegionVerifier = 1; 1211 let hasVerifier = 1; 1212 let extraClassDeclaration = [{ 1213 /// Returns the first operation in atomic capture region 1214 Operation* getFirstOp(); 1215 1216 /// Returns the second operation in atomic capture region 1217 Operation* getSecondOp(); 1218 1219 /// Returns the `atomic.read` operation inside the region, if any. 1220 /// Otherwise, it returns nullptr. 1221 AtomicReadOp getAtomicReadOp(); 1222 1223 /// Returns the `atomic.write` operation inside the region, if any. 1224 /// Otherwise, it returns nullptr. 1225 AtomicWriteOp getAtomicWriteOp(); 1226 1227 /// Returns the `atomic.update` operation inside the region, if any. 1228 /// Otherwise, it returns nullptr. 1229 AtomicUpdateOp getAtomicUpdateOp(); 1230 }]; 1231} 1232 1233//===----------------------------------------------------------------------===// 1234// [5.1] 2.21.2 threadprivate Directive 1235//===----------------------------------------------------------------------===// 1236 1237def ThreadprivateOp : OpenMP_Op<"threadprivate", 1238 [AllTypesMatch<["sym_addr", "tls_addr"]>]> { 1239 let summary = "threadprivate directive"; 1240 let description = [{ 1241 The threadprivate directive specifies that variables are replicated, with 1242 each thread having its own copy. 1243 1244 The current implementation uses the OpenMP runtime to provide thread-local 1245 storage (TLS). Using the TLS feature of the LLVM IR will be supported in 1246 future. 1247 1248 This operation takes in the address of a symbol that represents the original 1249 variable and returns the address of its TLS. All occurrences of 1250 threadprivate variables in a parallel region should use the TLS returned by 1251 this operation. 1252 1253 The `sym_addr` refers to the address of the symbol, which is a pointer to 1254 the original variable. 1255 }]; 1256 1257 let arguments = (ins OpenMP_PointerLikeType:$sym_addr); 1258 let results = (outs OpenMP_PointerLikeType:$tls_addr); 1259 let assemblyFormat = [{ 1260 $sym_addr `:` type($sym_addr) `->` type($tls_addr) attr-dict 1261 }]; 1262 let extraClassDeclaration = [{ 1263 /// The number of variable operands. 1264 unsigned getNumVariableOperands() { 1265 assert(sym_addr() && "expected one variable operand"); 1266 return 1; 1267 } 1268 1269 /// The i-th variable operand passed. 1270 Value getVariableOperand(unsigned i) { 1271 assert(i == 0 && "invalid index position for an operand"); 1272 return sym_addr(); 1273 } 1274 }]; 1275} 1276 1277//===----------------------------------------------------------------------===// 1278// 2.18.1 Cancel Construct 1279//===----------------------------------------------------------------------===// 1280def CancelOp : OpenMP_Op<"cancel"> { 1281 let summary = "cancel directive"; 1282 let description = [{ 1283 The cancel construct activates cancellation of the innermost enclosing 1284 region of the type specified. 1285 }]; 1286 let arguments = (ins CancellationConstructTypeAttr:$cancellation_construct_type_val, 1287 Optional<I1>:$if_expr); 1288 let assemblyFormat = [{ `cancellation_construct_type` `(` 1289 custom<ClauseAttr>($cancellation_construct_type_val) `)` 1290 ( `if` `(` $if_expr^ `)` )? attr-dict}]; 1291 let hasVerifier = 1; 1292} 1293 1294//===----------------------------------------------------------------------===// 1295// 2.18.2 Cancellation Point Construct 1296//===----------------------------------------------------------------------===// 1297def CancellationPointOp : OpenMP_Op<"cancellationpoint"> { 1298 let summary = "cancellation point directive"; 1299 let description = [{ 1300 The cancellation point construct introduces a user-defined cancellation 1301 point at which implicit or explicit tasks check if cancellation of the 1302 innermost enclosing region of the type specified has been activated. 1303 }]; 1304 let arguments = (ins CancellationConstructTypeAttr:$cancellation_construct_type_val); 1305 let assemblyFormat = [{ `cancellation_construct_type` `(` 1306 custom<ClauseAttr>($cancellation_construct_type_val) `)` 1307 attr-dict}]; 1308 let hasVerifier = 1; 1309} 1310 1311//===----------------------------------------------------------------------===// 1312// 2.19.5.7 declare reduction Directive 1313//===----------------------------------------------------------------------===// 1314 1315def ReductionDeclareOp : OpenMP_Op<"reduction.declare", [Symbol, 1316 IsolatedFromAbove]> { 1317 let summary = "declares a reduction kind"; 1318 1319 let description = [{ 1320 Declares an OpenMP reduction kind. This requires two mandatory and one 1321 optional region. 1322 1323 1. The initializer region specifies how to initialize the thread-local 1324 reduction value. This is usually the neutral element of the reduction. 1325 For convenience, the region has an argument that contains the value 1326 of the reduction accumulator at the start of the reduction. It is 1327 expected to `omp.yield` the new value on all control flow paths. 1328 2. The reduction region specifies how to combine two values into one, i.e. 1329 the reduction operator. It accepts the two values as arguments and is 1330 expected to `omp.yield` the combined value on all control flow paths. 1331 3. The atomic reduction region is optional and specifies how two values 1332 can be combined atomically given local accumulator variables. It is 1333 expected to store the combined value in the first accumulator variable. 1334 1335 Note that the MLIR type system does not allow for type-polymorphic 1336 reductions. Separate reduction declarations should be created for different 1337 element and accumulator types. 1338 1339 For initializer and reduction regions, the operand to `omp.yield` must 1340 match the parent operation's results. 1341 }]; 1342 1343 let arguments = (ins SymbolNameAttr:$sym_name, 1344 TypeAttr:$type); 1345 1346 let regions = (region AnyRegion:$initializerRegion, 1347 AnyRegion:$reductionRegion, 1348 AnyRegion:$atomicReductionRegion); 1349 1350 let assemblyFormat = "$sym_name `:` $type attr-dict-with-keyword " 1351 "`init` $initializerRegion " 1352 "`combiner` $reductionRegion " 1353 "custom<AtomicReductionRegion>($atomicReductionRegion)"; 1354 1355 let extraClassDeclaration = [{ 1356 PointerLikeType getAccumulatorType() { 1357 if (atomicReductionRegion().empty()) 1358 return {}; 1359 1360 return atomicReductionRegion().front().getArgument(0).getType(); 1361 } 1362 }]; 1363 let hasRegionVerifier = 1; 1364} 1365 1366//===----------------------------------------------------------------------===// 1367// 2.19.5.4 reduction clause 1368//===----------------------------------------------------------------------===// 1369 1370def ReductionOp : OpenMP_Op<"reduction", [ 1371 TypesMatchWith<"value types matches accumulator element type", 1372 "accumulator", "operand", 1373 "$_self.cast<::mlir::omp::PointerLikeType>().getElementType()"> 1374 ]> { 1375 let summary = "reduction construct"; 1376 let description = [{ 1377 Indicates the value that is produced by the current reduction-participating 1378 entity for a reduction requested in some ancestor. The reduction is 1379 identified by the accumulator, but the value of the accumulator may not be 1380 updated immediately. 1381 }]; 1382 1383 let arguments= (ins AnyType:$operand, OpenMP_PointerLikeType:$accumulator); 1384 let assemblyFormat = 1385 "$operand `,` $accumulator attr-dict `:` type($accumulator)"; 1386 let hasVerifier = 1; 1387} 1388 1389#endif // OPENMP_OPS 1390