[flang][OpenMP] Parser support for Target directive and Device clause

This patch adds support for the device clause on `Target` directive.
Device clause was added in OpenMP specification version 4.5 to
create a device data environment for the extent of a region. On
target construct, the device expression be either be `ancestor`
(taking after the parent) or assign a new `device_num`.

Reviewed By: kiranchandramohan

Differential Revision: https://reviews.llvm.org/D126441
This commit is contained in:
Sesha Kalyur 2022-08-21 22:23:51 +05:30 committed by Nimish Mishra
parent 7ff2a9f250
commit d9ff670330
9 changed files with 293 additions and 5 deletions

View File

@ -525,6 +525,8 @@ public:
NODE(OmpAllocateClause, Allocator)
NODE(parser, OmpScheduleClause)
NODE_ENUM(OmpScheduleClause, ScheduleType)
NODE(parser, OmpDeviceClause)
NODE_ENUM(OmpDeviceClause, DeviceModifier)
NODE(parser, OmpScheduleModifier)
NODE(OmpScheduleModifier, Modifier1)
NODE(OmpScheduleModifier, Modifier2)

View File

@ -3385,6 +3385,13 @@ struct OmpScheduleClause {
t;
};
// device([ device-modifier :] scalar-integer-expression)
struct OmpDeviceClause {
TUPLE_CLASS_BOILERPLATE(OmpDeviceClause);
ENUM_CLASS(DeviceModifier, Ancestor, Device_Num)
std::tuple<std::optional<DeviceModifier>, ScalarIntExpr> t;
};
// 2.12 if-clause -> IF ([ directive-name-modifier :] scalar-logical-expr)
struct OmpIfClause {
TUPLE_CLASS_BOILERPLATE(OmpIfClause);

View File

@ -97,6 +97,14 @@ TYPE_PARSER(construct<OmpScheduleClause>(maybe(Parser<OmpScheduleModifier>{}),
"RUNTIME" >> pure(OmpScheduleClause::ScheduleType::Runtime),
maybe("," >> scalarIntExpr)))
// device([ device-modifier :] scalar-integer-expression)
TYPE_PARSER(construct<OmpDeviceClause>(
maybe(
("ANCESTOR" >> pure(OmpDeviceClause::DeviceModifier::Ancestor) ||
"DEVICE_NUM" >> pure(OmpDeviceClause::DeviceModifier::Device_Num)) /
":"),
scalarIntExpr))
// 2.12 IF (directive-name-modifier: scalar-logical-expr)
TYPE_PARSER(construct<OmpIfClause>(
maybe(
@ -196,7 +204,7 @@ TYPE_PARSER(
"DEPEND" >> construct<OmpClause>(construct<OmpClause::Depend>(
parenthesized(Parser<OmpDependClause>{}))) ||
"DEVICE" >> construct<OmpClause>(construct<OmpClause::Device>(
parenthesized(scalarIntExpr))) ||
parenthesized(Parser<OmpDeviceClause>{}))) ||
"DIST_SCHEDULE" >>
construct<OmpClause>(construct<OmpClause::DistSchedule>(
parenthesized("STATIC" >> maybe("," >> scalarIntExpr)))) ||

View File

@ -2008,6 +2008,10 @@ public:
Walk(std::get<OmpScheduleClause::ScheduleType>(x.t));
Walk(",", std::get<std::optional<ScalarIntExpr>>(x.t));
}
void Unparse(const OmpDeviceClause &x) {
Walk(std::get<std::optional<OmpDeviceClause::DeviceModifier>>(x.t), ":");
Walk(std::get<ScalarIntExpr>(x.t));
}
void Unparse(const OmpAlignedClause &x) {
Walk(std::get<std::list<Name>>(x.t), ",");
Walk(std::get<std::optional<ScalarIntConstantExpr>>(x.t));
@ -2580,6 +2584,7 @@ public:
WALK_NESTED_ENUM(OmpDependenceType, Type) // OMP dependence-type
WALK_NESTED_ENUM(OmpMapType, Type) // OMP map-type
WALK_NESTED_ENUM(OmpScheduleClause, ScheduleType) // OMP schedule-type
WALK_NESTED_ENUM(OmpDeviceClause, DeviceModifier) // OMP device modifier
WALK_NESTED_ENUM(OmpIfClause, DirectiveNameModifier) // OMP directive-modifier
WALK_NESTED_ENUM(OmpCancelType, Type) // OMP cancel-type
#undef WALK_NESTED_ENUM

View File

@ -1874,7 +1874,6 @@ CHECK_REQ_SCALAR_INT_CLAUSE(NumTeams, OMPC_num_teams)
CHECK_REQ_SCALAR_INT_CLAUSE(NumThreads, OMPC_num_threads)
CHECK_REQ_SCALAR_INT_CLAUSE(Priority, OMPC_priority)
CHECK_REQ_SCALAR_INT_CLAUSE(ThreadLimit, OMPC_thread_limit)
CHECK_REQ_SCALAR_INT_CLAUSE(Device, OMPC_device)
CHECK_REQ_CONSTANT_SCALAR_INT_CLAUSE(Collapse, OMPC_collapse)
CHECK_REQ_CONSTANT_SCALAR_INT_CLAUSE(Safelen, OMPC_safelen)
@ -2373,6 +2372,14 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Schedule &x) {
}
}
void OmpStructureChecker::Enter(const parser::OmpClause::Device &x) {
CheckAllowed(llvm::omp::Clause::OMPC_device);
const parser::OmpDeviceClause &deviceClause = x.v;
const auto &device{std::get<1>(deviceClause.t)};
RequiresPositiveParameter(
llvm::omp::Clause::OMPC_device, device, "device expression");
}
void OmpStructureChecker::Enter(const parser::OmpClause::Depend &x) {
CheckAllowed(llvm::omp::Clause::OMPC_depend);
if (const auto *inOut{std::get_if<parser::OmpDependClause::InOut>(&x.v.u)}) {

View File

@ -0,0 +1,179 @@
! RUN: %flang_fc1 -fdebug-unparse-no-sema -fopenmp %s | FileCheck --ignore-case %s
! RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp %s | FileCheck --check-prefix="PARSE-TREE" %s
! Checks the parsing of Openmp 5.0 Target Device constructs
!
PROGRAM main
USE OMP_LIB
IMPLICIT NONE
INTEGER :: X, Y
INTEGER :: M = 1
!------------------------------------------------------
! Check Device clause with a constant argument
!------------------------------------------------------
!CHECK: !$OMP TARGET DEVICE(1)
!$OMP TARGET DEVICE(1)
M = M + 1
!CHECK: !$OMP END TARGET
!$OMP END TARGET
!PARSE-TREE: OmpBeginBlockDirective
!PARSE-TREE: OmpBlockDirective -> llvm::omp::Directive = target
!PARSE-TREE: OmpClauseList -> OmpClause -> Device -> OmpDeviceClause
!PARSE-TREE: Scalar -> Integer -> Expr = '1_4'
!PARSE-TREE: LiteralConstant -> IntLiteralConstant = '1'
!PARSE-TREE: OmpEndBlockDirective
!PARSE-TREE: OmpBlockDirective -> llvm::omp::Directive = target
!PARSE-TREE: OmpClauseList ->
!------------------------------------------------------
! Check Device clause with a constant integer expression argument
!------------------------------------------------------
!CHECK: !$OMP TARGET DEVICE(2-1)
!$OMP TARGET DEVICE(2-1)
M = M + 1
!CHECK: !$OMP END TARGET
!$OMP END TARGET
!PARSE-TREE: OmpBeginBlockDirective
!PARSE-TREE: OmpBlockDirective -> llvm::omp::Directive = target
!PARSE-TREE: OmpClauseList -> OmpClause -> Device -> OmpDeviceClause
!PARSE-TREE: Scalar -> Integer -> Expr = '1_4'
!PARSE-TREE: Subtract
!PARSE-TREE: Expr = '2_4'
!PARSE-TREE: LiteralConstant -> IntLiteralConstant = '2'
!PARSE-TREE: Expr = '1_4'
!PARSE-TREE: LiteralConstant -> IntLiteralConstant = '1'
!PARSE-TREE: OmpEndBlockDirective
!PARSE-TREE: OmpBlockDirective -> llvm::omp::Directive = target
!PARSE-TREE: OmpClauseList ->
!------------------------------------------------------
! Check Device clause with a variable argument
!------------------------------------------------------
!CHECK: !$OMP TARGET DEVICE(X)
!$OMP TARGET DEVICE(X)
M = M + 1
!CHECK: !$OMP END TARGET
!$OMP END TARGET
!PARSE-TREE: OmpBeginBlockDirective
!PARSE-TREE: OmpBlockDirective -> llvm::omp::Directive = target
!PARSE-TREE: OmpClauseList -> OmpClause -> Device -> OmpDeviceClause
!PARSE-TREE: Scalar -> Integer -> Expr = 'x'
!PARSE-TREE: Designator -> DataRef -> Name = 'x'
!PARSE-TREE: OmpEndBlockDirective
!PARSE-TREE: OmpBlockDirective -> llvm::omp::Directive = target
!PARSE-TREE: OmpClauseList ->
!------------------------------------------------------
! Check Device clause with an variable integer expression
!------------------------------------------------------
!CHECK: !$OMP TARGET DEVICE(X+Y)
!$OMP TARGET DEVICE(X+Y)
M = M + 1
!CHECK: !$OMP END TARGET
!$OMP END TARGET
!PARSE-TREE: OmpBeginBlockDirective
!PARSE-TREE: OmpBlockDirective -> llvm::omp::Directive = target
!PARSE-TREE: OmpClauseList -> OmpClause -> Device -> OmpDeviceClause
!PARSE-TREE: Scalar -> Integer -> Expr = 'x+y'
!PARSE-TREE: Add
!PARSE-TREE: Expr = 'x'
!PARSE-TREE: Designator -> DataRef -> Name = 'x'
!PARSE-TREE: Expr = 'y'
!PARSE-TREE: Designator -> DataRef -> Name = 'y'
!PARSE-TREE: OmpEndBlockDirective
!PARSE-TREE: OmpBlockDirective -> llvm::omp::Directive = target
!PARSE-TREE: OmpClauseList ->
!------------------------------------------------------
! Check Device Ancestor clause with a constant argument
!------------------------------------------------------
!CHECK: !$OMP TARGET DEVICE(ANCESTOR:1)
!$OMP TARGET DEVICE(ANCESTOR: 1)
M = M + 1
!CHECK: !$OMP END TARGET
!$OMP END TARGET
!PARSE-TREE: OmpBeginBlockDirective
!PARSE-TREE: OmpBlockDirective -> llvm::omp::Directive = target
!PARSE-TREE: OmpClauseList -> OmpClause -> Device -> OmpDeviceClause
!PARSE-TREE: DeviceModifier = Ancestor
!PARSE-TREE: Scalar -> Integer -> Expr = '1_4'
!PARSE-TREE: LiteralConstant -> IntLiteralConstant = '1'
!PARSE-TREE: OmpEndBlockDirective
!PARSE-TREE: OmpBlockDirective -> llvm::omp::Directive = target
!PARSE-TREE: OmpClauseList ->
!--------------------------------------------------------
! Check Device Devive-Num clause with a constant argument
!--------------------------------------------------------
!CHECK: !$OMP TARGET DEVICE(DEVICE_NUM:2)
!$OMP TARGET DEVICE(DEVICE_NUM: 2)
M = M + 1
!CHECK: !$OMP END TARGET
!$OMP END TARGET
!PARSE-TREE: OmpBeginBlockDirective
!PARSE-TREE: OmpBlockDirective -> llvm::omp::Directive = target
!PARSE-TREE: OmpClauseList -> OmpClause -> Device -> OmpDeviceClause
!PARSE-TREE: DeviceModifier = Device_Num
!PARSE-TREE: Scalar -> Integer -> Expr = '2_4'
!PARSE-TREE: LiteralConstant -> IntLiteralConstant = '2'
!PARSE-TREE: OmpEndBlockDirective
!PARSE-TREE: OmpBlockDirective -> llvm::omp::Directive = target
!PARSE-TREE: OmpClauseList ->
!-------------------------------------------------------------------
! Check Device Ancestor clause with a variable expression argument
!-------------------------------------------------------------------
!CHECK: !$OMP TARGET DEVICE(ANCESTOR:X+Y)
!$OMP TARGET DEVICE(ANCESTOR: X + Y)
M = M + 1
!CHECK: !$OMP END TARGET
!$OMP END TARGET
!PARSE-TREE: OmpBeginBlockDirective
!PARSE-TREE: OmpBlockDirective -> llvm::omp::Directive = target
!PARSE-TREE: OmpClauseList -> OmpClause -> Device -> OmpDeviceClause
!PARSE-TREE: DeviceModifier = Ancestor
!PARSE-TREE: Scalar -> Integer -> Expr = 'x+y'
!PARSE-TREE: Add
!PARSE-TREE: Expr = 'x'
!PARSE-TREE: Designator -> DataRef -> Name = 'x'
!PARSE-TREE: Expr = 'y'
!PARSE-TREE: Designator -> DataRef -> Name = 'y'
!PARSE-TREE: OmpEndBlockDirective
!PARSE-TREE: OmpBlockDirective -> llvm::omp::Directive = target
!PARSE-TREE: OmpClauseList ->
!-------------------------------------------------------------------
! Check Device Devive-Num clause with a variable expression argument
!-------------------------------------------------------------------
!CHECK: !$OMP TARGET DEVICE(DEVICE_NUM:X-Y)
!$OMP TARGET DEVICE(DEVICE_NUM: X - Y)
M = M + 1
!CHECK: !$OMP END TARGET
!$OMP END TARGET
!PARSE-TREE: OmpBeginBlockDirective
!PARSE-TREE: OmpBlockDirective -> llvm::omp::Directive = target
!PARSE-TREE: OmpClauseList -> OmpClause -> Device -> OmpDeviceClause
!PARSE-TREE: DeviceModifier = Device_Num
!PARSE-TREE: Scalar -> Integer -> Expr = 'x-y'
!PARSE-TREE: Subtract
!PARSE-TREE: Expr = 'x'
!PARSE-TREE: Designator -> DataRef -> Name = 'x'
!PARSE-TREE: Expr = 'y'
!PARSE-TREE: Designator -> DataRef -> Name = 'y'
!PARSE-TREE: OmpEndBlockDirective
!PARSE-TREE: OmpBlockDirective -> llvm::omp::Directive = target
END PROGRAM

View File

@ -0,0 +1,80 @@
! RUN: %flang_fc1 -fdebug-unparse-no-sema -fopenmp %s | FileCheck --ignore-case %s
! Verifies the unparsing of the Openmp Target Device constructs
PROGRAM main
USE OMP_LIB
IMPLICIT NONE
INTEGER:: X, Y
INTEGER:: M = 1
!--------------------------------------------
! constant argument
!--------------------------------------------
!CHECK: !$OMP TARGET DEVICE(0)
!CHECK: !$OMP END TARGET
!$OMP TARGET DEVICE(0)
M = M + 1
!$OMP END TARGET
!--------------------------------------------
! constant expression argument
!--------------------------------------------
!CHECK: !$OMP TARGET DEVICE(2+1)
!CHECK: !$OMP END TARGET
!$OMP TARGET DEVICE(2+1)
M = M + 1
!$OMP END TARGET
!--------------------------------------------
! variable argument
!--------------------------------------------
!CHECK: !$OMP TARGET DEVICE(X)
!CHECK: !$OMP END TARGET
!$OMP TARGET DEVICE(X)
M = M + 1
!$OMP END TARGET
!--------------------------------------------
! variable expression argument
!--------------------------------------------
!CHECK: !$OMP TARGET DEVICE(X-Y)
!CHECK: !$OMP END TARGET
!$OMP TARGET DEVICE(X-Y)
M = M + 1
!$OMP END TARGET
!--------------------------------------------
! Ancestor followed by constant argument
!--------------------------------------------
!CHECK: !$OMP TARGET DEVICE(ANCESTOR:0)
!CHECK: !$OMP END TARGET
!$OMP TARGET DEVICE(ANCESTOR: 0)
M = M + 1
!$OMP END TARGET
!--------------------------------------------
! Device_Num followed by constant argument
!--------------------------------------------
!CHECK: !$OMP TARGET DEVICE(DEVICE_NUM:1)
!CHECK: !$OMP END TARGET
!$OMP TARGET DEVICE(DEVICE_NUM: 1)
M = M + 1
!$OMP END TARGET
!--------------------------------------------
! Ancestor followed by variable expression argument
!--------------------------------------------
!CHECK: !$OMP TARGET DEVICE(ANCESTOR:X+Y)
!CHECK: !$OMP END TARGET
!$OMP TARGET DEVICE(ANCESTOR: X + Y)
M = M + 1
!$OMP END TARGET
!--------------------------------------------
! Device_Num followed by variable expression argument
!--------------------------------------------
!CHECK: !$OMP TARGET DEVICE(DEVICE_NUM:X-Y)
!CHECK: !$OMP END TARGET
!$OMP TARGET DEVICE(DEVICE_NUM: X - Y)
M = M + 1
!$OMP END TARGET
END PROGRAM

View File

@ -129,10 +129,10 @@ program main
enddo
!$omp end target data
!ERROR: The parameter of the DEVICE clause must be a positive integer expression
!ERROR: The device expression of the DEVICE clause must be a positive integer expression
!$omp target enter data map(alloc:A) device(-2)
!ERROR: The parameter of the DEVICE clause must be a positive integer expression
!ERROR: The device expression of the DEVICE clause must be a positive integer expression
!$omp target exit data map(delete:A) device(-2)
!ERROR: At most one IF clause can appear on the TARGET ENTER DATA directive

View File

@ -210,7 +210,7 @@ def OMPC_Depend : Clause<"depend"> {
}
def OMPC_Device : Clause<"device"> {
let clangClass = "OMPDeviceClause";
let flangClass = "ScalarIntExpr";
let flangClass = "OmpDeviceClause";
}
def OMPC_Threads : Clause<"threads"> { let clangClass = "OMPThreadsClause"; }
def OMPC_Simd : Clause<"simd"> { let clangClass = "OMPSIMDClause"; }