diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td --- a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td +++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td @@ -229,6 +229,46 @@ let assemblyFormat = "attr-dict"; } +//===----------------------------------------------------------------------===// +// 2.6.6 Exit Data Directive +//===----------------------------------------------------------------------===// + +def OpenACC_ExitDataOp : OpenACC_Op<"exit_data", [AttrSizedOperandSegments]> { + let summary = "exit data operation"; + + let description = [{ + The "acc.exit_data" operation represents the OpenACC exit data directive. + + Example: + + ```mlir + acc.exit_data delete(%d1 : memref<10xf32>) attributes {async} + ``` + }]; + + let arguments = (ins Optional:$ifCond, + Optional:$asyncOperand, + UnitAttr:$async, + Optional:$waitDevnum, + Variadic:$waitOperands, + UnitAttr:$wait, + Variadic:$copyoutOperands, + Variadic:$deleteOperands, + Variadic:$detachOperands, + UnitAttr:$finalize); + + let assemblyFormat = [{ + ( `if` `(` $ifCond^ `)` )? + ( `async` `(` $asyncOperand^ `:` type($asyncOperand) `)` )? + ( `wait_devnum` `(` $waitDevnum^ `:` type($waitDevnum) `)` )? + ( `wait` `(` $waitOperands^ `:` type($waitOperands) `)` )? + ( `copyout` `(` $copyoutOperands^ `:` type($copyoutOperands) `)` )? + ( `delete` `(` $deleteOperands^ `:` type($deleteOperands) `)` )? + ( `detach` `(` $detachOperands^ `:` type($detachOperands) `)` )? + attr-dict-with-keyword + }]; +} + //===----------------------------------------------------------------------===// // 2.9 loop Construct //===----------------------------------------------------------------------===// diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp --- a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp +++ b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp @@ -652,6 +652,36 @@ return success(); } +//===----------------------------------------------------------------------===// +// ExitDataOp +//===----------------------------------------------------------------------===// + +static LogicalResult verify(acc::ExitDataOp op) { + // 2.6.6. Data Exit Directive restriction + // At least one copyout, delete, or detach clause must appear on an exit data + // directive. + if (op.copyoutOperands().empty() && op.deleteOperands().empty() && + op.detachOperands().empty()) + return op.emitError( + "at least one operand in copyout, delete or detach must appear on the " + "exit data operation"); + + // The async attribute represent the async clause without value. Therefore the + // attribute and operand cannot appear at the same time. + if (op.asyncOperand() && op.async()) + return op.emitError("async attribute cannot appear with asyncOperand"); + + // The wait attribute represent the wait clause without values. Therefore the + // attribute and operands cannot appear at the same time. + if (!op.waitOperands().empty() && op.wait()) + return op.emitError("wait attribute cannot appear with waitOperands"); + + if (op.waitDevnum() && op.waitOperands().empty()) + return op.emitError("wait_devnum cannot appear without waitOperands"); + + return success(); +} + //===----------------------------------------------------------------------===// // InitOp //===----------------------------------------------------------------------===// diff --git a/mlir/test/Dialect/OpenACC/invalid.mlir b/mlir/test/Dialect/OpenACC/invalid.mlir --- a/mlir/test/Dialect/OpenACC/invalid.mlir +++ b/mlir/test/Dialect/OpenACC/invalid.mlir @@ -153,3 +153,29 @@ }) : () -> () acc.yield } + +// ----- + +// expected-error@+1 {{at least one operand in copyout, delete or detach must appear on the exit data operation}} +acc.exit_data attributes {async} + +// ----- + +%cst = constant 1 : index +%value = alloc() : memref<10xf32> +// expected-error@+1 {{async attribute cannot appear with asyncOperand}} +acc.exit_data async(%cst: index) delete(%value : memref<10xf32>) attributes {async} + +// ----- + +%cst = constant 1 : index +%value = alloc() : memref<10xf32> +// expected-error@+1 {{wait attribute cannot appear with waitOperands}} +acc.exit_data wait(%cst: index) delete(%value : memref<10xf32>) attributes {wait} + +// ----- + +%cst = constant 1 : index +%value = alloc() : memref<10xf32> +// expected-error@+1 {{wait_devnum cannot appear without waitOperands}} +acc.exit_data wait_devnum(%cst: index) delete(%value : memref<10xf32>) diff --git a/mlir/test/Dialect/OpenACC/ops.mlir b/mlir/test/Dialect/OpenACC/ops.mlir --- a/mlir/test/Dialect/OpenACC/ops.mlir +++ b/mlir/test/Dialect/OpenACC/ops.mlir @@ -648,3 +648,39 @@ // CHECK: acc.shutdown device_num([[I32VALUE]] : i32) // CHECK: acc.shutdown device_num([[IDXVALUE]] : index) // CHECK: acc.shutdown if([[IFCOND]]) + +// ----- + +func @testexitdataop(%a: memref<10xf32>, %b: memref<10xf32>, %c: memref<10x10xf32>) -> () { + %ifCond = constant true + %i64Value = constant 1 : i64 + %i32Value = constant 1 : i32 + %idxValue = constant 1 : index + + acc.exit_data copyout(%a : memref<10xf32>) + acc.exit_data delete(%a : memref<10xf32>) + acc.exit_data delete(%a : memref<10xf32>) attributes {async,finalize} + acc.exit_data detach(%a : memref<10xf32>) + acc.exit_data copyout(%a : memref<10xf32>) attributes {async} + acc.exit_data delete(%a : memref<10xf32>) attributes {wait} + acc.exit_data async(%i64Value : i64) copyout(%a : memref<10xf32>) + acc.exit_data if(%ifCond) copyout(%a : memref<10xf32>) + acc.exit_data wait_devnum(%i64Value: i64) wait(%i32Value, %idxValue : i32, index) copyout(%a : memref<10xf32>) + + return +} + +// CHECK: func @testexitdataop([[ARGA:%.*]]: memref<10xf32>, [[ARGB:%.*]]: memref<10xf32>, [[ARGC:%.*]]: memref<10x10xf32>) { +// CHECK: [[IFCOND1:%.*]] = constant true +// CHECK: [[I64VALUE:%.*]] = constant 1 : i64 +// CHECK: [[I32VALUE:%.*]] = constant 1 : i32 +// CHECK: [[IDXVALUE:%.*]] = constant 1 : index +// CHECK: acc.exit_data copyout([[ARGA]] : memref<10xf32>) +// CHECK: acc.exit_data delete([[ARGA]] : memref<10xf32>) +// CHECK: acc.exit_data delete([[ARGA]] : memref<10xf32>) attributes {async, finalize} +// CHECK: acc.exit_data detach([[ARGA]] : memref<10xf32>) +// CHECK: acc.exit_data copyout([[ARGA]] : memref<10xf32>) attributes {async} +// CHECK: acc.exit_data delete([[ARGA]] : memref<10xf32>) attributes {wait} +// CHECK: acc.exit_data async([[I64VALUE]] : i64) copyout([[ARGA]] : memref<10xf32>) +// CHECK: acc.exit_data if([[IFCOND]]) copyout([[ARGA]] : memref<10xf32>) +// CHECK: acc.exit_data wait_devnum([[I64VALUE]] : i64) wait([[I32VALUE]], [[IDXVALUE]] : i32, index) copyout([[ARGA]] : memref<10xf32>)