[Mlir-commits] [mlir] 320dc8c - [mlir][OpenMP] Added omp.atomic.capture operation
Shraiysh Vaishay
llvmlistbot at llvm.org
Mon Jan 24 22:56:05 PST 2022
Author: Shraiysh Vaishay
Date: 2022-01-25T12:25:54+05:30
New Revision: 320dc8c4df74ccce318c2c9bdb9b2937438711ac
URL: https://github.com/llvm/llvm-project/commit/320dc8c4df74ccce318c2c9bdb9b2937438711ac
DIFF: https://github.com/llvm/llvm-project/commit/320dc8c4df74ccce318c2c9bdb9b2937438711ac.diff
LOG: [mlir][OpenMP] Added omp.atomic.capture operation
This patch supports the atomic construct (capture) following section 2.17.7 of OpenMP 5.0 standard. Also added tests for the same.
Reviewed By: peixin, kiranchandramohan
Differential Revision: https://reviews.llvm.org/D115851
Added:
Modified:
mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
mlir/test/Dialect/OpenMP/invalid.mlir
mlir/test/Dialect/OpenMP/ops.mlir
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
index 384d629c4bf1d..311513f1682a6 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
@@ -708,6 +708,50 @@ def AtomicUpdateOp : OpenMP_Op<"atomic.update"> {
let verifier = [{ return verifyAtomicUpdateOp(*this); }];
}
+def AtomicCaptureOp : OpenMP_Op<"atomic.capture",
+ [SingleBlockImplicitTerminator<"TerminatorOp">]> {
+ let summary = "performs an atomic capture";
+ let description = [{
+ This operation performs an atomic capture.
+
+ `hint` is the value of hint (as used in the hint clause). It is a compile
+ time constant. As the name suggests, this is just a hint for optimization.
+
+ `memory_order` indicates the memory ordering behavior of the construct. It
+ can be one of `seq_cst`, `acq_rel`, `release`, `acquire` or `relaxed`.
+
+ The region has the following allowed forms:
+
+ ```
+ omp.atomic.capture {
+ omp.atomic.update ...
+ omp.atomic.read ...
+ omp.terminator
+ }
+
+ omp.atomic.capture {
+ omp.atomic.read ...
+ omp.atomic.update ...
+ omp.terminator
+ }
+
+ omp.atomic.capture {
+ omp.atomic.read ...
+ omp.atomic.write ...
+ omp.terminator
+ }
+ ```
+
+ }];
+
+ let arguments = (ins DefaultValuedAttr<I64Attr, "0">:$hint,
+ OptionalAttr<MemoryOrderKind>:$memory_order);
+ let regions = (region SizedRegion<1>:$region);
+ let parser = [{ return parseAtomicCaptureOp(parser, result); }];
+ let printer = [{ return printAtomicCaptureOp(p, *this); }];
+ let verifier = [{ return verifyAtomicCaptureOp(*this); }];
+}
+
//===----------------------------------------------------------------------===//
// 2.19.5.7 declare reduction Directive
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
index f0c5cdc6eb63e..1eeee3f65f3ba 100644
--- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
+++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
@@ -1539,6 +1539,68 @@ static LogicalResult verifyAtomicUpdateOp(AtomicUpdateOp op) {
return success();
}
+//===----------------------------------------------------------------------===//
+// AtomicCaptureOp
+//===----------------------------------------------------------------------===//
+
+/// Parser for AtomicCaptureOp
+static LogicalResult parseAtomicCaptureOp(OpAsmParser &parser,
+ OperationState &result) {
+ SmallVector<ClauseType> clauses = {memoryOrderClause, hintClause};
+ SmallVector<int> segments;
+ if (parseClauses(parser, result, clauses, segments) ||
+ parser.parseRegion(*result.addRegion()))
+ return failure();
+ return success();
+}
+
+/// Printer for AtomicCaptureOp
+static void printAtomicCaptureOp(OpAsmPrinter &p, AtomicCaptureOp op) {
+ if (op.memory_order())
+ p << "memory_order(" << op.memory_order() << ") ";
+ if (op.hintAttr())
+ printSynchronizationHint(p, op, op.hintAttr());
+ p.printRegion(op.region());
+}
+
+/// Verifier for AtomicCaptureOp
+static LogicalResult verifyAtomicCaptureOp(AtomicCaptureOp op) {
+ Block::OpListType &ops = op.region().front().getOperations();
+ if (ops.size() != 3)
+ return emitError(op.getLoc())
+ << "expected three operations in omp.atomic.capture region (one "
+ "terminator, and two atomic ops)";
+ auto &firstOp = ops.front();
+ auto &secondOp = *ops.getNextNode(firstOp);
+ auto firstReadStmt = dyn_cast<AtomicReadOp>(firstOp);
+ auto firstUpdateStmt = dyn_cast<AtomicUpdateOp>(firstOp);
+ auto secondReadStmt = dyn_cast<AtomicReadOp>(secondOp);
+ auto secondUpdateStmt = dyn_cast<AtomicUpdateOp>(secondOp);
+ auto secondWriteStmt = dyn_cast<AtomicWriteOp>(secondOp);
+
+ if (!((firstUpdateStmt && secondReadStmt) ||
+ (firstReadStmt && secondUpdateStmt) ||
+ (firstReadStmt && secondWriteStmt)))
+ return emitError(ops.front().getLoc())
+ << "invalid sequence of operations in the capture region";
+ if (firstUpdateStmt && secondReadStmt &&
+ firstUpdateStmt.x() != secondReadStmt.x())
+ return emitError(firstUpdateStmt.getLoc())
+ << "updated variable in omp.atomic.update must be captured in "
+ "second operation";
+ if (firstReadStmt && secondUpdateStmt &&
+ firstReadStmt.x() != secondUpdateStmt.x())
+ return emitError(firstReadStmt.getLoc())
+ << "captured variable in omp.atomic.read must be updated in second "
+ "operation";
+ if (firstReadStmt && secondWriteStmt &&
+ firstReadStmt.x() != secondWriteStmt.address())
+ return emitError(firstReadStmt.getLoc())
+ << "captured variable in omp.atomic.read must be updated in "
+ "second operation";
+ return success();
+}
+
#define GET_ATTRDEF_CLASSES
#include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.cpp.inc"
diff --git a/mlir/test/Dialect/OpenMP/invalid.mlir b/mlir/test/Dialect/OpenMP/invalid.mlir
index 2875c61013b75..d0f66c3218cbc 100644
--- a/mlir/test/Dialect/OpenMP/invalid.mlir
+++ b/mlir/test/Dialect/OpenMP/invalid.mlir
@@ -650,6 +650,122 @@ func @omp_atomic_update5(%x: memref<i32>, %expr: i32) {
// -----
+func @omp_atomic_capture(%x: memref<i32>, %v: memref<i32>, %expr: i32) {
+ // expected-error @below {{expected three operations in omp.atomic.capture region}}
+ omp.atomic.capture {
+ omp.atomic.read %v = %x : memref<i32>
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+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}}
+ omp.atomic.read %v = %x : memref<i32>
+ omp.atomic.read %v = %x : memref<i32>
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+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}}
+ omp.atomic.update %x = %x add %expr : memref<i32>, i32
+ omp.atomic.update %x = %x sub %expr : memref<i32>, i32
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+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}}
+ omp.atomic.write %x = %expr : memref<i32>, i32
+ omp.atomic.write %x = %expr : memref<i32>, i32
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+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}}
+ omp.atomic.write %x = %expr : memref<i32>, i32
+ omp.atomic.update %x = %x add %expr : memref<i32>, i32
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+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}}
+ omp.atomic.update %x = %x add %expr : memref<i32>, i32
+ omp.atomic.write %x = %expr : memref<i32>, i32
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+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}}
+ omp.atomic.write %x = %expr : memref<i32>, i32
+ omp.atomic.read %v = %x : memref<i32>
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+func @omp_atomic_capture(%x: memref<i32>, %y: memref<i32>, %v: memref<i32>, %expr: i32) {
+ omp.atomic.capture {
+ // expected-error @below {{updated variable in omp.atomic.update must be captured in second operation}}
+ omp.atomic.update %x = %x add %expr : memref<i32>, i32
+ omp.atomic.read %v = %y : memref<i32>
+ omp.terminator
+ }
+}
+
+// -----
+
+func @omp_atomic_capture(%x: memref<i32>, %y: memref<i32>, %v: memref<i32>, %expr: i32) {
+ omp.atomic.capture {
+ // expected-error @below {{captured variable in omp.atomic.read must be updated in second operation}}
+ omp.atomic.read %v = %y : memref<i32>
+ omp.atomic.update %x = %x add %expr : memref<i32>, i32
+ omp.terminator
+ }
+}
+
+// -----
+
+func @omp_atomic_capture(%x: memref<i32>, %y: memref<i32>, %v: memref<i32>, %expr: i32) {
+ omp.atomic.capture {
+ // expected-error @below {{captured variable in omp.atomic.read must be updated in second operation}}
+ omp.atomic.read %v = %x : memref<i32>
+ omp.atomic.write %y = %expr : memref<i32>, i32
+ omp.terminator
+ }
+}
+
+// -----
+
func @omp_sections(%data_var1 : memref<i32>, %data_var2 : memref<i32>, %data_var3 : memref<i32>) -> () {
// expected-error @below {{operand used in both private and firstprivate clauses}}
omp.sections private(%data_var1 : memref<i32>) firstprivate(%data_var1 : memref<i32>) {
diff --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir
index 950f3d0d472a5..96a0b427123f3 100644
--- a/mlir/test/Dialect/OpenMP/ops.mlir
+++ b/mlir/test/Dialect/OpenMP/ops.mlir
@@ -584,6 +584,42 @@ func @omp_atomic_update(%x : memref<i32>, %expr : i32, %xBool : memref<i1>, %exp
return
}
+// CHECK-LABEL: omp_atomic_capture
+// CHECK-SAME: (%[[v:.*]]: memref<i32>, %[[x:.*]]: memref<i32>, %[[expr:.*]]: i32)
+func @omp_atomic_capture(%v: memref<i32>, %x: memref<i32>, %expr: i32) {
+ // CHECK: omp.atomic.capture{
+ // CHECK-NEXT: omp.atomic.update %[[x]] = %[[expr]] add %[[x]] : memref<i32>, i32
+ // CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref<i32>
+ // CHECK-NEXT: omp.terminator
+ // CHECK-NEXT: }
+ omp.atomic.capture{
+ omp.atomic.update %x = %expr add %x : memref<i32>, i32
+ omp.atomic.read %v = %x : memref<i32>
+ omp.terminator
+ }
+ // CHECK: omp.atomic.capture{
+ // CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref<i32>
+ // CHECK-NEXT: omp.atomic.update %[[x]] = %[[expr]] add %[[x]] : memref<i32>, i32
+ // CHECK-NEXT: omp.terminator
+ // CHECK-NEXT: }
+ omp.atomic.capture{
+ omp.atomic.read %v = %x : memref<i32>
+ omp.atomic.update %x = %expr add %x : memref<i32>, i32
+ omp.terminator
+ }
+ // CHECK: omp.atomic.capture{
+ // CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref<i32>
+ // CHECK-NEXT: omp.atomic.write %[[x]] = %[[expr]] : memref<i32>, i32
+ // CHECK-NEXT: omp.terminator
+ // CHECK-NEXT: }
+ omp.atomic.capture{
+ omp.atomic.read %v = %x : memref<i32>
+ omp.atomic.write %x = %expr : memref<i32>, i32
+ omp.terminator
+ }
+ return
+}
+
// CHECK-LABEL: omp_sectionsop
func @omp_sectionsop(%data_var1 : memref<i32>, %data_var2 : memref<i32>,
%data_var3 : memref<i32>, %redn_var : !llvm.ptr<f32>) {
More information about the Mlir-commits
mailing list