-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[mlir][OpenACC][OpenMP] Modify atomic capture to allow update/write #167963
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
base: main
Are you sure you want to change the base?
Conversation
OpenACC's C++ version has a variant of capture that permits a update followed by a write. Therefore the verifier was overly strict in this case. According to our reading of the OpenMP 6.0 spec, it appears that `atomic captured update` (page 495) also requires this form, so it seems reasonable to allow this for both languages.
|
@razvanlupusoru : can you suggest OMP reviewers for me? |
|
@llvm/pr-subscribers-mlir-openacc @llvm/pr-subscribers-mlir Author: Erich Keane (erichkeane) ChangesOpenACC's C++ version has a variant of capture that permits a update followed by a write. Therefore the verifier was overly strict in this case. According to our reading of the OpenMP 6.0 spec, it appears that Full diff: https://github.com/llvm/llvm-project/pull/167963.diff 4 Files Affected:
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
index 5b89f741e296d..8c33be7ff1747 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
@@ -2999,6 +2999,12 @@ def AtomicCaptureOp : OpenACC_Op<"atomic.capture",
acc.atomic.write ...
acc.terminator
}
+
+ acc.atomic.capture {
+ acc.atomic.update ...
+ acc.atomic.write ...
+ acc.terminator
+ }
```
}];
diff --git a/mlir/include/mlir/Dialect/OpenACCMPCommon/Interfaces/AtomicInterfaces.td b/mlir/include/mlir/Dialect/OpenACCMPCommon/Interfaces/AtomicInterfaces.td
index 223bee9ab1c27..9df6b907eb326 100644
--- a/mlir/include/mlir/Dialect/OpenACCMPCommon/Interfaces/AtomicInterfaces.td
+++ b/mlir/include/mlir/Dialect/OpenACCMPCommon/Interfaces/AtomicInterfaces.td
@@ -239,6 +239,7 @@ def AtomicCaptureOpInterface : OpInterface<"AtomicCaptureOpInterface"> {
implement one of the atomic interfaces. It can be found in one of these
forms:
`{ atomic.update, atomic.read }`
+ `{ atomic.update, atomic.write }`
`{ atomic.read, atomic.update }`
`{ atomic.read, atomic.write }`
}];
@@ -291,12 +292,15 @@ def AtomicCaptureOpInterface : OpInterface<"AtomicCaptureOpInterface"> {
auto secondWriteStmt = dyn_cast<AtomicWriteOpInterface>(secondOp);
if (!((firstUpdateStmt && secondReadStmt) ||
+ (firstUpdateStmt && secondWriteStmt) ||
(firstReadStmt && secondUpdateStmt) ||
(firstReadStmt && secondWriteStmt)))
return ops.front().emitError()
<< "invalid sequence of operations in the capture region";
- if (firstUpdateStmt && secondReadStmt &&
- firstUpdateStmt.getX() != secondReadStmt.getX())
+ if ((firstUpdateStmt && secondReadStmt &&
+ firstUpdateStmt.getX() != secondReadStmt.getX()) ||
+ (firstUpdateStmt && secondWriteStmt &&
+ firstUpdateStmt.getX() != secondWriteStmt.getX()))
return firstUpdateStmt.emitError()
<< "updated variable in atomic.update must be captured in "
"second operation";
diff --git a/mlir/test/Dialect/OpenACC/invalid.mlir b/mlir/test/Dialect/OpenACC/invalid.mlir
index 0e75894eaeceb..173c6a74545f8 100644
--- a/mlir/test/Dialect/OpenACC/invalid.mlir
+++ b/mlir/test/Dialect/OpenACC/invalid.mlir
@@ -690,7 +690,6 @@ func.func @acc_atomic_capture(%x: memref<i32>, %v: memref<i32>, %expr: i32) {
func.func @acc_atomic_capture(%x: memref<i32>, %v: memref<i32>, %expr: i32) {
acc.atomic.capture {
- // expected-error @below {{invalid sequence of operations in the capture region}}
acc.atomic.update %x : memref<i32> {
^bb0(%xval: i32):
%newval = llvm.add %xval, %expr : i32
@@ -704,6 +703,23 @@ func.func @acc_atomic_capture(%x: memref<i32>, %v: memref<i32>, %expr: i32) {
// -----
+func.func @acc_atomic_capture(%x: memref<i32>, %v: memref<i32>, %expr: i32) {
+ acc.atomic.capture {
+ // expected-error @below {{updated variable in atomic.update must be captured in second operation}}
+ acc.atomic.update %x : memref<i32> {
+ ^bb0(%xval: i32):
+ %newval = llvm.add %xval, %expr : i32
+ acc.yield %newval : i32
+ }
+ acc.atomic.write %v = %expr : memref<i32>, i32
+
+ acc.terminator
+ }
+ return
+}
+
+// -----
+
func.func @acc_atomic_capture(%x: memref<i32>, %v: memref<i32>, %expr: i32) {
acc.atomic.capture {
// expected-error @below {{invalid sequence of operations in the capture region}}
diff --git a/mlir/test/Dialect/OpenMP/invalid.mlir b/mlir/test/Dialect/OpenMP/invalid.mlir
index af24d969064ab..6224a236e7c78 100644
--- a/mlir/test/Dialect/OpenMP/invalid.mlir
+++ b/mlir/test/Dialect/OpenMP/invalid.mlir
@@ -1263,7 +1263,22 @@ func.func @omp_atomic_capture(%x: memref<i32>, %v: memref<i32>, %expr: i32) {
func.func @omp_atomic_capture(%x: memref<i32>, %v: memref<i32>, %expr: i32) {
omp.atomic.capture {
- // expected-error @below {{invalid sequence of operations in the capture region}}
+ // expected-error @below {{updated variable in atomic.update must be captured in second operation}}
+ omp.atomic.update %x : memref<i32> {
+ ^bb0(%xval: i32):
+ %newval = llvm.add %xval, %expr : i32
+ omp.yield (%newval : i32)
+ }
+ omp.atomic.write %v = %expr : memref<i32>, i32
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+func.func @omp_atomic_capture(%x: memref<i32>, %v: memref<i32>, %expr: i32) {
+ omp.atomic.capture {
omp.atomic.update %x : memref<i32> {
^bb0(%xval: i32):
%newval = llvm.add %xval, %expr : i32
@@ -1289,6 +1304,22 @@ func.func @omp_atomic_capture(%x: memref<i32>, %v: memref<i32>, %expr: i32) {
// -----
+func.func @omp_atomic_capture(%x: memref<i32>, %v: memref<i32>, %expr: i32) {
+ omp.atomic.capture {
+ omp.atomic.update %x : memref<i32> {
+ ^bb0(%xval: i32):
+ %newval = llvm.add %xval, %expr : i32
+ omp.yield (%newval : i32)
+ }
+ omp.atomic.write %x = %expr : memref<i32>, i32
+
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
func.func @omp_atomic_capture(%x: memref<i32>, %y: memref<i32>, %v: memref<i32>, %expr: i32) {
omp.atomic.capture {
// expected-error @below {{updated variable in atomic.update must be captured in second operation}}
|
|
|
||
| // ----- | ||
|
|
||
| func.func @omp_atomic_capture(%x: memref<i32>, %v: memref<i32>, %expr: i32) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this test used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is supposed to be a 'valid' config test, so I don't have diagnostics. That said, I seem to have double-added this 'is valid' test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add the "valid" tests to ops.mlir (mlir/test/Dialect/OpenACC/ops.mlir and mlir/test/Dialect/OpenMP/ops.mlir)?
The invalid tests look great to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah! Yes, I did that. Thanks for the help on where to put those!
razvanlupusoru
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great to me! Can you please allow a bit of time for the omp reviewers to take a look also? Thank you for this!
OpenACC's C++ version has a variant of capture that permits a update followed by a write. Therefore the verifier was overly strict in this case.
According to our reading of the OpenMP 6.0 spec, it appears that
atomic captured update(page 495) also requires this form, so it seems reasonable to allow this for both languages.