Skip to content

Commit 9d9560f

Browse files
authored
[Flang] [OpenMP] [Semantics] [MLIR] [Lowering] Add lowering support for IS_DEVICE_PTR and HAS_DEVICE_ADDR clauses on OMP TARGET directive. (#74187)
Added lowering support for IS_DEVICE_PTR and HAS_DEVICE_ADDR clauses for OMP TARGET directive and added related tests for these changes. IS_DEVICE_PTR and HAS_DEVICE_ADDR clauses apply to OMP TARGET directive OpenMP spec states `The **is_device_ptr** clause indicates that its list items are device pointers.` `The **has_device_addr** clause indicates that its list items already have device addresses and therefore they may be directly accessed from a target device.` Whereas USE_DEVICE_PTR and USE_DEVICE_ADDR clauses apply to OMP TARGET DATA directive and OpenMP spec for them states `Each list item in the **use_device_ptr** clause results in a new list item that is a device pointer that refers to a device address` `Each list item in a **use_device_addr** clause that is present in the device data environment is treated as if it is implicitly mapped by a map clause on the construct with a map-type of alloc`
1 parent 9797a7e commit 9d9560f

File tree

7 files changed

+120
-14
lines changed

7 files changed

+120
-14
lines changed

flang/lib/Lower/OpenMP/ClauseProcessor.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,20 @@ bool ClauseProcessor::processDepend(
751751
});
752752
}
753753

754+
bool ClauseProcessor::processHasDeviceAddr(
755+
llvm::SmallVectorImpl<mlir::Value> &operands,
756+
llvm::SmallVectorImpl<mlir::Type> &isDeviceTypes,
757+
llvm::SmallVectorImpl<mlir::Location> &isDeviceLocs,
758+
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> &isDeviceSymbols)
759+
const {
760+
return findRepeatableClause<omp::clause::HasDeviceAddr>(
761+
[&](const omp::clause::HasDeviceAddr &devAddrClause,
762+
const Fortran::parser::CharBlock &) {
763+
addUseDeviceClause(converter, devAddrClause.v, operands, isDeviceTypes,
764+
isDeviceLocs, isDeviceSymbols);
765+
});
766+
}
767+
754768
bool ClauseProcessor::processIf(
755769
omp::clause::If::DirectiveNameModifier directiveName,
756770
mlir::Value &result) const {
@@ -771,6 +785,20 @@ bool ClauseProcessor::processIf(
771785
return found;
772786
}
773787

788+
bool ClauseProcessor::processIsDevicePtr(
789+
llvm::SmallVectorImpl<mlir::Value> &operands,
790+
llvm::SmallVectorImpl<mlir::Type> &isDeviceTypes,
791+
llvm::SmallVectorImpl<mlir::Location> &isDeviceLocs,
792+
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> &isDeviceSymbols)
793+
const {
794+
return findRepeatableClause<omp::clause::IsDevicePtr>(
795+
[&](const omp::clause::IsDevicePtr &devPtrClause,
796+
const Fortran::parser::CharBlock &) {
797+
addUseDeviceClause(converter, devPtrClause.v, operands, isDeviceTypes,
798+
isDeviceLocs, isDeviceSymbols);
799+
});
800+
}
801+
774802
bool ClauseProcessor::processLink(
775803
llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const {
776804
return findRepeatableClause<omp::clause::Link>(
@@ -993,6 +1021,7 @@ bool ClauseProcessor::processUseDevicePtr(
9931021
useDeviceLocs, useDeviceSymbols);
9941022
});
9951023
}
1024+
9961025
} // namespace omp
9971026
} // namespace lower
9981027
} // namespace Fortran

flang/lib/Lower/OpenMP/ClauseProcessor.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ class ClauseProcessor {
6666
bool processDeviceType(mlir::omp::DeclareTargetDeviceType &result) const;
6767
bool processFinal(Fortran::lower::StatementContext &stmtCtx,
6868
mlir::Value &result) const;
69+
bool
70+
processHasDeviceAddr(llvm::SmallVectorImpl<mlir::Value> &operands,
71+
llvm::SmallVectorImpl<mlir::Type> &isDeviceTypes,
72+
llvm::SmallVectorImpl<mlir::Location> &isDeviceLocs,
73+
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *>
74+
&isDeviceSymbols) const;
6975
bool processHint(mlir::IntegerAttr &result) const;
7076
bool processMergeable(mlir::UnitAttr &result) const;
7177
bool processNowait(mlir::UnitAttr &result) const;
@@ -104,6 +110,12 @@ class ClauseProcessor {
104110
bool processIf(omp::clause::If::DirectiveNameModifier directiveName,
105111
mlir::Value &result) const;
106112
bool
113+
processIsDevicePtr(llvm::SmallVectorImpl<mlir::Value> &operands,
114+
llvm::SmallVectorImpl<mlir::Type> &isDeviceTypes,
115+
llvm::SmallVectorImpl<mlir::Location> &isDeviceLocs,
116+
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *>
117+
&isDeviceSymbols) const;
118+
bool
107119
processLink(llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const;
108120

109121
// This method is used to process a map clause.

flang/lib/Lower/OpenMP/OpenMP.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,11 @@ genTargetOp(Fortran::lower::AbstractConverter &converter,
12941294
llvm::SmallVector<mlir::Type> mapSymTypes;
12951295
llvm::SmallVector<mlir::Location> mapSymLocs;
12961296
llvm::SmallVector<const Fortran::semantics::Symbol *> mapSymbols;
1297+
llvm::SmallVector<mlir::Value> devicePtrOperands, deviceAddrOperands;
1298+
llvm::SmallVector<mlir::Type> devicePtrTypes, deviceAddrTypes;
1299+
llvm::SmallVector<mlir::Location> devicePtrLocs, deviceAddrLocs;
1300+
llvm::SmallVector<const Fortran::semantics::Symbol *> devicePtrSymbols,
1301+
deviceAddrSymbols;
12971302

12981303
ClauseProcessor cp(converter, semaCtx, clauseList);
12991304
cp.processIf(llvm::omp::Directive::OMPD_target, ifClauseOperand);
@@ -1303,11 +1308,15 @@ genTargetOp(Fortran::lower::AbstractConverter &converter,
13031308
cp.processNowait(nowaitAttr);
13041309
cp.processMap(currentLocation, directive, stmtCtx, mapOperands, &mapSymTypes,
13051310
&mapSymLocs, &mapSymbols);
1311+
cp.processIsDevicePtr(devicePtrOperands, devicePtrTypes, devicePtrLocs,
1312+
devicePtrSymbols);
1313+
cp.processHasDeviceAddr(deviceAddrOperands, deviceAddrTypes, deviceAddrLocs,
1314+
deviceAddrSymbols);
13061315

1307-
cp.processTODO<clause::Private, clause::Firstprivate, clause::IsDevicePtr,
1308-
clause::HasDeviceAddr, clause::Reduction, clause::InReduction,
1309-
clause::Allocate, clause::UsesAllocators, clause::Defaultmap>(
1310-
currentLocation, llvm::omp::Directive::OMPD_target);
1316+
cp.processTODO<clause::Private, clause::Firstprivate, clause::Reduction,
1317+
clause::InReduction, clause::Allocate, clause::UsesAllocators,
1318+
clause::Defaultmap>(currentLocation,
1319+
llvm::omp::Directive::OMPD_target);
13111320

13121321
// 5.8.1 Implicit Data-Mapping Attribute Rules
13131322
// The following code follows the implicit data-mapping rules to map all the
@@ -1400,7 +1409,8 @@ genTargetOp(Fortran::lower::AbstractConverter &converter,
14001409
? nullptr
14011410
: mlir::ArrayAttr::get(converter.getFirOpBuilder().getContext(),
14021411
dependTypeOperands),
1403-
dependOperands, nowaitAttr, mapOperands);
1412+
dependOperands, nowaitAttr, devicePtrOperands, deviceAddrOperands,
1413+
mapOperands);
14041414

14051415
genBodyOfTargetOp(converter, semaCtx, eval, genNested, targetOp, mapSymTypes,
14061416
mapSymLocs, mapSymbols, currentLocation);
@@ -2059,6 +2069,8 @@ genOMP(Fortran::lower::AbstractConverter &converter,
20592069
!std::get_if<Fortran::parser::OmpClause::Map>(&clause.u) &&
20602070
!std::get_if<Fortran::parser::OmpClause::UseDevicePtr>(&clause.u) &&
20612071
!std::get_if<Fortran::parser::OmpClause::UseDeviceAddr>(&clause.u) &&
2072+
!std::get_if<Fortran::parser::OmpClause::IsDevicePtr>(&clause.u) &&
2073+
!std::get_if<Fortran::parser::OmpClause::HasDeviceAddr>(&clause.u) &&
20622074
!std::get_if<Fortran::parser::OmpClause::ThreadLimit>(&clause.u) &&
20632075
!std::get_if<Fortran::parser::OmpClause::NumTeams>(&clause.u)) {
20642076
TODO(clauseLocation, "OpenMP Block construct clause");

flang/test/Lower/OpenMP/FIR/target.f90

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,4 +506,45 @@ subroutine omp_target_parallel_do
506506
!CHECK: omp.terminator
507507
!CHECK: }
508508
!$omp end target parallel do
509-
end subroutine omp_target_parallel_do
509+
end subroutine omp_target_parallel_do
510+
511+
!===============================================================================
512+
! Target `is_device_ptr` clause
513+
!===============================================================================
514+
515+
!CHECK-LABEL: func.func @_QPomp_target_is_device_ptr() {
516+
subroutine omp_target_is_device_ptr
517+
use iso_c_binding, only : c_ptr, c_loc
518+
!CHECK: %[[VAL_0:.*]] = fir.alloca !fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}> {bindc_name = "a", uniq_name = "_QFomp_target_is_device_ptrEa"}
519+
type(c_ptr) :: a
520+
!CHECK: %[[VAL_1:.*]] = fir.alloca i32 {bindc_name = "b", fir.target, uniq_name = "_QFomp_target_is_device_ptrEb"}
521+
integer, target :: b
522+
!CHECK: %[[MAP_0:.*]] = omp.map.info var_ptr(%[[DEV_PTR:.*]] : !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>, !fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>) map_clauses(tofrom) capture(ByRef) -> !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>> {name = "a"}
523+
!CHECK: %[[MAP_1:.*]] = omp.map.info var_ptr(%[[VAL_0:.*]] : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> {name = "b"}
524+
!CHECK: %[[MAP_2:.*]] = omp.map.info var_ptr(%[[DEV_PTR:.*]] : !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>, !fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByRef) -> !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>> {name = "a"}
525+
!CHECK: omp.target is_device_ptr(%[[DEV_PTR:.*]] : !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>) map_entries(%[[MAP_0:.*]] -> %[[ARG0:.*]], %[[MAP_1:.*]] -> %[[ARG1:.*]], %[[MAP_2:.*]] -> %[[ARG2:.*]] : !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>, !fir.ref<i32>, !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>) {
526+
!CHECK: ^bb0(%[[ARG0]]: !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>, %[[ARG1]]: !fir.ref<i32>, %[[ARG2]]: !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>):
527+
!$omp target map(tofrom: a,b) is_device_ptr(a)
528+
!CHECK: {{.*}} = fir.coordinate_of %[[VAL_0:.*]], {{.*}} : (!fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>, !fir.field) -> !fir.ref<i64>
529+
a = c_loc(b)
530+
!CHECK: omp.terminator
531+
!$omp end target
532+
!CHECK: }
533+
end subroutine omp_target_is_device_ptr
534+
535+
!===============================================================================
536+
! Target `has_device_addr` clause
537+
!===============================================================================
538+
539+
!CHECK-LABEL: func.func @_QPomp_target_has_device_addr() {
540+
subroutine omp_target_has_device_addr
541+
!CHECK: %[[VAL_0:.*]] = fir.alloca !fir.box<!fir.ptr<i32>> {bindc_name = "a", uniq_name = "_QFomp_target_has_device_addrEa"}
542+
integer, pointer :: a
543+
!CHECK: omp.target has_device_addr(%[[VAL_0:.*]] : !fir.ref<!fir.box<!fir.ptr<i32>>>) map_entries({{.*}} -> {{.*}}, {{.*}} -> {{.*}} : !fir.llvm_ptr<!fir.ref<i32>>, !fir.ref<!fir.box<!fir.ptr<i32>>>) {
544+
!$omp target has_device_addr(a)
545+
!CHECK: {{.*}} = fir.load %[[VAL_0:.*]] : !fir.ref<!fir.box<!fir.ptr<i32>>>
546+
a = 10
547+
!CHECK: omp.terminator
548+
!$omp end target
549+
!CHECK: }
550+
end subroutine omp_target_has_device_addr

mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1678,14 +1678,23 @@ def TargetOp : OpenMP_Op<"target", [IsolatedFromAbove, MapClauseOwningOpInterfac
16781678

16791679
The optional $thread_limit specifies the limit on the number of threads
16801680

1681-
The optional $nowait elliminates the implicit barrier so the parent task can make progress
1681+
The optional $nowait eliminates the implicit barrier so the parent task can make progress
16821682
even if the target task is not yet completed.
16831683

16841684
The `depends` and `depend_vars` arguments are variadic lists of values
16851685
that specify the dependencies of this particular target task in relation to
16861686
other tasks.
16871687

1688-
TODO: is_device_ptr, defaultmap, in_reduction
1688+
The optional $is_device_ptr indicates list items are device pointers.
1689+
1690+
The optional $has_device_addr indicates that list items already have device
1691+
addresses, so they may be directly accessed from the target device. This
1692+
includes array sections.
1693+
1694+
The optional $map_operands maps data from the task’s environment to the
1695+
device environment.
1696+
1697+
TODO: defaultmap, in_reduction
16891698

16901699
}];
16911700

@@ -1695,8 +1704,9 @@ def TargetOp : OpenMP_Op<"target", [IsolatedFromAbove, MapClauseOwningOpInterfac
16951704
OptionalAttr<TaskDependArrayAttr>:$depends,
16961705
Variadic<OpenMP_PointerLikeType>:$depend_vars,
16971706
UnitAttr:$nowait,
1707+
Variadic<OpenMP_PointerLikeType>:$is_device_ptr,
1708+
Variadic<OpenMP_PointerLikeType>:$has_device_addr,
16981709
Variadic<AnyType>:$map_operands);
1699-
17001710
let regions = (region AnyRegion:$region);
17011711

17021712
let builders = [
@@ -1708,6 +1718,8 @@ def TargetOp : OpenMP_Op<"target", [IsolatedFromAbove, MapClauseOwningOpInterfac
17081718
| `device` `(` $device `:` type($device) `)`
17091719
| `thread_limit` `(` $thread_limit `:` type($thread_limit) `)`
17101720
| `nowait` $nowait
1721+
| `is_device_ptr` `(` $is_device_ptr `:` type($is_device_ptr) `)`
1722+
| `has_device_addr` `(` $has_device_addr `:` type($has_device_addr) `)`
17111723
| `map_entries` `(` custom<MapEntries>($map_operands, type($map_operands)) `)`
17121724
| `depend` `(` custom<DependVarList>($depend_vars, type($depend_vars), $depends) `)`
17131725
) $region attr-dict

mlir/test/Dialect/OpenMP/invalid.mlir

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1809,7 +1809,7 @@ func.func @omp_target_depend(%data_var: memref<i32>) {
18091809
// expected-error @below {{op expected as many depend values as depend variables}}
18101810
"omp.target"(%data_var) ({
18111811
"omp.terminator"() : () -> ()
1812-
}) {depends = [], operandSegmentSizes = array<i32: 0, 0, 0, 1, 0>} : (memref<i32>) -> ()
1812+
}) {depends = [], operandSegmentSizes = array<i32: 0, 0, 0, 1, 0, 0, 0>} : (memref<i32>) -> ()
18131813
"func.return"() : () -> ()
18141814
}
18151815

mlir/test/Dialect/OpenMP/ops.mlir

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -510,22 +510,22 @@ return
510510

511511

512512
// CHECK-LABEL: omp_target
513-
func.func @omp_target(%if_cond : i1, %device : si32, %num_threads : i32, %map1: memref<?xi32>, %map2: memref<?xi32>) -> () {
513+
func.func @omp_target(%if_cond : i1, %device : si32, %num_threads : i32, %device_ptr: memref<i32>, %device_addr: memref<?xi32>, %map1: memref<?xi32>, %map2: memref<?xi32>) -> () {
514514

515515
// Test with optional operands; if_expr, device, thread_limit, private, firstprivate and nowait.
516516
// CHECK: omp.target if({{.*}}) device({{.*}}) thread_limit({{.*}}) nowait
517517
"omp.target"(%if_cond, %device, %num_threads) ({
518518
// CHECK: omp.terminator
519519
omp.terminator
520-
}) {nowait, operandSegmentSizes = array<i32: 1,1,1,0,0>} : ( i1, si32, i32 ) -> ()
520+
}) {nowait, operandSegmentSizes = array<i32: 1,1,1,0,0,0,0>} : ( i1, si32, i32 ) -> ()
521521

522522
// Test with optional map clause.
523523
// CHECK: %[[MAP_A:.*]] = omp.map.info var_ptr(%[[VAL_1:.*]] : memref<?xi32>, tensor<?xi32>) map_clauses(tofrom) capture(ByRef) -> memref<?xi32> {name = ""}
524524
// CHECK: %[[MAP_B:.*]] = omp.map.info var_ptr(%[[VAL_2:.*]] : memref<?xi32>, tensor<?xi32>) map_clauses(exit_release_or_enter_alloc) capture(ByRef) -> memref<?xi32> {name = ""}
525-
// CHECK: omp.target map_entries(%[[MAP_A]] -> {{.*}}, %[[MAP_B]] -> {{.*}} : memref<?xi32>, memref<?xi32>) {
525+
// CHECK: omp.target is_device_ptr(%[[VAL_4:.*]] : memref<i32>) has_device_addr(%[[VAL_5:.*]] : memref<?xi32>) map_entries(%[[MAP_A]] -> {{.*}}, %[[MAP_B]] -> {{.*}} : memref<?xi32>, memref<?xi32>) {
526526
%mapv1 = omp.map.info var_ptr(%map1 : memref<?xi32>, tensor<?xi32>) map_clauses(tofrom) capture(ByRef) -> memref<?xi32> {name = ""}
527527
%mapv2 = omp.map.info var_ptr(%map2 : memref<?xi32>, tensor<?xi32>) map_clauses(exit_release_or_enter_alloc) capture(ByRef) -> memref<?xi32> {name = ""}
528-
omp.target map_entries(%mapv1 -> %arg0, %mapv2 -> %arg1 : memref<?xi32>, memref<?xi32>) {
528+
omp.target map_entries(%mapv1 -> %arg0, %mapv2 -> %arg1 : memref<?xi32>, memref<?xi32>) is_device_ptr(%device_ptr : memref<i32>) has_device_addr(%device_addr : memref<?xi32>) {
529529
^bb0(%arg0: memref<?xi32>, %arg1: memref<?xi32>):
530530
omp.terminator
531531
}

0 commit comments

Comments
 (0)