diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp index 3a48177942e08..d17dab6af33b4 100644 --- a/flang/lib/Lower/OpenACC.cpp +++ b/flang/lib/Lower/OpenACC.cpp @@ -422,7 +422,7 @@ createComputeOp(Fortran::lower::AbstractConverter &converter, 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 @@ -580,6 +580,7 @@ createComputeOp(Fortran::lower::AbstractConverter &converter, addOperands(operands, operandSegments, privateOperands); addOperands(operands, operandSegments, firstprivateOperands); } + addOperands(operands, operandSegments, dataClauseOperands); Op computeOp; if constexpr (std::is_same_v) @@ -608,7 +609,7 @@ static void genACCDataOp(Fortran::lower::AbstractConverter &converter, llvm::SmallVector copyOperands, copyinOperands, copyinReadonlyOperands, copyoutOperands, copyoutZeroOperands, createOperands, createZeroOperands, noCreateOperands, presentOperands, - deviceptrOperands, attachOperands; + deviceptrOperands, attachOperands, dataClauseOperands; fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); @@ -680,6 +681,7 @@ static void genACCDataOp(Fortran::lower::AbstractConverter &converter, addOperands(operands, operandSegments, presentOperands); addOperands(operands, operandSegments, deviceptrOperands); addOperands(operands, operandSegments, attachOperands); + addOperands(operands, operandSegments, dataClauseOperands); createRegionOp( firOpBuilder, currentLocation, operands, operandSegments); @@ -761,7 +763,7 @@ genACCEnterDataOp(Fortran::lower::AbstractConverter &converter, const Fortran::parser::AccClauseList &accClauseList) { mlir::Value ifCond, async, waitDevnum; llvm::SmallVector 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 @@ -821,6 +823,7 @@ genACCEnterDataOp(Fortran::lower::AbstractConverter &converter, addOperands(operands, operandSegments, createOperands); addOperands(operands, operandSegments, createZeroOperands); addOperands(operands, operandSegments, attachOperands); + addOperands(operands, operandSegments, dataClauseOperands); mlir::acc::EnterDataOp enterDataOp = createSimpleOp( firOpBuilder, currentLocation, operands, operandSegments); @@ -839,7 +842,7 @@ genACCExitDataOp(Fortran::lower::AbstractConverter &converter, const Fortran::parser::AccClauseList &accClauseList) { mlir::Value ifCond, async, waitDevnum; llvm::SmallVector 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 @@ -897,6 +900,7 @@ genACCExitDataOp(Fortran::lower::AbstractConverter &converter, addOperands(operands, operandSegments, copyoutOperands); addOperands(operands, operandSegments, deleteOperands); addOperands(operands, operandSegments, detachOperands); + addOperands(operands, operandSegments, dataClauseOperands); mlir::acc::ExitDataOp exitDataOp = createSimpleOp( firOpBuilder, currentLocation, operands, operandSegments); diff --git a/mlir/include/mlir/Dialect/OpenACC/CMakeLists.txt b/mlir/include/mlir/Dialect/OpenACC/CMakeLists.txt index 7170c2cb02614..119885eabfe91 100644 --- a/mlir/include/mlir/Dialect/OpenACC/CMakeLists.txt +++ b/mlir/include/mlir/Dialect/OpenACC/CMakeLists.txt @@ -2,15 +2,25 @@ set(LLVM_TARGET_DEFINITIONS ${LLVM_MAIN_INCLUDE_DIR}/llvm/Frontend/OpenACC/ACC.t 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) diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACC.h b/mlir/include/mlir/Dialect/OpenACC/OpenACC.h index 3e0ed12ef1b20..4e7db76bc0a31 100644 --- a/mlir/include/mlir/Dialect/OpenACC/OpenACC.h +++ b/mlir/include/mlir/Dialect/OpenACC/OpenACC.h @@ -13,11 +13,17 @@ #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" diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCBase.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCBase.td new file mode 100644 index 0000000000000..7bbe2cce56fb1 --- /dev/null +++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCBase.td @@ -0,0 +1,33 @@ +//===- 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 diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td index 1e8e1dee48f92..405ff782ad595 100644 --- a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td +++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td @@ -1,4 +1,4 @@ -//===- 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. @@ -13,21 +13,13 @@ #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" @@ -66,12 +58,241 @@ def OpenACC_ReductionOpAttr : EnumAttr; +// Simple alias to pointer-like interface to reduce verbosity. +def OpenACC_PointerLikeType : TypeAlias; + +// 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:$lowerbound, + Optional:$upperbound, + Optional:$extent, + Optional:$stride, + DefaultValuedAttr:$strideInBytes, + Optional:$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 traits = []> : + OpenACC_Op { + let arguments = (ins OpenACC_PointerLikeTypeInterface:$varPtr, + Optional:$varPtrPtr, + Variadic:$bounds, /* rank-0 to rank-{n-1} */ + DefaultValuedAttr:$dataClause, + OptionalAttr:$decomposedFrom, + DefaultValuedAttr:$structured, + DefaultValuedAttr:$implicit, + OptionalAttr:$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 traits = []> : + OpenACC_Op { + let arguments = (ins Optional:$varPtr, + OpenACC_PointerLikeTypeInterface:$accPtr, + Variadic:$bounds, + DefaultValuedAttr:$dataClause, + OptionalAttr:$decomposedFrom, + DefaultValuedAttr:$structured, + DefaultValuedAttr:$implicit, + OptionalAttr:$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 @@ -112,6 +333,7 @@ def OpenACC_ParallelOp : OpenACC_Op<"parallel", Variadic:$attachOperands, Variadic:$gangPrivateOperands, Variadic:$gangFirstPrivateOperands, + Variadic:$dataClauseOperands, OptionalAttr:$defaultAttr); let regions = (region AnyRegion:$region); @@ -126,7 +348,8 @@ def OpenACC_ParallelOp : OpenACC_Op<"parallel", 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) `)` @@ -160,7 +383,8 @@ def OpenACC_ParallelOp : OpenACC_Op<"parallel", // 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 @@ -197,6 +421,7 @@ def OpenACC_SerialOp : OpenACC_Op<"serial", [AttrSizedOperandSegments]> { Variadic:$attachOperands, Variadic:$gangPrivateOperands, Variadic:$gangFirstPrivateOperands, + Variadic:$dataClauseOperands, OptionalAttr:$defaultAttr); let regions = (region AnyRegion:$region); @@ -211,7 +436,8 @@ def OpenACC_SerialOp : OpenACC_Op<"serial", [AttrSizedOperandSegments]> { 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) `)` @@ -242,7 +468,8 @@ def OpenACC_SerialOp : OpenACC_Op<"serial", [AttrSizedOperandSegments]> { // 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 @@ -280,6 +507,7 @@ def OpenACC_KernelsOp : OpenACC_Op<"kernels", [AttrSizedOperandSegments]> { Variadic:$presentOperands, Variadic:$devicePtrOperands, Variadic:$attachOperands, + Variadic:$dataClauseOperands, OptionalAttr:$defaultAttr); let regions = (region AnyRegion:$region); @@ -294,7 +522,8 @@ def OpenACC_KernelsOp : OpenACC_Op<"kernels", [AttrSizedOperandSegments]> { 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) `)` @@ -324,7 +553,7 @@ def OpenACC_KernelsOp : OpenACC_Op<"kernels", [AttrSizedOperandSegments]> { //===----------------------------------------------------------------------===// def OpenACC_DataOp : OpenACC_Op<"data", - [AttrSizedOperandSegments]> { + [AttrSizedOperandSegments, RecursiveMemoryEffects]> { let summary = "data construct"; let description = [{ @@ -357,6 +586,7 @@ def OpenACC_DataOp : OpenACC_Op<"data", Variadic:$presentOperands, Variadic:$deviceptrOperands, Variadic:$attachOperands, + Variadic:$dataClauseOperands, OptionalAttr:$defaultAttr); let regions = (region AnyRegion:$region); @@ -372,6 +602,7 @@ def OpenACC_DataOp : OpenACC_Op<"data", let assemblyFormat = [{ oilist( `if` `(` $ifCond `)` + | `dataOperands` `(` $dataClauseOperands `:` type($dataClauseOperands) `)` | `copy` `(` $copyOperands `:` type($copyOperands) `)` | `copyin` `(` $copyinOperands `:` type($copyinOperands) `)` | `copyin_readonly` `(` $copyinReadonlyOperands `:` @@ -431,7 +662,8 @@ def OpenACC_EnterDataOp : OpenACC_Op<"enter_data", [AttrSizedOperandSegments]> { Variadic:$copyinOperands, Variadic:$createOperands, Variadic:$createZeroOperands, - Variadic:$attachOperands); + Variadic:$attachOperands, + Variadic:$dataClauseOperands); let extraClassDeclaration = [{ /// The number of data operands. @@ -452,6 +684,7 @@ def OpenACC_EnterDataOp : OpenACC_Op<"enter_data", [AttrSizedOperandSegments]> { | `create_zero` `(` $createZeroOperands `:` type($createZeroOperands) `)` | `attach` `(` $attachOperands `:` type($attachOperands) `)` + | `dataOperands` `(` $dataClauseOperands `:` type($dataClauseOperands) `)` ) attr-dict-with-keyword }]; @@ -486,6 +719,7 @@ def OpenACC_ExitDataOp : OpenACC_Op<"exit_data", [AttrSizedOperandSegments]> { Variadic:$copyoutOperands, Variadic:$deleteOperands, Variadic:$detachOperands, + Variadic:$dataClauseOperands, UnitAttr:$finalize); let extraClassDeclaration = [{ @@ -505,6 +739,7 @@ def OpenACC_ExitDataOp : OpenACC_Op<"exit_data", [AttrSizedOperandSegments]> { | `copyout` `(` $copyoutOperands `:` type($copyoutOperands) `)` | `delete` `(` $deleteOperands `:` type($deleteOperands) `)` | `detach` `(` $detachOperands `:` type($detachOperands) `)` + | `dataOperands` `(` $dataClauseOperands `:` type($dataClauseOperands) `)` ) attr-dict-with-keyword }]; @@ -517,7 +752,8 @@ def OpenACC_ExitDataOp : OpenACC_Op<"exit_data", [AttrSizedOperandSegments]> { // 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 = [{ diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOpsTypes.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOpsTypes.td new file mode 100644 index 0000000000000..41a18e4d206d4 --- /dev/null +++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOpsTypes.td @@ -0,0 +1,27 @@ +//===- 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 : TypeDef { + 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 diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td new file mode 100644 index 0000000000000..0a3edd5637704 --- /dev/null +++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td @@ -0,0 +1,34 @@ +//===-- 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 diff --git a/mlir/lib/Dialect/OpenACC/CMakeLists.txt b/mlir/lib/Dialect/OpenACC/CMakeLists.txt index 770623c9c72b7..5e09044ad2155 100644 --- a/mlir/lib/Dialect/OpenACC/CMakeLists.txt +++ b/mlir/lib/Dialect/OpenACC/CMakeLists.txt @@ -6,6 +6,9 @@ add_mlir_dialect_library(MLIROpenACCDialect DEPENDS MLIROpenACCOpsIncGen + MLIROpenACCEnumsIncGen + MLIROpenACCAttributesIncGen + MLIROpenACCTypeInterfacesIncGen LINK_LIBS PUBLIC MLIRIR diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp index 4b3b43881975a..17f1bbddff0cb 100644 --- a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp +++ b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp @@ -7,7 +7,9 @@ // ============================================================================= #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" @@ -20,6 +22,8 @@ using namespace mlir; 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 @@ -34,6 +38,161 @@ void OpenACCDialect::initialize() { #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(*getContext()); + MemRefType::attachInterface(*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 @@ -95,7 +254,8 @@ unsigned ParallelOp::getNumDataOperands() { 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) { @@ -119,7 +279,8 @@ unsigned SerialOp::getNumDataOperands() { 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) { @@ -139,7 +300,7 @@ unsigned KernelsOp::getNumDataOperands() { getCopyoutZeroOperands().size() + getCreateOperands().size() + getCreateZeroOperands().size() + getNoCreateOperands().size() + getPresentOperands().size() + getDevicePtrOperands().size() + - getAttachOperands().size(); + getAttachOperands().size() + getDataClauseOperands().size(); } Value KernelsOp::getDataOperand(unsigned i) { @@ -290,7 +451,7 @@ unsigned DataOp::getNumDataOperands() { getCopyoutZeroOperands().size() + getCreateOperands().size() + getCreateZeroOperands().size() + getNoCreateOperands().size() + getPresentOperands().size() + getDeviceptrOperands().size() + - getAttachOperands().size(); + getAttachOperands().size() + getDataClauseOperands().size(); } Value DataOp::getDataOperand(unsigned i) { @@ -307,7 +468,7 @@ LogicalResult acc::ExitDataOp::verify() { // 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"); @@ -330,7 +491,7 @@ LogicalResult acc::ExitDataOp::verify() { unsigned ExitDataOp::getNumDataOperands() { return getCopyoutOperands().size() + getDeleteOperands().size() + - getDetachOperands().size(); + getDetachOperands().size() + getDataClauseOperands().size(); } Value ExitDataOp::getDataOperand(unsigned i) { @@ -354,7 +515,8 @@ LogicalResult acc::EnterDataOp::verify() { // 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"); @@ -377,7 +539,8 @@ LogicalResult acc::EnterDataOp::verify() { unsigned EnterDataOp::getNumDataOperands() { return getCopyinOperands().size() + getCreateOperands().size() + - getCreateZeroOperands().size() + getAttachOperands().size(); + getCreateZeroOperands().size() + getAttachOperands().size() + + getDataClauseOperands().size(); } Value EnterDataOp::getDataOperand(unsigned i) { @@ -480,3 +643,6 @@ LogicalResult acc::WaitOp::verify() { #define GET_ATTRDEF_CLASSES #include "mlir/Dialect/OpenACC/OpenACCOpsAttributes.cpp.inc" + +#define GET_TYPEDEF_CLASSES +#include "mlir/Dialect/OpenACC/OpenACCOpsTypes.cpp.inc" diff --git a/mlir/test/Dialect/OpenACC/ops.mlir b/mlir/test/Dialect/OpenACC/ops.mlir index b1ee051699a8b..825bc067578c5 100644 --- a/mlir/test/Dialect/OpenACC/ops.mlir +++ b/mlir/test/Dialect/OpenACC/ops.mlir @@ -974,3 +974,145 @@ func.func @testenterdataop(%a: memref<10xf32>, %b: memref<10xf32>, %c: memref<10 // 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>, %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> + acc.parallel dataOperands(%attach : memref>) { + } + acc.detach accPtr(%attach : memref>) {decomposedFrom = 10} + + %copyinparent = acc.copyin varPtr(%a : memref<10xf32>) varPtrPtr(%b : memref>) -> 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>, [[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> +// CHECK-NEXT: acc.parallel dataOperands([[ATTACH]] : memref>) { +// CHECK-NEXT: } +// CHECK-NEXT: acc.detach accPtr([[ATTACH]] : memref>) {decomposedFrom = 10 : i64} +// CHECK: [[COPYINP:%.*]] = acc.copyin varPtr([[ARGA]] : memref<10xf32>) varPtrPtr([[ARGB]] : memref>) -> 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}