@@ -3485,6 +3485,137 @@ def fir_BoxTotalElementsOp
34853485 let hasCanonicalizer = 1;
34863486}
34873487
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 a 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 local and local_init 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 local_init.
3523+ ```
3524+ fir.local {type = local} @x.localizer : i32
3525+ ```
3526+
3527+ * `local_init(x)` would be emitted as:
3528+ ```
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+ ```
3540+ fir.local {type = local} @x.localizer : !some.type init {
3541+ ^bb0(%arg0: !fir.ref<!some.type>, %arg1: !fir.ref<!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 : !fir.ref<!some.type>)
3549+ } dealloc {
3550+ ^bb0(%arg0: !fir.ref<!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+
34883619def fir_DoConcurrentOp : fir_Op<"do_concurrent",
34893620 [SingleBlock, AutomaticAllocationScope]> {
34903621 let summary = "do concurrent loop wrapper";
0 commit comments