[Mlir-commits] [mlir] [MLIR][OpenMP] Add OMP Declare Mapper MLIR Op definition (PR #117045)
Sergio Afonso
llvmlistbot at llvm.org
Tue Nov 26 08:55:19 PST 2024
================
@@ -879,6 +879,14 @@ cleanup {
omp.yield
}
+// CHECK: %[[DECL_VAR:.*]] = llvm.alloca %{{.*}}
+// CHECK: %[[DECL_MAP_INFO:.*]] = omp.map.info var_ptr(%[[DECL_VAR]] : !llvm.ptr, !llvm.struct<"my_type", (i32)>) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""}
+// CHECK: omp.declare_mapper @my_mapper : %[[DECL_VAR]] : !llvm.ptr : !llvm.struct<"my_type", (i32)> map_entries(%[[DECL_MAP_INFO]] : !llvm.ptr)
+%decl_c1 = arith.constant 1 : i64
+%decl_var = llvm.alloca %decl_c1 x !llvm.struct<"my_type", (i32)> : (i64) -> !llvm.ptr
+%decl_map_info = omp.map.info var_ptr(%decl_var : !llvm.ptr, !llvm.struct<"my_type", (i32)>) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""}
+omp.declare_mapper @my_mapper : %decl_var : !llvm.ptr : !llvm.struct<"my_type", (i32)> map_entries(%decl_map_info : !llvm.ptr)
----------------
skatrak wrote:
I have one major concern about this operation definition, which is perhaps a result of misunderstanding it, so let me know if that's the case.
The declare mapper construct lets a user basically define a recipe that takes one argument of a given type and use it to represent an unspecified variable of that type within one or more map clauses. That placeholder variable is then bound to specific variables when encountering another map clause for which the defined mapper is implicitly or explicitly applied. The result is as if the encountered map clause was replaced by the map clause(s) defined in the mapper, after replacing the placeholder variable with the actual variable being mapped.
As such, I'd expect its definition to be global (just like privatizers and `omp.declare_reduction`) and contain a region with an entry block argument for that placeholder variable (and maybe also other(s) for bounds). My understanding is that the region would construct the map arguments and `omp.yield` them. Users of the mapper would "call" the mapper through its global symbol and a pointer-like variable. The translation to LLVM IR of map clauses using a declared mapper would have to inline the recipe body while binding the entry block argument to the variable being mapped and treating the yielded results like any other mapped variable.
In MLIR, I'm picturing something like this:
```mlir
omp.declare_mapper @my_mapper(%arg0 : !llvm.ptr) {
%mapinfo = omp.map.info var_ptr(%arg0 : !llvm.ptr, !llvm.struct<"my_type", (i32)>) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr
omp.yield(%mapinfo : !llvm.ptr)
}
func.func @foo(...) {
...
omp.target map_entries(@my_mapper %x -> %x.mapped : !llvm.ptr) {
...
}
return
}
```
And for declare mappers that result in multiple mapped variables something like this:
```mlir
omp.declare_mapper @my_mapper(%arg0 : !llvm.ptr) {
%gep1 = llvm.getelementptr %arg0[0, 3] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(f32, array<10 x i32>, struct<(f32, i32)>, i32)>
%mapinfo1 = omp.map.info var_ptr(%gep1 : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr
%gep2 = llvm.getelementptr %arg0[0, 2, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(f32, array<10 x i32>, struct<(f32, i32)>, i32)>
%mapinfo2 = omp.map.info var_ptr(%gep2 : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr
omp.yield(%mapinfo1, %mapinfo2 : !llvm.ptr, !llvm.ptr)
}
func.func @foo(...) {
...
omp.target map_entries(@my_mapper %x -> %x.mapped.1, %x.mapped.2 : !llvm.ptr, !llvm.ptr) {
...
}
return
}
```
My thinking is that, without making `omp.declare_mapper` a recipe operation, we're not able to actually define something that can be used when mapping variables elsewhere, but rather we have to produce an ad-hoc operation at each place where the mapper is instantiated, leaving all of the work to the frontend, in which case we don't even need an explicit MLIR representation for it.
https://github.com/llvm/llvm-project/pull/117045
More information about the Mlir-commits
mailing list