From 2b1bc65cbd8fceffd44a84e0339b5f0965d7f4b1 Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Tue, 23 Sep 2025 11:51:01 -0500 Subject: [PATCH 1/9] [flang][OpenMP] Introduce variant argument, customize OmpArgument parsing The DECLARE_VARIANT directive takes two names separated by a colon as an argument: base-name:variant-name. Define OmpBaseVariantNames to represent this, since no existing argument alternative matches it. However, there is an issue. The syntax "name1:name2" can be the argument to DECLARE_VARIANT (if both names are OmpObjects), but it can also be a reduction-specifier if "name2" is a type. This conflict can only be resolved once we know what the names are, which is after name resolution has visited them. The problem is that name resolution has side-effects that may be (practically) impossible to undo (e.g. creating new symbols, emitting diagnostic messages). To avoid this problem this PR makes the parsing of OmpArgument directive- sensitive: when the directive is DECLARE_VARIANT, don't attempt to parse a reduction-specifier, consider OmpBaseVariantNames instead. Otherwise ignore OmpBaseVariantNames in favor of reduction-specifier. --- flang/include/flang/Parser/dump-parse-tree.h | 1 + flang/include/flang/Parser/parse-tree.h | 13 ++++ flang/lib/Parser/openmp-parsers.cpp | 68 +++++++++++++++++--- flang/lib/Parser/unparse.cpp | 5 ++ flang/lib/Semantics/resolve-names.cpp | 4 ++ 5 files changed, 83 insertions(+), 8 deletions(-) diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h index b2341226c7688..7540d38baa584 100644 --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -522,6 +522,7 @@ class ParseTreeDumper { NODE(parser, OmpAtomicDefaultMemOrderClause) NODE(parser, OmpAutomapModifier) NODE_ENUM(OmpAutomapModifier, Value) + NODE(parser, OmpBaseVariantNames) NODE(parser, OmpBeginDirective) NODE(parser, OmpBeginLoopDirective) NODE(parser, OmpBeginSectionsDirective) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index 39dbeb5e7cfbe..4808a5b844a6f 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -3555,6 +3555,18 @@ struct OmpLocator { WRAPPER_CLASS(OmpLocatorList, std::list); +// Ref: [4.5:58-60], [5.0:58-60], [5.1:63-68], [5.2:197-198], [6.0:334-336] +// +// Argument to DECLARE VARIANT with the base-name present. (When only +// variant-name is present, it is a simple OmpObject). +// +// base-name-variant-name -> // since 4.5 +// base-name : variant-name +struct OmpBaseVariantNames { + TUPLE_CLASS_BOILERPLATE(OmpBaseVariantNames); + std::tuple t; +}; + // Ref: [5.0:326:10-16], [5.1:359:5-11], [5.2:163:2-7], [6.0:293:16-21] // // mapper-specifier -> @@ -3584,6 +3596,7 @@ struct OmpArgument { CharBlock source; UNION_CLASS_BOILERPLATE(OmpArgument); std::variant u; }; diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index 30bc02ce851db..3b32e1a4a67b1 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -315,15 +315,56 @@ TYPE_PARSER( // construct(Parser{}) || construct(Parser{})) -TYPE_PARSER(sourced( // - construct(Parser{}) || - construct(Parser{}) || - construct(Parser{}))) +TYPE_PARSER(construct( + Parser{} / ":", Parser{})) + +// Make the parsing of OmpArgument directive-sensitive. The issue is that +// name1:name2 can match either OmpBaseVariantNames or OmpReductionSpecifier. +// In the former case, "name2" is a name of a function, in the latter, of a +// type. To resolve the conflict we need information provided by name +// resolution, but by that time we can't modify the AST anymore, and the +// name resolution may have implicitly declared a symbol, or issued a message. +template +struct OmpArgumentParser { + using resultType = OmpArgument; + + std::optional Parse(ParseState &state) const { + constexpr auto parser{sourced(first( // + construct(Parser{}), + // By default, prefer OmpReductionSpecifier over OmpBaseVariantNames. + construct(Parser{}), + construct(Parser{})))}; + return parser.Parse(state); + } +}; + +template <> +struct OmpArgumentParser { + using resultType = OmpArgument; + + std::optional Parse(ParseState &state) const { + constexpr auto parser{sourced(first( // + construct(Parser{}), + // In DECLARE_VARIANT parse OmpBaseVariantNames instead of + // OmpReductionSpecifier. + construct(Parser{}), + construct(Parser{})))}; + return parser.Parse(state); + } +}; TYPE_PARSER(construct(nonemptyList(Parser{}))) -TYPE_PARSER(sourced( // - construct(nonemptyList(Parser{})))) +template +struct OmpArgumentListParser { + using resultType = OmpArgumentList; + + std::optional Parse(ParseState &state) const { + return sourced( + construct(nonemptyList(OmpArgumentParser{}))) + .Parse(state); + } +}; TYPE_PARSER( // construct(Parser{}) || @@ -1312,12 +1353,23 @@ TYPE_PARSER( applyFunction(makeFlushFromOldSyntax, verbatim("FLUSH"_tok) / !lookAhead("("_tok), maybe(Parser{}), - maybe(parenthesized(Parser{})), + maybe(parenthesized( + OmpArgumentListParser{})), pure(OmpDirectiveSpecification::Flags::DeprecatedSyntax)))) || + // Parse DECLARE_VARIANT individually, because the "[base:]variant" + // argument will conflict with DECLARE_REDUCTION's "ident:types...". + predicated(Parser{}, + IsDirective(llvm::omp::Directive::OMPD_declare_variant)) >= + sourced(construct( + sourced(OmpDirectiveNameParser{}), + maybe(parenthesized(OmpArgumentListParser< + llvm::omp::Directive::OMPD_declare_variant>{})), + maybe(Parser{}), + pure(OmpDirectiveSpecification::Flags::None))) || // Parse the standard syntax: directive [(arguments)] [clauses] sourced(construct( // sourced(OmpDirectiveNameParser{}), - maybe(parenthesized(Parser{})), + maybe(parenthesized(OmpArgumentListParser<>{})), maybe(Parser{}), pure(OmpDirectiveSpecification::Flags::None)))) diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp index 3455b535ccb51..1b3eef0eefba3 100644 --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2089,6 +2089,11 @@ class UnparseVisitor { // OpenMP Clauses & Directives void Unparse(const OmpArgumentList &x) { Walk(x.v, ", "); } + void Unparse(const OmpBaseVariantNames &x) { + Walk(std::get<0>(x.t)); // OmpObject + Put(":"); + Walk(std::get<1>(x.t)); // OmpObject + } void Unparse(const OmpTypeNameList &x) { // Walk(x.v, ","); } diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index 699cb562da8cc..b73d794c11d31 100644 --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -1998,6 +1998,10 @@ bool OmpVisitor::Pre(const parser::OmpDirectiveSpecification &x) { ProcessReductionSpecifier(spec, clauses); visitClauses = false; }, + [&](const parser::OmpBaseVariantNames &names) { + Walk(std::get<0>(names.t)); + Walk(std::get<1>(names.t)); + }, [&](const parser::OmpLocator &locator) { // Manually resolve names in CRITICAL directives. This is because // these names do not denote Fortran objects, and the CRITICAL From 38cf6a6c62918458888ec4899ae9faf357b9a633 Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Tue, 23 Sep 2025 13:40:10 -0500 Subject: [PATCH 2/9] [flang][OpenMP] Use OmpDirectiveSpecification in DECLARE_VARIANT --- flang/include/flang/Parser/openmp-utils.h | 4 +- flang/include/flang/Parser/parse-tree.h | 8 +- flang/lib/Parser/openmp-parsers.cpp | 5 +- flang/lib/Parser/unparse.cpp | 8 +- flang/lib/Semantics/check-omp-structure.cpp | 52 +++++++++++-- flang/lib/Semantics/resolve-names.cpp | 25 ++----- flang/test/Parser/OpenMP/declare-variant.f90 | 73 +++++++++++-------- .../OpenMP/openmp6-directive-spellings.f90 | 9 ++- .../test/Semantics/OpenMP/declare-variant.f90 | 6 +- 9 files changed, 116 insertions(+), 74 deletions(-) diff --git a/flang/include/flang/Parser/openmp-utils.h b/flang/include/flang/Parser/openmp-utils.h index 34eb6ac3436bc..64be9714f6cc2 100644 --- a/flang/include/flang/Parser/openmp-utils.h +++ b/flang/include/flang/Parser/openmp-utils.h @@ -38,7 +38,6 @@ struct ConstructId { static constexpr llvm::omp::Directive id{Id}; \ } -MAKE_CONSTR_ID(OmpDeclareVariantDirective, D::OMPD_declare_variant); MAKE_CONSTR_ID(OpenMPDeclarativeAllocate, D::OMPD_allocate); MAKE_CONSTR_ID(OpenMPDeclarativeAssumes, D::OMPD_assumes); MAKE_CONSTR_ID(OpenMPDeclareReductionConstruct, D::OMPD_declare_reduction); @@ -92,8 +91,7 @@ struct DirectiveNameScope { } else if constexpr (TupleTrait) { if constexpr (std::is_base_of_v) { return std::get(x.t).DirName(); - } else if constexpr (std::is_same_v || - std::is_same_v || + } else if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index 4808a5b844a6f..de65088c01eae 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -4933,10 +4933,14 @@ struct OpenMPSectionsConstruct { t; }; +// Ref: [4.5:58-60], [5.0:58-60], [5.1:63-68], [5.2:197-198], [6.0:334-336] +// +// declare-variant-directive -> +// DECLARE_VARIANT([base-name:]variant-name) // since 4.5 struct OmpDeclareVariantDirective { - TUPLE_CLASS_BOILERPLATE(OmpDeclareVariantDirective); + WRAPPER_CLASS_BOILERPLATE( + OmpDeclareVariantDirective, OmpDirectiveSpecification); CharBlock source; - std::tuple, Name, OmpClauseList> t; }; // 2.10.6 declare-target -> DECLARE TARGET (extended-list) | diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index 3b32e1a4a67b1..6ec6eb4038933 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -1763,8 +1763,9 @@ TYPE_PARSER(construct( // OpenMP 5.2: 7.5.4 Declare Variant directive TYPE_PARSER(sourced(construct( - verbatim("DECLARE VARIANT"_tok) || verbatim("DECLARE_VARIANT"_tok), - "(" >> maybe(name / ":"), name / ")", Parser{}))) + predicated(Parser{}, + IsDirective(llvm::omp::Directive::OMPD_declare_variant)) >= + Parser{}))) // 2.16 Declare Reduction Construct TYPE_PARSER(sourced(construct( diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp index 1b3eef0eefba3..fc81cfb7a3818 100644 --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2539,12 +2539,8 @@ class UnparseVisitor { } void Unparse(const OmpDeclareVariantDirective &x) { BeginOpenMP(); - Word("!$OMP DECLARE VARIANT "); - Put("("); - Walk(std::get>(x.t), ":"); - Walk(std::get(x.t)); - Put(")"); - Walk(std::get(x.t)); + Word("!$OMP "); + Walk(x.v); Put("\n"); EndOpenMP(); } diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index e9bd34d449461..f10858ac1356d 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -634,11 +634,6 @@ template struct DirectiveSpellingVisitor { std::get(x.t).source, Directive::OMPD_declare_target); return false; } - bool Pre(const parser::OmpDeclareVariantDirective &x) { - checker_(std::get(x.t).source, - Directive::OMPD_declare_variant); - return false; - } bool Pre(const parser::OpenMPGroupprivate &x) { checker_(x.v.DirName().source, Directive::OMPD_groupprivate); return false; @@ -1370,9 +1365,50 @@ void OmpStructureChecker::Leave(const parser::OpenMPDeclareSimdConstruct &) { } void OmpStructureChecker::Enter(const parser::OmpDeclareVariantDirective &x) { - const auto &dir{std::get(x.t)}; - PushContextAndClauseSets( - dir.source, llvm::omp::Directive::OMPD_declare_variant); + const parser::OmpDirectiveName &dirName{x.v.DirName()}; + PushContextAndClauseSets(dirName.source, dirName.v); + + const parser::OmpArgumentList &args{x.v.Arguments()}; + if (args.v.size() != 1) { + context_.Say(args.source, + "DECLARE_VARIANT directive should have a single argument"_err_en_US); + return; + } + + auto InvalidArgument{[&](parser::CharBlock source) { + context_.Say(source, + "The argument to the DECLARE_MAPPER directive should be [base-name:]variant-name"_err_en_US); + }}; + + auto CheckSymbol{[&](const Symbol *sym, parser::CharBlock source) { + if (sym) { + if (!IsProcedure(*sym) && !IsFunction(*sym)) { + context_.Say(source, + "The name '%s' should refer to a procedure"_err_en_US, sym->name()); + } + if (sym->test(Symbol::Flag::Implicit)) { + context_.Say(source, + "The name '%s' has been implicitly declared"_err_en_US, + sym->name()); + } + } else { + InvalidArgument(source); + } + }}; + + const parser::OmpArgument &arg{args.v.front()}; + common::visit( // + common::visitors{ + [&](const parser::OmpBaseVariantNames &y) { + CheckSymbol(GetObjectSymbol(std::get<0>(y.t)), arg.source); + CheckSymbol(GetObjectSymbol(std::get<1>(y.t)), arg.source); + }, + [&](const parser::OmpLocator &y) { + CheckSymbol(GetArgumentSymbol(arg), arg.source); + }, + [&](auto &&y) { InvalidArgument(arg.source); }, + }, + arg.u); } void OmpStructureChecker::Leave(const parser::OmpDeclareVariantDirective &) { diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index b73d794c11d31..3a6115dae2da5 100644 --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -1540,20 +1540,6 @@ class OmpVisitor : public virtual DeclarationVisitor { bool Pre(const parser::OmpDeclareVariantDirective &x) { AddOmpSourceRange(x.source); - auto FindSymbolOrError = [&](const parser::Name &procName) { - auto *symbol{FindSymbol(NonDerivedTypeScope(), procName)}; - if (!symbol) { - context().Say(procName.source, - "Implicit subroutine declaration '%s' in !$OMP DECLARE VARIANT"_err_en_US, - procName.source); - } - }; - auto &baseProcName = std::get>(x.t); - if (baseProcName) { - FindSymbolOrError(*baseProcName); - } - auto &varProcName = std::get(x.t); - FindSymbolOrError(varProcName); return true; } @@ -1687,16 +1673,19 @@ class OmpVisitor : public virtual DeclarationVisitor { PopScope(); } } + + // These objects are handled explicitly, and the AST traversal should not + // reach a point where it calls the Pre functions for them. bool Pre(const parser::OmpMapperSpecifier &x) { - // OmpMapperSpecifier is handled explicitly, and the AST traversal - // should not reach a point where it calls this function. llvm_unreachable("This function should not be reached by AST traversal"); } bool Pre(const parser::OmpReductionSpecifier &x) { - // OmpReductionSpecifier is handled explicitly, and the AST traversal - // should not reach a point where it calls this function. llvm_unreachable("This function should not be reached by AST traversal"); } + bool Pre(const parser::OmpBaseVariantNames &x) { + llvm_unreachable("This function should not be reached by AST traversal"); + } + bool Pre(const parser::OmpDirectiveSpecification &x); void Post(const parser::OmpDirectiveSpecification &) { messageHandler().set_currStmtSource(std::nullopt); diff --git a/flang/test/Parser/OpenMP/declare-variant.f90 b/flang/test/Parser/OpenMP/declare-variant.f90 index 3366b143e62e6..f5c34abd84ac7 100644 --- a/flang/test/Parser/OpenMP/declare-variant.f90 +++ b/flang/test/Parser/OpenMP/declare-variant.f90 @@ -2,15 +2,19 @@ ! RUN: %flang_fc1 -fdebug-dump-parse-tree-no-sema -fopenmp %s | FileCheck --check-prefix="PARSE-TREE" %s subroutine sub0 -!CHECK: !$OMP DECLARE VARIANT (sub:vsub) MATCH(CONSTRUCT={PARALLEL}) -!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -!PARSE-TREE: | Verbatim -!PARSE-TREE: | Name = 'sub' -!PARSE-TREE: | Name = 'vsub' +!CHECK: !$OMP DECLARE VARIANT(sub:vsub) MATCH(CONSTRUCT={PARALLEL}) + +!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare variant +!PARSE-TREE: | OmpArgumentList -> OmpArgument -> OmpBaseVariantNames +!PARSE-TREE: | | OmpObject -> Designator -> DataRef -> Name = 'sub' +!PARSE-TREE: | | OmpObject -> Designator -> DataRef -> Name = 'vsub' !PARSE-TREE: | OmpClauseList -> OmpClause -> Match -> OmpMatchClause -> OmpContextSelectorSpecification -> OmpTraitSetSelector !PARSE-TREE: | | OmpTraitSetSelectorName -> Value = Construct !PARSE-TREE: | | OmpTraitSelector !PARSE-TREE: | | | OmpTraitSelectorName -> llvm::omp::Directive = parallel +!PARSE-TREE: | Flags = None + !$omp declare variant (sub:vsub) match (construct={parallel}) contains subroutine vsub @@ -30,14 +34,17 @@ subroutine vsub (v1) integer, value :: v1 end subroutine sub (v1) -!CHECK: !$OMP DECLARE VARIANT (vsub) MATCH(CONSTRUCT={DISPATCH} -!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -!PARSE-TREE: | Verbatim -!PARSE-TREE: | Name = 'vsub' +!CHECK: !$OMP DECLARE VARIANT(vsub) MATCH(CONSTRUCT={DISPATCH}) + +!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare variant +!PARSE-TREE: | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'vsub' !PARSE-TREE: | OmpClauseList -> OmpClause -> Match -> OmpMatchClause -> OmpContextSelectorSpecification -> OmpTraitSetSelector !PARSE-TREE: | | OmpTraitSetSelectorName -> Value = Construct !PARSE-TREE: | | OmpTraitSelector !PARSE-TREE: | | | OmpTraitSelectorName -> llvm::omp::Directive = dispatch +!PARSE-TREE: | Flags = None + !$omp declare variant(vsub), match(construct={dispatch}) integer, value :: v1 end @@ -56,17 +63,20 @@ subroutine vsub (v1, a1, a2) integer(omp_interop_kind), value :: a2 end subroutine sub (v1) -!CHECK: !$OMP DECLARE VARIANT (vsub) MATCH(CONSTRUCT={DISPATCH}) APPEND_ARGS(INTEROP(T& -!CHECK: !$OMP&ARGET),INTEROP(TARGET)) -!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -!PARSE-TREE: | Verbatim -!PARSE-TREE: | Name = 'vsub' +!CHECK: !$OMP DECLARE VARIANT(vsub) MATCH(CONSTRUCT={DISPATCH}) APPEND_ARGS(INTEROP(TA& +!CHECK: !$OMP&RGET),INTEROP(TARGET)) + +!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare variant +!PARSE-TREE: | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'vsub' !PARSE-TREE: | OmpClauseList -> OmpClause -> Match -> OmpMatchClause -> OmpContextSelectorSpecification -> OmpTraitSetSelector !PARSE-TREE: | | OmpTraitSetSelectorName -> Value = Construct !PARSE-TREE: | | OmpTraitSelector !PARSE-TREE: | | | OmpTraitSelectorName -> llvm::omp::Directive = dispatch !PARSE-TREE: | OmpClause -> AppendArgs -> OmpAppendArgsClause -> OmpAppendOp -> OmpInteropType -> Value = Target !PARSE-TREE: | OmpAppendOp -> OmpInteropType -> Value = Target +!PARSE-TREE: | Flags = None + !$omp declare variant(vsub), match(construct={dispatch}), append_args (interop(target), interop(target)) integer, value :: v1 end @@ -81,11 +91,12 @@ subroutine sb3 (x1, x2) contains subroutine sub (v1, v2) type(c_ptr), value :: v1, v2 -!CHECK: !$OMP DECLARE VARIANT (vsub) MATCH(CONSTRUCT={DISPATCH}) ADJUST_ARGS(NOTHING:v& -!CHECK: !$OMP&1) ADJUST_ARGS(NEED_DEVICE_PTR:v2) -!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -!PARSE-TREE: | Verbatim -!PARSE-TREE: | Name = 'vsub' +!CHECK: !$OMP DECLARE VARIANT(vsub) MATCH(CONSTRUCT={DISPATCH}) ADJUST_ARGS(NOTHING:v1& +!CHECK: !$OMP&) ADJUST_ARGS(NEED_DEVICE_PTR:v2) + +!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare variant +!PARSE-TREE: | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'vsub' !PARSE-TREE: | OmpClauseList -> OmpClause -> Match -> OmpMatchClause -> OmpContextSelectorSpecification -> OmpTraitSetSelector !PARSE-TREE: | | OmpTraitSetSelectorName -> Value = Construct !PARSE-TREE: | | OmpTraitSelector @@ -96,6 +107,8 @@ subroutine sub (v1, v2) !PARSE-TREE: | OmpClause -> AdjustArgs -> OmpAdjustArgsClause !PARSE-TREE: | | OmpAdjustOp -> Value = Need_Device_Ptr !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'v2' +!PARSE-TREE: | Flags = None + !$omp declare variant(vsub) match ( construct = { dispatch } ) adjust_args(nothing : v1 ) adjust_args(need_device_ptr : v2) end subroutine vsub(v1, v2) @@ -119,13 +132,15 @@ subroutine f2 (x, y) !$omp declare variant (f1) match (construct={simd(uniform(y))}) end end subroutine -!CHECK: !$OMP DECLARE VARIANT (f1) MATCH(CONSTRUCT={SIMD(UNIFORM(y))}) -!PARSE-TREE: | | | | DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -!PARSE-TREE-NEXT: | | | | | Verbatim -!PARSE-TREE-NEXT: | | | | | Name = 'f1' -!PARSE-TREE-NEXT: | | | | | OmpClauseList -> OmpClause -> Match -> OmpMatchClause -> OmpContextSelectorSpecification -> OmpTraitSetSelector -!PARSE-TREE-NEXT: | | | | | | OmpTraitSetSelectorName -> Value = Construct -!PARSE-TREE-NEXT: | | | | | | OmpTraitSelector -!PARSE-TREE-NEXT: | | | | | | | OmpTraitSelectorName -> Value = Simd -!PARSE-TREE-NEXT: | | | | | | | Properties -!PARSE-TREE-NEXT: | | | | | | | | OmpTraitProperty -> OmpClause -> Uniform -> Name = 'y' +!CHECK: !$OMP DECLARE VARIANT(f1) MATCH(CONSTRUCT={SIMD(UNIFORM(y))}) + +!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare variant +!PARSE-TREE: | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'f1' +!PARSE-TREE: | OmpClauseList -> OmpClause -> Match -> OmpMatchClause -> OmpContextSelectorSpecification -> OmpTraitSetSelector +!PARSE-TREE: | | OmpTraitSetSelectorName -> Value = Construct +!PARSE-TREE: | | OmpTraitSelector +!PARSE-TREE: | | | OmpTraitSelectorName -> Value = Simd +!PARSE-TREE: | | | Properties +!PARSE-TREE: | | | | OmpTraitProperty -> OmpClause -> Uniform -> Name = 'y' +!PARSE-TREE: | Flags = None diff --git a/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90 b/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90 index a25d750adc39d..f55ff958b0952 100644 --- a/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90 +++ b/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90 @@ -145,12 +145,12 @@ subroutine g05 !UNPARSE: SUBROUTINE g05 !UNPARSE: END SUBROUTINE !UNPARSE: END INTERFACE -!UNPARSE: !$OMP DECLARE VARIANT (g05) MATCH(USER={CONDITION(.true._4)}) +!UNPARSE: !$OMP DECLARE_VARIANT(g05) MATCH(USER={CONDITION(.true._4)}) !UNPARSE: END SUBROUTINE -!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -!PARSE-TREE: | Verbatim -!PARSE-TREE: | Name = 'g05' +!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare variant +!PARSE-TREE: | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'g05' !PARSE-TREE: | OmpClauseList -> OmpClause -> Match -> OmpMatchClause -> OmpContextSelectorSpecification -> OmpTraitSetSelector !PARSE-TREE: | | OmpTraitSetSelectorName -> Value = User !PARSE-TREE: | | OmpTraitSelector @@ -159,6 +159,7 @@ subroutine g05 !PARSE-TREE: | | | | OmpTraitProperty -> Scalar -> Expr = '.true._4' !PARSE-TREE: | | | | | LiteralConstant -> LogicalLiteralConstant !PARSE-TREE: | | | | | | bool = 'true' +!PARSE-TREE: | Flags = None subroutine f06 implicit none diff --git a/flang/test/Semantics/OpenMP/declare-variant.f90 b/flang/test/Semantics/OpenMP/declare-variant.f90 index 84a0cdcd10d91..59b8bda3f2a99 100644 --- a/flang/test/Semantics/OpenMP/declare-variant.f90 +++ b/flang/test/Semantics/OpenMP/declare-variant.f90 @@ -1,9 +1,11 @@ ! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=51 subroutine sub0 -!ERROR: Implicit subroutine declaration 'vsub1' in !$OMP DECLARE VARIANT +!ERROR: The name 'vsub1' should refer to a procedure +!ERROR: The name 'vsub1' has been implicitly declared !$omp declare variant (sub:vsub1) match (construct={parallel}) -!ERROR: Implicit subroutine declaration 'sub1' in !$OMP DECLARE VARIANT +!ERROR: The name 'sub1' should refer to a procedure +!ERROR: The name 'sub1' has been implicitly declared !$omp declare variant (sub1:vsub) match (construct={parallel}) contains subroutine vsub From 7e54af8cd0a27970bccc319b5a23924a90aaea1d Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Tue, 23 Sep 2025 14:57:40 -0500 Subject: [PATCH 3/9] Fix directive name in message --- flang/lib/Semantics/check-omp-structure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index f10858ac1356d..9b1932255bd05 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -1377,7 +1377,7 @@ void OmpStructureChecker::Enter(const parser::OmpDeclareVariantDirective &x) { auto InvalidArgument{[&](parser::CharBlock source) { context_.Say(source, - "The argument to the DECLARE_MAPPER directive should be [base-name:]variant-name"_err_en_US); + "The argument to the DECLARE_VARIANT directive should be [base-name:]variant-name"_err_en_US); }}; auto CheckSymbol{[&](const Symbol *sym, parser::CharBlock source) { From 6f624f979480e2998ef276d47d95761919bf61e2 Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Tue, 23 Sep 2025 14:56:14 -0500 Subject: [PATCH 4/9] [flang][OpenMP] Use OmpDirectiveSpecification in DECLARE_SIMD --- flang/include/flang/Parser/openmp-utils.h | 2 - flang/include/flang/Parser/parse-tree.h | 4 +- flang/lib/Parser/openmp-parsers.cpp | 5 ++- flang/lib/Parser/unparse.cpp | 7 ++-- flang/lib/Semantics/check-omp-structure.cpp | 34 ++++++++++++---- flang/lib/Semantics/resolve-directives.cpp | 7 ++-- flang/test/Parser/OpenMP/linear-clause.f90 | 40 +++++++++---------- .../OpenMP/openmp6-directive-spellings.f90 | 7 ++-- flang/test/Semantics/OpenMP/declare-simd.f90 | 23 +++++++++++ 9 files changed, 84 insertions(+), 45 deletions(-) create mode 100644 flang/test/Semantics/OpenMP/declare-simd.f90 diff --git a/flang/include/flang/Parser/openmp-utils.h b/flang/include/flang/Parser/openmp-utils.h index 64be9714f6cc2..e17728b5413e2 100644 --- a/flang/include/flang/Parser/openmp-utils.h +++ b/flang/include/flang/Parser/openmp-utils.h @@ -41,7 +41,6 @@ struct ConstructId { MAKE_CONSTR_ID(OpenMPDeclarativeAllocate, D::OMPD_allocate); MAKE_CONSTR_ID(OpenMPDeclarativeAssumes, D::OMPD_assumes); MAKE_CONSTR_ID(OpenMPDeclareReductionConstruct, D::OMPD_declare_reduction); -MAKE_CONSTR_ID(OpenMPDeclareSimdConstruct, D::OMPD_declare_simd); MAKE_CONSTR_ID(OpenMPDeclareTargetConstruct, D::OMPD_declare_target); MAKE_CONSTR_ID(OpenMPExecutableAllocate, D::OMPD_allocate); MAKE_CONSTR_ID(OpenMPRequiresConstruct, D::OMPD_requires); @@ -94,7 +93,6 @@ struct DirectiveNameScope { } else if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || - std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v) { diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index de65088c01eae..be30a95763208 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -4987,9 +4987,9 @@ struct OpenMPDeclareReductionConstruct { // 2.8.2 declare-simd -> DECLARE SIMD [(proc-name)] [declare-simd-clause[ [,] // declare-simd-clause]...] struct OpenMPDeclareSimdConstruct { - TUPLE_CLASS_BOILERPLATE(OpenMPDeclareSimdConstruct); + WRAPPER_CLASS_BOILERPLATE( + OpenMPDeclareSimdConstruct, OmpDirectiveSpecification); CharBlock source; - std::tuple, OmpClauseList> t; }; // ref: [6.0:301-303] diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index 6ec6eb4038933..0085576292ff5 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -1836,8 +1836,9 @@ TYPE_PARSER( // 2.8.2 Declare Simd construct TYPE_PARSER(sourced(construct( - verbatim("DECLARE SIMD"_tok) || verbatim("DECLARE_SIMD"_tok), - maybe(parenthesized(name)), Parser{}))) + predicated(Parser{}, + IsDirective(llvm::omp::Directive::OMPD_declare_simd)) >= + Parser{}))) TYPE_PARSER(sourced( // construct( diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp index fc81cfb7a3818..c9774dd137d2b 100644 --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2573,11 +2573,10 @@ class UnparseVisitor { Put("\n"); EndOpenMP(); } - void Unparse(const OpenMPDeclareSimdConstruct &y) { + void Unparse(const OpenMPDeclareSimdConstruct &x) { BeginOpenMP(); - Word("!$OMP DECLARE SIMD "); - Walk("(", std::get>(y.t), ")"); - Walk(std::get(y.t)); + Word("!$OMP "); + Walk(x.v); Put("\n"); EndOpenMP(); } diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index 9b1932255bd05..55aa5a0a9f54d 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -624,11 +624,6 @@ template struct DirectiveSpellingVisitor { checker_(std::get(x.t).source, Directive::OMPD_assumes); return false; } - bool Pre(const parser::OpenMPDeclareSimdConstruct &x) { - checker_( - std::get(x.t).source, Directive::OMPD_declare_simd); - return false; - } bool Pre(const parser::OpenMPDeclareTargetConstruct &x) { checker_( std::get(x.t).source, Directive::OMPD_declare_target); @@ -1356,8 +1351,33 @@ void OmpStructureChecker::Leave(const parser::OpenMPThreadprivate &x) { } void OmpStructureChecker::Enter(const parser::OpenMPDeclareSimdConstruct &x) { - const auto &dir{std::get(x.t)}; - PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_declare_simd); + const parser::OmpDirectiveName &dirName{x.v.DirName()}; + PushContextAndClauseSets(dirName.source, dirName.v); + + const parser::OmpArgumentList &args{x.v.Arguments()}; + if (args.v.empty()) { + return; + } else if (args.v.size() > 1) { + context_.Say(args.source, + "DECLARE_SIMD directive should have at most one argument"_err_en_US); + return; + } + + const parser::OmpArgument &arg{args.v.front()}; + if (auto *sym{GetArgumentSymbol(arg)}) { + if (!IsProcedure(*sym) && !IsFunction(*sym)) { + context_.Say(arg.source, + "The name '%s' should refer to a procedure"_err_en_US, sym->name()); + } + if (sym->test(Symbol::Flag::Implicit)) { + context_.Say(arg.source, + "The name '%s' has been implicitly declared"_err_en_US, + sym->name()); + } + } else { + context_.Say(arg.source, + "The argument to the DECLARE_SIMD directive should be a procedure name"_err_en_US); + } } void OmpStructureChecker::Leave(const parser::OpenMPDeclareSimdConstruct &) { diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp index f1f78620532f5..218e3e7266ca9 100644 --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -473,9 +473,10 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor { bool Pre(const parser::OpenMPDeclareSimdConstruct &x) { PushContext(x.source, llvm::omp::Directive::OMPD_declare_simd); - const auto &name{std::get>(x.t)}; - if (name) { - ResolveOmpName(*name, Symbol::Flag::OmpDeclareSimd); + for (const parser::OmpArgument &arg : x.v.Arguments().v) { + if (auto *object{omp::GetArgumentObject(arg)}) { + ResolveOmpObject(*object, Symbol::Flag::OmpDeclareSimd); + } } return true; } diff --git a/flang/test/Parser/OpenMP/linear-clause.f90 b/flang/test/Parser/OpenMP/linear-clause.f90 index 5ea31ce58fc5a..b53dfe5f941a3 100644 --- a/flang/test/Parser/OpenMP/linear-clause.f90 +++ b/flang/test/Parser/OpenMP/linear-clause.f90 @@ -84,18 +84,16 @@ subroutine f03(x) !UNPARSE: SUBROUTINE f03 (x) !UNPARSE: INTEGER x -!UNPARSE: !$OMP DECLARE SIMD LINEAR(x: UVAL) +!UNPARSE: !$OMP DECLARE SIMD LINEAR(x: UVAL) !UNPARSE: END SUBROUTINE -!PARSE-TREE: SpecificationPart -![...] -!PARSE-TREE: | DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareSimdConstruct -!PARSE-TREE: | | Verbatim -!PARSE-TREE: | | OmpClauseList -> OmpClause -> Linear -> OmpLinearClause -!PARSE-TREE: | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' -!PARSE-TREE: | | | Modifier -> OmpLinearModifier -> Value = Uval -!PARSE-TREE: | | | bool = 'true' -!PARSE-TREE: ExecutionPart -> Block +!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareSimdConstruct -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare simd +!PARSE-TREE: | OmpClauseList -> OmpClause -> Linear -> OmpLinearClause +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | | Modifier -> OmpLinearModifier -> Value = Uval +!PARSE-TREE: | | bool = 'true' +!PARSE-TREE: | Flags = None subroutine f04(x) integer :: x @@ -104,17 +102,15 @@ subroutine f04(x) !UNPARSE: SUBROUTINE f04 (x) !UNPARSE: INTEGER x -!UNPARSE: !$OMP DECLARE SIMD LINEAR(x: UVAL, STEP(3_4)) +!UNPARSE: !$OMP DECLARE SIMD LINEAR(x: UVAL, STEP(3_4)) !UNPARSE: END SUBROUTINE -!PARSE-TREE: SpecificationPart -![...] -!PARSE-TREE: | DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareSimdConstruct -!PARSE-TREE: | | Verbatim -!PARSE-TREE: | | OmpClauseList -> OmpClause -> Linear -> OmpLinearClause -!PARSE-TREE: | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' -!PARSE-TREE: | | | Modifier -> OmpLinearModifier -> Value = Uval -!PARSE-TREE: | | | Modifier -> OmpStepComplexModifier -> Scalar -> Integer -> Expr = '3_4' -!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '3' -!PARSE-TREE: | | | bool = 'true' -!PARSE-TREE: ExecutionPart -> Block +!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareSimdConstruct -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare simd +!PARSE-TREE: | OmpClauseList -> OmpClause -> Linear -> OmpLinearClause +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | | Modifier -> OmpLinearModifier -> Value = Uval +!PARSE-TREE: | | Modifier -> OmpStepComplexModifier -> Scalar -> Integer -> Expr = '3_4' +!PARSE-TREE: | | | LiteralConstant -> IntLiteralConstant = '3' +!PARSE-TREE: | | bool = 'true' +!PARSE-TREE: | Flags = None diff --git a/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90 b/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90 index f55ff958b0952..b72c5a2c1c086 100644 --- a/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90 +++ b/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90 @@ -111,12 +111,13 @@ subroutine f03 end !UNPARSE: SUBROUTINE f03 -!UNPARSE: !$OMP DECLARE SIMD +!UNPARSE: !$OMP DECLARE_SIMD !UNPARSE: END SUBROUTINE -!PARSE-TREE: OpenMPDeclarativeConstruct -> OpenMPDeclareSimdConstruct -!PARSE-TREE: | Verbatim +!PARSE-TREE: OpenMPDeclarativeConstruct -> OpenMPDeclareSimdConstruct -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare simd !PARSE-TREE: | OmpClauseList -> +!PARSE-TREE: | Flags = None subroutine f04 !$omp declare_target diff --git a/flang/test/Semantics/OpenMP/declare-simd.f90 b/flang/test/Semantics/OpenMP/declare-simd.f90 new file mode 100644 index 0000000000000..825eb58f2adb5 --- /dev/null +++ b/flang/test/Semantics/OpenMP/declare-simd.f90 @@ -0,0 +1,23 @@ +! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=60 + +module m + +!ERROR: The name 'x' should refer to a procedure +!ERROR: The name 'x' has been implicitly declared +!$omp declare_simd(x) + +!ERROR: DECLARE_SIMD directive should have at most one argument +!$omp declare_simd(f00, f01) + +!ERROR: The argument to the DECLARE_SIMD directive should be a procedure name +!$omp declare_simd(v : integer) + +contains + +subroutine f00 +end + +subroutine f01 +end + +end module From acc37ebde987738210f7dc4a24e7591765858cc4 Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Tue, 23 Sep 2025 15:39:46 -0500 Subject: [PATCH 5/9] format --- flang/lib/Semantics/check-omp-structure.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index 55aa5a0a9f54d..cf89d305e3cb2 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -1371,8 +1371,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPDeclareSimdConstruct &x) { } if (sym->test(Symbol::Flag::Implicit)) { context_.Say(arg.source, - "The name '%s' has been implicitly declared"_err_en_US, - sym->name()); + "The name '%s' has been implicitly declared"_err_en_US, sym->name()); } } else { context_.Say(arg.source, From 30c575b992259508b690f691d83412ba506c9ce1 Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Tue, 23 Sep 2025 16:39:41 -0500 Subject: [PATCH 6/9] Add missing trivial overload --- flang/include/flang/Parser/openmp-utils.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/flang/include/flang/Parser/openmp-utils.h b/flang/include/flang/Parser/openmp-utils.h index e17728b5413e2..4b8fe6a5b49f0 100644 --- a/flang/include/flang/Parser/openmp-utils.h +++ b/flang/include/flang/Parser/openmp-utils.h @@ -56,6 +56,10 @@ struct DirectiveNameScope { return name; } + static OmpDirectiveName GetOmpDirectiveName(const OmpDirectiveName &x) { + return x; + } + static OmpDirectiveName GetOmpDirectiveName(const OmpBeginLoopDirective &x) { return x.DirName(); } From 525f12fa0da6c22dded6c19e2338b6bcc3c2da6f Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Wed, 24 Sep 2025 07:59:16 -0500 Subject: [PATCH 7/9] [flang][OpenMP] Use OmpDirectiveSpecification in DECLARE_TARGET --- flang/include/flang/Parser/openmp-utils.h | 2 - flang/include/flang/Parser/parse-tree.h | 10 +- flang/lib/Lower/OpenMP/OpenMP.cpp | 14 +- flang/lib/Parser/openmp-parsers.cpp | 18 +- flang/lib/Parser/unparse.cpp | 4 +- flang/lib/Semantics/check-omp-structure.cpp | 245 +++++++++--------- flang/lib/Semantics/check-omp-structure.h | 3 - flang/lib/Semantics/resolve-directives.cpp | 27 +- flang/lib/Semantics/resolve-names.cpp | 77 +++--- .../OpenMP/declare-target-indirect-tree.f90 | 28 +- .../OpenMP/declare-target-to-clause.f90 | 14 +- .../OpenMP/declare_target-device_type.f90 | 108 ++++++-- .../Parser/OpenMP/enter-automap-modifier.f90 | 11 +- .../OpenMP/openmp6-directive-spellings.f90 | 9 +- .../Semantics/OpenMP/blank-common-block.f90 | 1 + ...lare-target-function-name-with-symbols.f90 | 2 +- 16 files changed, 319 insertions(+), 254 deletions(-) diff --git a/flang/include/flang/Parser/openmp-utils.h b/flang/include/flang/Parser/openmp-utils.h index 4b8fe6a5b49f0..bf54f970a7d3a 100644 --- a/flang/include/flang/Parser/openmp-utils.h +++ b/flang/include/flang/Parser/openmp-utils.h @@ -41,7 +41,6 @@ struct ConstructId { MAKE_CONSTR_ID(OpenMPDeclarativeAllocate, D::OMPD_allocate); MAKE_CONSTR_ID(OpenMPDeclarativeAssumes, D::OMPD_assumes); MAKE_CONSTR_ID(OpenMPDeclareReductionConstruct, D::OMPD_declare_reduction); -MAKE_CONSTR_ID(OpenMPDeclareTargetConstruct, D::OMPD_declare_target); MAKE_CONSTR_ID(OpenMPExecutableAllocate, D::OMPD_allocate); MAKE_CONSTR_ID(OpenMPRequiresConstruct, D::OMPD_requires); @@ -97,7 +96,6 @@ struct DirectiveNameScope { } else if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || - std::is_same_v || std::is_same_v || std::is_same_v) { return MakeName(std::get(x.t).source, ConstructId::id); diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index be30a95763208..e7593d9875097 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -4961,10 +4961,16 @@ struct OmpDeclareTargetSpecifier { std::variant u; }; +// Ref: [4.5:110-113], [5.0:180-185], [5.1:210-216], [5.2:206-207], +// [6.0:346-348] +// +// declare-target-directive -> // since 4.5 +// DECLARE_TARGET[(extended-list)] | +// DECLARE_TARGET clause-list struct OpenMPDeclareTargetConstruct { - TUPLE_CLASS_BOILERPLATE(OpenMPDeclareTargetConstruct); + WRAPPER_CLASS_BOILERPLATE( + OpenMPDeclareTargetConstruct, OmpDirectiveSpecification); CharBlock source; - std::tuple t; }; // OMP v5.2: 5.8.8 diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp index d2e865b3e1d0c..1cb3335abbd06 100644 --- a/flang/lib/Lower/OpenMP/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP/OpenMP.cpp @@ -761,19 +761,17 @@ static void promoteNonCPtrUseDevicePtrArgsToUseDeviceAddr( static void getDeclareTargetInfo( lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval, - const parser::OpenMPDeclareTargetConstruct &declareTargetConstruct, + const parser::OpenMPDeclareTargetConstruct &construct, mlir::omp::DeclareTargetOperands &clauseOps, llvm::SmallVectorImpl &symbolAndClause) { - const auto &spec = - std::get(declareTargetConstruct.t); - if (const auto *objectList{parser::Unwrap(spec.u)}) { - ObjectList objects{makeObjects(*objectList, semaCtx)}; + + if (!construct.v.Arguments().v.empty()) { + ObjectList objects{makeObjects(construct.v.Arguments(), semaCtx)}; // Case: declare target(func, var1, var2) gatherFuncAndVarSyms(objects, mlir::omp::DeclareTargetCaptureClause::to, symbolAndClause, /*automap=*/false); - } else if (const auto *clauseList{ - parser::Unwrap(spec.u)}) { - List clauses = makeClauses(*clauseList, semaCtx); + } else { + List clauses = makeClauses(construct.v.Clauses(), semaCtx); if (clauses.empty()) { Fortran::lower::pft::FunctionLikeUnit *owningProc = eval.getOwningProcedure(); diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index 0085576292ff5..bd080386c0aea 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -1773,23 +1773,11 @@ TYPE_PARSER(sourced(construct( IsDirective(llvm::omp::Directive::OMPD_declare_reduction)) >= Parser{}))) -// declare-target with list -TYPE_PARSER(sourced(construct( - parenthesized(Parser{})))) - -// declare-target with clause -TYPE_PARSER( - sourced(construct(Parser{}))) - -// declare-target-specifier -TYPE_PARSER( - construct(Parser{}) || - construct(Parser{})) - // 2.10.6 Declare Target Construct TYPE_PARSER(sourced(construct( - verbatim("DECLARE TARGET"_tok) || verbatim("DECLARE_TARGET"_tok), - Parser{}))) + predicated(Parser{}, + IsDirective(llvm::omp::Directive::OMPD_declare_target)) >= + Parser{}))) static OmpMapperSpecifier ConstructOmpMapperSpecifier( std::optional &&mapperName, TypeSpec &&typeSpec, Name &&varName) { diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp index c9774dd137d2b..be166bcb743ba 100644 --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2582,8 +2582,8 @@ class UnparseVisitor { } void Unparse(const OpenMPDeclareTargetConstruct &x) { BeginOpenMP(); - Word("!$OMP DECLARE TARGET "); - Walk(std::get(x.t)); + Word("!$OMP "); + Walk(x.v); Put("\n"); EndOpenMP(); } diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index cf89d305e3cb2..05ff541657b1a 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -624,11 +624,6 @@ template struct DirectiveSpellingVisitor { checker_(std::get(x.t).source, Directive::OMPD_assumes); return false; } - bool Pre(const parser::OpenMPDeclareTargetConstruct &x) { - checker_( - std::get(x.t).source, Directive::OMPD_declare_target); - return false; - } bool Pre(const parser::OpenMPGroupprivate &x) { checker_(x.v.DirName().source, Directive::OMPD_groupprivate); return false; @@ -1615,38 +1610,6 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Allocate &x) { } } -void OmpStructureChecker::Enter(const parser::OmpDeclareTargetWithClause &x) { - SetClauseSets(llvm::omp::Directive::OMPD_declare_target); -} - -void OmpStructureChecker::Leave(const parser::OmpDeclareTargetWithClause &x) { - if (x.v.v.size() > 0) { - const parser::OmpClause *enterClause = - FindClause(llvm::omp::Clause::OMPC_enter); - const parser::OmpClause *toClause = FindClause(llvm::omp::Clause::OMPC_to); - const parser::OmpClause *linkClause = - FindClause(llvm::omp::Clause::OMPC_link); - const parser::OmpClause *indirectClause = - FindClause(llvm::omp::Clause::OMPC_indirect); - if (!enterClause && !toClause && !linkClause) { - context_.Say(x.source, - "If the DECLARE TARGET directive has a clause, it must contain at least one ENTER clause or LINK clause"_err_en_US); - } - if (indirectClause && !enterClause) { - context_.Say(x.source, - "The INDIRECT clause cannot be used without the ENTER clause with the DECLARE TARGET directive."_err_en_US); - } - unsigned version{context_.langOptions().OpenMPVersion}; - if (toClause && version >= 52) { - context_.Warn(common::UsageWarning::OpenMPUsage, toClause->source, - "The usage of TO clause on DECLARE TARGET directive has been deprecated. Use ENTER clause instead."_warn_en_US); - } - if (indirectClause) { - CheckAllowedClause(llvm::omp::Clause::OMPC_indirect); - } - } -} - void OmpStructureChecker::Enter(const parser::OpenMPDeclareMapperConstruct &x) { const parser::OmpDirectiveName &dirName{x.v.DirName()}; PushContextAndClauseSets(dirName.source, dirName.v); @@ -1698,42 +1661,6 @@ void OmpStructureChecker::Leave( dirContext_.pop_back(); } -void OmpStructureChecker::Enter(const parser::OpenMPDeclareTargetConstruct &x) { - const auto &dir{std::get(x.t)}; - PushContext(dir.source, llvm::omp::Directive::OMPD_declare_target); -} - -void OmpStructureChecker::Enter(const parser::OmpDeclareTargetWithList &x) { - SymbolSourceMap symbols; - GetSymbolsInObjectList(x.v, symbols); - for (auto &[symbol, source] : symbols) { - const GenericDetails *genericDetails = symbol->detailsIf(); - if (genericDetails) { - context_.Say(source, - "The procedure '%s' in DECLARE TARGET construct cannot be a generic name."_err_en_US, - symbol->name()); - genericDetails->specific(); - } - if (IsProcedurePointer(*symbol)) { - context_.Say(source, - "The procedure '%s' in DECLARE TARGET construct cannot be a procedure pointer."_err_en_US, - symbol->name()); - } - const SubprogramDetails *entryDetails = - symbol->detailsIf(); - if (entryDetails && entryDetails->entryScope()) { - context_.Say(source, - "The procedure '%s' in DECLARE TARGET construct cannot be an entry name."_err_en_US, - symbol->name()); - } - if (IsStmtFunction(*symbol)) { - context_.Say(source, - "The procedure '%s' in DECLARE TARGET construct cannot be a statement function."_err_en_US, - symbol->name()); - } - } -} - void OmpStructureChecker::CheckSymbolName( const parser::CharBlock &source, const parser::OmpObject &object) { common::visit( @@ -1766,62 +1693,138 @@ void OmpStructureChecker::CheckSymbolNames( } } +void OmpStructureChecker::Enter(const parser::OpenMPDeclareTargetConstruct &x) { + const parser::OmpDirectiveName &dirName{x.v.DirName()}; + PushContext(dirName.source, dirName.v); + + // Check if arguments are extended-list-items. + for (const parser::OmpArgument &arg : x.v.Arguments().v) { + const Symbol *symbol{GetArgumentSymbol(arg)}; + if (!symbol) { + context_.Say(arg.source, + "An argument to the DECLARE TARGET directive should be an extended-list-item"_err_en_US); + continue; + } + const GenericDetails *genericDetails = symbol->detailsIf(); + if (genericDetails) { + context_.Say(arg.source, + "The procedure '%s' in DECLARE TARGET construct cannot be a generic name."_err_en_US, + symbol->name()); + genericDetails->specific(); + } + if (IsProcedurePointer(*symbol)) { + context_.Say(arg.source, + "The procedure '%s' in DECLARE TARGET construct cannot be a procedure pointer."_err_en_US, + symbol->name()); + } + const SubprogramDetails *entryDetails = + symbol->detailsIf(); + if (entryDetails && entryDetails->entryScope()) { + context_.Say(arg.source, + "The procedure '%s' in DECLARE TARGET construct cannot be an entry name."_err_en_US, + symbol->name()); + } + if (IsStmtFunction(*symbol)) { + context_.Say(arg.source, + "The procedure '%s' in DECLARE TARGET construct cannot be a statement function."_err_en_US, + symbol->name()); + } + } + + // Check if there are arguments or clauses, but not both. + if (!x.v.Clauses().v.empty()) { + if (!x.v.Arguments().v.empty()) { + context_.Say(x.source, + "DECLARE TARGET directive can have argument or clauses, but not both"_err_en_US); + } + SetClauseSets(llvm::omp::Directive::OMPD_declare_target); + } +} + void OmpStructureChecker::Leave(const parser::OpenMPDeclareTargetConstruct &x) { - const auto &dir{std::get(x.t)}; - const auto &spec{std::get(x.t)}; + const parser::OmpDirectiveName &dirName{x.v.DirName()}; + // Handle both forms of DECLARE TARGET. // - Extended list: It behaves as if there was an ENTER/TO clause with the // list of objects as argument. It accepts no explicit clauses. // - With clauses. - if (const auto *objectList{parser::Unwrap(spec.u)}) { - deviceConstructFound_ = true; - CheckSymbolNames(dir.source, *objectList); - CheckVarIsNotPartOfAnotherVar(dir.source, *objectList); - CheckThreadprivateOrDeclareTargetVar(*objectList); - } else if (const auto *clauseList{ - parser::Unwrap(spec.u)}) { - bool toClauseFound{false}, deviceTypeClauseFound{false}, - enterClauseFound{false}; - for (const auto &clause : clauseList->v) { - common::visit( - common::visitors{ - [&](const parser::OmpClause::To &toClause) { - toClauseFound = true; - auto &objList{std::get(toClause.v.t)}; - CheckSymbolNames(dir.source, objList); - CheckVarIsNotPartOfAnotherVar(dir.source, objList); - CheckThreadprivateOrDeclareTargetVar(objList); - }, - [&](const parser::OmpClause::Link &linkClause) { - CheckSymbolNames(dir.source, linkClause.v); - CheckVarIsNotPartOfAnotherVar(dir.source, linkClause.v); - CheckThreadprivateOrDeclareTargetVar(linkClause.v); - }, - [&](const parser::OmpClause::Enter &enterClause) { - enterClauseFound = true; - auto &objList{std::get(enterClause.v.t)}; - CheckSymbolNames(dir.source, objList); - CheckVarIsNotPartOfAnotherVar(dir.source, objList); - CheckThreadprivateOrDeclareTargetVar(objList); - }, - [&](const parser::OmpClause::DeviceType &deviceTypeClause) { - deviceTypeClauseFound = true; - if (deviceTypeClause.v.v != - parser::OmpDeviceTypeClause::DeviceTypeDescription::Host) { - // Function / subroutine explicitly marked as runnable by the - // target device. - deviceConstructFound_ = true; - } - }, - [&](const auto &) {}, - }, - clause.u); + for (const parser::OmpArgument &arg : x.v.Arguments().v) { + if (auto *object{GetArgumentObject(arg)}) { + deviceConstructFound_ = true; + CheckSymbolName(dirName.source, *object); + CheckVarIsNotPartOfAnotherVar(dirName.source, *object); + CheckThreadprivateOrDeclareTargetVar(*object); + } + } - if ((toClauseFound || enterClauseFound) && !deviceTypeClauseFound) { - deviceConstructFound_ = true; - } + if (!x.v.Clauses().v.empty()) { + const parser::OmpClause *enterClause = + FindClause(llvm::omp::Clause::OMPC_enter); + const parser::OmpClause *toClause = FindClause(llvm::omp::Clause::OMPC_to); + const parser::OmpClause *linkClause = + FindClause(llvm::omp::Clause::OMPC_link); + const parser::OmpClause *indirectClause = + FindClause(llvm::omp::Clause::OMPC_indirect); + if (!enterClause && !toClause && !linkClause) { + context_.Say(x.source, + "If the DECLARE TARGET directive has a clause, it must contain at least one ENTER clause or LINK clause"_err_en_US); + } + if (indirectClause && !enterClause) { + context_.Say(x.source, + "The INDIRECT clause cannot be used without the ENTER clause with the DECLARE TARGET directive."_err_en_US); + } + unsigned version{context_.langOptions().OpenMPVersion}; + if (toClause && version >= 52) { + context_.Warn(common::UsageWarning::OpenMPUsage, toClause->source, + "The usage of TO clause on DECLARE TARGET directive has been deprecated. Use ENTER clause instead."_warn_en_US); + } + if (indirectClause) { + CheckAllowedClause(llvm::omp::Clause::OMPC_indirect); } } + + bool toClauseFound{false}, deviceTypeClauseFound{false}, + enterClauseFound{false}; + for (const parser::OmpClause &clause : x.v.Clauses().v) { + common::visit( + common::visitors{ + [&](const parser::OmpClause::To &toClause) { + toClauseFound = true; + auto &objList{std::get(toClause.v.t)}; + CheckSymbolNames(dirName.source, objList); + CheckVarIsNotPartOfAnotherVar(dirName.source, objList); + CheckThreadprivateOrDeclareTargetVar(objList); + }, + [&](const parser::OmpClause::Link &linkClause) { + CheckSymbolNames(dirName.source, linkClause.v); + CheckVarIsNotPartOfAnotherVar(dirName.source, linkClause.v); + CheckThreadprivateOrDeclareTargetVar(linkClause.v); + }, + [&](const parser::OmpClause::Enter &enterClause) { + enterClauseFound = true; + auto &objList{std::get(enterClause.v.t)}; + CheckSymbolNames(dirName.source, objList); + CheckVarIsNotPartOfAnotherVar(dirName.source, objList); + CheckThreadprivateOrDeclareTargetVar(objList); + }, + [&](const parser::OmpClause::DeviceType &deviceTypeClause) { + deviceTypeClauseFound = true; + if (deviceTypeClause.v.v != + parser::OmpDeviceTypeClause::DeviceTypeDescription::Host) { + // Function / subroutine explicitly marked as runnable by the + // target device. + deviceConstructFound_ = true; + } + }, + [&](const auto &) {}, + }, + clause.u); + + if ((toClauseFound || enterClauseFound) && !deviceTypeClauseFound) { + deviceConstructFound_ = true; + } + } + dirContext_.pop_back(); } diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h index 176f6568814c5..193784555a887 100644 --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -113,9 +113,6 @@ class OmpStructureChecker void Leave(const parser::OpenMPDeclareTargetConstruct &); void Enter(const parser::OpenMPDepobjConstruct &); void Leave(const parser::OpenMPDepobjConstruct &); - void Enter(const parser::OmpDeclareTargetWithList &); - void Enter(const parser::OmpDeclareTargetWithClause &); - void Leave(const parser::OmpDeclareTargetWithClause &); void Enter(const parser::OpenMPDispatchConstruct &); void Leave(const parser::OpenMPDispatchConstruct &); void Enter(const parser::OmpErrorDirective &); diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp index 218e3e7266ca9..7ef211c8b428c 100644 --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -2324,22 +2324,17 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPCriticalConstruct &x) { bool OmpAttributeVisitor::Pre(const parser::OpenMPDeclareTargetConstruct &x) { PushContext(x.source, llvm::omp::Directive::OMPD_declare_target); - const auto &spec{std::get(x.t)}; - if (const auto *objectList{parser::Unwrap(spec.u)}) { - ResolveOmpObjectList(*objectList, Symbol::Flag::OmpDeclareTarget); - } else if (const auto *clauseList{ - parser::Unwrap(spec.u)}) { - for (const auto &clause : clauseList->v) { - if (const auto *toClause{std::get_if(&clause.u)}) { - auto &objList{std::get(toClause->v.t)}; - ResolveOmpObjectList(objList, Symbol::Flag::OmpDeclareTarget); - } else if (const auto *linkClause{ - std::get_if(&clause.u)}) { - ResolveOmpObjectList(linkClause->v, Symbol::Flag::OmpDeclareTarget); - } else if (const auto *enterClause{ - std::get_if(&clause.u)}) { - ResolveOmpObjectList(std::get(enterClause->v.t), - Symbol::Flag::OmpDeclareTarget); + + for (const parser::OmpArgument &arg : x.v.Arguments().v) { + if (auto *object{omp::GetArgumentObject(arg)}) { + ResolveOmpObject(*object, Symbol::Flag::OmpDeclareTarget); + } + } + + for (const parser::OmpClause &clause : x.v.Clauses().v) { + if (auto *objects{parser::omp::GetOmpObjectList(clause)}) { + for (const parser::OmpObject &object : objects->v) { + ResolveOmpObject(object, Symbol::Flag::OmpDeclareTarget); } } } diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index 3a6115dae2da5..9b728d6b70deb 100644 --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -24,6 +24,7 @@ #include "flang/Evaluate/intrinsics.h" #include "flang/Evaluate/tools.h" #include "flang/Evaluate/type.h" +#include "flang/Parser/openmp-utils.h" #include "flang/Parser/parse-tree-visitor.h" #include "flang/Parser/parse-tree.h" #include "flang/Parser/tools.h" @@ -1572,51 +1573,41 @@ class OmpVisitor : public virtual DeclarationVisitor { } void Post(const parser::OpenMPThreadprivate &) { SkipImplicitTyping(false); } bool Pre(const parser::OpenMPDeclareTargetConstruct &x) { - const auto &spec{std::get(x.t)}; - auto populateDeclareTargetNames{[this](const parser::OmpObjectList - &objectList) { - for (const auto &ompObject : objectList.v) { - common::visit( - common::visitors{ - [&](const parser::Designator &designator) { - if (const auto *name{ - semantics::getDesignatorNameIfDataRef(designator)}) { - specPartState_.declareTargetNames.insert(name->source); - } - }, - [&](const parser::Name &name) { - specPartState_.declareTargetNames.insert(name.source); - }, - [&](const parser::OmpObject::Invalid &invalid) { - switch (invalid.v) { - SWITCH_COVERS_ALL_CASES - case parser::OmpObject::Invalid::Kind::BlankCommonBlock: - context().Say(invalid.source, - "Blank common blocks are not allowed as directive or clause arguments"_err_en_US); - break; - } - }, - }, - ompObject.u); - } + auto addObjectName{[&](const parser::OmpObject &object) { + common::visit( + common::visitors{ + [&](const parser::Designator &designator) { + if (const auto *name{ + semantics::getDesignatorNameIfDataRef(designator)}) { + specPartState_.declareTargetNames.insert(name->source); + } + }, + [&](const parser::Name &name) { + specPartState_.declareTargetNames.insert(name.source); + }, + [&](const parser::OmpObject::Invalid &invalid) { + switch (invalid.v) { + SWITCH_COVERS_ALL_CASES + case parser::OmpObject::Invalid::Kind::BlankCommonBlock: + context().Say(invalid.source, + "Blank common blocks are not allowed as directive or clause arguments"_err_en_US); + break; + } + }, + }, + object.u); }}; - if (const auto *objectList{parser::Unwrap(spec.u)}) { - populateDeclareTargetNames(*objectList); - } else if (const auto *clauseList{ - parser::Unwrap(spec.u)}) { - for (const auto &clause : clauseList->v) { - if (const auto *toClause{ - std::get_if(&clause.u)}) { - populateDeclareTargetNames( - std::get(toClause->v.t)); - } else if (const auto *linkClause{ - std::get_if(&clause.u)}) { - populateDeclareTargetNames(linkClause->v); - } else if (const auto *enterClause{ - std::get_if(&clause.u)}) { - populateDeclareTargetNames( - std::get(enterClause->v.t)); + for (const parser::OmpArgument &arg : x.v.Arguments().v) { + if (auto *object{omp::GetArgumentObject(arg)}) { + addObjectName(*object); + } + } + + for (const parser::OmpClause &clause : x.v.Clauses().v) { + if (auto *objects{parser::omp::GetOmpObjectList(clause)}) { + for (const parser::OmpObject &object : objects->v) { + addObjectName(object); } } } diff --git a/flang/test/Parser/OpenMP/declare-target-indirect-tree.f90 b/flang/test/Parser/OpenMP/declare-target-indirect-tree.f90 index 916bd66017ce0..16dc4eb44e6fd 100644 --- a/flang/test/Parser/OpenMP/declare-target-indirect-tree.f90 +++ b/flang/test/Parser/OpenMP/declare-target-indirect-tree.f90 @@ -1,5 +1,3 @@ -! REQUIRES: openmp_runtime - ! RUN: %flang_fc1 %openmp_flags -fopenmp-version=52 -fdebug-dump-parse-tree %s | FileCheck %s ! RUN: %flang_fc1 %openmp_flags -fdebug-unparse -fopenmp-version=52 %s | FileCheck %s --check-prefix="UNPARSE" @@ -15,11 +13,14 @@ function func() result(i) contains function func1() result(i) !$omp declare target enter(func1) indirect(.true.) - !CHECK: | | | | | OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> Enter -> OmpEnterClause - !CHECK-NEXT: | | | | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'func1' - !CHECK-NEXT: | | | | | OmpClause -> Indirect -> OmpIndirectClause -> Scalar -> Logical -> Expr = '.true._4' - !CHECK-NEXT: | | | | | | LiteralConstant -> LogicalLiteralConstant - !CHECK-NEXT: | | | | | | | bool = 'true' + !CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification + !CHECK-NEXT: | OmpDirectiveName -> llvm::omp::Directive = declare target + !CHECK-NEXT: | OmpClauseList -> OmpClause -> Enter -> OmpEnterClause + !CHECK-NEXT: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'func1' + !CHECK-NEXT: | OmpClause -> Indirect -> OmpIndirectClause -> Scalar -> Logical -> Expr = '.true._4' + !CHECK-NEXT: | | LiteralConstant -> LogicalLiteralConstant + !CHECK-NEXT: | | | bool = 'true' + !CHECK-NEXT: | Flags = None character(1) :: i i = 'a' return @@ -27,9 +28,12 @@ function func1() result(i) function func2() result(i) !$omp declare target enter(func2) indirect - !CHECK: | | | | | OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> Enter -> OmpEnterClause - !CHECK-NEXT: | | | | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'func2' - !CHECK-NEXT: | | | | | OmpClause -> Indirect -> OmpIndirectClause -> + !CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification + !CHECK-NEXT: | OmpDirectiveName -> llvm::omp::Directive = declare target + !CHECK-NEXT: | OmpClauseList -> OmpClause -> Enter -> OmpEnterClause + !CHECK-NEXT: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'func2' + !CHECK-NEXT: | OmpClause -> Indirect -> OmpIndirectClause -> + !CHECK-NEXT: | Flags = None character(1) :: i i = 'b' return @@ -51,5 +55,5 @@ program main end program -!UNPARSE: !$OMP DECLARE TARGET ENTER(func1) INDIRECT(.true._4) -!UNPARSE: !$OMP DECLARE TARGET ENTER(func2) INDIRECT() +!UNPARSE: !$OMP DECLARE TARGET ENTER(func1) INDIRECT(.true._4) +!UNPARSE: !$OMP DECLARE TARGET ENTER(func2) INDIRECT() diff --git a/flang/test/Parser/OpenMP/declare-target-to-clause.f90 b/flang/test/Parser/OpenMP/declare-target-to-clause.f90 index bcb23f821e403..8198f44bcec18 100644 --- a/flang/test/Parser/OpenMP/declare-target-to-clause.f90 +++ b/flang/test/Parser/OpenMP/declare-target-to-clause.f90 @@ -9,11 +9,13 @@ module m !UNPARSE: MODULE m !UNPARSE: INTEGER x, y -!UNPARSE: !$OMP DECLARE TARGET TO(x,y) +!UNPARSE: !$OMP DECLARE TARGET TO(x,y) !UNPARSE: END MODULE -!PARSE-TREE: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpToClause -!PARSE-TREE: | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' -!PARSE-TREE: | OmpObject -> Designator -> DataRef -> Name = 'y' -!PARSE-TREE: | bool = 'true' - +!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target +!PARSE-TREE: | OmpClauseList -> OmpClause -> To -> OmpToClause +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | | OmpObject -> Designator -> DataRef -> Name = 'y' +!PARSE-TREE: | | bool = 'true' +!PARSE-TREE: | Flags = None diff --git a/flang/test/Parser/OpenMP/declare_target-device_type.f90 b/flang/test/Parser/OpenMP/declare_target-device_type.f90 index b6903614a628e..7df796288f4d4 100644 --- a/flang/test/Parser/OpenMP/declare_target-device_type.f90 +++ b/flang/test/Parser/OpenMP/declare_target-device_type.f90 @@ -3,35 +3,113 @@ subroutine openmp_declare_target integer, save :: x, y - !CHECK: !$omp declare target device_type(host) enter(x) +!CHECK: !$omp declare target device_type(host) enter(x) + +!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target +!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Host +!PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | Flags = None !$omp declare target device_type(host) enter(x) - !CHECK: !$omp declare target device_type(nohost) enter(x) + +!CHECK: !$omp declare target device_type(nohost) enter(x) + +!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target +!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Nohost +!PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | Flags = None !$omp declare target device_type(nohost) enter(x) - !CHECK: !$omp declare target device_type(any) enter(x) + +!CHECK: !$omp declare target device_type(any) enter(x) + +!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target +!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Any +!PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | Flags = None !$omp declare target device_type(any) enter(x) - !CHECK: !$omp declare target device_type(host) to(x) +!CHECK: !$omp declare target device_type(host) to(x) + +!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target +!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Host +!PARSE-TREE: | OmpClause -> To -> OmpToClause +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | | bool = 'true' +!PARSE-TREE: | Flags = None !$omp declare target device_type(host) to(x) - !CHECK: !$omp declare target device_type(nohost) to(x) + +!CHECK: !$omp declare target device_type(nohost) to(x) + +!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target +!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Nohost +!PARSE-TREE: | OmpClause -> To -> OmpToClause +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | | bool = 'true' +!PARSE-TREE: | Flags = None !$omp declare target device_type(nohost) to(x) - !CHECK: !$omp declare target device_type(any) to(x) + +!CHECK: !$omp declare target device_type(any) to(x) + +!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target +!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Any +!PARSE-TREE: | OmpClause -> To -> OmpToClause +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | | bool = 'true' +!PARSE-TREE: | Flags = None !$omp declare target device_type(any) to(x) - !CHECK: !$omp declare target device_type(host) enter(y) to(x) +!CHECK: !$omp declare target device_type(host) enter(y) to(x) + +!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target +!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Host +!PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'y' +!PARSE-TREE: | OmpClause -> To -> OmpToClause +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | | bool = 'true' +!PARSE-TREE: | Flags = None !$omp declare target device_type(host) enter(y) to(x) - !CHECK: !$omp declare target device_type(nohost) enter(y) to(x) + +!CHECK: !$omp declare target device_type(nohost) enter(y) to(x) + +!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target +!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Nohost +!PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'y' +!PARSE-TREE: | OmpClause -> To -> OmpToClause +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | | bool = 'true' +!PARSE-TREE: | Flags = None !$omp declare target device_type(nohost) enter(y) to(x) - !CHECK: !$omp declare target device_type(any) enter(y) to(x) + +!CHECK: !$omp declare target device_type(any) enter(y) to(x) + +!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target +!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Any +!PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'y' +!PARSE-TREE: | OmpClause -> To -> OmpToClause +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | | bool = 'true' +!PARSE-TREE: | Flags = None !$omp declare target device_type(any) enter(y) to(x) + integer :: a(1024), i - !CHECK: do +!CHECK: do do i = 1, 1024 a(i) = i - !CHECK: end do +!CHECK: end do end do -!PARSE-TREE: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -!PARSE-TREE: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Host -!PARSE-TREE: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Nohost -!PARSE-TREE: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Any END subroutine openmp_declare_target diff --git a/flang/test/Parser/OpenMP/enter-automap-modifier.f90 b/flang/test/Parser/OpenMP/enter-automap-modifier.f90 index 1f361ca5c2f06..bc5b5eb3e7ef3 100644 --- a/flang/test/Parser/OpenMP/enter-automap-modifier.f90 +++ b/flang/test/Parser/OpenMP/enter-automap-modifier.f90 @@ -8,9 +8,12 @@ program automap !UNPARSE: PROGRAM AUTOMAP !UNPARSE: INTEGER x -!UNPARSE: !$OMP DECLARE TARGET ENTER(AUTOMAP: x) +!UNPARSE: !$OMP DECLARE_TARGET ENTER(AUTOMAP: x) !UNPARSE: END PROGRAM -!PARSE-TREE: OmpClauseList -> OmpClause -> Enter -> OmpEnterClause -!PARSE-TREE-NEXT: | Modifier -> OmpAutomapModifier -> Value = Automap -!PARSE-TREE-NEXT: | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' +!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target +!PARSE-TREE: | OmpClauseList -> OmpClause -> Enter -> OmpEnterClause +!PARSE-TREE: | | Modifier -> OmpAutomapModifier -> Value = Automap +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | Flags = None diff --git a/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90 b/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90 index b72c5a2c1c086..f4cdd556bd4e5 100644 --- a/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90 +++ b/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90 @@ -124,12 +124,13 @@ subroutine f04 end !UNPARSE: SUBROUTINE f04 -!UNPARSE: !$OMP DECLARE TARGET +!UNPARSE: !$OMP DECLARE_TARGET !UNPARSE: END SUBROUTINE -!PARSE-TREE: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -!PARSE-TREE: | Verbatim -!PARSE-TREE: | OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> +!PARSE-TREE: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target +!PARSE-TREE: | OmpClauseList -> +!PARSE-TREE: | Flags = None subroutine f05 implicit none diff --git a/flang/test/Semantics/OpenMP/blank-common-block.f90 b/flang/test/Semantics/OpenMP/blank-common-block.f90 index 4a217fced0ff7..e410f0c56d1c0 100644 --- a/flang/test/Semantics/OpenMP/blank-common-block.f90 +++ b/flang/test/Semantics/OpenMP/blank-common-block.f90 @@ -4,6 +4,7 @@ module m integer :: a common // a !ERROR: Blank common blocks are not allowed as directive or clause arguments + !ERROR: An argument to the DECLARE TARGET directive should be an extended-list-item !$omp declare_target(//) !ERROR: Blank common blocks are not allowed as directive or clause arguments !$omp threadprivate(//) diff --git a/flang/test/Semantics/OpenMP/declare-target-function-name-with-symbols.f90 b/flang/test/Semantics/OpenMP/declare-target-function-name-with-symbols.f90 index 9a0acdb3dd100..3439e6fd13981 100644 --- a/flang/test/Semantics/OpenMP/declare-target-function-name-with-symbols.f90 +++ b/flang/test/Semantics/OpenMP/declare-target-function-name-with-symbols.f90 @@ -19,7 +19,7 @@ end module test !CHECK: !DEF: /test/ex/b ObjectEntity INTEGER(4) !CHECK: !DEF: /test/ex/c ObjectEntity INTEGER(4) !CHECK: function ex(a, b, c) -!CHECK: !$omp declare target (ex) +!CHECK: !$omp declare target(ex) !CHECK: !REF: /test/ex/a !CHECK: !REF: /test/ex/b !CHECK: !REF: /test/ex/c From 0f8c8248ca815c1de700e93d7df1d753c10d215e Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Wed, 24 Sep 2025 12:58:20 -0500 Subject: [PATCH 8/9] Remove unused AST classes --- flang/include/flang/Parser/dump-parse-tree.h | 3 --- flang/include/flang/Parser/parse-tree.h | 18 ------------------ flang/lib/Parser/unparse.cpp | 3 --- 3 files changed, 24 deletions(-) diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h index 7540d38baa584..fadca0a3876f4 100644 --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -538,9 +538,6 @@ class ParseTreeDumper { NODE_ENUM(OmpCloseModifier, Value) NODE(parser, OmpContainsClause) NODE(parser, OmpContextSelectorSpecification) - NODE(parser, OmpDeclareTargetSpecifier) - NODE(parser, OmpDeclareTargetWithClause) - NODE(parser, OmpDeclareTargetWithList) NODE(parser, OmpDeclareVariantDirective) NODE(parser, OmpDefaultClause) NODE_ENUM(OmpDefaultClause, DataSharingAttribute) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index e7593d9875097..486be8b60ff8c 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -4943,24 +4943,6 @@ struct OmpDeclareVariantDirective { CharBlock source; }; -// 2.10.6 declare-target -> DECLARE TARGET (extended-list) | -// DECLARE TARGET [declare-target-clause[ [,] -// declare-target-clause]...] -struct OmpDeclareTargetWithList { - WRAPPER_CLASS_BOILERPLATE(OmpDeclareTargetWithList, OmpObjectList); - CharBlock source; -}; - -struct OmpDeclareTargetWithClause { - WRAPPER_CLASS_BOILERPLATE(OmpDeclareTargetWithClause, OmpClauseList); - CharBlock source; -}; - -struct OmpDeclareTargetSpecifier { - UNION_CLASS_BOILERPLATE(OmpDeclareTargetSpecifier); - std::variant u; -}; - // Ref: [4.5:110-113], [5.0:180-185], [5.1:210-216], [5.2:206-207], // [6.0:346-348] // diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp index be166bcb743ba..a2b0b9ef3196c 100644 --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2492,9 +2492,6 @@ class UnparseVisitor { void Unparse(const OpenMPCriticalConstruct &x) { Unparse(static_cast(x)); } - void Unparse(const OmpDeclareTargetWithList &x) { - Put("("), Walk(x.v), Put(")"); - } void Unparse(const OmpInitializerProc &x) { Walk(std::get(x.t)); Put("("); From f5eb99ffbc20b6d787b62d620471e556cf71ab57 Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Wed, 24 Sep 2025 14:12:44 -0500 Subject: [PATCH 9/9] Fix example --- flang/examples/FeatureList/FeatureList.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/flang/examples/FeatureList/FeatureList.cpp b/flang/examples/FeatureList/FeatureList.cpp index 569d2b2307f36..daa012e3eb08b 100644 --- a/flang/examples/FeatureList/FeatureList.cpp +++ b/flang/examples/FeatureList/FeatureList.cpp @@ -451,9 +451,6 @@ struct NodeVisitor { READ_FEATURE(OmpBlockConstruct) READ_FEATURE(OmpClause) READ_FEATURE(OmpClauseList) - READ_FEATURE(OmpDeclareTargetSpecifier) - READ_FEATURE(OmpDeclareTargetWithClause) - READ_FEATURE(OmpDeclareTargetWithList) READ_FEATURE(OmpDefaultClause) READ_FEATURE(OmpDefaultClause::DataSharingAttribute) READ_FEATURE(OmpDefaultmapClause)