[mlir][openacc] Introduce acc.enter_data operation
authorValentin Clement <clementval@gmail.com>
Mon, 12 Oct 2020 01:26:54 +0000 (21:26 -0400)
committerclementval <clementval@gmail.com>
Mon, 12 Oct 2020 01:27:06 +0000 (21:27 -0400)
This patch introduces the acc.enter_data operation that represents an OpenACC Enter Data directive.
Operands and attributes are dervied from clauses in the spec 2.6.6.

Reviewed By: kiranchandramohan

Differential Revision: https://reviews.llvm.org/D88941

mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
mlir/test/Dialect/OpenACC/invalid.mlir
mlir/test/Dialect/OpenACC/ops.mlir

index 237aa06..c217d9a 100644 (file)
@@ -230,6 +230,48 @@ def OpenACC_TerminatorOp : OpenACC_Op<"terminator", [Terminator]> {
 }
 
 //===----------------------------------------------------------------------===//
+// 2.6.6 Enter Data Directive
+//===----------------------------------------------------------------------===//
+
+def OpenACC_EnterDataOp : OpenACC_Op<"enter_data", [AttrSizedOperandSegments]> {
+  let summary = "enter data operation";
+
+  let description = [{
+    The "acc.enter_data" operation represents the OpenACC enter data directive.
+
+    Example:
+
+    ```mlir
+    acc.enter_data create(%d1 : memref<10xf32>) attributes {async}
+    ```
+  }];
+
+  let arguments = (ins Optional<I1>:$ifCond,
+                       Optional<IntOrIndex>:$asyncOperand,
+                       UnitAttr:$async,
+                       Optional<IntOrIndex>:$waitDevnum,
+                       Variadic<IntOrIndex>:$waitOperands,
+                       UnitAttr:$wait,
+                       Variadic<AnyType>:$copyinOperands,
+                       Variadic<AnyType>:$createOperands,
+                       Variadic<AnyType>:$createZeroOperands,
+                       Variadic<AnyType>:$attachOperands);
+
+  let assemblyFormat = [{
+    ( `if` `(` $ifCond^ `)` )?
+    ( `async` `(` $asyncOperand^ `:` type($asyncOperand) `)` )?
+    ( `wait_devnum` `(` $waitDevnum^ `:` type($waitDevnum) `)` )?
+    ( `wait` `(` $waitOperands^ `:` type($waitOperands) `)` )?
+    ( `copyin` `(` $copyinOperands^ `:` type($copyinOperands) `)` )?
+    ( `create` `(` $createOperands^ `:` type($createOperands) `)` )?
+    ( `create_zero` `(` $createZeroOperands^ `:`
+        type($createZeroOperands) `)` )?
+    ( `attach` `(` $attachOperands^ `:` type($attachOperands) `)` )?
+    attr-dict-with-keyword
+  }];
+}
+
+//===----------------------------------------------------------------------===//
 // 2.6.6 Exit Data Directive
 //===----------------------------------------------------------------------===//
 
index ed70669..ae2d1c1 100644 (file)
@@ -683,6 +683,36 @@ static LogicalResult verify(acc::ExitDataOp op) {
 }
 
 //===----------------------------------------------------------------------===//
+// DataEnterOp
+//===----------------------------------------------------------------------===//
+
+static LogicalResult verify(acc::EnterDataOp op) {
+  // 2.6.6. Data Enter Directive restriction
+  // At least one copyin, create, or attach clause must appear on an enter data
+  // directive.
+  if (op.copyinOperands().empty() && op.createOperands().empty() &&
+      op.createZeroOperands().empty() && op.attachOperands().empty())
+    return op.emitError(
+        "at least one operand in copyin, create, "
+        "create_zero or attach must appear on the enter 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
 //===----------------------------------------------------------------------===//
 
index 33c6fea..df52b0c 100644 (file)
@@ -170,12 +170,31 @@ acc.exit_data async(%cst: index) delete(%value : memref<10xf32>) attributes {asy
 
 %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>)
+
+// -----
+
+// expected-error@+1 {{at least one operand in copyin, create, create_zero or attach must appear on the enter data operation}}
+acc.enter_data attributes {async}
+
+// -----
+
+%cst = constant 1 : index
+%value = alloc() : memref<10xf32>
+// expected-error@+1 {{async attribute cannot appear with asyncOperand}}
+acc.enter_data async(%cst: index) create(%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}
+acc.enter_data wait(%cst: index) create(%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>)
+acc.enter_data wait_devnum(%cst: index) create(%value : memref<10xf32>)
index af055b5..01089ff 100644 (file)
@@ -684,3 +684,37 @@ func @testexitdataop(%a: memref<10xf32>, %b: memref<10xf32>, %c: memref<10x10xf3
 // 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>)
+// -----
+
+
+func @testenterdataop(%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.enter_data copyin(%a : memref<10xf32>)
+  acc.enter_data create(%a : memref<10xf32>) create_zero(%b, %c : memref<10xf32>, memref<10x10xf32>)
+  acc.enter_data attach(%a : memref<10xf32>)
+  acc.enter_data copyin(%a : memref<10xf32>) attributes {async}
+  acc.enter_data create(%a : memref<10xf32>) attributes {wait}
+  acc.enter_data async(%i64Value : i64) copyin(%a : memref<10xf32>)
+  acc.enter_data if(%ifCond) copyin(%a : memref<10xf32>)
+  acc.enter_data wait_devnum(%i64Value: i64) wait(%i32Value, %idxValue : i32, index) copyin(%a : memref<10xf32>)
+
+  return
+}
+
+// CHECK: func @testenterdataop([[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.enter_data copyin([[ARGA]] : memref<10xf32>)
+// CHECK: acc.enter_data create([[ARGA]] : memref<10xf32>) create_zero([[ARGB]], [[ARGC]] : memref<10xf32>, memref<10x10xf32>)
+// CHECK: acc.enter_data attach([[ARGA]] : memref<10xf32>)
+// CHECK: acc.enter_data copyin([[ARGA]] : memref<10xf32>) attributes {async}
+// CHECK: acc.enter_data create([[ARGA]] : memref<10xf32>) attributes {wait}
+// CHECK: acc.enter_data async([[I64VALUE]] : i64) copyin([[ARGA]] : memref<10xf32>)
+// CHECK: acc.enter_data if([[IFCOND]]) copyin([[ARGA]] : memref<10xf32>)
+// CHECK: acc.enter_data wait_devnum([[I64VALUE]] : i64) wait([[I32VALUE]], [[IDXVALUE]] : i32, index) copyin([[ARGA]] : memref<10xf32>)