From 62ed2a19644de44d532555d4e0205d7dd09c2cc3 Mon Sep 17 00:00:00 2001 From: Andrew Gozillon Date: Mon, 12 Feb 2024 10:20:30 -0600 Subject: [PATCH] [OpenMP][MLIR] Add new arguments to map_info to help support record type maps This PR adds two new fields to omp.map_info, one BoolAttr and one I64ArrayAttr. The BoolAttr is named partial_map, and is a flag that indicates if the record type captured by the map_info operation is a partial map, or if it is mapped in its entirety, this currently helps the later lowering determine the type of map entries that need to be generated. The I64ArrayAttr named members_index is intended to track the placement of each member map_info operations (and by extension mapped member variable) placement in the parent record type. This may need to be extended to an N-D array for nested member mapping. Pull Request: https://github.com/llvm/llvm-project/pull/82851 --- mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td | 18 ++++++++---- mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp | 7 +++++ mlir/test/Dialect/OpenMP/ops.mlir | 29 +++++++++++++++---- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td index dcf04ab242257..6e19bcceaa10f 100644 --- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td +++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td @@ -1308,10 +1308,12 @@ def MapInfoOp : OpenMP_Op<"map_info", [AttrSizedOperandSegments]> { TypeAttr:$var_type, Optional:$var_ptr_ptr, Variadic:$members, + OptionalAttr:$members_index, Variadic:$bounds, /* rank-0 to rank-{n-1} */ OptionalAttr:$map_type, OptionalAttr:$map_capture_type, - OptionalAttr:$name); + OptionalAttr:$name, + DefaultValuedAttr:$partial_map); let results = (outs OpenMP_PointerLikeType:$omp_ptr); let description = [{ @@ -1347,10 +1349,14 @@ def MapInfoOp : OpenMP_Op<"map_info", [AttrSizedOperandSegments]> { - `var_type`: The type of the variable to copy. - `var_ptr_ptr`: Used when the variable copied is a member of a class, structure or derived type and refers to the originating struct. - - `members`: Used to indicate mapped child members for the current MapInfoOp, - represented as other MapInfoOp's, utilised in cases where a parent structure - type and members of the structure type are being mapped at the same time. + - `members`: Used to indicate mapped child members for the current MapInfoOp, + represented as other MapInfoOp's, utilised in cases where a parent structure + type and members of the structure type are being mapped at the same time. For example: map(to: parent, parent->member, parent->member2[:10]) + - `members_index`: Used to indicate the ordering of members within the containing + parent (generally a record type such as a structure, class or derived type), + e.g. struct {int x, float y, double z}, x would be 0, y would be 1, and z + would be 2. This aids the mapping - `bounds`: Used when copying slices of array's, pointers or pointer members of objects (e.g. derived types or classes), indicates the bounds to be copied of the variable. When it's an array slice it is in rank order where rank 0 @@ -1361,6 +1367,8 @@ def MapInfoOp : OpenMP_Op<"map_info", [AttrSizedOperandSegments]> { - 'map_capture_type': Capture type for the variable e.g. this, byref, byvalue, byvla this can affect how the variable is lowered. - `name`: Holds the name of variable as specified in user clause (including bounds). + - `partial_map`: The record type being mapped will not be mapped in its entirety, + it may be used however, in a mapping to bind it's mapped components together. }]; let assemblyFormat = [{ @@ -1369,7 +1377,7 @@ def MapInfoOp : OpenMP_Op<"map_info", [AttrSizedOperandSegments]> { `var_ptr_ptr` `(` $var_ptr_ptr `:` type($var_ptr_ptr) `)` | `map_clauses` `(` custom($map_type) `)` | `capture` `(` custom($map_capture_type) `)` - | `members` `(` $members `:` type($members) `)` + | `members` `(` $members `:` type($members) `:` $members_index `)` | `bounds` `(` $bounds `)` ) `->` type($omp_ptr) attr-dict }]; diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp index e7b899aec4afb..06c6c73b3e568 100644 --- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp +++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp @@ -915,6 +915,9 @@ static ParseResult parseMapClause(OpAsmParser &parser, IntegerAttr &mapType) { if (mapTypeMod == "delete") mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_DELETE; + if (mapTypeMod == "ptr_and_obj") + mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ; + return success(); }; @@ -951,6 +954,10 @@ static void printMapClause(OpAsmPrinter &p, Operation *op, if (mapTypeToBitFlag(mapTypeBits, llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_PRESENT)) mapTypeStrs.push_back("present"); + if (mapTypeToBitFlag( + mapTypeBits, + llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ)) + mapTypeStrs.push_back("ptr_and_obj"); // special handling of to/from/tofrom/delete and release/alloc, release + // alloc are the abscense of one of the other flags, whereas tofrom requires diff --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir index 211ff0ff9272e..981923cbdaef4 100644 --- a/mlir/test/Dialect/OpenMP/ops.mlir +++ b/mlir/test/Dialect/OpenMP/ops.mlir @@ -2063,8 +2063,6 @@ func.func @omp_requires_multiple() -> () return } -// ----- - // CHECK-LABEL: @opaque_pointers_atomic_rwu // CHECK-SAME: (%[[v:.*]]: !llvm.ptr, %[[x:.*]]: !llvm.ptr) func.func @opaque_pointers_atomic_rwu(%v: !llvm.ptr, %x: !llvm.ptr) { @@ -2171,10 +2169,10 @@ func.func @omp_target_update_data (%if_cond : i1, %device : si32, %map1: memref< // CHECK-LABEL: omp_targets_is_allocatable // CHECK-SAME: (%[[ARG0:.*]]: !llvm.ptr, %[[ARG1:.*]]: !llvm.ptr) func.func @omp_targets_is_allocatable(%arg0: !llvm.ptr, %arg1: !llvm.ptr) -> () { - // CHECK: %[[MAP0:.*]] = omp.map_info var_ptr(%[[ARG0]] : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""} - %mapv1 = omp.map_info var_ptr(%arg0 : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""} - // CHECK: %[[MAP1:.*]] = omp.map_info var_ptr(%[[ARG1]] : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>) map_clauses(tofrom) capture(ByRef) members(%[[MAP0]] : !llvm.ptr) -> !llvm.ptr {name = ""} - %mapv2 = omp.map_info var_ptr(%arg1 : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>) map_clauses(tofrom) capture(ByRef) members(%mapv1 : !llvm.ptr) -> !llvm.ptr {name = ""} + // CHECK: %[[MAP0:.*]] = omp.map_info var_ptr(%[[ARG0]] : !llvm.ptr, i32) map_clauses(ptr_and_obj, tofrom) capture(ByRef) -> !llvm.ptr {name = ""} + %mapv1 = omp.map_info var_ptr(%arg0 : !llvm.ptr, i32) map_clauses(ptr_and_obj, tofrom) capture(ByRef) -> !llvm.ptr {name = ""} + // CHECK: %[[MAP1:.*]] = omp.map_info var_ptr(%[[ARG1]] : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>) map_clauses(tofrom) capture(ByRef) members(%[[MAP0]] : !llvm.ptr : [0]) -> !llvm.ptr {name = ""} + %mapv2 = omp.map_info var_ptr(%arg1 : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>) map_clauses(tofrom) capture(ByRef) members(%mapv1 : !llvm.ptr : [0]) -> !llvm.ptr {name = ""} // CHECK: omp.target map_entries(%[[MAP0]] -> {{.*}}, %[[MAP1]] -> {{.*}} : !llvm.ptr, !llvm.ptr) omp.target map_entries(%mapv1 -> %arg2, %mapv2 -> %arg3 : !llvm.ptr, !llvm.ptr) { ^bb0(%arg2: !llvm.ptr, %arg3 : !llvm.ptr): @@ -2229,6 +2227,25 @@ func.func @omp_target_enter_update_exit_data_depend(%a: memref, %b: memre } // CHECK: omp.target_exit_data map_entries([[MAP2]] : memref) depend(taskdependin -> [[ARG2]] : memref) omp.target_exit_data map_entries(%map_c : memref) depend(taskdependin -> %c : memref) + + return +} + +// CHECK-LABEL: omp_map_with_members +// CHECK-SAME: (%[[ARG0:.*]]: !llvm.ptr, %[[ARG1:.*]]: !llvm.ptr, %[[ARG2:.*]]: !llvm.ptr) +func.func @omp_map_with_members(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) -> () { + // CHECK: %[[MAP0:.*]] = omp.map_info var_ptr(%[[ARG0]] : !llvm.ptr, i32) map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""} + %mapv1 = omp.map_info var_ptr(%arg0 : !llvm.ptr, i32) map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""} + + // CHECK: %[[MAP1:.*]] = omp.map_info var_ptr(%[[ARG1]] : !llvm.ptr, f32) map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""} + %mapv2 = omp.map_info var_ptr(%arg1 : !llvm.ptr, f32) map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""} + + // CHECK: %[[MAP2:.*]] = omp.map_info var_ptr(%[[ARG2]] : !llvm.ptr, !llvm.struct<(i32, f32)>) map_clauses(to) capture(ByRef) members(%[[MAP0]], %[[MAP1]] : !llvm.ptr, !llvm.ptr : [0, 1]) -> !llvm.ptr {name = "", partial_map = true} + %mapv3 = omp.map_info var_ptr(%arg2 : !llvm.ptr, !llvm.struct<(i32, f32)>) map_clauses(to) capture(ByRef) members(%mapv1, %mapv2 : !llvm.ptr, !llvm.ptr : [0, 1]) -> !llvm.ptr {name = "", partial_map = true} + + // CHECK: omp.target_enter_data map_entries(%[[MAP0]], %[[MAP1]], %[[MAP2]] : !llvm.ptr, !llvm.ptr, !llvm.ptr) + omp.target_enter_data map_entries(%mapv1, %mapv2, %mapv3 : !llvm.ptr, !llvm.ptr, !llvm.ptr){} + return }