-
Notifications
You must be signed in to change notification settings - Fork 12.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[mlir][OpenMP] - MLIR to LLVMIR translation support for delayed priva…
…tization of allocatables in `omp.target` ops This PR adds support to translate the `private` clause from MLIR to LLVMIR when used on allocatables in the context of an `omp.target` op.
- Loading branch information
Showing
7 changed files
with
368 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
80 changes: 80 additions & 0 deletions
80
mlir/test/Target/LLVMIR/openmp-target-multiple-private.mlir
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s | ||
|
||
llvm.func @dealloc_foo_0(!llvm.ptr) | ||
|
||
omp.private {type = private} @box.heap_privatizer0 : !llvm.ptr alloc { | ||
^bb0(%arg0: !llvm.ptr): | ||
%0 = llvm.mlir.constant(1 : i32) : i32 | ||
%7 = llvm.alloca %0 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> : (i32) -> !llvm.ptr | ||
omp.yield(%7 : !llvm.ptr) | ||
} dealloc { | ||
^bb0(%arg0: !llvm.ptr): | ||
llvm.call @dealloc_foo_0(%arg0) : (!llvm.ptr) -> () | ||
omp.yield | ||
} | ||
|
||
llvm.func @alloc_foo_1(!llvm.ptr) | ||
llvm.func @dealloc_foo_1(!llvm.ptr) | ||
|
||
omp.private {type = private} @box.heap_privatizer1 : !llvm.ptr alloc { | ||
^bb0(%arg0: !llvm.ptr): | ||
%0 = llvm.mlir.constant(1 : i32) : i32 | ||
%7 = llvm.alloca %0 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> : (i32) -> !llvm.ptr | ||
llvm.call @alloc_foo_1(%arg0) : (!llvm.ptr) -> () | ||
omp.yield(%7 : !llvm.ptr) | ||
} dealloc { | ||
^bb0(%arg0: !llvm.ptr): | ||
llvm.call @dealloc_foo_1(%arg0) : (!llvm.ptr) -> () | ||
omp.yield | ||
} | ||
|
||
llvm.func @target_allocatable_(%arg0: !llvm.ptr {fir.bindc_name = "lb"}, %arg1: !llvm.ptr {fir.bindc_name = "ub"}, %arg2: !llvm.ptr {fir.bindc_name = "l"}) attributes {fir.internal_name = "_QPtarget_allocatable"} { | ||
%6 = llvm.mlir.constant(1 : i64) : i64 | ||
%7 = llvm.alloca %6 x i32 {bindc_name = "mapped_var"} : (i64) -> !llvm.ptr | ||
%13 = llvm.alloca %6 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> {bindc_name = "alloc_var0"} : (i64) -> !llvm.ptr | ||
%14 = llvm.alloca %6 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> {bindc_name = "alloc_var1"} : (i64) -> !llvm.ptr | ||
%53 = omp.map.info var_ptr(%7 : !llvm.ptr, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !llvm.ptr {name = "mapped_var"} | ||
%54 = omp.map.info var_ptr(%13 : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>) map_clauses(to) capture(ByRef) -> !llvm.ptr | ||
%55 = omp.map.info var_ptr(%14 : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>) map_clauses(to) capture(ByRef) -> !llvm.ptr | ||
omp.target map_entries(%53 -> %arg3, %54 -> %arg4, %55 ->%arg5 : !llvm.ptr, !llvm.ptr, !llvm.ptr) private(@box.heap_privatizer0 %13 -> %arg6 [map_idx=1], @box.heap_privatizer1 %14 -> %arg7 [map_idx=2]: !llvm.ptr, !llvm.ptr) { | ||
llvm.call @use_private_var0(%arg6) : (!llvm.ptr) -> () | ||
llvm.call @use_private_var1(%arg7) : (!llvm.ptr) -> () | ||
omp.terminator | ||
} | ||
llvm.return | ||
} | ||
|
||
|
||
llvm.func @use_private_var0(!llvm.ptr) -> () | ||
llvm.func @use_private_var1(!llvm.ptr) -> () | ||
|
||
// The first set of checks ensure that we are calling the offloaded function | ||
// with the right arguments, especially the second argument which needs to | ||
// be a memory reference to the descriptor for the privatized allocatable | ||
// CHECK: define void @target_allocatable_ | ||
// CHECK-NOT: define internal void | ||
// CHECK: %[[DESC_ALLOC0:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8 }, i64 1 | ||
// CHECK: %[[DESC_ALLOC1:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8 }, i64 1 | ||
// CHECK: call void @__omp_offloading_[[OFFLOADED_FUNCTION:.*]](ptr {{[^,]+}}, | ||
// CHECK-SAME: ptr %[[DESC_ALLOC0]], ptr %[[DESC_ALLOC1]]) | ||
|
||
// CHECK: define internal void @__omp_offloading_[[OFFLOADED_FUNCTION]] | ||
// CHECK-SAME: (ptr {{[^,]+}}, ptr %[[DESCRIPTOR_ARG0:[^,]+]], | ||
// CHECK-SAME: ptr %[[DESCRIPTOR_ARG1:.*]]) { | ||
|
||
// `var0` privatrizer `alloc` | ||
// CHECK: %[[PRIV_DESC0:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8 } | ||
|
||
// `var1` privatrizer `alloc` | ||
// CHECK: %[[PRIV_DESC1:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8 } | ||
// CHECK: call void @alloc_foo_1(ptr %[[DESCRIPTOR_ARG1]]) | ||
|
||
// target op body | ||
// CHECK: call void @use_private_var0(ptr %[[PRIV_DESC0]] | ||
// CHECK: call void @use_private_var1(ptr %[[PRIV_DESC1]] | ||
|
||
// `var0` privatrizer `dealloc` | ||
// CHECK: call void @dealloc_foo_0(ptr %[[PRIV_DESC0]]) | ||
|
||
// `var1` privatrizer `dealloc` | ||
// CHECK: call void @dealloc_foo_1(ptr %[[PRIV_DESC1]]) |
64 changes: 64 additions & 0 deletions
64
mlir/test/Target/LLVMIR/openmp-target-private-allocatable.mlir
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s | ||
|
||
llvm.func @alloc_foo_1(!llvm.ptr) | ||
llvm.func @dealloc_foo_1(!llvm.ptr) | ||
|
||
omp.private {type = private} @box.heap_privatizer : !llvm.ptr alloc { | ||
^bb0(%arg0: !llvm.ptr): | ||
%0 = llvm.mlir.constant(1 : i32) : i32 | ||
%7 = llvm.alloca %0 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> : (i32) -> !llvm.ptr | ||
llvm.call @alloc_foo_1(%arg0) : (!llvm.ptr) -> () | ||
omp.yield(%7 : !llvm.ptr) | ||
} dealloc { | ||
^bb0(%arg0: !llvm.ptr): | ||
llvm.call @dealloc_foo_1(%arg0) : (!llvm.ptr) -> () | ||
omp.yield | ||
} | ||
|
||
llvm.func @target_allocatable_(%arg0: !llvm.ptr {fir.bindc_name = "lb"}, %arg1: !llvm.ptr {fir.bindc_name = "ub"}, %arg2: !llvm.ptr {fir.bindc_name = "l"}) attributes {fir.internal_name = "_QPtarget_allocatable"} { | ||
%0 = llvm.mlir.constant(1 : i32) : i32 | ||
%1 = llvm.alloca %0 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> {alignment = 8 : i64} : (i32) -> !llvm.ptr | ||
%3 = llvm.alloca %0 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> {alignment = 8 : i64} : (i32) -> !llvm.ptr | ||
%4 = llvm.mlir.constant(1 : i64) : i64 | ||
%5 = llvm.alloca %4 x f32 {bindc_name = "real_var"} : (i64) -> !llvm.ptr | ||
%7 = llvm.alloca %4 x i32 {bindc_name = "mapped_var"} : (i64) -> !llvm.ptr | ||
%9 = llvm.alloca %4 x !llvm.struct<(f32, f32)> {bindc_name = "comp_var"} : (i64) -> !llvm.ptr | ||
%11 = llvm.alloca %0 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> {alignment = 8 : i64} : (i32) -> !llvm.ptr | ||
%13 = llvm.alloca %4 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> {bindc_name = "alloc_var"} : (i64) -> !llvm.ptr | ||
%39 = llvm.load %arg2 : !llvm.ptr -> i64 | ||
%52 = llvm.alloca %39 x f32 {bindc_name = "real_arr"} : (i64) -> !llvm.ptr | ||
%53 = omp.map.info var_ptr(%7 : !llvm.ptr, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !llvm.ptr {name = "mapped_var"} | ||
%54 = omp.map.info var_ptr(%13 : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>) map_clauses(to) capture(ByRef) -> !llvm.ptr | ||
omp.target map_entries(%53 -> %arg3, %54 -> %arg4 : !llvm.ptr, !llvm.ptr) private(@box.heap_privatizer %13 -> %arg5 [map_idx=1] : !llvm.ptr) { | ||
llvm.call @use_private_var(%arg5) : (!llvm.ptr) -> () | ||
omp.terminator | ||
} | ||
llvm.return | ||
} | ||
|
||
llvm.func @use_private_var(!llvm.ptr) -> () | ||
|
||
llvm.func @_FortranAAssign(!llvm.ptr, !llvm.ptr, !llvm.ptr, i32) -> !llvm.struct<()> attributes {fir.runtime, sym_visibility = "private"} | ||
|
||
// The first set of checks ensure that we are calling the offloaded function | ||
// with the right arguments, especially the second argument which needs to | ||
// be a memory reference to the descriptor for the privatized allocatable | ||
// CHECK: define void @target_allocatable_ | ||
// CHECK-NOT: define internal void | ||
// CHECK: %[[DESC_ALLOC:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8 }, i64 1 | ||
// CHECK: call void @__omp_offloading_[[OFFLOADED_FUNCTION:.*]](ptr {{[^,]+}}, | ||
// CHECK-SAME: ptr %[[DESC_ALLOC]]) | ||
|
||
// The second set of checks ensure that to allocate memory for the | ||
// allocatable, we are, in fact, using the memory reference of the descriptor | ||
// passed as the second argument to the offloaded function. | ||
// CHECK: define internal void @__omp_offloading_[[OFFLOADED_FUNCTION]] | ||
// CHECK-SAME: (ptr {{[^,]+}}, ptr %[[DESCRIPTOR_ARG:.*]]) { | ||
// CHECK: %[[DESC_TO_DEALLOC:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8 } | ||
// CHECK: call void @alloc_foo_1(ptr %[[DESCRIPTOR_ARG]]) | ||
|
||
|
||
// CHECK: call void @use_private_var(ptr %[[DESC_TO_DEALLOC]] | ||
|
||
// Now, check the deallocation of the private var. | ||
// CHECK: call void @dealloc_foo_1(ptr %[[DESC_TO_DEALLOC]]) |
Oops, something went wrong.