diff --git a/flang/docs/OpenMP-semantics.md b/flang/docs/OpenMP-semantics.md --- a/flang/docs/OpenMP-semantics.md +++ b/flang/docs/OpenMP-semantics.md @@ -626,6 +626,66 @@ all the data-sharing or data-mapping attributes marked for the `Symbols` may be used later in the Semantics Analysis and in the Code Generation. +## Declare Target & Target Region Implicit Function Capture Analysis + +The OpenMP specification states that all functions and subroutines called +from a _declare target_ function/subroutine or _target region_ are to +be treated as if they are marked as _declare target_ with a _to_ clause. + +The OpenMP specifications current wording (emphasis on current) gives +wiggle room for this to be done later in the compilation pipeline (e.g. +the MLIR -> LLVM IR phase). However, this means filtering out functions +from modules they do not belong in requires significant extra work on the +compilers behalf and less strict semantic rules can be applied to these +implicit target functions. So, in this case we have opted to perform this +implicit capture as a semantic analysis pass (_ImplicitDeclareTargetCapture_), +which marks all functions and subroutines (and their callees) that are called +within _target_ and _declare target_ functions as _declare _target_ +themselves by materializing the function or subroutines name in the original +declare target's clause list. + +This pass occurs after name and scope resolution and the first statements +semantic pass, this is primarily so that all name and symbol information +is available for access and use and all functions are now resolved as +functions (i.e. no misinterpretation as an array) and all CallStmts are +resolved to contain the underlying function when they have been aliased. + +The _ImplicitDeclareTargetCapture_ pass works by passing over the +modules PFT and collecting all of the ProgramUnits(subroutines / functions) +and InterfaceBlocks related to these units as it passes through these nodes. +When it meets a declare target or target region node, it begins to parse +through the region or function tied to the declare target or target region. +It reads through the extended-list of the declare target directive's clause +finding functions (the current function should be referred to in this +declare target if a list is specified), if no list is specified the function +the declare target is in, is considered the only function in the declare +target list. For target region's the functions calls contained within the +region are recursively processed. + +The functions processed with the algorithm then have a declare target +construct generated within them, referencing themselves with the device_type +Any (as even if it's from a nohost region we cannot assume it's not used +elsewhere for the host without more information, we can only state it is +needed for device), only if they do not already have one already. If there +is one in existence, and the device_type is host then we switch the device +type to any, as it now exists on device. However, if the declare target has +more than just the function within the declare target's to list, then we +seperate it out into a new declare target and change the device_type of this +newly generated declare target, the original declare target remains the same +minus the removed function name. This is intended to avoid issues of +switching device_type of unrelated declare target items. Declare target's +with extended-lists or no list at all are ignored, as they already refer to +the function they are nested in by default. + +Multiple declare targets referencing the same thing utilisng +To clauses are not illegal (only when it's a link clause, which cannot be +used in conjunction with functions), so on the off chance the pass generates +more than one declare target with differing device_types (perhaps another +declare target already refers to it and we did not find it as it's external) +we handle this apon lowering, simply ignoring it if we already have a declare +target with the same device_type, or changing it to any if we meet two of +differing types referencing the same function. + ## Module File Extensions for OpenMP After the successful compilation of modules and submodules diff --git a/flang/lib/Semantics/CMakeLists.txt b/flang/lib/Semantics/CMakeLists.txt --- a/flang/lib/Semantics/CMakeLists.txt +++ b/flang/lib/Semantics/CMakeLists.txt @@ -28,6 +28,7 @@ data-to-inits.cpp definable.cpp expression.cpp + finalize-omp.cpp mod-file.cpp pointer-assignment.cpp program-tree.cpp diff --git a/flang/lib/Semantics/finalize-omp.h b/flang/lib/Semantics/finalize-omp.h new file mode 100644 --- /dev/null +++ b/flang/lib/Semantics/finalize-omp.h @@ -0,0 +1,21 @@ +//===-- lib/Semantics/finalize-omp.h ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_SEMANTICS_FINALIZE_OMP_H_ +#define FORTRAN_SEMANTICS_FINALIZE_OMP_H_ + +namespace Fortran::parser { +struct Program; +} // namespace Fortran::parser + +namespace Fortran::semantics { +class SemanticsContext; +bool FinalizeOMP(SemanticsContext &context, parser::Program &program); +} // namespace Fortran::semantics + +#endif // FORTRAN_SEMANTICS_FINALIZE_OMP_H_ diff --git a/flang/lib/Semantics/finalize-omp.cpp b/flang/lib/Semantics/finalize-omp.cpp new file mode 100644 --- /dev/null +++ b/flang/lib/Semantics/finalize-omp.cpp @@ -0,0 +1,478 @@ +#include "finalize-omp.h" +#include "flang/Parser/parse-tree-visitor.h" +#include "flang/Semantics/tools.h" + +#include +#include + +namespace Fortran::semantics { + +using namespace parser::literals; + +namespace { +using Subprograms = + std::variant; + +parser::Name *getNameFromVariant(Subprograms &x) { + if (std::holds_alternative(x)) { + parser::FunctionStmt &Stmt = + std::get<0>(std::get(x)->t).statement; + return &std::get(Stmt.t); + } + + if (std::holds_alternative(x)) { + parser::SubroutineStmt &Stmt = + std::get<0>(std::get(x)->t).statement; + return &std::get(Stmt.t); + } + + return nullptr; +} + +class GatherCallRefs { +public: + GatherCallRefs(std::map &subprograms) + : subprograms(subprograms) {} + + // Default action for a parse tree node is to visit children. + template bool Pre(T &) { return true; } + template void Post(T &) {} + + void Post(parser::Call &call) { + if (std::holds_alternative(std::get<0>(call.t).u)) + callNames.push_back(std::get(std::get<0>(call.t).u)); + } + + void Post(parser::CallStmt &call) { + if (call.typedCall) { + // find function in list of functions, get name from function + auto subprogram = subprograms.find(call.typedCall->proc().GetName()); + if (subprogram != subprograms.end()) + callNames.push_back(*getNameFromVariant(subprogram->second)); + } + } + + std::map &subprograms; + llvm::SmallVector callNames; +}; + +class GatherDeclareTargetConstruct { +public: + GatherDeclareTargetConstruct() {} + + // Default action for a parse tree node is to visit children. + template bool Pre(T &) { return true; } + template void Post(T &) {} + + void Post(parser::OpenMPDeclareTargetConstruct &DeclTar) { + declTarCons.push_back(&DeclTar); + } + + llvm::SmallVector declTarCons; +}; + +} // namespace + +// This pass works by passing over the modules PFT and collecting all of the +// ProgramUnits(subroutines / functions) and InterfaceBlocks related to these +// units as it passes through these nodes. When it meets a declare target +// or target region node, it begins to parse through the region or function tied +// to the declare target or target region. it reads through the extended-list of +// the declare target directive's clause finding functions (the current function +// should be referred to in this declare target if a list is specified), if no +// list is specified the function the declare target is in, is considered the +// only function in the declare target list. For target region's the functions +// calls contained within the region are recursively processed. + +// The functions processed with the algorithm then have a declare target +// construct generated within them, referencing themselves with the device_type +// Any (as even if it's from a nohost region we cannot assume it's not used +// elsewhere for the host without more information, we can only state it is +// needed for device), only if they do not already have one already. If there +// is one in existence, and the device_type is host then we switch the device +// type to any, as it now exists on device. However, if the declare target has +// more than just the function within the declare target's to list, then we +// seperate it out into a new declare target and change the device_type of this +// newly generated declare target, the original declare target remains the same +// minus the removed function name. This is intended to avoid issues of +// switching device_type of unrelated declare target items. Declare target's +// with extended-lists or no list at all are ignored, as they already refer to +// the function they are nested in by default. + +// Multiple declare targets referencing the same thing utilisng +// To clauses are not illegal (only when it's a link clause, which cannot be +// used in conjunction with functions), so on the off chance the pass generates +// more than one declare target with differing device_types (perhaps another +// declare target already refers to it and we did not find it as it's external) +// we handle this apon lowering, simply ignoring it if we already have a declare +// target with the same device_type, or changing it to any if we meet two of +// differing types referencing the same function. +class ImplicitDeclareTargetCapture { + Subprograms currentSubprogram_; + std::map subPrograms_; + std::map interfaces_; + bool insideOfInterfaceBody_ = false; + + parser::Messages &messages_; + + template + parser::OpenMPDeclareTargetConstruct *getDeclTarConstruct( + T &body, parser::Name name) { + + GatherDeclareTargetConstruct gatherer{}; + parser::Walk(body, gatherer); + if (gatherer.declTarCons.size() > 0) { + // Find if there is a construct the function is already referenced in + for (auto *declTar : gatherer.declTarCons) { + if (existsInDeclareTargetOrClauseless(*declTar, name)) + return declTar; + } + } + + return nullptr; + } + + std::list *getDeclarativeConstructList( + parser::InterfaceBody &body) { + if (auto *func{parser::Unwrap(body.u)}) { + auto &spec{ + std::get>(func->t)}; + return &std::get>( + spec.value().t); + } + + if (auto *subr{parser::Unwrap(body.u)}) { + auto &spec{ + std::get>(subr->t)}; + return &std::get>( + spec.value().t); + } + + return nullptr; + } + + void createOrModifyDeclareTargetTo(parser::OpenMPDeclareTargetConstruct *x, + std::list *conList, parser::Name name, + parser::OmpClause::DeviceType *parentsDeviceTypeClause) { + auto createDeclareTargetTo = [](parser::Name name) { + // Create the object list containing the functions name + std::list objects; + objects.push_back(parser::OmpObject{ + parser::Designator{parser::DataRef{std::move(name)}}}); + auto objList = parser::OmpObjectList{std::move(objects)}; + // Create ClauseList of: to(FunctionName) device_type(Any) + std::list clauses; + clauses.push_back(parser::OmpClause::To{std::move(objList)}); + clauses.push_back(parser::OmpClause::DeviceType{ + Fortran::parser::OmpDeviceTypeClause::Type::Any}); + auto newClauseList = parser::OmpClauseList{std::move(clauses)}; + // Create the Declare Target construct adding our clauses: declare target + // to(FunctionName) device_type(Any) + auto declTarget = + parser::OmpDeclareTargetWithClause{std::move(newClauseList)}; + auto specifier = parser::OmpDeclareTargetSpecifier{std::move(declTarget)}; + return parser::OpenMPDeclareTargetConstruct{ + parser::Verbatim{}, std::move(specifier)}; + }; + + if (x) { + auto &spec{std::get(x->t)}; + auto *clauseList{parser::Unwrap(spec.u)}; + parser::OmpClause::DeviceType *deviceType = nullptr; + + // clauseless and extended-list cases don't need to be considered here, + // they should just return with no alterations. This is because + // extended-lists cannot have device_types and are implicitly device_type + // any already, and declare target without any clauses or extended-lists + // are implicitly extended-lists. + if (clauseList && !clauseList->v.empty()) { + for (auto &clause : clauseList->v) { + if (auto *devType{ + std::get_if(&clause.u)}) { + deviceType = devType; + } + } + + // We have a declare target already, however, it is marked host and the + // function is sharing it with other list-items, we do not want to + // change the markings on the existing declare target, so we wish to + // split our function from the rest of the list into a newly generated + // declare target. + for (auto &clause : clauseList->v) { + if (auto *toClause{std::get_if(&clause.u)}) { + if (toClause->v.v.size() > 1 && + deviceType->v.v == + Fortran::parser::OmpDeviceTypeClause::Type::Host) { + // remove from existing declare target with multiple objects + for (auto ompObject = toClause->v.v.begin(); + ompObject != toClause->v.v.end(); ompObject++) { + if (auto *objName{parser::Unwrap(ompObject->u)}) + if (objName->ToString() == name.ToString()) { + toClause->v.v.erase(ompObject); + break; + } + } + + // generate the new declare target + conList->push_back(createDeclareTargetTo(name)); + return; + } + } + } + + // This function, is required by a target function, we must swap + // it to a new device type. + if ((parentsDeviceTypeClause && + parentsDeviceTypeClause->v.v != deviceType->v.v) || + deviceType->v.v == + Fortran::parser::OmpDeviceTypeClause::Type::Host) { + deviceType->v.v = Fortran::parser::OmpDeviceTypeClause::Type::Any; + } + } + return; + } + + // There is no declare target referencing this function within the function + // yet, we must generate one. + conList->push_back(createDeclareTargetTo(name)); + } + + bool isTargetRegion(parser::OpenMPBlockConstruct &x) { + auto &blockDir{std::get( + std::get(x.t).t)}; + if (blockDir.v == llvm::omp::Directive::OMPD_target) + return true; + return false; + } + + bool existsInDeclareTargetOrClauseless( + parser::OpenMPDeclareTargetConstruct &x, parser::Name name) { + auto existsInObjList = [](parser::OmpObjectList &objList, + parser::Name name) { + for (auto &ompObject : objList.v) + if (auto *objName{parser::Unwrap(ompObject)}) + if (objName->ToString() == name.ToString()) + return true; + return false; + }; + + auto &spec{std::get(x.t)}; + if (parser::OmpObjectList * + objectList{parser::Unwrap(spec.u)}) { + return existsInObjList(*objectList, name); + } + + if (auto *clauseList{parser::Unwrap(spec.u)}) { + // declare target with no clause case. + if (clauseList->v.empty()) + return true; + + for (auto &clause : clauseList->v) { + if (auto *toClause{std::get_if(&clause.u)}) { + return existsInObjList(toClause->v, name); + } + + if (auto *linkClause{std::get_if(&clause.u)}) { + return existsInObjList(linkClause->v, name); + } + } + } + + return false; + } + + void addDeclareTarget(Subprograms &x, parser::Name name, + parser::OmpClause::DeviceType *parentsDeviceTypeClause) { + std::list *conList = nullptr; + if (std::holds_alternative(x)) { + conList = &std::get>( + std::get( + std::get(x)->t) + .t); + } else if (std::holds_alternative(x)) { + conList = &std::get>( + std::get( + std::get(x)->t) + .t); + } + + GatherDeclareTargetConstruct gatherer{}; + parser::OpenMPDeclareTargetConstruct *declareTarget = nullptr; + if (std::holds_alternative(x)) + declareTarget = getDeclTarConstruct( + *std::get(x), name); + else + declareTarget = + getDeclTarConstruct(*std::get(x), name); + + createOrModifyDeclareTargetTo( + declareTarget, conList, name, parentsDeviceTypeClause); + + // If the declare targetted function has an interface we must make sure + // the changes are reflected in the interface, as they should be identical + // executing the same function on it, should result in the same set of + // changes, if they are not idenitcal, then this is already incorrect + // OpenMP. + auto interface = interfaces_.find(name.ToString()); + if (interface != interfaces_.end()) { + createOrModifyDeclareTargetTo( + getDeclTarConstruct(*interface->second, name), + getDeclarativeConstructList(*interface->second), name, + parentsDeviceTypeClause); + } + } + + void markDeclTarForEachProgramUnit( + std::map subPrograms, parser::Name name, + parser::OmpClause::DeviceType *parentsDeviceTypeClause = nullptr, + bool isOriginalDeclTar = false) { + + auto subProgram = subPrograms.extract(name.ToString()); + if (subProgram.empty()) + return; + + // Add a declare target to the subprogram and its InterfaceBlock (if + // it has one) if one does not already exist + if (!isOriginalDeclTar) + addDeclareTarget(subProgram.mapped(), name, parentsDeviceTypeClause); + + GatherCallRefs gatherer{subPrograms_}; + if (std::holds_alternative( + subProgram.mapped())) + parser::Walk( + *std::get(subProgram.mapped()), + gatherer); + else + parser::Walk(*std::get(subProgram.mapped()), + gatherer); + + // Recurse on all calls found within the function, removing + // visited functions from the programUnits list as we go, if it + // is no longer in the list of units, then we have already + // processed it and made it declare target + for (auto v : gatherer.callNames) { + markDeclTarForEachProgramUnit(subPrograms, v, parentsDeviceTypeClause); + } + } + +public: + template bool Pre(T &) { return true; } + template void Post(T &) {} + ImplicitDeclareTargetCapture(SemanticsContext &context) + : messages_{context.messages()} {} + + // The entry point for rewriting declare target regions which + // contain functions nested within to be declare target + // themselves. + void Post(parser::OpenMPBlockConstruct &x) { + if (isTargetRegion(x)) { + GatherCallRefs gatherer{subPrograms_}; + parser::Walk(std::get(x.t), gatherer); + + auto deviceType = parser::OmpClause::DeviceType{ + Fortran::parser::OmpDeviceTypeClause::Type::Nohost}; + for (auto call : gatherer.callNames) + markDeclTarForEachProgramUnit(subPrograms_, call, &deviceType); + } + } + + // The entry point for rewriting declare target specifiers which + // contain functions nested within to be declare target themselves. + void Post(parser::OpenMPDeclareTargetConstruct &x) { + // InterfaceBody specifications of functions are handled as we parse the + // functions, if we alter a function to add a declare target, + // we check if an interface body also exists for it, if it does we must + // keep them in synch. The OpenMP specification states that a user must + // define synchronized interface and functions definitions for declare + // target. + if (!insideOfInterfaceBody_) { + auto &spec{std::get(x.t)}; + if (parser::OmpObjectList * + objectList{parser::Unwrap(spec.u)}) { + for (auto &ompObject : objectList->v) + if (auto *name{parser::Unwrap(ompObject)}) + markDeclTarForEachProgramUnit(subPrograms_, *name, nullptr, true); + } else if (auto *clauseList{ + parser::Unwrap(spec.u)}) { + parser::OmpClause::DeviceType *devType = nullptr; + for (auto &clause : clauseList->v) { + if (auto *deviceType{ + std::get_if(&clause.u)}) { + devType = deviceType; + } + } + + // We do not process link clauses these are not allowed to have + // functions as list items. And we do not care about host specific + // declare targets, the specification states that the implicit marking + // only happens for nohost (and by extension any, one would assume). + // Every non-declare target function can be assumed to be "host". + if (!devType || + devType->v.v != Fortran::parser::OmpDeviceTypeClause::Type::Host) + for (auto &clause : clauseList->v) { + if (auto *toClause{std::get_if(&clause.u)}) { + for (auto &ompObject : toClause->v.v) + if (auto *name{parser::Unwrap(ompObject)}) + markDeclTarForEachProgramUnit( + subPrograms_, *name, devType, true); + } + } + + // The default "declare target" inside of a function case, we must + // process the functions called from within + if (clauseList->v.empty()) { + if (auto *name = getNameFromVariant(currentSubprogram_)) { + markDeclTarForEachProgramUnit(subPrograms_, *name, nullptr, true); + } + } + } + } + } + + bool Pre(parser::FunctionSubprogram &x) { + insideOfInterfaceBody_ = false; + auto &stmt = + std::get>(x.t).statement; + auto name = std::get(stmt.t); + subPrograms_[name.ToString()] = &x; + currentSubprogram_ = &x; + return true; + } + + bool Pre(parser::SubroutineSubprogram &x) { + insideOfInterfaceBody_ = false; + auto &stmt = + std::get>(x.t).statement; + auto name = std::get(stmt.t); + subPrograms_[name.ToString()] = &x; + currentSubprogram_ = &x; + return true; + } + + bool Pre(parser::InterfaceBody &x) { + insideOfInterfaceBody_ = true; + if (auto *func{parser::Unwrap(x.u)}) { + const auto &stmt{ + std::get>(func->t)}; + auto name = std::get(stmt.statement.t); + interfaces_[name.ToString()] = &x; + } + + if (auto *subr{parser::Unwrap(x.u)}) { + const auto &stmt{ + std::get>(subr->t)}; + auto name = std::get(stmt.statement.t); + interfaces_[name.ToString()] = &x; + } + + return true; + } +}; + +bool FinalizeOMP(SemanticsContext &context, parser::Program &program) { + ImplicitDeclareTargetCapture impCap{context}; + Walk(program, impCap); + return !context.AnyFatalError(); +} + +} // namespace Fortran::semantics diff --git a/flang/lib/Semantics/semantics.cpp b/flang/lib/Semantics/semantics.cpp --- a/flang/lib/Semantics/semantics.cpp +++ b/flang/lib/Semantics/semantics.cpp @@ -31,6 +31,7 @@ #include "check-select-type.h" #include "check-stop.h" #include "compute-offsets.h" +#include "finalize-omp.h" #include "mod-file.h" #include "resolve-labels.h" #include "resolve-names.h" @@ -172,6 +173,7 @@ ComputeOffsets(context, context.globalScope()); CheckDeclarations(context); StatementSemanticsPass1{context}.Walk(program); + FinalizeOMP(context, program); StatementSemanticsPass2 pass2{context}; pass2.Walk(program); if (!context.AnyFatalError()) { diff --git a/flang/test/Examples/omp-declarative-directive.f90 b/flang/test/Examples/omp-declarative-directive.f90 --- a/flang/test/Examples/omp-declarative-directive.f90 +++ b/flang/test/Examples/omp-declarative-directive.f90 @@ -37,5 +37,5 @@ ! CHECK-NEXT:- file: '{{[^"]*}}omp-declarative-directive.f90' ! CHECK-NEXT: line: 21 ! CHECK-NEXT: construct: declare target -! CHECK-NEXT: clauses: [] +! CHECK-NEXT: clauses: [] ! CHECK-NEXT:... diff --git a/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite01.f90 b/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite01.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite01.f90 @@ -0,0 +1,325 @@ +! RUN: %flang_fc1 -fopenmp -fdebug-dump-parse-tree %s 2>&1 | FileCheck %s +! +! Ensure that functions and subroutines referenced within +! declare target functions and target regions are +! made declare target as specified by more recent iterations +! of the OpenMP specification. This is done through a +! semantic pass which generates declare target directives +! inside of the implicitly captured functions which match +! the callers. +! +! This test checks that the pass does simple declare target +! function implicit capture and marking with no issues. + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_nest_twice' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION IMPLICITLY_CAPTURED_NEST_TWICE() RESULT(I) + INTEGER :: I + I = 10 +END FUNCTION IMPLICITLY_CAPTURED_NEST_TWICE + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_one_twice' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION IMPLICITLY_CAPTURED_ONE_TWICE() RESULT(K) + K = IMPLICITLY_CAPTURED_NEST_TWICE() +END FUNCTION IMPLICITLY_CAPTURED_ONE_TWICE + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_two_twice' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION IMPLICITLY_CAPTURED_TWO_TWICE() RESULT(Y) + INTEGER :: Y + Y = 5 +END FUNCTION IMPLICITLY_CAPTURED_TWO_TWICE + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'target_function_test_device' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +FUNCTION TARGET_FUNCTION_TEST_DEVICE() RESULT(J) +!$omp declare target to(TARGET_FUNCTION_TEST_DEVICE) device_type(nohost) + INTEGER :: I, J + I = IMPLICITLY_CAPTURED_ONE_TWICE() + J = IMPLICITLY_CAPTURED_TWO_TWICE() + I +END FUNCTION TARGET_FUNCTION_TEST_DEVICE + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'target_function_test_host' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Host +FUNCTION TARGET_FUNCTION_TEST_HOST() RESULT(J) +!$omp declare target to(TARGET_FUNCTION_TEST_HOST) device_type(host) + INTEGER :: I, J + I = IMPLICITLY_CAPTURED_ONE_TWICE() + J = IMPLICITLY_CAPTURED_TWO_TWICE() + I +END FUNCTION TARGET_FUNCTION_TEST_HOST + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'func_t_device' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +FUNCTION FUNC_T_DEVICE() RESULT(I) +!$omp declare target to(FUNC_T_DEVICE) device_type(nohost) + INTEGER :: I + I = 1 +END FUNCTION FUNC_T_DEVICE + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'func_t_host' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Host +FUNCTION FUNC_T_HOST() RESULT(I) +!$omp declare target to(FUNC_T_HOST) device_type(host) + INTEGER :: I + I = 1 +END FUNCTION FUNC_T_HOST + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'subr_t_any' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +SUBROUTINE SUBR_T_ANY() +!$omp declare target to(SUBR_T_ANY) device_type(any) +END + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithList -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'subr_default_extendedlist' +SUBROUTINE SUBR_DEFAULT_EXTENDEDLIST() +!$omp declare target(SUBR_DEFAULT_EXTENDEDLIST) +END + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> +SUBROUTINE SUBR_UNSPECIFIED() +!$omp declare target +END + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'unspecified_capture' +FUNCTION UNSPECIFIED_CAPTURE() RESULT(K) + REAL :: K + K = 1 +END FUNCTION UNSPECIFIED_CAPTURE + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> +SUBROUTINE SUBR_UNSPECIFIED_CAPTURE() +!$omp declare target + REAL :: I + I = UNSPECIFIED_CAPTURE() +END + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_nest' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION IMPLICITLY_CAPTURED_NEST() RESULT(K) + INTEGER :: I + I = 10 + K = I +END FUNCTION IMPLICITLY_CAPTURED_NEST + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_one' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION IMPLICITLY_CAPTURED_ONE() RESULT(K) + K = IMPLICITLY_CAPTURED_NEST() +END FUNCTION IMPLICITLY_CAPTURED_ONE + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_two' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION IMPLICITLY_CAPTURED_TWO() RESULT(K) + INTEGER :: I + I = 10 + K = I +END FUNCTION IMPLICITLY_CAPTURED_TWO + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'target_function_test' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +FUNCTION TARGET_FUNCTION_TEST() RESULT(J) +!$omp declare target to(TARGET_FUNCTION_TEST) device_type(nohost) + INTEGER :: I, J + I = IMPLICITLY_CAPTURED_ONE() + J = IMPLICITLY_CAPTURED_TWO() + I +END FUNCTION TARGET_FUNCTION_TEST + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'no_declare_target' +FUNCTION NO_DECLARE_TARGET() RESULT(K) + implicit none + REAL :: I, K + I = 10.0 + K = I +END FUNCTION NO_DECLARE_TARGET + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'declare_target_two' +FUNCTION DECLARE_TARGET_TWO() RESULT(J) +!$omp declare target to(DECLARE_TARGET_TWO) + implicit none + REAL :: I, J + I = NO_DECLARE_TARGET() + J = I +END FUNCTION DECLARE_TARGET_TWO + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK:OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_recursive' +RECURSIVE FUNCTION IMPLICITLY_CAPTURED_RECURSIVE(INCREMENT) RESULT(K) + INTEGER :: INCREMENT, K + IF (INCREMENT == 10) THEN + K = INCREMENT + ELSE + K = IMPLICITLY_CAPTURED_RECURSIVE(INCREMENT + 1) + END IF +END FUNCTION IMPLICITLY_CAPTURED_RECURSIVE + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithList -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'target_function_recurse' +FUNCTION TARGET_FUNCTION_RECURSE() RESULT(I) +!$omp declare target(TARGET_FUNCTION_RECURSE) + INTEGER :: I + I = IMPLICITLY_CAPTURED_RECURSIVE(0) +END FUNCTION TARGET_FUNCTION_RECURSE + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_with_dev_type_recursive' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +RECURSIVE FUNCTION IMPLICITLY_CAPTURED_WITH_DEV_TYPE_RECURSIVE(INCREMENT) RESULT(K) +INTEGER :: INCREMENT, K +IF (INCREMENT == 10) THEN + K = INCREMENT +ELSE + K = IMPLICITLY_CAPTURED_WITH_DEV_TYPE_RECURSIVE(INCREMENT + 1) +END IF +END FUNCTION IMPLICITLY_CAPTURED_WITH_DEV_TYPE_RECURSIVE + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'target_function_with_dev_type_recurse' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +FUNCTION TARGET_FUNCTION_WITH_DEV_TYPE_RECURSE() RESULT(I) +!$omp declare target to(TARGET_FUNCTION_WITH_DEV_TYPE_RECURSE) device_type(nohost) +INTEGER :: I +I = IMPLICITLY_CAPTURED_WITH_DEV_TYPE_RECURSIVE(0) +END FUNCTION TARGET_FUNCTION_WITH_DEV_TYPE_RECURSE + +!! ----- + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_link_func' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +! CHECK: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> Link -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'p' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Host +FUNCTION IMPLICITLY_CAPTURED_LINK_FUNC() RESULT(I) + IMPLICIT NONE + INTEGER :: I + INTEGER :: P + SAVE P +!$omp declare target link(P) device_type(host) + P = 10 + I = P +END FUNCTION IMPLICITLY_CAPTURED_LINK_FUNC + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_capture_func_with_link' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +FUNCTION IMPLICITLY_CAPTURE_FUNC_WITH_LINK() RESULT(K) +!$omp declare target to(IMPLICITLY_CAPTURE_FUNC_WITH_LINK) device_type(nohost) + K = IMPLICITLY_CAPTURED_LINK_FUNC() +END FUNCTION IMPLICITLY_CAPTURE_FUNC_WITH_LINK + +!! ----- + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_to_func' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +! CHECK: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'p' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Host +FUNCTION IMPLICITLY_CAPTURED_TO_FUNC() RESULT(I) + IMPLICIT NONE + INTEGER :: I + INTEGER :: P + SAVE P +!$omp declare target to(P) device_type(host) + P = 10 + I = P +END FUNCTION IMPLICITLY_CAPTURED_TO_FUNC + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_capture_func_with_to' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +FUNCTION IMPLICITLY_CAPTURE_FUNC_WITH_TO() RESULT(K) +!$omp declare target to(IMPLICITLY_CAPTURE_FUNC_WITH_TO) device_type(nohost) + K = IMPLICITLY_CAPTURED_TO_FUNC() +END FUNCTION IMPLICITLY_CAPTURE_FUNC_WITH_TO diff --git a/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite02.f90 b/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite02.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite02.f90 @@ -0,0 +1,271 @@ +! RUN: %flang_fc1 -fopenmp -fdebug-dump-parse-tree %s 2>&1 | FileCheck %s +! +! Ensure that functions and subroutines referenced within +! declare target functions and target regions are +! made declare target as specified by more recent iterations +! of the OpenMP specification. This is done through a +! semantic pass which generates declare target directives +! inside of the implicitly captured functions which match +! the callers. +! +! This test case is declare-target-implicit-capture-rewrite01.f90 +! except placed into a module, to verify the pass works and continues +! to work in conjunction with modules. + +MODULE test_module + CONTAINS +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_nest_twice' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION IMPLICITLY_CAPTURED_NEST_TWICE() RESULT(I) + INTEGER :: I + I = 10 +END FUNCTION IMPLICITLY_CAPTURED_NEST_TWICE + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_one_twice' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION IMPLICITLY_CAPTURED_ONE_TWICE() RESULT(K) + K = IMPLICITLY_CAPTURED_NEST_TWICE() +END FUNCTION IMPLICITLY_CAPTURED_ONE_TWICE + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_two_twice' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION IMPLICITLY_CAPTURED_TWO_TWICE() RESULT(Y) + INTEGER :: Y + Y = 5 +END FUNCTION IMPLICITLY_CAPTURED_TWO_TWICE + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'target_function_test_device' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +FUNCTION TARGET_FUNCTION_TEST_DEVICE() RESULT(J) +!$omp declare target to(TARGET_FUNCTION_TEST_DEVICE) device_type(nohost) + INTEGER :: I, J + I = IMPLICITLY_CAPTURED_ONE_TWICE() + J = IMPLICITLY_CAPTURED_TWO_TWICE() + I +END FUNCTION TARGET_FUNCTION_TEST_DEVICE + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'target_function_test_host' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Host +FUNCTION TARGET_FUNCTION_TEST_HOST() RESULT(J) +!$omp declare target to(TARGET_FUNCTION_TEST_HOST) device_type(host) + INTEGER :: I, J + I = IMPLICITLY_CAPTURED_ONE_TWICE() + J = IMPLICITLY_CAPTURED_TWO_TWICE() + I +END FUNCTION TARGET_FUNCTION_TEST_HOST + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'func_t_device' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +FUNCTION FUNC_T_DEVICE() RESULT(I) +!$omp declare target to(FUNC_T_DEVICE) device_type(nohost) + INTEGER :: I + I = 1 +END FUNCTION FUNC_T_DEVICE + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'func_t_host' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Host +FUNCTION FUNC_T_HOST() RESULT(I) +!$omp declare target to(FUNC_T_HOST) device_type(host) + INTEGER :: I + I = 1 +END FUNCTION FUNC_T_HOST + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'subr_t_any' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +SUBROUTINE SUBR_T_ANY() +!$omp declare target to(SUBR_T_ANY) device_type(any) +END + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithList -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'subr_default_extendedlist' +SUBROUTINE SUBR_DEFAULT_EXTENDEDLIST() +!$omp declare target(SUBR_DEFAULT_EXTENDEDLIST) +END + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> +SUBROUTINE SUBR_UNSPECIFIED() +!$omp declare target +END + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'unspecified_capture' +FUNCTION UNSPECIFIED_CAPTURE() RESULT(K) + REAL :: K + K = 1 +END FUNCTION UNSPECIFIED_CAPTURE + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> +SUBROUTINE SUBR_UNSPECIFIED_CAPTURE() +!$omp declare target + REAL :: I + I = UNSPECIFIED_CAPTURE() +END + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_nest' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION IMPLICITLY_CAPTURED_NEST() RESULT(K) + INTEGER :: I + I = 10 + K = I +END FUNCTION IMPLICITLY_CAPTURED_NEST + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_one' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION IMPLICITLY_CAPTURED_ONE() RESULT(K) + K = IMPLICITLY_CAPTURED_NEST() +END FUNCTION IMPLICITLY_CAPTURED_ONE + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_two' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION IMPLICITLY_CAPTURED_TWO() RESULT(K) + INTEGER :: I + I = 10 + K = I +END FUNCTION IMPLICITLY_CAPTURED_TWO + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'target_function_test' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +FUNCTION TARGET_FUNCTION_TEST() RESULT(J) +!$omp declare target to(TARGET_FUNCTION_TEST) device_type(nohost) + INTEGER :: I, J + I = IMPLICITLY_CAPTURED_ONE() + J = IMPLICITLY_CAPTURED_TWO() + I +END FUNCTION TARGET_FUNCTION_TEST + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'no_declare_target' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION NO_DECLARE_TARGET() RESULT(K) + implicit none + REAL :: I, K + I = 10.0 + K = I +END FUNCTION NO_DECLARE_TARGET + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'declare_target_two' +FUNCTION DECLARE_TARGET_TWO() RESULT(J) +!$omp declare target to(DECLARE_TARGET_TWO) + implicit none + REAL :: I, J + I = NO_DECLARE_TARGET() + J = I +END FUNCTION DECLARE_TARGET_TWO + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK:OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_recursive' +RECURSIVE FUNCTION IMPLICITLY_CAPTURED_RECURSIVE(INCREMENT) RESULT(K) + INTEGER :: INCREMENT, K + IF (INCREMENT == 10) THEN + K = INCREMENT + ELSE + K = IMPLICITLY_CAPTURED_RECURSIVE(INCREMENT + 1) + END IF +END FUNCTION IMPLICITLY_CAPTURED_RECURSIVE + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithList -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'target_function_recurse' +FUNCTION TARGET_FUNCTION_RECURSE() RESULT(I) +!$omp declare target(TARGET_FUNCTION_RECURSE) + INTEGER :: I + I = IMPLICITLY_CAPTURED_RECURSIVE(0) +END FUNCTION TARGET_FUNCTION_RECURSE + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_with_dev_type_recursive' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +RECURSIVE FUNCTION IMPLICITLY_CAPTURED_WITH_DEV_TYPE_RECURSIVE(INCREMENT) RESULT(K) +INTEGER :: INCREMENT, K +IF (INCREMENT == 10) THEN + K = INCREMENT +ELSE + K = IMPLICITLY_CAPTURED_WITH_DEV_TYPE_RECURSIVE(INCREMENT + 1) +END IF +END FUNCTION IMPLICITLY_CAPTURED_WITH_DEV_TYPE_RECURSIVE + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'target_function_with_dev_type_recurse' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +FUNCTION TARGET_FUNCTION_WITH_DEV_TYPE_RECURSE() RESULT(I) +!$omp declare target to(TARGET_FUNCTION_WITH_DEV_TYPE_RECURSE) device_type(nohost) +INTEGER :: I +I = IMPLICITLY_CAPTURED_WITH_DEV_TYPE_RECURSIVE(0) +END FUNCTION TARGET_FUNCTION_WITH_DEV_TYPE_RECURSE + +END MODULE test_module diff --git a/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite03.f90 b/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite03.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite03.f90 @@ -0,0 +1,196 @@ +! RUN: %flang_fc1 -fopenmp -fdebug-dump-parse-tree %s 2>&1 | FileCheck %s +! +! Ensure that functions and subroutines referenced within +! declare target functions and target regions are +! made declare target as specified by more recent iterations +! of the OpenMP specification. This is done through a +! semantic pass which generates declare target directives +! inside of the implicitly captured functions which match +! the callers. +! +! This test aims to test the declare target implict capture +! rewrite passes interaction with interfaces, which they are +! allowed to be placed inside. However, the declare target in +! the interface and the function definition must be equivalent. + +!! The foo and bar tests are technically a semantic error +!! (unimplemented as of creation), the user must specify the +!! exact same declare target in both interface and defintion. +!! The semanitc analysis pass will do nothing with this. It +!! only updates interfaces if the definition itself is modified, +!! to keep it inline with the changes made. + +PROGRAM MB + INTERFACE + +!! This test-case, should eventually be an error. The two declare target pragmas are not +!! aligned (the body doesn't match the interface), and the pass correctly will not update +!! this subroutine to match it. + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> + SUBROUTINE FOO + !$omp declare target + END SUBROUTINE + +!! ----- + +! CHECK-NOT: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK-NOT: Verbatim +! CHECK-NOT: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> + SUBROUTINE BAR + END SUBROUTINE + +!! ----- + +!! This test-case, should eventually be an error. The two declare target pragmas are not +!! aligned (the body doesn't match the interface), and the pass correctly will not update +!! this subroutine to match it. + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> + SUBROUTINE BAZ + !$omp declare target + END SUBROUTINE + +!! ----- + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicit_callee' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any + SUBROUTINE IMPLICIT_CALLEE + END SUBROUTINE + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'caller_one' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Host + SUBROUTINE CALLER_ONE + !$omp declare target to(CALLER_ONE) device_type(host) + END SUBROUTINE + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'caller_two' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost + SUBROUTINE CALLER_TWO + !$omp declare target to(CALLER_TWO) device_type(nohost) + END SUBROUTINE + +!! ----- + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'caller_recursive' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost + SUBROUTINE CALLER_RECURSIVE + !$omp declare target to(CALLER_RECURSIVE) device_type(nohost) + END SUBROUTINE + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_recursive' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any + RECURSIVE SUBROUTINE IMPLICITLY_CAPTURED_RECURSIVE(INCREMENT) + INTEGER :: INCREMENT + END SUBROUTINE + END INTERFACE +END PROGRAM + +!! ----- + +! CHECK-NOT: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK-NOT: Verbatim +! CHECK-NOT: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> +SUBROUTINE FOO + print *, "foo" +END SUBROUTINE + +!! ----- + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> +SUBROUTINE BAR +!$omp declare target + print *, "bar" +END SUBROUTINE + +!! ----- + + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'baz' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +SUBROUTINE BAZ +!$omp declare target to(BAZ) device_type(nohost) + print *, "baz" +END SUBROUTINE + +!! ----- + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicit_callee' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +SUBROUTINE IMPLICIT_CALLEE +END SUBROUTINE + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'caller_one' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Host +SUBROUTINE CALLER_ONE + implicit none +!$omp declare target to(CALLER_ONE) device_type(host) + CALL IMPLICIT_CALLEE() +END SUBROUTINE + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'non_interface_function' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION NON_INTERFACE_FUNCTION() RESULT(I) + INTEGER :: I + I = 10 +END FUNCTION NON_INTERFACE_FUNCTION + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'caller_two' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +SUBROUTINE CALLER_TWO + implicit none + INTEGER :: I +!$omp declare target to(CALLER_TWO) device_type(nohost) + I = NON_INTERFACE_FUNCTION() + CALL IMPLICIT_CALLEE() +END SUBROUTINE + +!! ----- + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_recursive' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +RECURSIVE SUBROUTINE IMPLICITLY_CAPTURED_RECURSIVE(INCREMENT) + INTEGER :: INCREMENT + IF (INCREMENT == 10) THEN + RETURN + ELSE + CALL IMPLICITLY_CAPTURED_RECURSIVE(INCREMENT + 1) + END IF +END SUBROUTINE + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'caller_recursive' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +SUBROUTINE CALLER_RECURSIVE +!$omp declare target to(CALLER_RECURSIVE) device_type(nohost) + CALL IMPLICITLY_CAPTURED_RECURSIVE(0) +END SUBROUTINE diff --git a/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite04.f90 b/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite04.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite04.f90 @@ -0,0 +1,47 @@ +! RUN: %flang_fc1 -fopenmp -fdebug-dump-parse-tree %s 2>&1 | FileCheck %s +! +! Ensure that functions and subroutines referenced within +! declare target functions and target regions are +! made declare target as specified by more recent iterations +! of the OpenMP specification. This is done through a +! semantic pass which generates declare target directives +! inside of the implicitly captured functions which match +! the callers. +! +! This test aims to test the declare target implict capture +! rewrite passes interaction with static dispatch/function +! name aliases. + +MODULE m + CONTAINS +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 's1' + SUBROUTINE S1(I) + INTEGER :: I + PRINT *, I + END SUBROUTINE +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 's2' + SUBROUTINE s2(R) + REAL :: R + PRINT *, R + END SUBROUTINE +END + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 's' +SUBROUTINE S + USE m +!$omp declare target to(s) + INTERFACE SS + MODULE PROCEDURE S1, S2 + END INTERFACE + INTEGER :: X = 1 + REAL :: Y = 2.2 + CALL SS(X) + CALL SS(Y) +END SUBROUTINE + \ No newline at end of file diff --git a/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite05.f90 b/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite05.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite05.f90 @@ -0,0 +1,38 @@ +! RUN: %flang_fc1 -fopenmp -fdebug-dump-parse-tree %s 2>&1 | FileCheck %s +! +! Ensure that functions and subroutines referenced within +! declare target functions and target regions are +! made declare target as specified by more recent iterations +! of the OpenMP specification. This is done through a +! semantic pass which generates declare target directives +! inside of the implicitly captured functions which match +! the callers. +! +! This test aims to test the passes interaction with +! declare target functions with nested functions, the +! specification dictates that the nested functions are not +! allowed to have there own declare target directive, +! they instead inherit their parents. So, for now we follow +! this behaviour, leaving the inner function unmarked, however, +! there is no issue currently with adding the declare target +! to both, provided they match (minus the clause list with +! the functions name in it). + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'sub' +SUBROUTINE SUB + IMPLICIT NONE +!$omp declare target to(SUB) + INTEGER :: N + N = FORCED() + CONTAINS +! CHECK-NOT: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK-NOT: Verbatim +! CHECK-NOT: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'forced' + FUNCTION FORCED() + IMPLICIT NONE + INTEGER :: FORCED + FORCED = 1 + END FUNCTION FORCED +END SUBROUTINE diff --git a/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite06.f90 b/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite06.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite06.f90 @@ -0,0 +1,94 @@ +! RUN: %flang_fc1 -fopenmp -fdebug-dump-parse-tree %s 2>&1 | FileCheck %s +! +! Ensure that functions and subroutines referenced within +! declare target functions and target regions are +! made declare target as specified by more recent iterations +! of the OpenMP specification. This is done through a +! semantic pass which generates declare target directives +! inside of the implicitly captured functions which match +! the callers. +! +! This test aims to test the passes interaction with +! functions called from target regions, which should +! be marked as declare target + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicit_capture' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION IMPLICIT_CAPTURE() RESULT(I) + IMPLICIT NONE + INTEGER :: I + I = 1 +END FUNCTION IMPLICIT_CAPTURE + +SUBROUTINE SUBR_TARGET() + INTEGER :: N +!$omp target map(N) + N = IMPLICIT_CAPTURE() +!$omp end target +END SUBROUTINE + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_nest_twice' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION IMPLICITLY_CAPTURED_NEST_TWICE() RESULT(I) + INTEGER :: I + I = 10 +END FUNCTION IMPLICITLY_CAPTURED_NEST_TWICE + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_one_twice' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION IMPLICITLY_CAPTURED_ONE_TWICE() RESULT(K) + K = IMPLICITLY_CAPTURED_NEST_TWICE() +END FUNCTION IMPLICITLY_CAPTURED_ONE_TWICE + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_two_twice' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION IMPLICITLY_CAPTURED_TWO_TWICE() RESULT(Y) + INTEGER :: Y + Y = 5 +END FUNCTION IMPLICITLY_CAPTURED_TWO_TWICE + + +FUNCTION TARGET_FUNCTION_TEST_DEVICE() RESULT(J) + INTEGER :: I, J + !$omp target map(I, J) + I = IMPLICITLY_CAPTURED_ONE_TWICE() + J = IMPLICITLY_CAPTURED_TWO_TWICE() + I + !$omp end target +END FUNCTION TARGET_FUNCTION_TEST_DEVICE + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK:OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_recursive' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +RECURSIVE FUNCTION IMPLICITLY_CAPTURED_RECURSIVE(INCREMENT) RESULT(K) + INTEGER :: INCREMENT, K + IF (INCREMENT == 10) THEN + K = INCREMENT + ELSE + K = IMPLICITLY_CAPTURED_RECURSIVE(INCREMENT + 1) + END IF +END FUNCTION IMPLICITLY_CAPTURED_RECURSIVE + +FUNCTION TARGET_FUNCTION_RECURSE() RESULT(I) + INTEGER :: I + !$omp target map(I) + I = IMPLICITLY_CAPTURED_RECURSIVE(0) + !$omp end target +END FUNCTION TARGET_FUNCTION_RECURSE diff --git a/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite07.f90 b/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite07.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite07.f90 @@ -0,0 +1,150 @@ +! RUN: %flang_fc1 -fopenmp -fdebug-dump-parse-tree %s 2>&1 | FileCheck %s +! +! Ensure that functions and subroutines referenced within +! declare target functions and target regions are +! made declare target as specified by more recent iterations +! of the OpenMP specification. This is done through a +! semantic pass which generates declare target directives +! inside of the implicitly captured functions which match +! the callers. +! +! This test aims to test the passes interaction with +! intermixed declare target functions and target regions +! which both incur the pass to perform implicit marking. + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'declare_target_capture_host' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION DECLARE_TARGET_CAPTURE_HOST() RESULT(I) +!$omp declare target to(DECLARE_TARGET_CAPTURE_HOST) device_type(host) + IMPLICIT NONE + INTEGER :: I + I = 1 +END FUNCTION DECLARE_TARGET_CAPTURE_HOST + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'declare_target_capture_nohost' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +FUNCTION DECLARE_TARGET_CAPTURE_NOHOST() RESULT(I) +!$omp declare target to(DECLARE_TARGET_CAPTURE_NOHOST) device_type(nohost) + IMPLICIT NONE + INTEGER :: I + I = 1 +END FUNCTION DECLARE_TARGET_CAPTURE_NOHOST + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'declare_target_capture_any' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION DECLARE_TARGET_CAPTURE_ANY() RESULT(I) +!$omp declare target to(DECLARE_TARGET_CAPTURE_ANY) device_type(any) + IMPLICIT NONE + INTEGER :: I + I = 1 +END FUNCTION DECLARE_TARGET_CAPTURE_ANY + +! CHECK-NOT: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'subr_target' +! CHECK-NOT: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +SUBROUTINE SUBR_TARGET() + IMPLICIT NONE + INTEGER :: I, J, K +!$omp target map(I,J,K) + I = DECLARE_TARGET_CAPTURE_HOST() + J = DECLARE_TARGET_CAPTURE_NOHOST() + K = DECLARE_TARGET_CAPTURE_ANY() +!$omp end target +END SUBROUTINE + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'declare_target_captured_by_both' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION DECLARE_TARGET_CAPTURED_BY_BOTH() RESULT(I) + IMPLICIT NONE + INTEGER :: I + I = 1 +END FUNCTION DECLARE_TARGET_CAPTURED_BY_BOTH + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'func_declare_target' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Host +FUNCTION FUNC_DECLARE_TARGET() RESULT(K) +!$omp declare target to(FUNC_DECLARE_TARGET) device_type(host) + IMPLICIT NONE + INTEGER :: K + K = DECLARE_TARGET_CAPTURED_BY_BOTH() +END FUNCTION FUNC_DECLARE_TARGET + +! CHECK-NOT: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'func_target' +! CHECK-NOT: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +FUNCTION FUNC_TARGET() RESULT(I) + IMPLICIT NONE + INTEGER :: I +!$omp target map(I) + I = DECLARE_TARGET_CAPTURED_BY_BOTH() +!$omp end target +END FUNCTION FUNC_TARGET + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'declare_target_captured_twice_from_same_func' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION DECLARE_TARGET_CAPTURED_TWICE_FROM_SAME_FUNC() RESULT(I) + IMPLICIT NONE + INTEGER :: I + I = 1 +END FUNCTION DECLARE_TARGET_CAPTURED_TWICE_FROM_SAME_FUNC + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'func_declare_target_and_target' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +FUNCTION FUNC_DECLARE_TARGET_AND_TARGET() RESULT(I) +!$omp declare target to(FUNC_DECLARE_TARGET_AND_TARGET) device_type(nohost) + IMPLICIT NONE + INTEGER :: I +!$omp target map(I) + I = DECLARE_TARGET_CAPTURED_TWICE_FROM_SAME_FUNC() +!$omp end target +END FUNCTION FUNC_DECLARE_TARGET_AND_TARGET + +!! ----- + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'declare_target_captured_twice_from_same_func_any' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION DECLARE_TARGET_CAPTURED_TWICE_FROM_SAME_FUNC_ANY() RESULT(I) + IMPLICIT NONE + INTEGER :: I + I = 1 +END FUNCTION DECLARE_TARGET_CAPTURED_TWICE_FROM_SAME_FUNC_ANY + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'func_declare_target_host_and_target' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Host +FUNCTION FUNC_DECLARE_TARGET_HOST_AND_TARGET() RESULT(I) +!$omp declare target to(FUNC_DECLARE_TARGET_HOST_AND_TARGET) device_type(host) + IMPLICIT NONE + INTEGER :: I +!$omp target map(I) + I = DECLARE_TARGET_CAPTURED_TWICE_FROM_SAME_FUNC_ANY() +!$omp end target +END FUNCTION FUNC_DECLARE_TARGET_HOST_AND_TARGET diff --git a/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite08.f90 b/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite08.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite08.f90 @@ -0,0 +1,64 @@ +! RUN: %flang_fc1 -fopenmp -fdebug-dump-parse-tree %s 2>&1 | FileCheck %s +! +! Ensure that functions and subroutines referenced within +! declare target functions and target regions are +! made declare target as specified by more recent iterations +! of the OpenMP specification. This is done through a +! semantic pass which generates declare target directives +! inside of the implicitly captured functions which match +! the callers. +! +! This test aims to test the passes interaction with illegal +! code, which may be written accidentally by a user. While +! the pass shouldn't neccessarily do anything sensible with +! the code, it should not ICE the compiler or disrupt future +! or existing semantic errors. And as this pass executes before +! semantic analysis we must verify these cases. +! +! NOTE: Some of these will eventually have to be changed to +! check for the error diagnostic that is emitted, rather than +! (or in addition to) checking what the pass itself does to the +! PFT. + +!! ----- + +!! Illegal to have device_type without either link, to or an extended-list + +! CHECK-NOT: OmpDeclareTargetSpecifier +FUNCTION IMPLICITLY_CAPTURED_NEST() RESULT(I) + IMPLICIT NONE + INTEGER :: I + I = 10 +END FUNCTION IMPLICITLY_CAPTURED_NEST + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +! CHECK: ImplicitPart -> +FUNCTION IMPLICITLY_CAPTURE_ILLEGAL() RESULT(K) +!$omp declare target device_type(nohost) + K = IMPLICITLY_CAPTURED_NEST() +END FUNCTION IMPLICITLY_CAPTURE_ILLEGAL + +!! ----- + +!! Illegal to have a function passed to a link clause, the specification only +!! allows variables or arrays + +! CHECK-NOT: OmpDeclareTargetSpecifier +FUNCTION IMPLICITLY_CAPTURED_NEST_TWO() RESULT(I) + IMPLICIT NONE + INTEGER :: I + I = 10 +END FUNCTION IMPLICITLY_CAPTURED_NEST_TWO + +! CHECK: SpecificationPart +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> Link -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_capture_illegal_link' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Host +FUNCTION IMPLICITLY_CAPTURE_ILLEGAL_LINK() RESULT(K) +!$omp declare target link(IMPLICITLY_CAPTURE_ILLEGAL_LINK) device_type(host) + K = IMPLICITLY_CAPTURED_NEST_TWO() +END FUNCTION IMPLICITLY_CAPTURE_ILLEGAL_LINK diff --git a/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite09.f90 b/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite09.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/OpenMP/declare-target-implicit-capture-rewrite09.f90 @@ -0,0 +1,189 @@ +! RUN: %flang_fc1 -fopenmp -fdebug-dump-parse-tree %s 2>&1 | FileCheck %s +! +! Ensure that functions and subroutines referenced within +! declare target functions and target regions are +! made declare target as specified by more recent iterations +! of the OpenMP specification. This is done through a +! semantic pass which generates declare target directives +! inside of the implicitly captured functions which match +! the callers. +! +! This test aims to test the behaviour of mixed declare +! targets with functions and variables and multiple declare +! targets. + +!! ----- + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_nest_one' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +! CHECK: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'p' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Host +FUNCTION IMPLICITLY_CAPTURED_NEST_ONE() RESULT(I) + IMPLICIT NONE + INTEGER :: I + INTEGER :: P + SAVE P +!$omp declare target to(IMPLICITLY_CAPTURED_NEST_ONE, P) device_type(host) + P = 10 + I = P +END FUNCTION IMPLICITLY_CAPTURED_NEST_ONE + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_capture_one' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +FUNCTION IMPLICITLY_CAPTURE_ONE() RESULT(K) +!$omp declare target to(IMPLICITLY_CAPTURE_ONE) device_type(nohost) + K = IMPLICITLY_CAPTURED_NEST_ONE() +END FUNCTION IMPLICITLY_CAPTURE_ONE + +!! ----- + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_nest_two' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +! CHECK: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'p' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Host +FUNCTION IMPLICITLY_CAPTURED_NEST_TWO() RESULT(I) + IMPLICIT NONE + INTEGER :: I + INTEGER :: P + SAVE P +!$omp declare target to(P) device_type(host) + P = 10 + I = P +END FUNCTION IMPLICITLY_CAPTURED_NEST_TWO + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_capture_two' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION IMPLICITLY_CAPTURE_TWO() RESULT(K) +!$omp declare target to(IMPLICITLY_CAPTURE_TWO) device_type(Any) + K = IMPLICITLY_CAPTURED_NEST_TWO() +END FUNCTION IMPLICITLY_CAPTURE_TWO + +!! ----- + +! CHECK: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'p' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Host +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_nest_three' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION IMPLICITLY_CAPTURED_NEST_THREE() RESULT(I) + IMPLICIT NONE + INTEGER :: I + INTEGER :: P + SAVE P +!$omp declare target to(P) device_type(host) +!$omp declare target to(IMPLICITLY_CAPTURED_NEST_THREE) device_type(host) + P = 10 + I = P +END FUNCTION IMPLICITLY_CAPTURED_NEST_THREE + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_capture_three' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +FUNCTION IMPLICITLY_CAPTURE_THREE() RESULT(K) +!$omp declare target to(IMPLICITLY_CAPTURE_THREE) device_type(nohost) + K = IMPLICITLY_CAPTURED_NEST_THREE() +END FUNCTION IMPLICITLY_CAPTURE_THREE + +!! ----- + +! CHECK: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> Link -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'p' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_nest_four' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION IMPLICITLY_CAPTURED_NEST_FOUR() RESULT(I) + IMPLICIT NONE + INTEGER :: I + INTEGER :: P + SAVE P +!$omp declare target link(P) device_type(any) +!$omp declare target to(IMPLICITLY_CAPTURED_NEST_FOUR) device_type(host) + P = 10 + I = P +END FUNCTION IMPLICITLY_CAPTURED_NEST_FOUR + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_capture_four' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +FUNCTION IMPLICITLY_CAPTURE_FOUR() RESULT(K) +!$omp declare target to(IMPLICITLY_CAPTURE_FOUR) device_type(nohost) + K = IMPLICITLY_CAPTURED_NEST_FOUR() +END FUNCTION IMPLICITLY_CAPTURE_FOUR + +!! ----- + +! CHECK: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> Link -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'p' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +! CHECK: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithList -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_captured_nest_five' +FUNCTION IMPLICITLY_CAPTURED_NEST_FIVE() RESULT(I) + IMPLICIT NONE + INTEGER :: I + INTEGER :: P + SAVE P +!$omp declare target link(P) device_type(any) +!$omp declare target(IMPLICITLY_CAPTURED_NEST_FIVE) + P = 10 + I = P +END FUNCTION IMPLICITLY_CAPTURED_NEST_FIVE + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_capture_five' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +FUNCTION IMPLICITLY_CAPTURE_FIVE() RESULT(K) +!$omp declare target to(IMPLICITLY_CAPTURE_FIVE) device_type(nohost) + K = IMPLICITLY_CAPTURED_NEST_FIVE() +END FUNCTION IMPLICITLY_CAPTURE_FIVE + +!! ----- + +! CHECK: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> +! CHECK: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> Link -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'p' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Any +FUNCTION IMPLICITLY_CAPTURED_NEST_SIX() RESULT(I) + IMPLICIT NONE + INTEGER :: I + INTEGER :: P + SAVE P +!$omp declare target +!$omp declare target link(P) device_type(any) + P = 10 + I = P +END FUNCTION IMPLICITLY_CAPTURED_NEST_SIX + +! CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +! CHECK: Verbatim +! CHECK: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'implicitly_capture_six' +! CHECK: OmpClause -> DeviceType -> OmpDeviceTypeClause -> Type = Nohost +FUNCTION IMPLICITLY_CAPTURE_SIX() RESULT(K) +!$omp declare target to(IMPLICITLY_CAPTURE_SIX) device_type(nohost) + K = IMPLICITLY_CAPTURED_NEST_SIX() +END FUNCTION IMPLICITLY_CAPTURE_SIX