copyOperands, copyinOperands, copyinReadonlyOperands, copyoutOperands,
copyoutZeroOperands, createOperands, createZeroOperands, noCreateOperands,
presentOperands, devicePtrOperands, attachOperands, firstprivateOperands,
- privateOperands;
+ privateOperands, dataClauseOperands;
// Async, wait and self clause have optional values but can be present with
// no value as well. When there is no value, the op has an attribute to
addOperands(operands, operandSegments, privateOperands);
addOperands(operands, operandSegments, firstprivateOperands);
}
+ addOperands(operands, operandSegments, dataClauseOperands);
Op computeOp;
if constexpr (std::is_same_v<Op, mlir::acc::KernelsOp>)
llvm::SmallVector<mlir::Value> copyOperands, copyinOperands,
copyinReadonlyOperands, copyoutOperands, copyoutZeroOperands,
createOperands, createZeroOperands, noCreateOperands, presentOperands,
- deviceptrOperands, attachOperands;
+ deviceptrOperands, attachOperands, dataClauseOperands;
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
addOperands(operands, operandSegments, presentOperands);
addOperands(operands, operandSegments, deviceptrOperands);
addOperands(operands, operandSegments, attachOperands);
+ addOperands(operands, operandSegments, dataClauseOperands);
createRegionOp<mlir::acc::DataOp, mlir::acc::TerminatorOp>(
firOpBuilder, currentLocation, operands, operandSegments);
const Fortran::parser::AccClauseList &accClauseList) {
mlir::Value ifCond, async, waitDevnum;
llvm::SmallVector<mlir::Value> copyinOperands, createOperands,
- createZeroOperands, attachOperands, waitOperands;
+ createZeroOperands, attachOperands, waitOperands, dataClauseOperands;
// Async, wait and self clause have optional values but can be present with
// no value as well. When there is no value, the op has an attribute to
addOperands(operands, operandSegments, createOperands);
addOperands(operands, operandSegments, createZeroOperands);
addOperands(operands, operandSegments, attachOperands);
+ addOperands(operands, operandSegments, dataClauseOperands);
mlir::acc::EnterDataOp enterDataOp = createSimpleOp<mlir::acc::EnterDataOp>(
firOpBuilder, currentLocation, operands, operandSegments);
const Fortran::parser::AccClauseList &accClauseList) {
mlir::Value ifCond, async, waitDevnum;
llvm::SmallVector<mlir::Value> copyoutOperands, deleteOperands,
- detachOperands, waitOperands;
+ detachOperands, waitOperands, dataClauseOperands;
// Async and wait clause have optional values but can be present with
// no value as well. When there is no value, the op has an attribute to
addOperands(operands, operandSegments, copyoutOperands);
addOperands(operands, operandSegments, deleteOperands);
addOperands(operands, operandSegments, detachOperands);
+ addOperands(operands, operandSegments, dataClauseOperands);
mlir::acc::ExitDataOp exitDataOp = createSimpleOp<mlir::acc::ExitDataOp>(
firOpBuilder, currentLocation, operands, operandSegments);
mlir_tablegen(AccCommon.td --gen-directive-decl --directives-dialect=OpenACC)
add_public_tablegen_target(acc_common_td)
+add_mlir_dialect(OpenACCOps acc)
+
+add_mlir_doc(OpenACCOps OpenACCDialect Dialects/ -gen-dialect-doc)
+add_dependencies(OpenACCDialectDocGen acc_common_td)
+
set(LLVM_TARGET_DEFINITIONS OpenACCOps.td)
-mlir_tablegen(OpenACCOpsDialect.h.inc -gen-dialect-decls -dialect=acc)
-mlir_tablegen(OpenACCOpsDialect.cpp.inc -gen-dialect-defs -dialect=acc)
-mlir_tablegen(OpenACCOps.h.inc -gen-op-decls)
-mlir_tablegen(OpenACCOps.cpp.inc -gen-op-defs)
mlir_tablegen(OpenACCOpsEnums.h.inc -gen-enum-decls)
mlir_tablegen(OpenACCOpsEnums.cpp.inc -gen-enum-defs)
+add_public_tablegen_target(MLIROpenACCEnumsIncGen)
+add_dependencies(mlir-headers MLIROpenACCEnumsIncGen)
+
+set(LLVM_TARGET_DEFINITIONS OpenACCOps.td)
mlir_tablegen(OpenACCOpsAttributes.h.inc -gen-attrdef-decls -attrdefs-dialect=acc)
mlir_tablegen(OpenACCOpsAttributes.cpp.inc -gen-attrdef-defs -attrdefs-dialect=acc)
-add_mlir_doc(OpenACCOps OpenACCDialect Dialects/ -gen-dialect-doc)
-add_public_tablegen_target(MLIROpenACCOpsIncGen)
-add_dependencies(OpenACCDialectDocGen acc_common_td)
+add_public_tablegen_target(MLIROpenACCAttributesIncGen)
+add_dependencies(mlir-headers MLIROpenACCAttributesIncGen)
+
+set(LLVM_TARGET_DEFINITIONS OpenACCTypeInterfaces.td)
+mlir_tablegen(OpenACCTypeInterfaces.h.inc -gen-type-interface-decls)
+mlir_tablegen(OpenACCTypeInterfaces.cpp.inc -gen-type-interface-defs)
+add_public_tablegen_target(MLIROpenACCTypeInterfacesIncGen)
+add_dependencies(mlir-headers MLIROpenACCTypeInterfacesIncGen)
#ifndef MLIR_DIALECT_OPENACC_OPENACC_H_
#define MLIR_DIALECT_OPENACC_OPENACC_H_
+#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/OpDefinition.h"
#include "mlir/Dialect/OpenACC/OpenACCOpsDialect.h.inc"
#include "mlir/Dialect/OpenACC/OpenACCOpsEnums.h.inc"
+#include "mlir/Dialect/OpenACC/OpenACCTypeInterfaces.h.inc"
+#include "mlir/Interfaces/SideEffectInterfaces.h"
+
+#define GET_TYPEDEF_CLASSES
+#include "mlir/Dialect/OpenACC/OpenACCOpsTypes.h.inc"
#define GET_ATTRDEF_CLASSES
#include "mlir/Dialect/OpenACC/OpenACCOpsAttributes.h.inc"
--- /dev/null
+//===- OpenACCBase.td - OpenACC dialect definition ---------*- tablegen -*-===//
+//
+// Part of the MLIR Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// =============================================================================
+//
+// Defines MLIR OpenACC dialect.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef OPENACC_BASE
+#define OPENACC_BASE
+
+include "mlir/IR/AttrTypeBase.td"
+
+def OpenACC_Dialect : Dialect {
+ let name = "acc";
+
+ let summary = "An OpenACC dialect for MLIR.";
+
+ let description = [{
+ This dialect models the construct from the OpenACC 3.1 directive language.
+ }];
+
+ let useDefaultAttributePrinterParser = 1;
+ let useDefaultTypePrinterParser = 1;
+ let cppNamespace = "::mlir::acc";
+ let dependentDialects = ["::mlir::memref::MemRefDialect","::mlir::LLVM::LLVMDialect"];
+}
+
+#endif // OPENACC_BASE
-//===- OpenACC.td - OpenACC operation definitions ----------*- tablegen -*-===//
+//===- OpenACCOps.td - OpenACC operation definitions -------*- tablegen -*-===//
//
// Part of the MLIR Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
#ifndef OPENACC_OPS
#define OPENACC_OPS
+include "mlir/Interfaces/SideEffectInterfaces.td"
+include "mlir/IR/BuiltinTypes.td"
include "mlir/IR/EnumAttr.td"
include "mlir/IR/OpBase.td"
-
-def OpenACC_Dialect : Dialect {
- let name = "acc";
-
- let summary = "An OpenACC dialect for MLIR.";
-
- let description = [{
- This dialect models the construct from the OpenACC 3.1 directive language.
- }];
-
- let useDefaultAttributePrinterParser = 1;
- let cppNamespace = "::mlir::acc";
-}
+include "mlir/Dialect/OpenACC/OpenACCBase.td"
+include "mlir/Dialect/OpenACC/OpenACCOpsTypes.td"
+include "mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td"
// AccCommon requires definition of OpenACC_Dialect.
include "mlir/Dialect/OpenACC/AccCommon.td"
// Type used in operation below.
def IntOrIndex : AnyTypeOf<[AnyInteger, Index]>;
+// Simple alias to pointer-like interface to reduce verbosity.
+def OpenACC_PointerLikeType : TypeAlias<OpenACC_PointerLikeTypeInterface,
+ "pointer-like type">;
+
+// Define the OpenACC data clauses. There are a few cases where a modifier
+// is used, like create(zero), copyin(readonly), and copyout(zero). Since in
+// some cases we decompose the original acc data clauses into multiple acc
+// dialect operations, we need to keep track of original clause. Thus even
+// for the clause with modifier, we create separate operation to make this
+// possible.
+def OpenACC_CopyinClause : I64EnumAttrCase<"acc_copyin", 1>;
+def OpenACC_CopyinReadonlyClause : I64EnumAttrCase<"acc_copyin_readonly", 2>;
+def OpenACC_CopyClause : I64EnumAttrCase<"acc_copy", 3>;
+def OpenACC_CopyoutClause : I64EnumAttrCase<"acc_copyout", 4>;
+def OpenACC_CopyoutZeroClause : I64EnumAttrCase<"acc_copyout_zero", 5>;
+def OpenACC_PresentClause : I64EnumAttrCase<"acc_present", 6>;
+def OpenACC_CreateClause : I64EnumAttrCase<"acc_create", 7>;
+def OpenACC_CreateZeroClause : I64EnumAttrCase<"acc_create_zero", 8>;
+def OpenACC_DeleteClause : I64EnumAttrCase<"acc_delete", 9>;
+def OpenACC_AttachClause : I64EnumAttrCase<"acc_attach", 10>;
+def OpenACC_DetachClause : I64EnumAttrCase<"acc_detach", 11>;
+def OpenACC_NoCreateClause : I64EnumAttrCase<"acc_no_create", 12>;
+def OpenACC_PrivateClause : I64EnumAttrCase<"acc_private", 13>;
+def OpenACC_FirstPrivateClause : I64EnumAttrCase<"acc_firstprivate", 14>;
+def OpenACC_IsDevicePtrClause : I64EnumAttrCase<"acc_deviceptr", 15>;
+def OpenACC_GetDevicePtrClause : I64EnumAttrCase<"acc_getdeviceptr", 16>;
+
+def OpenACC_DataClauseEnum : I64EnumAttr<"DataClause",
+ "data clauses supported by OpenACC",
+ [OpenACC_CopyinClause, OpenACC_CopyinReadonlyClause, OpenACC_CopyClause,
+ OpenACC_CopyoutClause, OpenACC_CopyoutZeroClause, OpenACC_PresentClause,
+ OpenACC_CreateClause, OpenACC_CreateZeroClause, OpenACC_DeleteClause,
+ OpenACC_AttachClause, OpenACC_DetachClause, OpenACC_NoCreateClause,
+ OpenACC_PrivateClause, OpenACC_FirstPrivateClause,
+ OpenACC_IsDevicePtrClause, OpenACC_GetDevicePtrClause
+ ]> {
+ let cppNamespace = "::mlir::acc";
+}
+
+// Used for data specification in data clauses (2.7.1).
+// Either (or both) extent and upperbound must be specified.
+def OpenACC_DataBoundsOp : OpenACC_Op<"bounds",
+ [AttrSizedOperandSegments, NoMemoryEffect]> {
+ let summary = "Represents bounds information for acc data clause.";
+
+ let arguments = (ins Optional<AnyType>:$lowerbound,
+ Optional<AnyType>:$upperbound,
+ Optional<AnyType>:$extent,
+ Optional<AnyType>:$stride,
+ DefaultValuedAttr<BoolAttr, "false">:$strideInBytes,
+ Optional<AnyType>:$startIdx);
+ let results = (outs OpenACC_DataBoundsType:$result);
+
+ let assemblyFormat = [{
+ oilist(
+ `lowerbound` `(` $lowerbound `:` type($lowerbound) `)`
+ | `upperbound` `(` $upperbound `:` type($upperbound) `)`
+ | `extent` `(` $extent `:` type($extent) `)`
+ | `stride` `(` $stride `:` type($stride) `)`
+ | `startIdx` `(` $startIdx `:` type($startIdx) `)`
+ ) attr-dict
+ }];
+
+ let hasVerifier = 1;
+}
+
+// Data entry operation does not refer to OpenACC spec terminology, but to
+// terminology used in this dialect. It refers to data operations that will
+// appear before data or compute region. It will be used as the base of acc
+// dialect operations for the following OpenACC data clauses: copyin, create,
+// present, attach, deviceptr.
+//
+// The bounds are represented in rank order. Rank 0 (inner-most dimension) is
+// the first.
+class OpenACC_DataEntryOp<string mnemonic, string clause, list<Trait> traits = []> :
+ OpenACC_Op<mnemonic, !listconcat(traits,
+ [AttrSizedOperandSegments])> {
+ let arguments = (ins OpenACC_PointerLikeTypeInterface:$varPtr,
+ Optional<OpenACC_PointerLikeTypeInterface>:$varPtrPtr,
+ Variadic<OpenACC_DataBoundsType>:$bounds, /* rank-0 to rank-{n-1} */
+ DefaultValuedAttr<OpenACC_DataClauseEnum,clause>:$dataClause,
+ OptionalAttr<OpenACC_DataClauseEnum>:$decomposedFrom,
+ DefaultValuedAttr<BoolAttr, "true">:$structured,
+ DefaultValuedAttr<BoolAttr, "false">:$implicit,
+ OptionalAttr<StrAttr>:$name);
+ let results = (outs OpenACC_PointerLikeTypeInterface:$accPtr);
+
+ let assemblyFormat = [{
+ `varPtr` `(` $varPtr `:` type($varPtr) `)`
+ oilist(
+ `varPtrPtr` `(` $varPtrPtr `:` type($varPtrPtr) `)`
+ | `bounds` `(` $bounds `)`
+ ) `->` type($accPtr) attr-dict
+ }];
+
+ let hasVerifier = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// 2.7.4 deviceptr clause
+//===----------------------------------------------------------------------===//
+def OpenACC_DevicePtrOp : OpenACC_DataEntryOp<"deviceptr",
+ "mlir::acc::DataClause::acc_deviceptr"> {
+ let summary = "Specifies that the variable pointer is a device pointer.";
+}
+
+//===----------------------------------------------------------------------===//
+// 2.7.5 present clause
+//===----------------------------------------------------------------------===//
+def OpenACC_PresentOp : OpenACC_DataEntryOp<"present",
+ "mlir::acc::DataClause::acc_present"> {
+ let summary = "Specifies that the variable is already present on device.";
+}
+
+//===----------------------------------------------------------------------===//
+// 2.7.7 copyin clause
+//===----------------------------------------------------------------------===//
+def OpenACC_CopyinOp : OpenACC_DataEntryOp<"copyin",
+ "mlir::acc::DataClause::acc_copyin"> {
+ let summary = "Represents copyin semantics for acc data clauses like acc "
+ "copyin and acc copy.";
+
+ let extraClassDeclaration = [{
+ /// Check if this is a copyin with readonly modifier.
+ bool isCopyinReadonly();
+ }];
+}
+
+//===----------------------------------------------------------------------===//
+// 2.7.9 create clause
+//===----------------------------------------------------------------------===//
+def OpenACC_CreateOp : OpenACC_DataEntryOp<"create",
+ "mlir::acc::DataClause::acc_create"> {
+ let summary = "Represents create semantics for acc data clauses like acc "
+ "create and acc copyout.";
+
+ let extraClassDeclaration = [{
+ /// Check if this is a create with zero modifier.
+ bool isCreateZero();
+ }];
+}
+
+//===----------------------------------------------------------------------===//
+// 2.7.10 no_create clause
+//===----------------------------------------------------------------------===//
+def OpenACC_NoCreateOp : OpenACC_DataEntryOp<"nocreate",
+ "mlir::acc::DataClause::acc_no_create"> {
+ let summary = "Represents acc no_create semantics.";
+}
+
+//===----------------------------------------------------------------------===//
+// 2.7.12 attach clause
+//===----------------------------------------------------------------------===//
+def OpenACC_AttachOp : OpenACC_DataEntryOp<"attach",
+ "mlir::acc::DataClause::acc_attach"> {
+ let summary = "Represents acc attach semantics which updates a pointer in "
+ "device memory with the corresponding device address of the "
+ "pointee.";
+}
+
+//===----------------------------------------------------------------------===//
+// 3.2.23 acc_deviceptr
+//===----------------------------------------------------------------------===//
+// This is needed to get device address without the additional semantics in
+// acc present.
+// It is also useful for providing the device address for unstructured construct
+// exit_data since unlike structured constructs, there is no matching data entry
+// operation.
+def OpenACC_GetDevicePtrOp : OpenACC_DataEntryOp<"getdeviceptr",
+ "mlir::acc::DataClause::acc_getdeviceptr"> {
+ let summary = "Gets device address from host address if it exists on device.";
+}
+
+// Data exit operation does not refer to OpenACC spec terminology, but to
+// terminology used in this dialect. It refers to data operations that will appear
+// after data or compute region. It will be used as the base of acc dialect
+// operations for the following OpenACC data clauses: copyout, detach, delete.
+class OpenACC_DataExitOp<string mnemonic, string clause, list<Trait> traits = []> :
+ OpenACC_Op<mnemonic, !listconcat(traits,
+ [AttrSizedOperandSegments])> {
+ let arguments = (ins Optional<OpenACC_PointerLikeTypeInterface>:$varPtr,
+ OpenACC_PointerLikeTypeInterface:$accPtr,
+ Variadic<OpenACC_DataBoundsType>:$bounds,
+ DefaultValuedAttr<OpenACC_DataClauseEnum,clause>:$dataClause,
+ OptionalAttr<OpenACC_DataClauseEnum>:$decomposedFrom,
+ DefaultValuedAttr<BoolAttr, "true">:$structured,
+ DefaultValuedAttr<BoolAttr, "false">:$implicit,
+ OptionalAttr<StrAttr>:$name);
+
+ let assemblyFormat = [{
+ `accPtr` `(` $accPtr `:` type($accPtr) `)`
+ oilist(
+ `bounds` `(` $bounds `)`
+ | `to` `varPtr` `(` $varPtr `:` type($varPtr) `)`
+ ) attr-dict
+ }];
+
+ let hasVerifier = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// 2.7.8 copyout clause
+//===----------------------------------------------------------------------===//
+def OpenACC_CopyoutOp : OpenACC_DataExitOp<"copyout",
+ "mlir::acc::DataClause::acc_copyout"> {
+ let summary = "Represents acc copyout semantics - reverse of copyin.";
+
+ let extraClassDeclaration = [{
+ /// Check if this is a copyout with zero modifier.
+ bool isCopyoutZero();
+ }];
+}
+
+//===----------------------------------------------------------------------===//
+// 2.7.11 delete clause
+//===----------------------------------------------------------------------===//
+def OpenACC_DeleteOp : OpenACC_DataExitOp<"delete",
+ "mlir::acc::DataClause::acc_delete"> {
+ let summary = "Represents acc delete semantics - reverse of create.";
+}
+
+//===----------------------------------------------------------------------===//
+// 2.7.13 detach clause
+//===----------------------------------------------------------------------===//
+def OpenACC_DetachOp : OpenACC_DataExitOp<"detach",
+ "mlir::acc::DataClause::acc_detach"> {
+ let summary = "Represents acc detach semantics - reverse of attach.";
+}
+
//===----------------------------------------------------------------------===//
// 2.5.1 parallel Construct
//===----------------------------------------------------------------------===//
def OpenACC_ParallelOp : OpenACC_Op<"parallel",
- [AttrSizedOperandSegments]> {
+ [AttrSizedOperandSegments, RecursiveMemoryEffects]> {
let summary = "parallel construct";
let description = [{
The "acc.parallel" operation represents a parallel construct block. It has
Variadic<AnyType>:$attachOperands,
Variadic<AnyType>:$gangPrivateOperands,
Variadic<AnyType>:$gangFirstPrivateOperands,
+ Variadic<OpenACC_PointerLikeTypeInterface>:$dataClauseOperands,
OptionalAttr<DefaultValueAttr>:$defaultAttr);
let regions = (region AnyRegion:$region);
let assemblyFormat = [{
oilist(
- `attach` `(` $attachOperands `:` type($attachOperands) `)`
+ `dataOperands` `(` $dataClauseOperands `:` type($dataClauseOperands) `)`
+ | `attach` `(` $attachOperands `:` type($attachOperands) `)`
| `async` `(` $async `:` type($async) `)`
| `copy` `(` $copyOperands `:` type($copyOperands) `)`
| `copyin` `(` $copyinOperands `:` type($copyinOperands) `)`
// 2.5.2 serial Construct
//===----------------------------------------------------------------------===//
-def OpenACC_SerialOp : OpenACC_Op<"serial", [AttrSizedOperandSegments]> {
+def OpenACC_SerialOp : OpenACC_Op<"serial",
+ [AttrSizedOperandSegments, RecursiveMemoryEffects]> {
let summary = "serial construct";
let description = [{
The "acc.serial" operation represents a serial construct block. It has
Variadic<AnyType>:$attachOperands,
Variadic<AnyType>:$gangPrivateOperands,
Variadic<AnyType>:$gangFirstPrivateOperands,
+ Variadic<OpenACC_PointerLikeTypeInterface>:$dataClauseOperands,
OptionalAttr<DefaultValueAttr>:$defaultAttr);
let regions = (region AnyRegion:$region);
let assemblyFormat = [{
oilist(
- `attach` `(` $attachOperands `:` type($attachOperands) `)`
+ `dataOperands` `(` $dataClauseOperands `:` type($dataClauseOperands) `)`
+ | `attach` `(` $attachOperands `:` type($attachOperands) `)`
| `async` `(` $async `:` type($async) `)`
| `copy` `(` $copyOperands `:` type($copyOperands) `)`
| `copyin` `(` $copyinOperands `:` type($copyinOperands) `)`
// 2.5.1 kernels Construct
//===----------------------------------------------------------------------===//
-def OpenACC_KernelsOp : OpenACC_Op<"kernels", [AttrSizedOperandSegments]> {
+def OpenACC_KernelsOp : OpenACC_Op<"kernels",
+ [AttrSizedOperandSegments, RecursiveMemoryEffects]> {
let summary = "kernels construct";
let description = [{
The "acc.kernels" operation represents a kernels construct block. It has
Variadic<AnyType>:$presentOperands,
Variadic<AnyType>:$devicePtrOperands,
Variadic<AnyType>:$attachOperands,
+ Variadic<OpenACC_PointerLikeTypeInterface>:$dataClauseOperands,
OptionalAttr<DefaultValueAttr>:$defaultAttr);
let regions = (region AnyRegion:$region);
let assemblyFormat = [{
oilist(
- `attach` `(` $attachOperands `:` type($attachOperands) `)`
+ `dataOperands` `(` $dataClauseOperands `:` type($dataClauseOperands) `)`
+ | `attach` `(` $attachOperands `:` type($attachOperands) `)`
| `async` `(` $async `:` type($async) `)`
| `copy` `(` $copyOperands `:` type($copyOperands) `)`
| `copyin` `(` $copyinOperands `:` type($copyinOperands) `)`
//===----------------------------------------------------------------------===//
def OpenACC_DataOp : OpenACC_Op<"data",
- [AttrSizedOperandSegments]> {
+ [AttrSizedOperandSegments, RecursiveMemoryEffects]> {
let summary = "data construct";
let description = [{
Variadic<AnyType>:$presentOperands,
Variadic<AnyType>:$deviceptrOperands,
Variadic<AnyType>:$attachOperands,
+ Variadic<OpenACC_PointerLikeTypeInterface>:$dataClauseOperands,
OptionalAttr<DefaultValueAttr>:$defaultAttr);
let regions = (region AnyRegion:$region);
let assemblyFormat = [{
oilist(
`if` `(` $ifCond `)`
+ | `dataOperands` `(` $dataClauseOperands `:` type($dataClauseOperands) `)`
| `copy` `(` $copyOperands `:` type($copyOperands) `)`
| `copyin` `(` $copyinOperands `:` type($copyinOperands) `)`
| `copyin_readonly` `(` $copyinReadonlyOperands `:`
Variadic<AnyType>:$copyinOperands,
Variadic<AnyType>:$createOperands,
Variadic<AnyType>:$createZeroOperands,
- Variadic<AnyType>:$attachOperands);
+ Variadic<AnyType>:$attachOperands,
+ Variadic<OpenACC_PointerLikeTypeInterface>:$dataClauseOperands);
let extraClassDeclaration = [{
/// The number of data operands.
| `create_zero` `(` $createZeroOperands `:`
type($createZeroOperands) `)`
| `attach` `(` $attachOperands `:` type($attachOperands) `)`
+ | `dataOperands` `(` $dataClauseOperands `:` type($dataClauseOperands) `)`
)
attr-dict-with-keyword
}];
Variadic<AnyType>:$copyoutOperands,
Variadic<AnyType>:$deleteOperands,
Variadic<AnyType>:$detachOperands,
+ Variadic<OpenACC_PointerLikeTypeInterface>:$dataClauseOperands,
UnitAttr:$finalize);
let extraClassDeclaration = [{
| `copyout` `(` $copyoutOperands `:` type($copyoutOperands) `)`
| `delete` `(` $deleteOperands `:` type($deleteOperands) `)`
| `detach` `(` $detachOperands `:` type($detachOperands) `)`
+ | `dataOperands` `(` $dataClauseOperands `:` type($dataClauseOperands) `)`
)
attr-dict-with-keyword
}];
// 2.9 loop Construct
//===----------------------------------------------------------------------===//
-def OpenACC_LoopOp : OpenACC_Op<"loop", [AttrSizedOperandSegments]> {
+def OpenACC_LoopOp : OpenACC_Op<"loop",
+ [AttrSizedOperandSegments, RecursiveMemoryEffects]> {
let summary = "loop construct";
let description = [{
--- /dev/null
+//===- OpenACCOpsTypes.td - OpenACC operation types definitions -*- tablegen -*-===//
+//
+// Part of the MLIR Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// =============================================================================
+//
+// Defines MLIR OpenACC operation types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef OPENACC_OPS_TYPES
+#define OPENACC_OPS_TYPES
+
+include "mlir/IR/AttrTypeBase.td"
+include "OpenACCBase.td"
+
+class OpenACC_Type<string name, string typeMnemonic> : TypeDef<OpenACC_Dialect, name> {
+ let mnemonic = typeMnemonic;
+}
+
+def OpenACC_DataBoundsType : OpenACC_Type<"DataBounds", "data_bounds_ty"> {
+ let summary = "Type for representing acc data clause bounds information";
+}
+
+#endif // OPENACC_OPS_TYPES
--- /dev/null
+//===-- OpenACCTypeInterfaces.td - OpenACC type interfaces ---*- tablegen -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef OPENACC_TYPE_INTERFACES
+#define OPENACC_TYPE_INTERFACES
+
+include "mlir/IR/OpBase.td"
+
+def OpenACC_PointerLikeTypeInterface : TypeInterface<"PointerLikeType"> {
+ let cppNamespace = "::mlir::acc";
+
+ let description = [{
+ An interface for pointer-like types that point to an OpenACC var.
+ }];
+
+ // By convention, any of the pointer types associated with this interface
+ // will need to provide getElementType.
+ let methods = [
+ InterfaceMethod<
+ /*description=*/[{
+ Returns the pointee type or null if the pointer has no pointee type
+ }],
+ /*retTy=*/"::mlir::Type",
+ /*methodName=*/"getElementType"
+ >,
+ ];
+}
+
+#endif // OPENACC_TYPE_INTERFACES
DEPENDS
MLIROpenACCOpsIncGen
+ MLIROpenACCEnumsIncGen
+ MLIROpenACCAttributesIncGen
+ MLIROpenACCTypeInterfacesIncGen
LINK_LIBS PUBLIC
MLIRIR
// =============================================================================
#include "mlir/Dialect/OpenACC/OpenACC.h"
-#include "mlir/Dialect/OpenACC/OpenACCOpsEnums.cpp.inc"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
+#include "mlir/Dialect/MemRef/IR/MemRef.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/DialectImplementation.h"
using namespace acc;
#include "mlir/Dialect/OpenACC/OpenACCOpsDialect.cpp.inc"
+#include "mlir/Dialect/OpenACC/OpenACCOpsEnums.cpp.inc"
+#include "mlir/Dialect/OpenACC/OpenACCTypeInterfaces.cpp.inc"
//===----------------------------------------------------------------------===//
// OpenACC operations
#define GET_ATTRDEF_LIST
#include "mlir/Dialect/OpenACC/OpenACCOpsAttributes.cpp.inc"
>();
+ addTypes<
+#define GET_TYPEDEF_LIST
+#include "mlir/Dialect/OpenACC/OpenACCOpsTypes.cpp.inc"
+ >();
+
+ // By attaching interfaces here, we make the OpenACC dialect dependent on
+ // the other dialects. This is probably better than having dialects like LLVM
+ // and memref be dependent on OpenACC.
+ LLVM::LLVMPointerType::attachInterface<PointerLikeType>(*getContext());
+ MemRefType::attachInterface<PointerLikeType>(*getContext());
+}
+
+//===----------------------------------------------------------------------===//
+// DataBoundsOp
+//===----------------------------------------------------------------------===//
+LogicalResult acc::DataBoundsOp::verify() {
+ auto extent = getExtent();
+ auto upperbound = getUpperbound();
+ if (!extent && !upperbound) {
+ return emitError("expected extent or upperbound.");
+ }
+ return success();
+}
+
+//===----------------------------------------------------------------------===//
+// DevicePtrOp
+//===----------------------------------------------------------------------===//
+LogicalResult acc::DevicePtrOp::verify() {
+ if (getDataClause() != acc::DataClause::acc_deviceptr) {
+ return emitError("data clause associated with deviceptr operation must "
+ "match its intent");
+ }
+ return success();
+}
+
+//===----------------------------------------------------------------------===//
+// PresentOp
+//===----------------------------------------------------------------------===//
+LogicalResult acc::PresentOp::verify() {
+ if (getDataClause() != acc::DataClause::acc_present) {
+ return emitError(
+ "data clause associated with present operation must match its intent");
+ }
+ return success();
+}
+
+//===----------------------------------------------------------------------===//
+// CopyinOp
+//===----------------------------------------------------------------------===//
+LogicalResult acc::CopyinOp::verify() {
+ if (getDataClause() != acc::DataClause::acc_copyin &&
+ getDataClause() != acc::DataClause::acc_copyin_readonly) {
+ return emitError(
+ "data clause associated with copyin operation must match its intent");
+ }
+ return success();
+}
+
+bool acc::CopyinOp::isCopyinReadonly() {
+ return getDataClause() == acc::DataClause::acc_copyin_readonly;
+}
+
+//===----------------------------------------------------------------------===//
+// CreateOp
+//===----------------------------------------------------------------------===//
+LogicalResult acc::CreateOp::verify() {
+ if (getDataClause() != acc::DataClause::acc_create &&
+ getDataClause() != acc::DataClause::acc_create_zero) {
+ return emitError(
+ "data clause associated with create operation must match its intent");
+ }
+ return success();
+}
+
+bool acc::CreateOp::isCreateZero() {
+ return getDataClause() == acc::DataClause::acc_create_zero;
+}
+
+//===----------------------------------------------------------------------===//
+// NoCreateOp
+//===----------------------------------------------------------------------===//
+LogicalResult acc::NoCreateOp::verify() {
+ if (getDataClause() != acc::DataClause::acc_no_create) {
+ return emitError("data clause associated with no_create operation must "
+ "match its intent");
+ }
+ return success();
+}
+
+//===----------------------------------------------------------------------===//
+// AttachOp
+//===----------------------------------------------------------------------===//
+LogicalResult acc::AttachOp::verify() {
+ if (getDataClause() != acc::DataClause::acc_attach) {
+ return emitError(
+ "data clause associated with attach operation must match its intent");
+ }
+ return success();
+}
+
+//===----------------------------------------------------------------------===//
+// GetDevicePtrOp
+//===----------------------------------------------------------------------===//
+LogicalResult acc::GetDevicePtrOp::verify() {
+ if (getDataClause() != acc::DataClause::acc_getdeviceptr) {
+ return emitError("getDevicePtr mismatch");
+ }
+ return success();
+}
+
+//===----------------------------------------------------------------------===//
+// CopyoutOp
+//===----------------------------------------------------------------------===//
+LogicalResult acc::CopyoutOp::verify() {
+ if (getDataClause() != acc::DataClause::acc_copyout &&
+ getDataClause() != acc::DataClause::acc_copyout_zero) {
+ return emitError(
+ "data clause associated with copyout operation must match its intent");
+ }
+ if (!getVarPtr() || !getAccPtr()) {
+ return emitError("must have both host and device pointers");
+ }
+ return success();
+}
+
+bool acc::CopyoutOp::isCopyoutZero() {
+ return getDataClause() == acc::DataClause::acc_copyout_zero;
+}
+
+//===----------------------------------------------------------------------===//
+// DeleteOp
+//===----------------------------------------------------------------------===//
+LogicalResult acc::DeleteOp::verify() {
+ if (getDataClause() != acc::DataClause::acc_delete) {
+ return emitError(
+ "data clause associated with delete operation must match its intent");
+ }
+ if (!getVarPtr() && !getAccPtr()) {
+ return emitError("must have either host or device pointer");
+ }
+ return success();
+}
+
+//===----------------------------------------------------------------------===//
+// DetachOp
+//===----------------------------------------------------------------------===//
+LogicalResult acc::DetachOp::verify() {
+ if (getDataClause() != acc::DataClause::acc_detach) {
+ return emitError(
+ "data clause associated with detach operation must match its intent");
+ }
+ if (!getVarPtr() && !getAccPtr()) {
+ return emitError("must have either host or device pointer");
+ }
+ return success();
}
template <typename StructureOp>
getCreateOperands().size() + getCreateZeroOperands().size() +
getNoCreateOperands().size() + getPresentOperands().size() +
getDevicePtrOperands().size() + getAttachOperands().size() +
- getGangPrivateOperands().size() + getGangFirstPrivateOperands().size();
+ getGangPrivateOperands().size() +
+ getGangFirstPrivateOperands().size() + getDataClauseOperands().size();
}
Value ParallelOp::getDataOperand(unsigned i) {
getCreateOperands().size() + getCreateZeroOperands().size() +
getNoCreateOperands().size() + getPresentOperands().size() +
getDevicePtrOperands().size() + getAttachOperands().size() +
- getGangPrivateOperands().size() + getGangFirstPrivateOperands().size();
+ getGangPrivateOperands().size() +
+ getGangFirstPrivateOperands().size() + getDataClauseOperands().size();
}
Value SerialOp::getDataOperand(unsigned i) {
getCopyoutZeroOperands().size() + getCreateOperands().size() +
getCreateZeroOperands().size() + getNoCreateOperands().size() +
getPresentOperands().size() + getDevicePtrOperands().size() +
- getAttachOperands().size();
+ getAttachOperands().size() + getDataClauseOperands().size();
}
Value KernelsOp::getDataOperand(unsigned i) {
getCopyoutZeroOperands().size() + getCreateOperands().size() +
getCreateZeroOperands().size() + getNoCreateOperands().size() +
getPresentOperands().size() + getDeviceptrOperands().size() +
- getAttachOperands().size();
+ getAttachOperands().size() + getDataClauseOperands().size();
}
Value DataOp::getDataOperand(unsigned i) {
// At least one copyout, delete, or detach clause must appear on an exit data
// directive.
if (getCopyoutOperands().empty() && getDeleteOperands().empty() &&
- getDetachOperands().empty())
+ getDetachOperands().empty() && getDataClauseOperands().empty())
return emitError(
"at least one operand in copyout, delete or detach must appear on the "
"exit data operation");
unsigned ExitDataOp::getNumDataOperands() {
return getCopyoutOperands().size() + getDeleteOperands().size() +
- getDetachOperands().size();
+ getDetachOperands().size() + getDataClauseOperands().size();
}
Value ExitDataOp::getDataOperand(unsigned i) {
// At least one copyin, create, or attach clause must appear on an enter data
// directive.
if (getCopyinOperands().empty() && getCreateOperands().empty() &&
- getCreateZeroOperands().empty() && getAttachOperands().empty())
+ getCreateZeroOperands().empty() && getAttachOperands().empty() &&
+ getDataClauseOperands().empty())
return emitError(
"at least one operand in copyin, create, "
"create_zero or attach must appear on the enter data operation");
unsigned EnterDataOp::getNumDataOperands() {
return getCopyinOperands().size() + getCreateOperands().size() +
- getCreateZeroOperands().size() + getAttachOperands().size();
+ getCreateZeroOperands().size() + getAttachOperands().size() +
+ getDataClauseOperands().size();
}
Value EnterDataOp::getDataOperand(unsigned i) {
#define GET_ATTRDEF_CLASSES
#include "mlir/Dialect/OpenACC/OpenACCOpsAttributes.cpp.inc"
+
+#define GET_TYPEDEF_CLASSES
+#include "mlir/Dialect/OpenACC/OpenACCOpsTypes.cpp.inc"
// 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>)
+
+// -----
+
+func.func @teststructureddataclauseops(%a: memref<10xf32>, %b: memref<memref<10xf32>>, %c: memref<10x20xf32>) -> () {
+ %deviceptr = acc.deviceptr varPtr(%a : memref<10xf32>) -> memref<10xf32> {name = "arrayA"}
+ acc.parallel dataOperands(%deviceptr : memref<10xf32>) {
+ }
+
+ %present = acc.present varPtr(%a : memref<10xf32>) -> memref<10xf32>
+ acc.data dataOperands(%present : memref<10xf32>) {
+ }
+
+ %copyin = acc.copyin varPtr(%a : memref<10xf32>) -> memref<10xf32>
+ acc.parallel dataOperands(%copyin : memref<10xf32>) {
+ }
+
+ %copyinreadonly = acc.copyin varPtr(%a : memref<10xf32>) -> memref<10xf32> {dataClause = 2}
+ acc.kernels dataOperands(%copyinreadonly : memref<10xf32>) {
+ }
+
+ %copyinfromcopy = acc.copyin varPtr(%a : memref<10xf32>) -> memref<10xf32> {decomposedFrom = 3}
+ acc.serial dataOperands(%copyinfromcopy : memref<10xf32>) {
+ }
+ acc.copyout accPtr(%copyinfromcopy : memref<10xf32>) to varPtr(%a : memref<10xf32>) {decomposedFrom = 3}
+
+ %create = acc.create varPtr(%a : memref<10xf32>) -> memref<10xf32>
+ %createimplicit = acc.create varPtr(%c : memref<10x20xf32>) -> memref<10x20xf32> {implicit = true}
+ acc.parallel dataOperands(%create, %createimplicit : memref<10xf32>, memref<10x20xf32>) {
+ }
+ acc.delete accPtr(%create : memref<10xf32>) {decomposedFrom = 7}
+ acc.delete accPtr(%createimplicit : memref<10x20xf32>) {decomposedFrom = 7, implicit = true}
+
+ %copyoutzero = acc.create varPtr(%a : memref<10xf32>) -> memref<10xf32> {decomposedFrom = 5}
+ acc.parallel dataOperands(%copyoutzero: memref<10xf32>) {
+ }
+ acc.copyout accPtr(%copyoutzero : memref<10xf32>) to varPtr(%a : memref<10xf32>) {dataClause = 5}
+
+ %attach = acc.attach varPtr(%b : memref<memref<10xf32>>) -> memref<memref<10xf32>>
+ acc.parallel dataOperands(%attach : memref<memref<10xf32>>) {
+ }
+ acc.detach accPtr(%attach : memref<memref<10xf32>>) {decomposedFrom = 10}
+
+ %copyinparent = acc.copyin varPtr(%a : memref<10xf32>) varPtrPtr(%b : memref<memref<10xf32>>) -> memref<10xf32> {decomposedFrom = 3}
+ acc.parallel dataOperands(%copyinparent : memref<10xf32>) {
+ }
+ acc.copyout accPtr(%copyinparent : memref<10xf32>) to varPtr(%a : memref<10xf32>) {decomposedFrom = 3}
+
+ %c0 = arith.constant 0 : index
+ %c1 = arith.constant 1 : index
+ %c4 = arith.constant 4 : index
+ %c9 = arith.constant 9 : index
+ %c10 = arith.constant 10 : index
+ %c20 = arith.constant 20 : index
+
+ %bounds1full = acc.bounds lowerbound(%c0 : index) upperbound(%c9 : index) stride(%c1 : index)
+ %copyinfullslice1 = acc.copyin varPtr(%a : memref<10xf32>) bounds(%bounds1full) -> memref<10xf32> {name = "arrayA[0:9]"}
+ // Specify full-bounds but assume that startIdx of array reference is 1.
+ %bounds2full = acc.bounds lowerbound(%c1 : index) upperbound(%c20 : index) extent(%c20 : index) stride(%c4 : index) startIdx(%c1 : index) {strideInBytes = true}
+ %copyinfullslice2 = acc.copyin varPtr(%c : memref<10x20xf32>) bounds(%bounds1full, %bounds2full) -> memref<10x20xf32>
+ acc.parallel dataOperands(%copyinfullslice1, %copyinfullslice2 : memref<10xf32>, memref<10x20xf32>) {
+ }
+
+ %bounds1partial = acc.bounds lowerbound(%c4 : index) upperbound(%c9 : index) stride(%c1 : index)
+ %copyinpartial = acc.copyin varPtr(%a : memref<10xf32>) bounds(%bounds1partial) -> memref<10xf32> {decomposedFrom = 3}
+ acc.parallel dataOperands(%copyinpartial : memref<10xf32>) {
+ }
+ acc.copyout accPtr(%copyinpartial : memref<10xf32>) bounds(%bounds1partial) to varPtr(%a : memref<10xf32>) {decomposedFrom = 3}
+
+ return
+}
+
+// CHECK: func.func @teststructureddataclauseops([[ARGA:%.*]]: memref<10xf32>, [[ARGB:%.*]]: memref<memref<10xf32>>, [[ARGC:%.*]]: memref<10x20xf32>) {
+// CHECK: [[DEVICEPTR:%.*]] = acc.deviceptr varPtr([[ARGA]] : memref<10xf32>) -> memref<10xf32> {name = "arrayA"}
+// CHECK-NEXT: acc.parallel dataOperands([[DEVICEPTR]] : memref<10xf32>) {
+// CHECK-NEXT: }
+// CHECK: [[PRESENT:%.*]] = acc.present varPtr([[ARGA]] : memref<10xf32>) -> memref<10xf32>
+// CHECK-NEXT: acc.data dataOperands([[PRESENT]] : memref<10xf32>) {
+// CHECK-NEXT: }
+// CHECK: [[COPYIN:%.*]] = acc.copyin varPtr([[ARGA]] : memref<10xf32>) -> memref<10xf32>
+// CHECK-NEXT: acc.parallel dataOperands([[COPYIN]] : memref<10xf32>) {
+// CHECK-NEXT: }
+// CHECK: [[COPYINRO:%.*]] = acc.copyin varPtr([[ARGA]] : memref<10xf32>) -> memref<10xf32> {dataClause = 2 : i64}
+// CHECK-NEXT: acc.kernels dataOperands([[COPYINRO]] : memref<10xf32>) {
+// CHECK-NEXT: }
+// CHECK: [[COPYINCOPY:%.*]] = acc.copyin varPtr([[ARGA]] : memref<10xf32>) -> memref<10xf32> {decomposedFrom = 3 : i64}
+// CHECK-NEXT: acc.serial dataOperands([[COPYINCOPY]] : memref<10xf32>) {
+// CHECK-NEXT: }
+// CHECK-NEXT: acc.copyout accPtr([[COPYINCOPY]] : memref<10xf32>) to varPtr([[ARGA]] : memref<10xf32>) {decomposedFrom = 3 : i64}
+// CHECK: [[CREATE:%.*]] = acc.create varPtr([[ARGA]] : memref<10xf32>) -> memref<10xf32>
+// CHECK-NEXT: [[CREATEIMP:%.*]] = acc.create varPtr([[ARGC]] : memref<10x20xf32>) -> memref<10x20xf32> {implicit = true}
+// CHECK-NEXT: acc.parallel dataOperands([[CREATE]], [[CREATEIMP]] : memref<10xf32>, memref<10x20xf32>) {
+// CHECK-NEXT: }
+// CHECK-NEXT: acc.delete accPtr([[CREATE]] : memref<10xf32>) {decomposedFrom = 7 : i64}
+// CHECK-NEXT: acc.delete accPtr([[CREATEIMP]] : memref<10x20xf32>) {decomposedFrom = 7 : i64, implicit = true}
+// CHECK: [[COPYOUTZ:%.*]] = acc.create varPtr([[ARGA]] : memref<10xf32>) -> memref<10xf32> {decomposedFrom = 5 : i64}
+// CHECK-NEXT: acc.parallel dataOperands([[COPYOUTZ]] : memref<10xf32>) {
+// CHECK-NEXT: }
+// CHECK-NEXT: acc.copyout accPtr([[COPYOUTZ]] : memref<10xf32>) to varPtr([[ARGA]] : memref<10xf32>) {dataClause = 5 : i64}
+// CHECK: [[ATTACH:%.*]] = acc.attach varPtr([[ARGB]] : memref<memref<10xf32>>) -> memref<memref<10xf32>>
+// CHECK-NEXT: acc.parallel dataOperands([[ATTACH]] : memref<memref<10xf32>>) {
+// CHECK-NEXT: }
+// CHECK-NEXT: acc.detach accPtr([[ATTACH]] : memref<memref<10xf32>>) {decomposedFrom = 10 : i64}
+// CHECK: [[COPYINP:%.*]] = acc.copyin varPtr([[ARGA]] : memref<10xf32>) varPtrPtr([[ARGB]] : memref<memref<10xf32>>) -> memref<10xf32> {decomposedFrom = 3 : i64}
+// CHECK-NEXT: acc.parallel dataOperands([[COPYINP]] : memref<10xf32>) {
+// CHECK-NEXT: }
+// CHECK-NEXT: acc.copyout accPtr([[COPYINP]] : memref<10xf32>) to varPtr([[ARGA]] : memref<10xf32>) {decomposedFrom = 3 : i64}
+// CHECK-DAG: [[CON0:%.*]] = arith.constant 0 : index
+// CHECK-DAG: [[CON1:%.*]] = arith.constant 1 : index
+// CHECK-DAG: [[CON4:%.*]] = arith.constant 4 : index
+// CHECK-DAG: [[CON9:%.*]] = arith.constant 9 : index
+// CHECK-DAG: [[CON20:%.*]] = arith.constant 20 : index
+// CHECK: [[BOUNDS1F:%.*]] = acc.bounds lowerbound([[CON0]] : index) upperbound([[CON9]] : index) stride([[CON1]] : index)
+// CHECK-NEXT: [[COPYINF1:%.*]] = acc.copyin varPtr([[ARGA]] : memref<10xf32>) bounds([[BOUNDS1F]]) -> memref<10xf32> {name = "arrayA[0:9]"}
+// CHECK-NEXT: [[BOUNDS2F:%.*]] = acc.bounds lowerbound([[CON1]] : index) upperbound([[CON20]] : index) extent([[CON20]] : index) stride([[CON4]] : index) startIdx([[CON1]] : index) {strideInBytes = true}
+// CHECK-NEXT: [[COPYINF2:%.*]] = acc.copyin varPtr([[ARGC]] : memref<10x20xf32>) bounds([[BOUNDS1F]], [[BOUNDS2F]]) -> memref<10x20xf32>
+// CHECK-NEXT: acc.parallel dataOperands([[COPYINF1]], [[COPYINF2]] : memref<10xf32>, memref<10x20xf32>) {
+// CHECK-NEXT: }
+// CHECK: [[BOUNDS1P:%.*]] = acc.bounds lowerbound([[CON4]] : index) upperbound([[CON9]] : index) stride([[CON1]] : index)
+// CHECK-NEXT: [[COPYINPART:%.*]] = acc.copyin varPtr([[ARGA]] : memref<10xf32>) bounds([[BOUNDS1P]]) -> memref<10xf32> {decomposedFrom = 3 : i64}
+// CHECK-NEXT: acc.parallel dataOperands([[COPYINPART]] : memref<10xf32>) {
+// CHECK-NEXT: }
+// CHECK-NEXT: acc.copyout accPtr([[COPYINPART]] : memref<10xf32>) bounds([[BOUNDS1P]]) to varPtr([[ARGA]] : memref<10xf32>) {decomposedFrom = 3 : i64}
+
+// -----
+
+func.func @testunstructuredclauseops(%a: memref<10xf32>) -> () {
+ %copyin = acc.copyin varPtr(%a : memref<10xf32>) -> memref<10xf32> {structured = false}
+ acc.enter_data dataOperands(%copyin : memref<10xf32>)
+
+ %devptr = acc.getdeviceptr varPtr(%a : memref<10xf32>) -> memref<10xf32> {decomposedFrom = 4}
+ acc.exit_data dataOperands(%devptr : memref<10xf32>)
+ acc.copyout accPtr(%devptr : memref<10xf32>) to varPtr(%a : memref<10xf32>) {structured = false}
+
+ return
+}
+
+// CHECK: func.func @testunstructuredclauseops([[ARGA:%.*]]: memref<10xf32>) {
+// CHECK: [[COPYIN:%.*]] = acc.copyin varPtr([[ARGA]] : memref<10xf32>) -> memref<10xf32> {structured = false}
+// CHECK-NEXT: acc.enter_data dataOperands([[COPYIN]] : memref<10xf32>)
+// CHECK: [[DEVPTR:%.*]] = acc.getdeviceptr varPtr([[ARGA]] : memref<10xf32>) -> memref<10xf32> {decomposedFrom = 4 : i64}
+// CHECK-NEXT: acc.exit_data dataOperands([[DEVPTR]] : memref<10xf32>)
+// CHECK-NEXT: acc.copyout accPtr([[DEVPTR]] : memref<10xf32>) to varPtr([[ARGA]] : memref<10xf32>) {structured = false}