diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td --- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td +++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td @@ -785,6 +785,154 @@ let assemblyFormat = "attr-dict"; } +//===---------------------------------------------------------------------===// +// 2.12.2 target data Construct +//===---------------------------------------------------------------------===// + +def Target_Data: OpenMP_Op<"target_data", [AttrSizedOperandSegments]>{ + let summary = "target data construct"; + let description = [{ + Map variables to a device data environment for the extent of the region. + + The omp target data directive maps variables to a device data + environment, and defines the lexical scope of the data environment + that is created. The omp target data directive can reduce data copies + to and from the offloading device when multiple target regions are using + the same data. + + The optional $if_expr parameter specifies a boolean result of a + conditional check. If this value is 1 or is not provided then the target + region runs on a device, if it is 0 then the target region is executed + on the host device. + + The optional $device parameter specifies the device number for the target + region. + + The optional $use_device_ptr specifies the device pointers to the + corresponding list items in the device data environment. + + The optional $use_device_addr specifies the address of the objects in the + device data enviornment. + + The $map_operands specifies operands in map clause along with it's type and modifiers. + + The $map_operand_segments specifies the segment sizes for $map_operands. + + TODO: depend clause and map_type_modifier values iterator and mapper. + }]; + + let arguments = (ins Optional:$if_expr, + Optional:$device, + Variadic:$use_device_ptr, + Variadic:$use_device_addr, + VariadicOfVariadic:$map_operands, + DenseI32ArrayAttr:$map_operand_segments); + + let regions = (region AnyRegion:$region); + + let assemblyFormat = [{ + oilist(`if` `(` $if_expr `:` type($if_expr) `)` + | `device` `(` $device `:` type($device) `)` + | `use_device_ptr` `(` $use_device_ptr `:` type($use_device_ptr) `)` + | `use_device_addr` `(` $use_device_addr `:` type($use_device_addr) `)` + | `map` `(` custom($map_operands, type($map_operands)) `)`) + $region attr-dict + }]; + +} + +//===---------------------------------------------------------------------===// +// 2.12.3 target enter data Construct +//===---------------------------------------------------------------------===// + +def Target_EnterDataOp: OpenMP_Op<"target_enter_data", + [AttrSizedOperandSegments]>{ + let summary = "target enter data construct"; + let description = [{ + The target enter data directive specifies that variables are mapped to + a device data environment. The target enter data directive is a + stand-alone directive. + + The optional $if_expr parameter specifies a boolean result of a + conditional check. If this value is 1 or is not provided then the target + region runs on a device, if it is 0 then the target region is executed on + the host device. + + The optional $device parameter specifies the device number for the + target region. + + The optional $nowait eliminates the implicit barrier so the parent task + can make progress even if the target task is not yet completed. + + The $map_operands specifies operands in map clause along with it's type and modifiers. + + The $map_operand_segments specifies the segment sizes for $map_operands. + + TODO: depend clause and map_type_modifier values iterator and mapper. + }]; + + let arguments = (ins Optional:$if_expr, + Optional:$device, + UnitAttr:$nowait, + VariadicOfVariadic:$map_operands, + DenseI32ArrayAttr:$map_operand_segments); + + let assemblyFormat = [{ + oilist(`if` `(` $if_expr `:` type($if_expr) `)` + | `device` `(` $device `:` type($device) `)` + | `nowait` $nowait + | `map` `(` custom($map_operands, type($map_operands)) `)`) + attr-dict + }]; + +} + +//===---------------------------------------------------------------------===// +// 2.12.4 target exit data Construct +//===---------------------------------------------------------------------===// + +def Target_ExitDataOp: OpenMP_Op<"target_exit_data", + [AttrSizedOperandSegments]>{ + let summary = "target exit data construct"; + let description = [{ + The target exit data directive specifies that variables are mapped to a + device data environment. The target exit data directive is + a stand-alone directive. + + The optional $if_expr parameter specifies a boolean result of a + conditional check. If this value is 1 or is not provided then the target + region runs on a device, if it is 0 then the target region is executed + on the host device. + + The optional $device parameter specifies the device number for the + target region. + + The optional $nowait eliminates the implicit barrier so the parent + task can make progress even if the target task is not yet completed. + + The $map_operands specifies operands in map clause along with it's type and modifiers. + + The $map_operand_segments specifies the segment sizes for $map_operands. + + TODO: depend clause and map_type_modifier values iterator and mapper. + }]; + + let arguments = (ins Optional:$if_expr, + Optional:$device, + UnitAttr:$nowait, + VariadicOfVariadic:$map_operands, + DenseI32ArrayAttr:$map_operand_segments); + + let assemblyFormat = [{ + oilist(`if` `(` $if_expr `:` type($if_expr) `)` + | `device` `(` $device `:` type($device) `)` + | `nowait` $nowait + | `map` `(` custom($map_operands, type($map_operands)) `)`) + attr-dict + }]; + +} + //===----------------------------------------------------------------------===// // 2.13.7 flush Construct //===----------------------------------------------------------------------===// diff --git a/mlir/lib/Dialect/OpenMP/CMakeLists.txt b/mlir/lib/Dialect/OpenMP/CMakeLists.txt --- a/mlir/lib/Dialect/OpenMP/CMakeLists.txt +++ b/mlir/lib/Dialect/OpenMP/CMakeLists.txt @@ -12,4 +12,5 @@ LINK_LIBS PUBLIC MLIRIR MLIRLLVMDialect + MLIRArithDialect ) diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp --- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp +++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "mlir/Dialect/OpenMP/OpenMPDialect.h" +#include "mlir/Dialect/Arith/IR/Arith.h" #include "mlir/Dialect/LLVMIR/LLVMTypes.h" #include "mlir/IR/Attributes.h" #include "mlir/IR/DialectImplementation.h" @@ -23,6 +24,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/TypeSwitch.h" #include +#include #include "mlir/Dialect/OpenMP/OpenMPOpsDialect.cpp.inc" #include "mlir/Dialect/OpenMP/OpenMPOpsEnums.cpp.inc" @@ -536,6 +538,74 @@ return success(); } +//===----------------------------------------------------------------------===// +// Parser, printer and verifier for Target Data +//===----------------------------------------------------------------------===// +static ParseResult parseMapClause( + OpAsmParser &parser, + SmallVector> &map_operands, + SmallVector> &map_operand_types) { + StringRef mapTypeMod, mapType; + OpAsmParser::UnresolvedOperand arg1, arg2; + Type arg2Type; + auto parseKeyword = [&]() -> ParseResult { + if (parser.parseLParen() || parser.parseOperand(arg1) || + parser.parseArrow() || parser.parseKeyword(&mapTypeMod) || + parser.parseComma() || parser.parseKeyword(&mapType) || + parser.parseColon() || parser.parseOperand(arg2) || + parser.parseColon() || parser.parseType(arg2Type) || + parser.parseRParen()) + return failure(); + map_operands.push_back({arg1, arg2}); + map_operand_types.push_back({parser.getBuilder().getI64Type(), arg2Type}); + return success(); + }; + if (parser.parseCommaSeparatedList(parseKeyword)) + return failure(); + return success(); +} + +static void printMapClause(OpAsmPrinter &p, Operation *op, + OperandRangeRange map_operands, + TypeRangeRange map_operand_types) { + for (const auto &a : map_operands) { + auto mapTypeBits = 0x00; + if (auto constOp = + mlir::dyn_cast(a.front().getDefiningOp())) + mapTypeBits = constOp.getValue() + .cast() + .getValue() + .getSExtValue(); + else if (auto constOp = mlir::dyn_cast( + a.front().getDefiningOp())) + mapTypeBits = constOp.getValue().dyn_cast().getInt(); + + std::stringstream typeMod, type; + if (mapTypeBits & 0x04) + typeMod << "always "; + if (mapTypeBits & 0x400) + typeMod << "close "; + if (mapTypeBits & 0x1000) + typeMod << "present "; + if (typeMod.str().empty()) + typeMod << "none "; + + if (mapTypeBits & 0x01) + type << "to "; + if (mapTypeBits & 0x02) + type << "from "; + if (mapTypeBits & 0x08) + type << "delete "; + if (type.str().empty()) + type << (isa(op) ? "alloc " : "release "); + + p << '(' << a.front() << " -> " << typeMod.str() << ", " << type.str() + << ": " << a.back() << " : " << a.back().getType() << ')'; + if (a != map_operands.back()) + p << ", "; + } +} + //===----------------------------------------------------------------------===// // ParallelOp //===----------------------------------------------------------------------===// diff --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir --- a/mlir/test/Dialect/OpenMP/ops.mlir +++ b/mlir/test/Dialect/OpenMP/ops.mlir @@ -451,6 +451,23 @@ return } +// CHECK-LABEL: omp_target_data +func.func @omp_target_data (%if_cond : i1, %device : si32, %map: memref) -> () { + %c6_i64 = arith.constant 6 : i64 + + // CHECK: omp.target_data if({{.*}}) device({{.*}}) map({{.*}}) + "omp.target_data"(%if_cond, %device, %c6_i64, %map) ({}) {operand_segment_sizes = array, map_operand_segments = array } : ( i1, si32, i64, memref ) -> () + + // CHECK: omp.target_enter_data map({{.*}}) + "omp.target_enter_data"(%c6_i64, %map) {operand_segment_sizes = array, map_operand_segments = array } : ( i64, memref ) -> () + + // CHECK: omp.target_exit_data nowait map({{.*}}) + "omp.target_exit_data"(%c6_i64, %map) {nowait, operand_segment_sizes = array, map_operand_segments = array } : ( i64, memref ) -> () + return +} + + + // CHECK-LABEL: omp_target_pretty func.func @omp_target_pretty(%if_cond : i1, %device : si32, %num_threads : i32) -> () { // CHECK: omp.target if({{.*}}) device({{.*}})