diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index 30b5d4f9513a7..ee88cce288cae 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -19,6 +19,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Frontend/OpenMP/OMP.h" // OpenMP Directives and Clauses @@ -104,8 +105,13 @@ struct OmpDirectiveNameParser { using Token = TokenStringMatch; std::optional Parse(ParseState &state) const { + if (state.BytesRemaining() == 0) { + return std::nullopt; + } auto begin{state.GetLocation()}; - for (const NameWithId &nid : directives()) { + char next{static_cast(std::tolower(*begin))}; + + for (const NameWithId &nid : directives_starting_with(next)) { if (attempt(Token(nid.first.data())).Parse(state)) { OmpDirectiveName n; n.v = nid.second; @@ -118,30 +124,46 @@ struct OmpDirectiveNameParser { private: using NameWithId = std::pair; + using ConstIterator = std::vector::const_iterator; - llvm::iterator_range directives() const; - void initTokens(NameWithId *) const; + llvm::iterator_range directives_starting_with( + char initial) const; + void initTokens(std::vector[]) const; }; -llvm::iterator_range -OmpDirectiveNameParser::directives() const { - static NameWithId table[llvm::omp::Directive_enumSize]; +llvm::iterator_range +OmpDirectiveNameParser::directives_starting_with(char initial) const { + static const std::vector empty{}; + if (initial < 'a' || initial > 'z') { + return llvm::make_range(std::cbegin(empty), std::cend(empty)); + } + + static std::vector table['z' - 'a' + 1]; [[maybe_unused]] static bool init = (initTokens(table), true); - return llvm::make_range(std::cbegin(table), std::cend(table)); + + int index = initial - 'a'; + return llvm::make_range(std::cbegin(table[index]), std::cend(table[index])); } -void OmpDirectiveNameParser::initTokens(NameWithId *table) const { +void OmpDirectiveNameParser::initTokens(std::vector table[]) const { for (size_t i{0}, e{llvm::omp::Directive_enumSize}; i != e; ++i) { + llvm::StringSet spellings; auto id{static_cast(i)}; - llvm::StringRef name{ - llvm::omp::getOpenMPDirectiveName(id, llvm::omp::FallbackVersion)}; - table[i] = std::make_pair(name.str(), id); + for (unsigned version : llvm::omp::getOpenMPVersions()) { + spellings.insert(llvm::omp::getOpenMPDirectiveName(id, version)); + } + for (auto &[name, _] : spellings) { + char initial{static_cast(std::tolower(name.front()))}; + table[initial - 'a'].emplace_back(name.str(), id); + } } // Sort the table with respect to the directive name length in a descending // order. This is to make sure that longer names are tried first, before // any potential prefix (e.g. "target update" before "target"). - std::sort(table, table + llvm::omp::Directive_enumSize, - [](auto &a, auto &b) { return a.first.size() > b.first.size(); }); + for (int initial{'a'}; initial != 'z' + 1; ++initial) { + llvm::stable_sort(table[initial - 'a'], + [](auto &a, auto &b) { return a.first.size() > b.first.size(); }); + } } // --- Modifier helpers ----------------------------------------------- @@ -1478,7 +1500,7 @@ TYPE_PARSER( // In this context "TARGET UPDATE" can be parsed as a TARGET directive // followed by an UPDATE clause. This is the only combination at the // moment, exclude it explicitly. - (!"TARGET UPDATE"_sptok) >= + (!("TARGET UPDATE"_sptok || "TARGET_UPDATE"_sptok)) >= construct(first( "MASKED" >> pure(llvm::omp::Directive::OMPD_masked), "MASTER" >> pure(llvm::omp::Directive::OMPD_master), @@ -1491,6 +1513,7 @@ TYPE_PARSER( "SCOPE" >> pure(llvm::omp::Directive::OMPD_scope), "SINGLE" >> pure(llvm::omp::Directive::OMPD_single), "TARGET DATA" >> pure(llvm::omp::Directive::OMPD_target_data), + "TARGET_DATA" >> pure(llvm::omp::Directive::OMPD_target_data), "TARGET PARALLEL" >> pure(llvm::omp::Directive::OMPD_target_parallel), "TARGET TEAMS" >> pure(llvm::omp::Directive::OMPD_target_teams), "TARGET" >> pure(llvm::omp::Directive::OMPD_target), @@ -1510,13 +1533,13 @@ TYPE_PARSER(construct( construct(Parser{}))) // OpenMP 5.2: 7.5.4 Declare Variant directive -TYPE_PARSER(sourced( - construct(verbatim("DECLARE VARIANT"_tok), - "(" >> maybe(name / ":"), name / ")", Parser{}))) +TYPE_PARSER(sourced(construct( + verbatim("DECLARE VARIANT"_tok) || verbatim("DECLARE_VARIANT"_tok), + "(" >> maybe(name / ":"), name / ")", Parser{}))) // 2.16 Declare Reduction Construct TYPE_PARSER(sourced(construct( - verbatim("DECLARE REDUCTION"_tok), + verbatim("DECLARE REDUCTION"_tok) || verbatim("DECLARE_REDUCTION"_tok), "(" >> indirect(Parser{}) / ")", maybe(Parser{})))) @@ -1535,7 +1558,8 @@ TYPE_PARSER( // 2.10.6 Declare Target Construct TYPE_PARSER(sourced(construct( - verbatim("DECLARE TARGET"_tok), Parser{}))) + verbatim("DECLARE TARGET"_tok) || verbatim("DECLARE_TARGET"_tok), + Parser{}))) static OmpMapperSpecifier ConstructOmpMapperSpecifier( std::optional &&mapperName, TypeSpec &&typeSpec, Name &&varName) { @@ -1562,9 +1586,9 @@ TYPE_PARSER(applyFunction(ConstructOmpMapperSpecifier, maybe(name / ":" / !":"_tok), typeSpec / "::", name)) // OpenMP 5.2: 5.8.8 Declare Mapper Construct -TYPE_PARSER(sourced( - construct(verbatim("DECLARE MAPPER"_tok), - parenthesized(Parser{}), Parser{}))) +TYPE_PARSER(sourced(construct( + verbatim("DECLARE MAPPER"_tok) || verbatim("DECLARE_MAPPER"_tok), + parenthesized(Parser{}), Parser{}))) TYPE_PARSER(construct(Parser{}) || construct(Parser{})) @@ -1609,9 +1633,9 @@ TYPE_PARSER(sourced(construct( TYPE_PARSER(construct(startOmpLine >> "END ALLOCATORS"_tok)) // 2.8.2 Declare Simd construct -TYPE_PARSER( - sourced(construct(verbatim("DECLARE SIMD"_tok), - maybe(parenthesized(name)), Parser{}))) +TYPE_PARSER(sourced(construct( + verbatim("DECLARE SIMD"_tok) || verbatim("DECLARE_SIMD"_tok), + maybe(parenthesized(name)), Parser{}))) // 2.4 Requires construct TYPE_PARSER(sourced(construct( diff --git a/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90 b/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90 new file mode 100644 index 0000000000000..6a1d565451220 --- /dev/null +++ b/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90 @@ -0,0 +1,252 @@ +!RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=60 %s -o - | FileCheck --check-prefix=UNPARSE %s +!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=60 %s -o - | FileCheck --check-prefix=PARSE-TREE %s + +! The directives to check: +! cancellation_point +! declare_mapper +! declare_reduction +! declare_simd +! declare_target +! declare_variant +! target_data +! target_enter_data +! target_exit_data +! target_update + +subroutine f00 + implicit none + integer :: i + + !$omp parallel + do i = 1, 10 + !$omp cancellation_point parallel + enddo + !$omp end parallel +end + +!UNPARSE: SUBROUTINE f00 +!UNPARSE: IMPLICIT NONE +!UNPARSE: INTEGER i +!UNPARSE: !$OMP PARALLEL +!UNPARSE: DO i=1_4,10_4 +!UNPARSE: !$OMP CANCELLATION_POINT PARALLEL +!UNPARSE: END DO +!UNPARSE: !$OMP END PARALLEL +!UNPARSE: END SUBROUTINE + +!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPCancellationPointConstruct -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = cancellation point +!PARSE-TREE: | OmpClauseList -> OmpClause -> CancellationConstructType -> OmpCancellationConstructTypeClause +!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = parallel +!PARSE-TREE: | Flags = None + +subroutine f01 + type :: t + integer :: x + end type + !$omp declare_mapper(t :: v) map(v%x) +end + +!UNPARSE: SUBROUTINE f01 +!UNPARSE: TYPE :: t +!UNPARSE: INTEGER :: x +!UNPARSE: END TYPE +!UNPARSE: !$OMP DECLARE MAPPER (t::v) MAP(v%x) +!UNPARSE: END SUBROUTINE + +!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareMapperConstruct +!PARSE-TREE: | Verbatim +!PARSE-TREE: | OmpMapperSpecifier +!PARSE-TREE: | | string = 't.omp.default.mapper' +!PARSE-TREE: | | TypeSpec -> DerivedTypeSpec +!PARSE-TREE: | | | Name = 't' +!PARSE-TREE: | | Name = 'v' +!PARSE-TREE: | OmpClauseList -> OmpClause -> Map -> OmpMapClause +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> StructureComponent +!PARSE-TREE: | | | DataRef -> Name = 'v' +!PARSE-TREE: | | | Name = 'x' +!PARSE-TREE: | | bool = 'true' + +subroutine f02 + type :: t + integer :: x + end type + !$omp declare_reduction(+ : t : omp_out%x = omp_out%x + omp_in%x) +end + +!UNPARSE: SUBROUTINE f02 +!UNPARSE: TYPE :: t +!UNPARSE: INTEGER :: x +!UNPARSE: END TYPE +!UNPARSE: !$OMP DECLARE REDUCTION (+:t: omp_out%x=omp_out%x+omp_in%x +!UNPARSE: ) +!UNPARSE: END SUBROUTINE + +!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareReductionConstruct +!PARSE-TREE: | Verbatim +!PARSE-TREE: | OmpReductionSpecifier +!PARSE-TREE: | | OmpReductionIdentifier -> DefinedOperator -> IntrinsicOperator = Add +!PARSE-TREE: | | OmpTypeNameList -> OmpTypeSpecifier -> TypeSpec -> DerivedTypeSpec +!PARSE-TREE: | | | Name = 't' +!PARSE-TREE: | | OmpReductionCombiner -> AssignmentStmt = 'omp_out%x=omp_out%x+omp_in%x' +!PARSE-TREE: | | | Variable = 'omp_out%x' +!PARSE-TREE: | | | | Designator -> DataRef -> StructureComponent +!PARSE-TREE: | | | | | DataRef -> Name = 'omp_out' +!PARSE-TREE: | | | | | Name = 'x' +!PARSE-TREE: | | | Expr = 'omp_out%x+omp_in%x' +!PARSE-TREE: | | | | Add +!PARSE-TREE: | | | | | Expr = 'omp_out%x' +!PARSE-TREE: | | | | | | Designator -> DataRef -> StructureComponent +!PARSE-TREE: | | | | | | | DataRef -> Name = 'omp_out' +!PARSE-TREE: | | | | | | | Name = 'x' +!PARSE-TREE: | | | | | Expr = 'omp_in%x' +!PARSE-TREE: | | | | | | Designator -> DataRef -> StructureComponent +!PARSE-TREE: | | | | | | | DataRef -> Name = 'omp_in' +!PARSE-TREE: | | | | | | | Name = 'x' +!PARSE-TREE: | OmpClauseList -> + +subroutine f03 + !$omp declare_simd +end + +!UNPARSE: SUBROUTINE f03 +!UNPARSE: !$OMP DECLARE SIMD +!UNPARSE: END SUBROUTINE + +!PARSE-TREE: OpenMPDeclarativeConstruct -> OpenMPDeclareSimdConstruct +!PARSE-TREE: | Verbatim +!PARSE-TREE: | OmpClauseList -> + +subroutine f04 + !$omp declare_target +end + +!UNPARSE: SUBROUTINE f04 +!UNPARSE: !$OMP DECLARE TARGET +!UNPARSE: END SUBROUTINE + +!PARSE-TREE: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct +!PARSE-TREE: | Verbatim +!PARSE-TREE: | OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> + +subroutine f05 + implicit none + interface + subroutine g05 + end + end interface + !$omp declare_variant(g05) match(user={condition(.true.)}) +end + +!UNPARSE: SUBROUTINE f05 +!UNPARSE: IMPLICIT NONE +!UNPARSE: INTERFACE +!UNPARSE: SUBROUTINE g05 +!UNPARSE: END SUBROUTINE +!UNPARSE: END INTERFACE +!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: | OmpClauseList -> OmpClause -> Match -> OmpMatchClause -> OmpContextSelectorSpecification -> OmpTraitSetSelector +!PARSE-TREE: | | OmpTraitSetSelectorName -> Value = User +!PARSE-TREE: | | OmpTraitSelector +!PARSE-TREE: | | | OmpTraitSelectorName -> Value = Condition +!PARSE-TREE: | | | Properties +!PARSE-TREE: | | | | OmpTraitProperty -> Scalar -> Expr = '.true._4' +!PARSE-TREE: | | | | | LiteralConstant -> LogicalLiteralConstant +!PARSE-TREE: | | | | | | bool = 'true' + +subroutine f06 + implicit none + integer :: i + !$omp target_data map(tofrom: i) + i = 0 + !$omp end target data +end + +!UNPARSE: SUBROUTINE f06 +!UNPARSE: IMPLICIT NONE +!UNPARSE: INTEGER i +!UNPARSE: !$OMP TARGET DATA MAP(TOFROM: i) +!UNPARSE: i=0_4 +!UNPARSE: !$OMP END TARGET DATA +!UNPARSE: END SUBROUTINE + +!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPBlockConstruct +!PARSE-TREE: | OmpBeginBlockDirective +!PARSE-TREE: | | OmpBlockDirective -> llvm::omp::Directive = target data +!PARSE-TREE: | | OmpClauseList -> OmpClause -> Map -> OmpMapClause +!PARSE-TREE: | | | Modifier -> OmpMapType -> Value = Tofrom +!PARSE-TREE: | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'i' +!PARSE-TREE: | | | bool = 'true' +!PARSE-TREE: | Block +!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AssignmentStmt = 'i=0_4' +!PARSE-TREE: | | | Variable = 'i' +!PARSE-TREE: | | | | Designator -> DataRef -> Name = 'i' +!PARSE-TREE: | | | Expr = '0_4' +!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '0' +!PARSE-TREE: | OmpEndBlockDirective +!PARSE-TREE: | | OmpBlockDirective -> llvm::omp::Directive = target data +!PARSE-TREE: | | OmpClauseList -> + +subroutine f07 + implicit none + integer :: i + !$omp target_enter_data map(to: i) +end + +!UNPARSE: SUBROUTINE f07 +!UNPARSE: IMPLICIT NONE +!UNPARSE: INTEGER i +!UNPARSE: !$OMP TARGET_ENTER_DATA MAP(TO: i) +!UNPARSE: END SUBROUTINE + +!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPSimpleStandaloneConstruct -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = target enter data +!PARSE-TREE: | OmpClauseList -> OmpClause -> Map -> OmpMapClause +!PARSE-TREE: | | Modifier -> OmpMapType -> Value = To +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'i' +!PARSE-TREE: | | bool = 'true' +!PARSE-TREE: | Flags = None + +subroutine f08 + implicit none + integer :: i + !$omp target_exit_data map(from: i) +end + +!UNPARSE: SUBROUTINE f08 +!UNPARSE: IMPLICIT NONE +!UNPARSE: INTEGER i +!UNPARSE: !$OMP TARGET_EXIT_DATA MAP(FROM: i) +!UNPARSE: END SUBROUTINE + +!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPSimpleStandaloneConstruct -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = target exit data +!PARSE-TREE: | OmpClauseList -> OmpClause -> Map -> OmpMapClause +!PARSE-TREE: | | Modifier -> OmpMapType -> Value = From +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'i' +!PARSE-TREE: | | bool = 'true' +!PARSE-TREE: | Flags = None + +subroutine f09 + implicit none + integer :: i + !$omp target_update to(i) +end + +!UNPARSE: SUBROUTINE f09 +!UNPARSE: IMPLICIT NONE +!UNPARSE: INTEGER i +!UNPARSE: !$OMP TARGET_UPDATE TO(i) +!UNPARSE: END SUBROUTINE + +!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPSimpleStandaloneConstruct -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = target update +!PARSE-TREE: | OmpClauseList -> OmpClause -> To -> OmpToClause +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'i' +!PARSE-TREE: | | bool = 'true' +!PARSE-TREE: | Flags = None