@@ -3485,6 +3485,137 @@ def fir_BoxTotalElementsOp
3485
3485
let hasCanonicalizer = 1;
3486
3486
}
3487
3487
3488
+ def YieldOp : fir_Op<"yield",
3489
+ [Pure, ReturnLike, Terminator,
3490
+ ParentOneOf<["LocalitySpecifierOp"]>]> {
3491
+ let summary = "loop yield and termination operation";
3492
+ let description = [{
3493
+ "fir.yield" yields SSA values from the fir dialect op region and
3494
+ terminates the region. The semantics of how the values are yielded is
3495
+ defined by the parent operation.
3496
+ }];
3497
+
3498
+ let arguments = (ins Variadic<AnyType>:$results);
3499
+
3500
+ let builders = [
3501
+ OpBuilder<(ins), [{ build($_builder, $_state, {}); }]>
3502
+ ];
3503
+
3504
+ let assemblyFormat = "( `(` $results^ `:` type($results) `)` )? attr-dict";
3505
+ }
3506
+
3507
+ def fir_LocalitySpecifierOp : fir_Op<"local", [IsolatedFromAbove]> {
3508
+ let summary = "Provides declaration of [first]private logic.";
3509
+ let description = [{
3510
+ This operation provides a declaration of how to implement the
3511
+ localization of a variable. The dialect users should provide
3512
+ which type should be allocated for this variable. The allocated (usually by
3513
+ alloca) variable is passed to the initialization region which does everything
3514
+ else (e.g. initialization of Fortran runtime descriptors). Information about
3515
+ how to initialize the copy from the original item should be given in the
3516
+ copy region, and if needed, how to deallocate memory (allocated by the
3517
+ initialization region) in the dealloc region.
3518
+
3519
+ Examples:
3520
+
3521
+ * `local(x)` would not need any regions because no initialization is
3522
+ required by the standard for i32 variables and this is not firstprivate.
3523
+ ```mlir
3524
+ fir.local {type = local} @x.localizer : i32
3525
+ ```
3526
+
3527
+ * `local_init(x)` would be emitted as:
3528
+ ```mlir
3529
+ fir.local {type = local_init} @x.localizer : i32 copy {
3530
+ ^bb0(%arg0: !fir.ref<i32>, %arg1: !fir.ref<i32>):
3531
+ // %arg0 is the original host variable.
3532
+ // %arg1 represents the memory allocated for this private variable.
3533
+ ... copy from host to the localized clone ....
3534
+ fir.yield(%arg1 : !fir.ref<i32>)
3535
+ }
3536
+ ```
3537
+
3538
+ * `local(x)` for "allocatables" would be emitted as:
3539
+ ```mlir
3540
+ fir.local {type = local} @x.privatizer : !some.type init {
3541
+ ^bb0(%arg0: !some.pointer<!some.type>, %arg1: !some.pointer<!some.type>):
3542
+ // initialize %arg1, using %arg0 as a mold for allocations.
3543
+ // For example if %arg0 is a heap allocated array with a runtime determined
3544
+ // length and !some.type is a runtime type descriptor, the init region
3545
+ // will read the array length from %arg0, and heap allocate an array of the
3546
+ // right length and initialize %arg1 to contain the array allocation and
3547
+ // length.
3548
+ fir.yield(%arg1 : !some.pointer<!some.type>)
3549
+ } dealloc {
3550
+ ^bb0(%arg0: !some.pointer<!some.type>):
3551
+ // ... deallocate memory allocated by the init region...
3552
+ // In the example above, this will free the heap allocated array data.
3553
+ fir.yield
3554
+ }
3555
+ ```
3556
+
3557
+ There are no restrictions on the body except for:
3558
+ - The `dealloc` regions has a single argument.
3559
+ - The `init` & `copy` regions have 2 arguments.
3560
+ - All three regions are terminated by `fir.yield` ops.
3561
+ The above restrictions and other obvious restrictions (e.g. verifying the
3562
+ type of yielded values) are verified by the custom op verifier. The actual
3563
+ contents of the blocks inside all regions are not verified.
3564
+
3565
+ Instances of this op would then be used by ops that model directives that
3566
+ accept data-sharing attribute clauses.
3567
+
3568
+ The `sym_name` attribute provides a symbol by which the privatizer op can be
3569
+ referenced by other dialect ops.
3570
+
3571
+ The `type` attribute is the type of the value being localized. This type
3572
+ will be implicitly allocated in MLIR->LLVMIR conversion and passed as the
3573
+ second argument to the init region. Therefore the type of arguments to
3574
+ the regions should be a type which represents a pointer to `type`.
3575
+
3576
+ The `locality_specifier_type` attribute specifies whether the localized
3577
+ corresponds to a `local` or a `local_init` specifier.
3578
+ }];
3579
+
3580
+ let arguments = (ins SymbolNameAttr:$sym_name,
3581
+ TypeAttrOf<AnyType>:$type,
3582
+ LocalitySpecifierTypeAttr:$locality_specifier_type);
3583
+
3584
+ let regions = (region AnyRegion:$init_region,
3585
+ AnyRegion:$copy_region,
3586
+ AnyRegion:$dealloc_region);
3587
+
3588
+ let assemblyFormat = [{
3589
+ $locality_specifier_type $sym_name `:` $type
3590
+ (`init` $init_region^)?
3591
+ (`copy` $copy_region^)?
3592
+ (`dealloc` $dealloc_region^)?
3593
+ attr-dict
3594
+ }];
3595
+
3596
+ let builders = [
3597
+ OpBuilder<(ins CArg<"mlir::TypeRange">:$result,
3598
+ CArg<"mlir::StringAttr">:$sym_name,
3599
+ CArg<"mlir::TypeAttr">:$type)>
3600
+ ];
3601
+
3602
+ let extraClassDeclaration = [{
3603
+ /// Get the type for arguments to nested regions. This should
3604
+ /// generally be either the same as getType() or some pointer
3605
+ /// type (pointing to the type allocated by this op).
3606
+ /// This method will return Type{nullptr} if there are no nested
3607
+ /// regions.
3608
+ mlir::Type getArgType() {
3609
+ for (mlir::Region *region : getRegions())
3610
+ for (mlir::Type ty : region->getArgumentTypes())
3611
+ return ty;
3612
+ return nullptr;
3613
+ }
3614
+ }];
3615
+
3616
+ let hasRegionVerifier = 1;
3617
+ }
3618
+
3488
3619
def fir_DoConcurrentOp : fir_Op<"do_concurrent",
3489
3620
[SingleBlock, AutomaticAllocationScope]> {
3490
3621
let summary = "do concurrent loop wrapper";
0 commit comments