Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[mlir][OpenMP] Extend omp.private with a dealloc region #90456

Merged
merged 4 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,9 @@ def PrivateClauseOp : OpenMP_Op<"private", [IsolatedFromAbove]> {
let description = [{
This operation provides a declaration of how to implement the
[first]privatization of a variable. The dialect users should provide
information about how to create an instance of the type in the alloc region
and how to initialize the copy from the original item in the copy region.
information about how to create an instance of the type in the alloc region,
how to initialize the copy from the original item in the copy region, and if
needed, how to deallocate allocated memory in the dealloc region.

Examples:

Expand Down Expand Up @@ -187,10 +188,23 @@ def PrivateClauseOp : OpenMP_Op<"private", [IsolatedFromAbove]> {
}
```

* `private(x)` for "allocatables" would be emitted as:
```mlir
omp.private {type = private} @x.privatizer : !some.type alloc {
^bb0(%arg0: !some.type):
%0 = ... allocate proper memory for the private clone ...
omp.yield(%0 : !fir.ref<i32>)
} deaclloc {
ergawy marked this conversation as resolved.
Show resolved Hide resolved
^bb0(%arg0: !some.type):
... deallocate allocated memory ...
omp.yield
}
```

There are no restrictions on the body except for:
- The `alloc` region has a single argument.
- The `alloc` & `dealloc` regions have a single argument.
- The `copy` region has 2 arguments.
- Both regions are terminated by `omp.yield` ops.
- All 3 regions are terminated by `omp.yield` ops.
ergawy marked this conversation as resolved.
Show resolved Hide resolved
The above restrictions and other obvious restrictions (e.g. verifying the
type of yielded values) are verified by the custom op verifier. The actual
contents of the blocks inside both regions are not verified.
Expand All @@ -212,12 +226,14 @@ def PrivateClauseOp : OpenMP_Op<"private", [IsolatedFromAbove]> {
DataSharingClauseTypeAttr:$data_sharing_type);

let regions = (region MinSizedRegion<1>:$alloc_region,
AnyRegion:$copy_region);
AnyRegion:$copy_region,
AnyRegion:$dealloc_region);

let assemblyFormat = [{
$data_sharing_type $sym_name `:` $type
`alloc` $alloc_region
(`copy` $copy_region^)?
(`dealloc` $dealloc_region^)?
attr-dict
}];

Expand Down
29 changes: 24 additions & 5 deletions mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2258,17 +2258,28 @@ void PrivateClauseOp::build(OpBuilder &odsBuilder, OperationState &odsState,
LogicalResult PrivateClauseOp::verify() {
Type symType = getType();

auto verifyTerminator = [&](Operation *terminator) -> LogicalResult {
auto verifyTerminator = [&](Operation *terminator,
bool yieldsValue) -> LogicalResult {
if (!terminator->getBlock()->getSuccessors().empty())
return success();

if (!llvm::isa<YieldOp>(terminator))
return mlir::emitError(terminator->getLoc())
<< "expected exit block terminator to be an `omp.yield` op.";



YieldOp yieldOp = llvm::cast<YieldOp>(terminator);
TypeRange yieldedTypes = yieldOp.getResults().getTypes();

if (!yieldsValue) {
if (yieldedTypes.empty())
return success();

return mlir::emitError(terminator->getLoc())
<< "Did not expect any values to be yielded.";
}

if (yieldedTypes.size() == 1 && yieldedTypes.front() == symType)
return success();

Expand All @@ -2285,7 +2296,8 @@ LogicalResult PrivateClauseOp::verify() {
};

auto verifyRegion = [&](Region &region, unsigned expectedNumArgs,
StringRef regionName) -> LogicalResult {
StringRef regionName,
bool yieldsValue) -> LogicalResult {
assert(!region.empty());

if (region.getNumArguments() != expectedNumArgs)
Expand All @@ -2299,14 +2311,15 @@ LogicalResult PrivateClauseOp::verify() {
if (!block.mightHaveTerminator())
continue;

if (failed(verifyTerminator(block.getTerminator())))
if (failed(verifyTerminator(block.getTerminator(), yieldsValue)))
return failure();
}

return success();
};

if (failed(verifyRegion(getAllocRegion(), /*expectedNumArgs=*/1, "alloc")))
if (failed(verifyRegion(getAllocRegion(), /*expectedNumArgs=*/1, "alloc",
/*yieldsValue=*/true)))
return failure();

DataSharingClauseType dsType = getDataSharingType();
Expand All @@ -2319,7 +2332,13 @@ LogicalResult PrivateClauseOp::verify() {
"`firstprivate` clauses require both `alloc` and `copy` regions.");

if (dsType == DataSharingClauseType::FirstPrivate &&
failed(verifyRegion(getCopyRegion(), /*expectedNumArgs=*/2, "copy")))
failed(verifyRegion(getCopyRegion(), /*expectedNumArgs=*/2, "copy",
/*yieldsValue=*/true)))
return failure();

if (!getDeallocRegion().empty() &&
failed(verifyRegion(getDeallocRegion(), /*expectedNumArgs=*/1, "dealloc",
/*yieldsValue=*/false)))
return failure();

return success();
Expand Down
24 changes: 23 additions & 1 deletion mlir/test/Dialect/OpenMP/invalid.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -2151,6 +2151,17 @@ omp.private {type = private} @x.privatizer : i32 alloc {

// -----

omp.private {type = private} @x.privatizer : f32 alloc {
^bb0(%arg0: f32):
omp.yield(%arg0 : f32)
} dealloc {
^bb0(%arg0: f32):
// expected-error @below {{Did not expect any values to be yielded.}}
omp.yield(%arg0 : f32)
}

// -----

omp.private {type = private} @x.privatizer : i32 alloc {
^bb0(%arg0: i32):
// expected-error @below {{expected exit block terminator to be an `omp.yield` op.}}
Expand Down Expand Up @@ -2178,6 +2189,17 @@ omp.private {type = firstprivate} @x.privatizer : f32 alloc {

// -----

// expected-error @below {{`dealloc`: expected 1 region arguments, got: 2}}
omp.private {type = private} @x.privatizer : f32 alloc {
^bb0(%arg0: f32):
omp.yield(%arg0 : f32)
} dealloc {
^bb0(%arg0: f32, %arg1: f32):
omp.yield
}

// -----

// expected-error @below {{`private` clauses require only an `alloc` region.}}
omp.private {type = private} @x.privatizer : f32 alloc {
^bb0(%arg0: f32):
Expand Down Expand Up @@ -2249,4 +2271,4 @@ func.func @undefined_privatizer(%arg0: !llvm.ptr) {
omp.terminator
}) : (!llvm.ptr) -> ()
return
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit:

}
15 changes: 15 additions & 0 deletions mlir/test/Dialect/OpenMP/ops.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -2492,11 +2492,22 @@ func.func @parallel_op_privatizers(%arg0: !llvm.ptr, %arg1: !llvm.ptr) {
return
}

// CHECK-LABEL: omp.private {type = private} @a.privatizer : !llvm.ptr alloc {
omp.private {type = private} @a.privatizer : !llvm.ptr alloc {
// CHECK: ^bb0(%{{.*}}: {{.*}}):
^bb0(%arg0: !llvm.ptr):
omp.yield(%arg0 : !llvm.ptr)
}

// CHECK-LABEL: omp.private {type = private} @x.privatizer : !llvm.ptr alloc {
omp.private {type = private} @x.privatizer : !llvm.ptr alloc {
// CHECK: ^bb0(%{{.*}}: {{.*}}):
^bb0(%arg0: !llvm.ptr):
omp.yield(%arg0 : !llvm.ptr)
} dealloc {
// CHECK: ^bb0(%{{.*}}: {{.*}}):
^bb0(%arg0: !llvm.ptr):
omp.yield
}

// CHECK-LABEL: omp.private {type = firstprivate} @y.privatizer : !llvm.ptr alloc {
Expand All @@ -2509,6 +2520,10 @@ omp.private {type = firstprivate} @y.privatizer : !llvm.ptr alloc {
// CHECK: ^bb0(%{{.*}}: {{.*}}, %{{.*}}: {{.*}}):
^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr):
omp.yield(%arg0 : !llvm.ptr)
} dealloc {
// CHECK: ^bb0(%{{.*}}: {{.*}}):
^bb0(%arg0: !llvm.ptr):
omp.yield
}

// CHECK-LABEL: parallel_op_reduction_and_private
Expand Down
Loading