https://github.com/NouTimbaler updated https://github.com/llvm/llvm-project/pull/204225
>From 363734d427fa5b7f1f2eb850f6300d850a620c20 Mon Sep 17 00:00:00 2001 From: Ferran Toda <[email protected]> Date: Tue, 16 Jun 2026 17:42:05 +0000 Subject: [PATCH 1/8] apply parsing and basic checks --- flang/include/flang/Parser/dump-parse-tree.h | 8 + flang/include/flang/Parser/parse-tree.h | 29 ++++ flang/lib/Parser/openmp-parsers.cpp | 17 +++ flang/lib/Parser/unparse.cpp | 10 ++ flang/lib/Semantics/check-omp-loop.cpp | 45 ++++++ flang/lib/Semantics/check-omp-structure.h | 6 + flang/lib/Semantics/check-omp-variant.cpp | 4 +- flang/test/Parser/OpenMP/apply01.f90 | 137 ++++++++++++++++++ flang/test/Parser/OpenMP/apply02.f90 | 114 +++++++++++++++ flang/test/Semantics/OpenMP/apply01.f90 | 34 +++++ flang/test/Semantics/OpenMP/apply02.f90 | 34 +++++ .../llvm/Frontend/Directive/DirectiveBase.td | 24 +++ llvm/include/llvm/Frontend/OpenMP/OMP.td | 55 +++++++ llvm/include/llvm/TableGen/DirectiveEmitter.h | 12 ++ .../utils/TableGen/Basic/DirectiveEmitter.cpp | 60 +++++++- 15 files changed, 586 insertions(+), 3 deletions(-) create mode 100644 flang/test/Parser/OpenMP/apply01.f90 create mode 100644 flang/test/Parser/OpenMP/apply02.f90 create mode 100644 flang/test/Semantics/OpenMP/apply01.f90 create mode 100644 flang/test/Semantics/OpenMP/apply02.f90 diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h index ceba23d7d4706..2b55be38abf34 100644 --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -556,6 +556,14 @@ class ParseTreeDumper { NODE_ENUM(OmpAlwaysModifier, Value) NODE(parser, OmpAppendArgsClause) NODE(OmpAppendArgsClause, OmpAppendOp) + NODE(parser, OmpLoopModifier) + + static std::string GetNodeName(const llvm::omp::LoopModifier &x) { + return llvm::Twine( + "llvm::omp::LoopModifier = ", llvm::omp::getOpenMPLoopModifierName(x)) + .str(); + } + NODE(parser, OmpApplyClause) NODE(parser, OmpArgument) NODE(parser, OmpArgumentList) NODE(parser, OmpAssumeDirective) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index 84c22c21cf30b..fe2558fa464b2 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -4359,6 +4359,24 @@ struct OmpxHoldModifier { WRAPPER_CLASS_BOILERPLATE(OmpxHoldModifier, Value); }; +// Ref: [6.0:372-373] +// +// loop-modifier -> +// FLATTENED | +// FUSED | GRID | IDENTITY | +// INTERCHANGED | +// INTRATILE | OFFSETS | +// REVERSED | SPLIT | +// UNROLLED +// [( ScalarIntConstantExpr-list )] +struct OmpLoopModifier { + TUPLE_CLASS_BOILERPLATE(OmpLoopModifier); + std::tuple<llvm::omp::LoopModifier, + std::optional<std::list<ScalarIntConstantExpr>>> + t; + CharBlock source; +}; + // context-selector using OmpContextSelector = traits::OmpContextSelectorSpecification; } // namespace modifier @@ -4486,6 +4504,17 @@ struct OmpContainsClause { WRAPPER_CLASS_BOILERPLATE(OmpContainsClause, OmpDirectiveList); }; +// Ref: [6.0:372-373] +// +// apply-clause -> +// APPLY( [loop-modifier :] directive-specification-list ) +struct OmpApplyClause { + TUPLE_CLASS_BOILERPLATE(OmpApplyClause); + std::tuple<std::optional<OmpLoopModifier>, + std::list<OmpDirectiveSpecification>> + t; +}; + // Ref: [4.5:46-50], [5.0:74-78], [5.1:92-96], [5.2:109] // // When used as a data-sharing clause: diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index 2c5f9c19a944e..8ad1f10614587 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -1133,6 +1133,18 @@ TYPE_PARSER(construct<OmpAdjustArgsClause::OmpAdjustOp>( "NEED_DEVICE_PTR" >> pure(OmpAdjustArgsClause::OmpAdjustOp::Value::Need_Device_Ptr))) +TYPE_PARSER(sourced(construct<OmpLoopModifier>( + "FUSED" >> pure(llvm::omp::LoopModifier::OMPLM_fused) || + "GRID" >> pure(llvm::omp::LoopModifier::OMPLM_grid) || + "IDENTITY" >> pure(llvm::omp::LoopModifier::OMPLM_identity) || + "INTERCHANGED" >> pure(llvm::omp::LoopModifier::OMPLM_interchanged) || + "INTRATILE" >> pure(llvm::omp::LoopModifier::OMPLM_intratile) || + "OFFSETS" >> pure(llvm::omp::LoopModifier::OMPLM_offsets) || + "REVERSED" >> pure(llvm::omp::LoopModifier::OMPLM_reversed) || + "SPLIT" >> pure(llvm::omp::LoopModifier::OMPLM_split) || + "UNROLLED" >> pure(llvm::omp::LoopModifier::OMPLM_unrolled), + maybe(parenthesized(nonemptyList(scalarIntConstantExpr)))))) + // --- Parsers for clauses -------------------------------------------- // Declaration of the ODS parser. This type must be complete for some of @@ -1175,6 +1187,9 @@ TYPE_PARSER(construct<OmpAffinityClause>( maybe(nonemptyList(Parser<OmpAffinityClause::Modifier>{}) / ":"), Parser<OmpObjectList>{})) +TYPE_PARSER(construct<OmpApplyClause>(maybe(Parser<OmpLoopModifier>{} / ":"), + nonemptyList(OmpDirectiveSpecificationParser(/*allowCommas=*/false)))) + // 2.4 Requires construct [OpenMP 5.0] // atomic-default-mem-order-clause -> // acq_rel @@ -1483,6 +1498,8 @@ TYPE_PARSER( // parenthesized(Parser<OmpAllocateClause>{}))) || "APPEND_ARGS" >> construct<OmpClause>(construct<OmpClause::AppendArgs>( parenthesized(Parser<OmpAppendArgsClause>{}))) || + "APPLY" >> construct<OmpClause>(construct<OmpClause::Apply>( + parenthesized(Parser<OmpApplyClause>{}))) || "ALLOCATOR" >> construct<OmpClause>(construct<OmpClause::Allocator>( parenthesized(scalarIntExpr))) || "AT" >> construct<OmpClause>(construct<OmpClause::At>( diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp index 7d0038767a9c4..889e4ee3de958 100644 --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2213,6 +2213,16 @@ class UnparseVisitor { } void Unparse(const OmpAppendArgsClause &x) { Walk(x.v, ","); } void Unparse(const OmpArgumentList &x) { Walk(x.v, ", "); } + void Unparse(const OmpLoopModifier &x) { + Word(llvm::omp::getOpenMPLoopModifierName( + std::get<llvm::omp::LoopModifier>(x.t))); + Walk("(", std::get<std::optional<std::list<ScalarIntConstantExpr>>>(x.t), + ")"); + } + void Unparse(const OmpApplyClause &x) { + Walk(std::get<std::optional<OmpLoopModifier>>(x.t), ": "); + Walk(std::get<std::list<OmpDirectiveSpecification>>(x.t)); + } void Unparse(const OmpAttachModifier &x) { Word("ATTACH("); Walk(x.v); diff --git a/flang/lib/Semantics/check-omp-loop.cpp b/flang/lib/Semantics/check-omp-loop.cpp index 38b77157e33b8..b969014d34e17 100644 --- a/flang/lib/Semantics/check-omp-loop.cpp +++ b/flang/lib/Semantics/check-omp-loop.cpp @@ -869,6 +869,51 @@ void OmpStructureChecker::Enter(const parser::DoConstruct &x) { constructStack_.push_back(&x); } +void OmpStructureChecker::Enter(const parser::OmpLoopModifier &x) { + DirectiveContext &dirCtx = GetContext(); + llvm::omp::Directive dir{dirCtx.directive}; + unsigned version{context_.langOptions().OpenMPVersion}; + auto &m{std::get<llvm::omp::LoopModifier>(x.t)}; + if (!llvm::omp::isAllowedLoopModifier(dir, m)) { + llvm::StringRef name = llvm::omp::getOpenMPLoopModifierName(m); + context_.Say(x.source, + "%s modifier is not allowed on %s directive"_err_en_US, + parser::ToUpperCaseLetters(name), + parser::omp::GetUpperName(dir, version)); + } + if (const auto &il{ + std::get<std::optional<std::list<parser::ScalarIntConstantExpr>>>( + x.t)}) { + int64_t last = -1; + for (auto &i : il.value()) { + if (const auto v{GetIntValue(i)}) { + if (*v <= 0) { + context_.Say(x.source, + "The loop modifier indexes of the %s clause must be constant positive integer expressions"_err_en_US, + parser::ToUpperCaseLetters( + getClauseName(llvm::omp::Clause::OMPC_apply).str())); + } else if (*v <= last) { + context_.Say(x.source, + "The loop modifier indexes of the %s clause must be in ascending order"_err_en_US, + parser::ToUpperCaseLetters( + getClauseName(llvm::omp::Clause::OMPC_apply).str())); + } else { + last = *v; + } + } + } + } +} + +void OmpStructureChecker::Enter(const parser::OmpApplyClause &x) { + EnterDirectiveNest(ApplyNest); + CheckAllowedClause(llvm::omp::Clause::OMPC_apply); +} + +void OmpStructureChecker::Leave(const parser::OmpApplyClause &x) { + ExitDirectiveNest(ApplyNest); +} + void OmpStructureChecker::Leave(const parser::DoConstruct &x) { assert(!constructStack_.empty() && "Expecting non-empty construct stack"); #ifndef NDEBUG diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h index 011b29d370ba3..6cd39db19bdd8 100644 --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -144,6 +144,11 @@ class OmpStructureChecker : public OmpStructureCheckerBase { void Enter(const parser::OmpContextSelector &); void Leave(const parser::OmpContextSelector &); + void Enter(const parser::OmpLoopModifier &); + + void Enter(const parser::OmpApplyClause &); + void Leave(const parser::OmpApplyClause &); + template <typename A> void Enter(const parser::Statement<A> &); void Leave(const parser::GotoStmt &); void Leave(const parser::ComputedGotoStmt &); @@ -437,6 +442,7 @@ class OmpStructureChecker : public OmpStructureCheckerBase { bool deviceConstructFound_{false}; enum directiveNestType : int { + ApplyNest, SIMDNest, TargetBlockOnlyTeams, TargetNest, diff --git a/flang/lib/Semantics/check-omp-variant.cpp b/flang/lib/Semantics/check-omp-variant.cpp index a60f46ba760d9..1eff064dcbc80 100644 --- a/flang/lib/Semantics/check-omp-variant.cpp +++ b/flang/lib/Semantics/check-omp-variant.cpp @@ -549,7 +549,7 @@ void OmpStructureChecker::Enter(const parser::OmpDirectiveSpecification &x) { // METADIRECTIVE. // In other cases it's a part of other constructs that handle directive // context stack by themselves. - if (!GetDirectiveNest(MetadirectiveNest)) { + if (!GetDirectiveNest(MetadirectiveNest) && !GetDirectiveNest(ApplyNest)) { return; } @@ -578,7 +578,7 @@ void OmpStructureChecker::Enter(const parser::OmpDirectiveSpecification &x) { } void OmpStructureChecker::Leave(const parser::OmpDirectiveSpecification &x) { - if (GetDirectiveNest(MetadirectiveNest)) { + if (GetDirectiveNest(MetadirectiveNest) || GetDirectiveNest(ApplyNest)) { dirContext_.pop_back(); } } diff --git a/flang/test/Parser/OpenMP/apply01.f90 b/flang/test/Parser/OpenMP/apply01.f90 new file mode 100644 index 0000000000000..c1c5d4be2d0eb --- /dev/null +++ b/flang/test/Parser/OpenMP/apply01.f90 @@ -0,0 +1,137 @@ +!RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=60 %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s +!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=60 %s | FileCheck --check-prefix="PARSE-TREE" %s + +subroutine apply_1(x) + implicit none + integer :: x, i, j + + !$omp interchange apply(nothing, reverse) + do i = 1,10 + do j = 1,10 + x = x + 1 + end do + end do +end + +!UNPARSE: !$OMP INTERCHANGE APPLY(NOTHING, REVERSE) +!UNPARSE: DO i=1_4,10_4 +!UNPARSE: DO j=1_4,10_4 +!UNPARSE: x=x+1_4 +!UNPARSE: END DO +!UNPARSE: END DO + +!PARSE-TREE: OmpBeginDirective +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = interchange +!PARSE-TREE: | OmpClauseList -> OmpClause -> Apply -> OmpApplyClause +!PARSE-TREE: | | OmpDirectiveSpecification +!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = nothing +!PARSE-TREE: | | | OmpClauseList -> +!PARSE-TREE: | | | Flags = {} +!PARSE-TREE: | | OmpDirectiveSpecification +!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = reverse +!PARSE-TREE: | | | OmpClauseList -> +!PARSE-TREE: | | | Flags = {} + +subroutine apply_modifier(x) + implicit none + integer :: x, i + + !$omp tile sizes(2) apply(grid: reverse) + do i = 1, 10 + x = x + 1 + end do +end + +!UNPARSE: !$OMP TILE SIZES(2_4) APPLY(GRID: REVERSE) +!UNPARSE: DO i=1_4,10_4 +!UNPARSE: x=x+1_4 +!UNPARSE: END DO + +!PARSE-TREE: OmpBeginDirective +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = tile +!PARSE-TREE: | OmpClauseList -> OmpClause -> Sizes -> Scalar -> Integer -> Expr = '2_4' +!PARSE-TREE: | | LiteralConstant -> IntLiteralConstant = '2' +!PARSE-TREE: | OmpClause -> Apply -> OmpApplyClause +!PARSE-TREE: | | OmpLoopModifier +!PARSE-TREE: | | | llvm::omp::LoopModifier = grid +!PARSE-TREE: | | OmpDirectiveSpecification +!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = reverse +!PARSE-TREE: | | | OmpClauseList -> +!PARSE-TREE: | | | Flags = {} + +subroutine apply_2_clauses(x) + implicit none + integer :: x, i + + !$omp tile sizes(2) apply(intratile: unroll) apply(grid: reverse) + do i = 1, 10 + x = x + 1 + end do +end + +!UNPARSE: !$OMP TILE SIZES(2_4) APPLY(INTRATILE: UNROLL) APPLY(GRID: REVERSE) +!UNPARSE: DO i=1_4,10_4 +!UNPARSE: x=x+1_4 +!UNPARSE: END DO + +!PARSE-TREE: OmpBeginDirective +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = tile +!PARSE-TREE: | OmpClauseList -> OmpClause -> Sizes -> Scalar -> Integer -> Expr = '2_4' +!PARSE-TREE: | | LiteralConstant -> IntLiteralConstant = '2' +!PARSE-TREE: | OmpClause -> Apply -> OmpApplyClause +!PARSE-TREE: | | OmpLoopModifier +!PARSE-TREE: | | | llvm::omp::LoopModifier = intratile +!PARSE-TREE: | | OmpDirectiveSpecification +!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = unroll +!PARSE-TREE: | | | OmpClauseList -> +!PARSE-TREE: | | | Flags = {} +!PARSE-TREE: | OmpClause -> Apply -> OmpApplyClause +!PARSE-TREE: | | OmpLoopModifier +!PARSE-TREE: | | | llvm::omp::LoopModifier = grid +!PARSE-TREE: | | OmpDirectiveSpecification +!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = reverse +!PARSE-TREE: | | | OmpClauseList -> +!PARSE-TREE: | | | Flags = {} + + +subroutine apply_inside_apply(x) + implicit none + integer :: x, i, j + + !$omp fuse apply(fused: tile sizes(2) apply(grid: reverse)) + do i = 1, 10 + x = x + 1 + end do + do j = 1, 10 + x = x - 1 + end do + !$omp end fuse +end + +!UNPARSE: !$OMP FUSE APPLY(FUSED: TILE SIZES(2_4) APPLY(GRID: REVERSE)) +!UNPARSE: DO i=1_4,10_4 +!UNPARSE: x=x+1_4 +!UNPARSE: END DO +!UNPARSE: DO j=1_4,10_4 +!UNPARSE: x=x-1_4 +!UNPARSE: END DO +!UNPARSE: !$OMP END FUSE + +!PARSE-TREE: OmpBeginDirective +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = fuse +!PARSE-TREE: | OmpClauseList -> OmpClause -> Apply -> OmpApplyClause +!PARSE-TREE: | | OmpLoopModifier +!PARSE-TREE: | | | llvm::omp::LoopModifier = fused +!PARSE-TREE: | | OmpDirectiveSpecification +!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = tile +!PARSE-TREE: | | | OmpClauseList -> OmpClause -> Sizes -> Scalar -> Integer -> Expr = '2_4' +!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '2' +!PARSE-TREE: | | | OmpClause -> Apply -> OmpApplyClause +!PARSE-TREE: | | | | OmpLoopModifier +!PARSE-TREE: | | | | | llvm::omp::LoopModifier = grid +!PARSE-TREE: | | | | OmpDirectiveSpecification +!PARSE-TREE: | | | | | OmpDirectiveName -> llvm::omp::Directive = reverse +!PARSE-TREE: | | | | | OmpClauseList -> +!PARSE-TREE: | | | | | Flags = {} +!PARSE-TREE: | | | Flags = {} + diff --git a/flang/test/Parser/OpenMP/apply02.f90 b/flang/test/Parser/OpenMP/apply02.f90 new file mode 100644 index 0000000000000..803f0ac73d25a --- /dev/null +++ b/flang/test/Parser/OpenMP/apply02.f90 @@ -0,0 +1,114 @@ +!RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=60 %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s +!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=60 %s | FileCheck --check-prefix="PARSE-TREE" %s + +subroutine apply_all(x) + implicit none + integer :: x, i, j + + !$omp interchange apply(interchanged(1,2): nothing, reverse) + do i = 1,10 + do j = 1,10 + x = x + 1 + end do + end do +end + +!UNPARSE: !$OMP INTERCHANGE APPLY(INTERCHANGED(1_4, 2_4): NOTHING, REVERSE) +!UNPARSE: DO i=1_4,10_4 +!UNPARSE: DO j=1_4,10_4 +!UNPARSE: x=x+1_4 +!UNPARSE: END DO +!UNPARSE: END DO + +!PARSE-TREE: OmpBeginDirective +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = interchange +!PARSE-TREE: | OmpClauseList -> OmpClause -> Apply -> OmpApplyClause +!PARSE-TREE: | | OmpLoopModifier +!PARSE-TREE: | | | llvm::omp::LoopModifier = interchanged +!PARSE-TREE: | | | Scalar -> Integer -> Constant -> Expr = '1_4' +!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '1' +!PARSE-TREE: | | | Scalar -> Integer -> Constant -> Expr = '2_4' +!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '2' +!PARSE-TREE: | | OmpDirectiveSpecification +!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = nothing +!PARSE-TREE: | | | OmpClauseList -> +!PARSE-TREE: | | | Flags = {} +!PARSE-TREE: | | OmpDirectiveSpecification +!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = reverse +!PARSE-TREE: | | | OmpClauseList -> +!PARSE-TREE: | | | Flags = {} + +subroutine apply_one(x) + implicit none + integer :: x, i, j + + !$omp interchange apply(interchanged(2): reverse) + do i = 1,10 + do j = 1,10 + x = x + 1 + end do + end do +end + +!UNPARSE: !$OMP INTERCHANGE APPLY(INTERCHANGED(2_4): REVERSE) +!UNPARSE: DO i=1_4,10_4 +!UNPARSE: DO j=1_4,10_4 +!UNPARSE: x=x+1_4 +!UNPARSE: END DO +!UNPARSE: END DO + +!PARSE-TREE: OmpBeginDirective +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = interchange +!PARSE-TREE: | OmpClauseList -> OmpClause -> Apply -> OmpApplyClause +!PARSE-TREE: | | OmpLoopModifier +!PARSE-TREE: | | | llvm::omp::LoopModifier = interchanged +!PARSE-TREE: | | | Scalar -> Integer -> Constant -> Expr = '2_4' +!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '2' +!PARSE-TREE: | | OmpDirectiveSpecification +!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = reverse +!PARSE-TREE: | | | OmpClauseList -> +!PARSE-TREE: | | | Flags = {} + +subroutine apply_inside_apply(x) + implicit none + integer :: x, i, j + + !$omp tile sizes(2,2) apply(grid(1): interchange apply(interchanged(2): reverse)) + do i = 1,10 + do j = 1,10 + x = x + 1 + end do + end do +end + +!UNPARSE: !$OMP TILE SIZES(2_4,2_4) APPLY(GRID(1_4): INTERCHANGE APPLY(INTERCHANGED(2_4): REVERSE)) +!UNPARSE: DO i=1_4,10_4 +!UNPARSE: DO j=1_4,10_4 +!UNPARSE: x=x+1_4 +!UNPARSE: END DO +!UNPARSE: END DO + +!PARSE-TREE: OmpBeginDirective +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = tile +!PARSE-TREE: | OmpClauseList -> OmpClause -> Sizes -> Scalar -> Integer -> Expr = '2_4' +!PARSE-TREE: | | LiteralConstant -> IntLiteralConstant = '2' +!PARSE-TREE: | Scalar -> Integer -> Expr = '2_4' +!PARSE-TREE: | | LiteralConstant -> IntLiteralConstant = '2' +!PARSE-TREE: | OmpClause -> Apply -> OmpApplyClause +!PARSE-TREE: | | OmpLoopModifier +!PARSE-TREE: | | | llvm::omp::LoopModifier = grid +!PARSE-TREE: | | | Scalar -> Integer -> Constant -> Expr = '1_4' +!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '1' +!PARSE-TREE: | | OmpDirectiveSpecification +!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = interchange +!PARSE-TREE: | | | OmpClauseList -> OmpClause -> Apply -> OmpApplyClause +!PARSE-TREE: | | | | OmpLoopModifier +!PARSE-TREE: | | | | | llvm::omp::LoopModifier = interchanged +!PARSE-TREE: | | | | | Scalar -> Integer -> Constant -> Expr = '2_4' +!PARSE-TREE: | | | | | | LiteralConstant -> IntLiteralConstant = '2' +!PARSE-TREE: | | | | OmpDirectiveSpecification +!PARSE-TREE: | | | | | OmpDirectiveName -> llvm::omp::Directive = reverse +!PARSE-TREE: | | | | | OmpClauseList -> +!PARSE-TREE: | | | | | Flags = {} +!PARSE-TREE: | | | Flags = {} + diff --git a/flang/test/Semantics/OpenMP/apply01.f90 b/flang/test/Semantics/OpenMP/apply01.f90 new file mode 100644 index 0000000000000..f146c4e7730d8 --- /dev/null +++ b/flang/test/Semantics/OpenMP/apply01.f90 @@ -0,0 +1,34 @@ +! Testing the Semantics of tile +!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=60 + + +subroutine wrong_modifier(x) + implicit none + integer i, j, x + + !ERROR: INTERCHANGED modifier is not allowed on TILE directive + !$omp tile sizes(2,2) apply(interchanged: nothing, reverse) + do i = 1, 10 + do j = 1, 10 + x = x + 1 + end do + end do + + !ERROR: INTERCHANGED modifier is not allowed on TILE directive + !ERROR: FUSED modifier is not allowed on TILE directive + !$omp tile sizes(2,2) apply(interchanged: nothing, reverse) apply(fused: reverse) + do i = 1, 10 + do j = 1, 10 + x = x + 1 + end do + end do + + !ERROR: INTRATILE modifier is not allowed on UNROLL directive + !$omp tile sizes(2,2) apply(grid: nothing, unroll partial(2) apply(intratile: reverse)) + do i = 1, 10 + do j = 1, 10 + x = x + 1 + end do + end do +end subroutine + diff --git a/flang/test/Semantics/OpenMP/apply02.f90 b/flang/test/Semantics/OpenMP/apply02.f90 new file mode 100644 index 0000000000000..81fc436f96fe6 --- /dev/null +++ b/flang/test/Semantics/OpenMP/apply02.f90 @@ -0,0 +1,34 @@ +! Testing the Semantics of tile +!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=60 + + +subroutine wrong_modifier(x) + implicit none + integer i, j, x + + !ERROR: Must be a constant value + !$omp tile sizes(2,2) apply(grid(x): unroll) + do i = 1, 10 + do j = 1, 10 + x = x + 1 + end do + end do + + !ERROR: The loop modifier indexes of the APPLY clause must be constant positive integer expressions + !$omp tile sizes(2,2) apply(grid(-1): unroll) + do i = 1, 10 + do j = 1, 10 + x = x + 1 + end do + end do + + !ERROR: The loop modifier indexes of the APPLY clause must be in ascending order + !$omp tile sizes(2,2) apply(grid(2,1): unroll, nothing) + do i = 1, 10 + do j = 1, 10 + x = x + 1 + end do + end do + +end subroutine + diff --git a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td index 2aa0649479023..56d5457481bc3 100644 --- a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td +++ b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td @@ -33,6 +33,10 @@ class DirectiveLanguage { // enum. string clausePrefix = ""; + // Optional prefix used for the generation of the enumerator in the + // LoopModifier enum. + string loopModifierPrefix = ""; + // Make the enum values available in the namespace. This allows us to // write something like Enum_X if we have a `using namespace cppNamespace`. bit makeEnumAvailableInNamespace = false; @@ -201,6 +205,23 @@ class SourceLanguage<string n> { def L_C : SourceLanguage<"C"> {} def L_Fortran : SourceLanguage<"Fortran"> {} +// Loop Modifier for Apply clause +class LoopModifier<list<Spelling> ss> { + // Spellings of the loop modifer. + list<Spelling> spellings = ss; +} + +def LM_Flattened: LoopModifier<[Spelling<"flattened">]> {} +def LM_Fused: LoopModifier<[Spelling<"fused">]> {} +def LM_Grid: LoopModifier<[Spelling<"grid">]> {} +def LM_Identity: LoopModifier<[Spelling<"identity">]> {} +def LM_Interchanged: LoopModifier<[Spelling<"interchanged">]> {} +def LM_Intratile: LoopModifier<[Spelling<"intratile">]> {} +def LM_Offsets: LoopModifier<[Spelling<"offsets">]> {} +def LM_Reversed: LoopModifier<[Spelling<"reversed">]> {} +def LM_Split: LoopModifier<[Spelling<"split">]> {} +def LM_Unrolled: LoopModifier<[Spelling<"unrolled">]> {} + // Information about a specific directive. class Directive<list<Spelling> ss> { // Spellings of the directive. @@ -235,6 +256,9 @@ class Directive<list<Spelling> ss> { // The category of the directive. Category category = ?; + // List of allowed loop modifiers for the apply clause. + list<LoopModifier> allowedLoopModifiers = []; + // The languages that allow this directive. Default: all languages. list<SourceLanguage> languages = [L_C, L_Fortran]; } diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td index 189bdaeb4f8d4..bbd55962ba455 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMP.td +++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -21,6 +21,7 @@ def OpenMP : DirectiveLanguage { let cppNamespace = "omp"; // final namespace will be llvm::omp let directivePrefix = "OMPD_"; let clausePrefix = "OMPC_"; + let loopModifierPrefix = "OMPLM_"; let makeEnumAvailableInNamespace = true; let enableBitmaskEnumInNamespace = true; let clauseEnumSetClass = "OmpClauseSet"; @@ -66,6 +67,7 @@ def OMPC_Allocator : Clause<[Spelling<"allocator">]> { let flangClass = "ScalarIntExpr"; } def OMPC_Apply : Clause<[Spelling<"apply">]> { + let flangClass = "OmpApplyClause"; } def OMPC_AppendArgs : Clause<[Spelling<"append_args">]> { let flangClass = "OmpAppendArgsClause"; @@ -938,6 +940,9 @@ def OMP_Flatten : Directive<[Spelling<"flatten">]> { ]; let association = AS_LoopNest; let category = CA_Executable; + let allowedLoopModifiers = [ + LM_Flattened, + ]; } def OMP_Flush : Directive<[Spelling<"flush">]> { let allowedOnceClauses = [ @@ -981,19 +986,31 @@ def OMP_Groupprivate : Directive<[Spelling<"groupprivate">]> { let languages = [L_C, L_Fortran]; } def OMP_Fuse : Directive<[Spelling<"fuse">]> { + let allowedClauses = [ + VersionedClause<OMPC_Apply, 60>, + ]; let allowedOnceClauses = [ VersionedClause<OMPC_Depth, 61>, VersionedClause<OMPC_LoopRange, 60>, ]; let association = AS_LoopSeq; let category = CA_Executable; + let allowedLoopModifiers = [ + LM_Fused, + ]; } def OMP_Interchange : Directive<[Spelling<"interchange">]> { + let allowedClauses = [ + VersionedClause<OMPC_Apply, 60>, + ]; let allowedOnceClauses = [ VersionedClause<OMPC_Permutation>, ]; let association = AS_LoopNest; let category = CA_Executable; + let allowedLoopModifiers = [ + LM_Interchanged, + ]; } def OMP_interop : Directive<[Spelling<"interop">]> { let allowedClauses = [ @@ -1046,8 +1063,14 @@ def OMP_Metadirective : Directive<[Spelling<"metadirective">]> { let category = CA_Meta; } def OMP_Nothing : Directive<[Spelling<"nothing">]> { + let allowedClauses = [ + VersionedClause<OMPC_Apply, 60>, + ]; let association = AS_None; let category = CA_Utility; + let allowedLoopModifiers = [ + LM_Identity, + ]; } def OMP_Ordered : Directive<[Spelling<"ordered">]> { let allowedClauses = [ @@ -1097,8 +1120,14 @@ def OMP_Requires : Directive<[Spelling<"requires">]> { let category = CA_Informational; } def OMP_Reverse : Directive<[Spelling<"reverse">]> { + let allowedClauses = [ + VersionedClause<OMPC_Apply, 60>, + ]; let association = AS_LoopNest; let category = CA_Executable; + let allowedLoopModifiers = [ + LM_Reversed, + ]; } def OMP_Scan : Directive<[Spelling<"scan">]> { let allowedOnceClauses = [ @@ -1382,6 +1411,9 @@ def OMP_ThreadPrivate : Directive<[Spelling<"threadprivate">]> { let category = CA_Declarative; } def OMP_Tile : Directive<[Spelling<"tile">]> { + let allowedClauses = [ + VersionedClause<OMPC_Apply, 60>, + ]; let allowedOnceClauses = [ VersionedClause<OMPC_Sizes, 51>, ]; @@ -1390,15 +1422,29 @@ def OMP_Tile : Directive<[Spelling<"tile">]> { ]; let association = AS_LoopNest; let category = CA_Executable; + let allowedLoopModifiers = [ + LM_Grid, + LM_Intratile, + ]; } def OMP_Stripe : Directive<[Spelling<"stripe">]> { + let allowedClauses = [ + VersionedClause<OMPC_Apply, 60>, + ]; let allowedOnceClauses = [ VersionedClause<OMPC_Sizes, 60>, ]; let association = AS_LoopNest; let category = CA_Executable; + let allowedLoopModifiers = [ + LM_Grid, + LM_Offsets, + ]; } def OMP_Split : Directive<[Spelling<"split">]> { + let allowedClauses = [ + VersionedClause<OMPC_Apply, 60>, + ]; let allowedOnceClauses = [ VersionedClause<OMPC_Counts, 60>, ]; @@ -1407,6 +1453,9 @@ def OMP_Split : Directive<[Spelling<"split">]> { ]; let association = AS_LoopNest; let category = CA_Executable; + let allowedLoopModifiers = [ + LM_Split, + ]; } def OMP_Unknown : Directive<[Spelling<"unknown">]> { let isDefault = true; @@ -1414,12 +1463,18 @@ def OMP_Unknown : Directive<[Spelling<"unknown">]> { let category = CA_Utility; } def OMP_Unroll : Directive<[Spelling<"unroll">]> { + let allowedClauses = [ + VersionedClause<OMPC_Apply, 60>, + ]; let allowedOnceClauses = [ VersionedClause<OMPC_Full, 51>, VersionedClause<OMPC_Partial, 51>, ]; let association = AS_LoopNest; let category = CA_Executable; + let allowedLoopModifiers = [ + LM_Unrolled, + ]; } def OMP_Workshare : Directive<[Spelling<"workshare">]> { let allowedOnceClauses = [ diff --git a/llvm/include/llvm/TableGen/DirectiveEmitter.h b/llvm/include/llvm/TableGen/DirectiveEmitter.h index 2080f75eb8cfc..d111f666ff31a 100644 --- a/llvm/include/llvm/TableGen/DirectiveEmitter.h +++ b/llvm/include/llvm/TableGen/DirectiveEmitter.h @@ -48,6 +48,10 @@ class DirectiveLanguage { return Def->getValueAsString("clausePrefix"); } + StringRef getLoopModifierPrefix() const { + return Def->getValueAsString("loopModifierPrefix"); + } + StringRef getClauseEnumSetClass() const { return Def->getValueAsString("clauseEnumSetClass"); } @@ -84,6 +88,10 @@ class DirectiveLanguage { return Records.getAllDerivedDefinitions("Clause"); } + ArrayRef<const Record *> getLoopModifiers() const { + return Records.getAllDerivedDefinitions("LoopModifier"); + } + bool HasValidityErrors() const; private: @@ -262,6 +270,10 @@ class Directive : public BaseRecord { return Def->getValueAsListOfDefs("languages"); } + std::vector<const Record *> getAllowedLoopModifiers() const { + return Def->getValueAsListOfDefs("allowedLoopModifiers"); + } + // Clang uses a different format for names of its directives enum. std::string getClangAccSpelling() const { StringRef Name = getSpellingForIdentifier(); diff --git a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp index 55675fdec8448..f9791050c56db 100644 --- a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp +++ b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp @@ -311,6 +311,11 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) { DirLang.getClausePrefix(), DirLang.hasMakeEnumAvailableInNamespace()); + // Emit LoopModifier + generateEnumClass(DirLang.getLoopModifiers(), OS, "LoopModifier", + DirLang.getLoopModifierPrefix(), + DirLang.hasMakeEnumAvailableInNamespace()); + // Emit ClauseVals enumeration std::string EnumHelperFuncs; generateClauseEnumVal(DirLang.getClauses(), OS, DirLang, EnumHelperFuncs); @@ -354,11 +359,16 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) { OS << "\n"; OS << "constexpr std::size_t getMaxLeafCount() { return " << getMaxLeafCount(DirLang) << "; }\n"; + OS << "LLVM_ABI bool isAllowedLoopModifier(Directive D, LoopModifier " + "LM);\n"; + OS << "LLVM_ABI StringRef get" << Lang + << "LoopModifierName(LoopModifier LM, unsigned Ver = 0);\n"; OS << EnumHelperFuncs; } // close DirLangNS // These specializations need to be in ::llvm. - for (StringRef Enum : {"Association", "Category", "Directive", "Clause"}) { + for (StringRef Enum : + {"Association", "Category", "Directive", "Clause", "LoopModifier"}) { OS << "\n"; OS << "template <> struct enum_iteration_traits<" << DirLang.getCppNamespace() << "::" << Enum << "> {\n"; @@ -909,6 +919,47 @@ static void generateGetDirectiveLanguages(const DirectiveLanguage &DirLang, OS << "}\n"; } +// Generate the isAllowedLoopModifier function implementation. +static void generateIsAllowedLoopModifier(const DirectiveLanguage &DirLang, + raw_ostream &OS) { + std::string Qual = getQualifier(DirLang); + + OS << "\n"; + OS << "bool " << Qual << "isAllowedLoopModifier(" << Qual << "Directive D, " + << Qual << "LoopModifier LM) {\n"; + OS << " assert(unsigned(D) <= Directive_enumSize);\n"; + + OS << " switch (D) {\n"; + + StringRef DPrefix = DirLang.getDirectivePrefix(); + StringRef LMPrefix = DirLang.getLoopModifierPrefix(); + for (const Record *R : DirLang.getDirectives()) { + Directive Dir(R); + OS << " case " << getIdentifierName(R, DPrefix) << ":\n"; + if (Dir.getAllowedLoopModifiers().empty()) { + OS << " return false;\n"; + } else { + OS << " switch (LM) {\n"; + + for (const Record *LMR : Dir.getAllowedLoopModifiers()) { + std::string Name = getIdentifierName(LMR, LMPrefix); + OS << " case LoopModifier::" << Name << ":\n"; + OS << " return true;\n"; + } + + OS << " default:\n"; + OS << " return false;\n"; + OS << " }\n"; // End of modifier switch + } + OS << " break;\n"; + } + + OS << " }\n"; // End of directives switch + OS << " llvm_unreachable(\"Invalid " << DirLang.getName() + << " Directive kind\");\n"; + OS << "}\n"; // End of function isAllowedLoopModifier +} + // Generate a simple enum set with the give clauses. static void generateClauseSet(ArrayRef<const Record *> VerClauses, raw_ostream &OS, StringRef ClauseSetPrefix, @@ -1360,6 +1411,13 @@ void emitDirectivesBasicImpl(const DirectiveLanguage &DirLang, // isAllowedClauseForDirective(Directive D, Clause C, unsigned Version) generateIsAllowedClause(DirLang, OS); + // isAllowedLoopModifier(Directive D, LoopModifier LM) + generateIsAllowedLoopModifier(DirLang, OS); + + // getLoopModifierName(LoopModifier Kind) + generateGetName(DirLang.getLoopModifiers(), OS, "LoopModifier", DirLang, + DirLang.getLoopModifierPrefix()); + // Leaf table for getLeafConstructs, etc. emitLeafTable(DirLang, OS, "LeafConstructTable"); } >From 1859f22a23bb158e084d34f0b4cb8eeeebdc16be Mon Sep 17 00:00:00 2001 From: Ferran Toda <[email protected]> Date: Wed, 17 Jun 2026 14:05:23 +0000 Subject: [PATCH 2/8] remove lang name from function --- flang/include/flang/Parser/dump-parse-tree.h | 2 +- flang/lib/Parser/unparse.cpp | 4 ++-- flang/lib/Semantics/check-omp-loop.cpp | 2 +- .../utils/TableGen/Basic/DirectiveEmitter.cpp | 22 ++++++++++--------- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h index 2b55be38abf34..9032fa7c00c2f 100644 --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -560,7 +560,7 @@ class ParseTreeDumper { static std::string GetNodeName(const llvm::omp::LoopModifier &x) { return llvm::Twine( - "llvm::omp::LoopModifier = ", llvm::omp::getOpenMPLoopModifierName(x)) + "llvm::omp::LoopModifier = ", llvm::omp::getLoopModifierName(x)) .str(); } NODE(parser, OmpApplyClause) diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp index 889e4ee3de958..759ec2f814d07 100644 --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2214,8 +2214,8 @@ class UnparseVisitor { void Unparse(const OmpAppendArgsClause &x) { Walk(x.v, ","); } void Unparse(const OmpArgumentList &x) { Walk(x.v, ", "); } void Unparse(const OmpLoopModifier &x) { - Word(llvm::omp::getOpenMPLoopModifierName( - std::get<llvm::omp::LoopModifier>(x.t))); + Word( + llvm::omp::getLoopModifierName(std::get<llvm::omp::LoopModifier>(x.t))); Walk("(", std::get<std::optional<std::list<ScalarIntConstantExpr>>>(x.t), ")"); } diff --git a/flang/lib/Semantics/check-omp-loop.cpp b/flang/lib/Semantics/check-omp-loop.cpp index b969014d34e17..267c6525c5b3d 100644 --- a/flang/lib/Semantics/check-omp-loop.cpp +++ b/flang/lib/Semantics/check-omp-loop.cpp @@ -875,7 +875,7 @@ void OmpStructureChecker::Enter(const parser::OmpLoopModifier &x) { unsigned version{context_.langOptions().OpenMPVersion}; auto &m{std::get<llvm::omp::LoopModifier>(x.t)}; if (!llvm::omp::isAllowedLoopModifier(dir, m)) { - llvm::StringRef name = llvm::omp::getOpenMPLoopModifierName(m); + llvm::StringRef name = llvm::omp::getLoopModifierName(m); context_.Say(x.source, "%s modifier is not allowed on %s directive"_err_en_US, parser::ToUpperCaseLetters(name), diff --git a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp index f9791050c56db..93d83f909bfd2 100644 --- a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp +++ b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp @@ -361,8 +361,8 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) { << getMaxLeafCount(DirLang) << "; }\n"; OS << "LLVM_ABI bool isAllowedLoopModifier(Directive D, LoopModifier " "LM);\n"; - OS << "LLVM_ABI StringRef get" << Lang - << "LoopModifierName(LoopModifier LM, unsigned Ver = 0);\n"; + OS << "LLVM_ABI StringRef getLoopModifierName(LoopModifier LM, unsigned " + "Ver = 0);\n"; OS << EnumHelperFuncs; } // close DirLangNS @@ -394,12 +394,11 @@ orderSpellings(ArrayRef<Spelling::Value> Spellings) { // Generate function implementation for get<Enum>Name(StringRef Str) static void generateGetName(ArrayRef<const Record *> Records, raw_ostream &OS, StringRef Enum, const DirectiveLanguage &DirLang, - StringRef Prefix) { - StringRef Lang = DirLang.getName(); + StringRef LangName, StringRef Prefix) { std::string Qual = getQualifier(DirLang); OS << "\n"; - OS << "llvm::StringRef " << Qual << "get" << Lang << Enum << "Name(" << Qual - << Enum << " Kind, unsigned Version) {\n"; + OS << "llvm::StringRef " << Qual << "get" << LangName << Enum << "Name(" + << Qual << Enum << " Kind, unsigned Version) {\n"; OS << " switch (Kind) {\n"; for (const Record *R : Records) { BaseRecord Rec(R); @@ -426,7 +425,8 @@ static void generateGetName(ArrayRef<const Record *> Records, raw_ostream &OS, } } OS << " }\n"; // switch - OS << " llvm_unreachable(\"Invalid " << Lang << " " << Enum << " kind\");\n"; + OS << " llvm_unreachable(\"Invalid " << LangName << " " << Enum + << " kind\");\n"; OS << "}\n"; } @@ -1395,14 +1395,16 @@ void emitDirectivesBasicImpl(const DirectiveLanguage &DirLang, /*ImplicitAsUnknown=*/false); // getDirectiveName(Directive Kind) - generateGetName(DirLang.getDirectives(), OS, "Directive", DirLang, DPrefix); + generateGetName(DirLang.getDirectives(), OS, "Directive", DirLang, + DirLang.getName(), DPrefix); // getClauseKind(StringRef Str) generateGetKind(DirLang.getClauses(), OS, "Clause", DirLang, CPrefix, /*ImplicitAsUnknown=*/true); // getClauseName(Clause Kind) - generateGetName(DirLang.getClauses(), OS, "Clause", DirLang, CPrefix); + generateGetName(DirLang.getClauses(), OS, "Clause", DirLang, + DirLang.getName(), CPrefix); // <enumClauseValue> get<enumClauseValue>(StringRef Str) ; string -> value // StringRef get<enumClauseValue>Name(<enumClauseValue>) ; value -> string @@ -1415,7 +1417,7 @@ void emitDirectivesBasicImpl(const DirectiveLanguage &DirLang, generateIsAllowedLoopModifier(DirLang, OS); // getLoopModifierName(LoopModifier Kind) - generateGetName(DirLang.getLoopModifiers(), OS, "LoopModifier", DirLang, + generateGetName(DirLang.getLoopModifiers(), OS, "LoopModifier", DirLang, "", DirLang.getLoopModifierPrefix()); // Leaf table for getLeafConstructs, etc. >From 416540b277f54bc75b35297c6efbe5ea4a6cc0b7 Mon Sep 17 00:00:00 2001 From: Ferran Toda <[email protected]> Date: Thu, 18 Jun 2026 15:30:49 +0000 Subject: [PATCH 3/8] using modifier mechanisms --- flang/include/flang/Parser/dump-parse-tree.h | 1 + flang/include/flang/Parser/parse-tree.h | 39 ++++++++++--------- .../flang/Semantics/openmp-modifiers.h | 3 +- flang/lib/Parser/openmp-parsers.cpp | 4 +- flang/lib/Parser/unparse.cpp | 3 +- flang/lib/Semantics/check-omp-loop.cpp | 5 ++- flang/lib/Semantics/check-omp-structure.h | 3 +- flang/lib/Semantics/openmp-modifiers.cpp | 16 ++++++++ flang/test/Parser/OpenMP/apply01.f90 | 10 ++--- flang/test/Parser/OpenMP/apply02.f90 | 8 ++-- 10 files changed, 57 insertions(+), 35 deletions(-) diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h index 9032fa7c00c2f..030b0cc6f5301 100644 --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -564,6 +564,7 @@ class ParseTreeDumper { .str(); } NODE(parser, OmpApplyClause) + NODE(OmpApplyClause, Modifier) NODE(parser, OmpArgument) NODE(parser, OmpArgumentList) NODE(parser, OmpAssumeDirective) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index fe2558fa464b2..bf726a8451f25 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -4156,6 +4156,24 @@ struct OmpLinearModifier { WRAPPER_CLASS_BOILERPLATE(OmpLinearModifier, Value); }; +// Ref: [6.0:372-373] +// +// loop-modifier -> +// FLATTENED | +// FUSED | GRID | IDENTITY | +// INTERCHANGED | +// INTRATILE | OFFSETS | +// REVERSED | SPLIT | +// UNROLLED +// [( ScalarIntConstantExpr-list )] +struct OmpLoopModifier { + TUPLE_CLASS_BOILERPLATE(OmpLoopModifier); + std::tuple<llvm::omp::LoopModifier, + std::optional<std::list<ScalarIntConstantExpr>>> + t; + CharBlock source; +}; + // Ref: [5.1:100-104], [5.2:277], [6.0:452-453] // // lower-bound -> @@ -4359,24 +4377,6 @@ struct OmpxHoldModifier { WRAPPER_CLASS_BOILERPLATE(OmpxHoldModifier, Value); }; -// Ref: [6.0:372-373] -// -// loop-modifier -> -// FLATTENED | -// FUSED | GRID | IDENTITY | -// INTERCHANGED | -// INTRATILE | OFFSETS | -// REVERSED | SPLIT | -// UNROLLED -// [( ScalarIntConstantExpr-list )] -struct OmpLoopModifier { - TUPLE_CLASS_BOILERPLATE(OmpLoopModifier); - std::tuple<llvm::omp::LoopModifier, - std::optional<std::list<ScalarIntConstantExpr>>> - t; - CharBlock source; -}; - // context-selector using OmpContextSelector = traits::OmpContextSelectorSpecification; } // namespace modifier @@ -4510,7 +4510,8 @@ struct OmpContainsClause { // APPLY( [loop-modifier :] directive-specification-list ) struct OmpApplyClause { TUPLE_CLASS_BOILERPLATE(OmpApplyClause); - std::tuple<std::optional<OmpLoopModifier>, + MODIFIER_BOILERPLATE(OmpLoopModifier); + std::tuple<MODIFIERS(), std::list<OmpDirectiveSpecification>> t; }; diff --git a/flang/include/flang/Semantics/openmp-modifiers.h b/flang/include/flang/Semantics/openmp-modifiers.h index 8dcac9b179924..1e549c288925b 100644 --- a/flang/include/flang/Semantics/openmp-modifiers.h +++ b/flang/include/flang/Semantics/openmp-modifiers.h @@ -44,7 +44,7 @@ namespace Fortran::semantics { // or post-modifier (i.e. item: modifier). The default is pre-. // Add an additional property that reflects the type of modifier. -ENUM_CLASS(OmpProperty, Required, Unique, Exclusive, Ultimate, Post) +ENUM_CLASS(OmpProperty, Required, Unique, Exclusive, Ultimate, Post, Optional) using OmpProperties = common::EnumSet<OmpProperty, OmpProperty_enumSize>; using OmpClauses = common::EnumSet<llvm::omp::Clause, llvm::omp::Clause_enumSize>; @@ -90,6 +90,7 @@ DECLARE_DESCRIPTOR(parser::OmpInteropType); DECLARE_DESCRIPTOR(parser::OmpIterator); DECLARE_DESCRIPTOR(parser::OmpLastprivateModifier); DECLARE_DESCRIPTOR(parser::OmpLinearModifier); +DECLARE_DESCRIPTOR(parser::OmpLoopModifier); DECLARE_DESCRIPTOR(parser::OmpLowerBound); DECLARE_DESCRIPTOR(parser::OmpMapper); DECLARE_DESCRIPTOR(parser::OmpMapType); diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index 8ad1f10614587..8690bffe244d6 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -1133,6 +1133,8 @@ TYPE_PARSER(construct<OmpAdjustArgsClause::OmpAdjustOp>( "NEED_DEVICE_PTR" >> pure(OmpAdjustArgsClause::OmpAdjustOp::Value::Need_Device_Ptr))) +TYPE_PARSER(construct<OmpApplyClause::Modifier>(Parser<OmpLoopModifier>{})) + TYPE_PARSER(sourced(construct<OmpLoopModifier>( "FUSED" >> pure(llvm::omp::LoopModifier::OMPLM_fused) || "GRID" >> pure(llvm::omp::LoopModifier::OMPLM_grid) || @@ -1187,7 +1189,7 @@ TYPE_PARSER(construct<OmpAffinityClause>( maybe(nonemptyList(Parser<OmpAffinityClause::Modifier>{}) / ":"), Parser<OmpObjectList>{})) -TYPE_PARSER(construct<OmpApplyClause>(maybe(Parser<OmpLoopModifier>{} / ":"), +TYPE_PARSER(construct<OmpApplyClause>(maybe(nonemptyList(Parser<OmpApplyClause::Modifier>{} / ":")), nonemptyList(OmpDirectiveSpecificationParser(/*allowCommas=*/false)))) // 2.4 Requires construct [OpenMP 5.0] diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp index 759ec2f814d07..c7fc6da4b8268 100644 --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2220,7 +2220,8 @@ class UnparseVisitor { ")"); } void Unparse(const OmpApplyClause &x) { - Walk(std::get<std::optional<OmpLoopModifier>>(x.t), ": "); + using Modifier = OmpApplyClause::Modifier; + Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": "); Walk(std::get<std::list<OmpDirectiveSpecification>>(x.t)); } void Unparse(const OmpAttachModifier &x) { diff --git a/flang/lib/Semantics/check-omp-loop.cpp b/flang/lib/Semantics/check-omp-loop.cpp index 267c6525c5b3d..0b0b6592befd9 100644 --- a/flang/lib/Semantics/check-omp-loop.cpp +++ b/flang/lib/Semantics/check-omp-loop.cpp @@ -905,12 +905,13 @@ void OmpStructureChecker::Enter(const parser::OmpLoopModifier &x) { } } -void OmpStructureChecker::Enter(const parser::OmpApplyClause &x) { +void OmpStructureChecker::Enter(const parser::OmpClause::Apply &x) { EnterDirectiveNest(ApplyNest); CheckAllowedClause(llvm::omp::Clause::OMPC_apply); + OmpVerifyModifiers(x.v, llvm::omp::Clause::OMPC_apply, GetContext().clauseSource, context_); } -void OmpStructureChecker::Leave(const parser::OmpApplyClause &x) { +void OmpStructureChecker::Leave(const parser::OmpClause::Apply &x) { ExitDirectiveNest(ApplyNest); } diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h index 6cd39db19bdd8..4acfd5961d421 100644 --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -146,8 +146,7 @@ class OmpStructureChecker : public OmpStructureCheckerBase { void Enter(const parser::OmpLoopModifier &); - void Enter(const parser::OmpApplyClause &); - void Leave(const parser::OmpApplyClause &); + void Leave(const parser::OmpClause::Apply &); template <typename A> void Enter(const parser::Statement<A> &); void Leave(const parser::GotoStmt &); diff --git a/flang/lib/Semantics/openmp-modifiers.cpp b/flang/lib/Semantics/openmp-modifiers.cpp index b6a6d476ceec6..c261240480f63 100644 --- a/flang/lib/Semantics/openmp-modifiers.cpp +++ b/flang/lib/Semantics/openmp-modifiers.cpp @@ -456,6 +456,22 @@ const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpLinearModifier>() { return desc; } +template <> +const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpLoopModifier>() { + static const OmpModifierDescriptor desc{ + /*name=*/"loop-modifier", + /*props=*/ + { + {60, {OmpProperty::Optional}}, + }, + /*clauses=*/ + { + {60, {Clause::OMPC_apply}}, + }, + }; + return desc; +} + template <> const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpLowerBound>() { static const OmpModifierDescriptor desc{ diff --git a/flang/test/Parser/OpenMP/apply01.f90 b/flang/test/Parser/OpenMP/apply01.f90 index c1c5d4be2d0eb..555ef769e22b3 100644 --- a/flang/test/Parser/OpenMP/apply01.f90 +++ b/flang/test/Parser/OpenMP/apply01.f90 @@ -52,7 +52,7 @@ subroutine apply_modifier(x) !PARSE-TREE: | OmpClauseList -> OmpClause -> Sizes -> Scalar -> Integer -> Expr = '2_4' !PARSE-TREE: | | LiteralConstant -> IntLiteralConstant = '2' !PARSE-TREE: | OmpClause -> Apply -> OmpApplyClause -!PARSE-TREE: | | OmpLoopModifier +!PARSE-TREE: | | Modifier -> OmpLoopModifier !PARSE-TREE: | | | llvm::omp::LoopModifier = grid !PARSE-TREE: | | OmpDirectiveSpecification !PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = reverse @@ -79,14 +79,14 @@ subroutine apply_2_clauses(x) !PARSE-TREE: | OmpClauseList -> OmpClause -> Sizes -> Scalar -> Integer -> Expr = '2_4' !PARSE-TREE: | | LiteralConstant -> IntLiteralConstant = '2' !PARSE-TREE: | OmpClause -> Apply -> OmpApplyClause -!PARSE-TREE: | | OmpLoopModifier +!PARSE-TREE: | | Modifier -> OmpLoopModifier !PARSE-TREE: | | | llvm::omp::LoopModifier = intratile !PARSE-TREE: | | OmpDirectiveSpecification !PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = unroll !PARSE-TREE: | | | OmpClauseList -> !PARSE-TREE: | | | Flags = {} !PARSE-TREE: | OmpClause -> Apply -> OmpApplyClause -!PARSE-TREE: | | OmpLoopModifier +!PARSE-TREE: | | Modifier -> OmpLoopModifier !PARSE-TREE: | | | llvm::omp::LoopModifier = grid !PARSE-TREE: | | OmpDirectiveSpecification !PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = reverse @@ -120,14 +120,14 @@ subroutine apply_inside_apply(x) !PARSE-TREE: OmpBeginDirective !PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = fuse !PARSE-TREE: | OmpClauseList -> OmpClause -> Apply -> OmpApplyClause -!PARSE-TREE: | | OmpLoopModifier +!PARSE-TREE: | | Modifier -> OmpLoopModifier !PARSE-TREE: | | | llvm::omp::LoopModifier = fused !PARSE-TREE: | | OmpDirectiveSpecification !PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = tile !PARSE-TREE: | | | OmpClauseList -> OmpClause -> Sizes -> Scalar -> Integer -> Expr = '2_4' !PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '2' !PARSE-TREE: | | | OmpClause -> Apply -> OmpApplyClause -!PARSE-TREE: | | | | OmpLoopModifier +!PARSE-TREE: | | | | Modifier -> OmpLoopModifier !PARSE-TREE: | | | | | llvm::omp::LoopModifier = grid !PARSE-TREE: | | | | OmpDirectiveSpecification !PARSE-TREE: | | | | | OmpDirectiveName -> llvm::omp::Directive = reverse diff --git a/flang/test/Parser/OpenMP/apply02.f90 b/flang/test/Parser/OpenMP/apply02.f90 index 803f0ac73d25a..e2160796bf40e 100644 --- a/flang/test/Parser/OpenMP/apply02.f90 +++ b/flang/test/Parser/OpenMP/apply02.f90 @@ -23,7 +23,7 @@ subroutine apply_all(x) !PARSE-TREE: OmpBeginDirective !PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = interchange !PARSE-TREE: | OmpClauseList -> OmpClause -> Apply -> OmpApplyClause -!PARSE-TREE: | | OmpLoopModifier +!PARSE-TREE: | | Modifier -> OmpLoopModifier !PARSE-TREE: | | | llvm::omp::LoopModifier = interchanged !PARSE-TREE: | | | Scalar -> Integer -> Constant -> Expr = '1_4' !PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '1' @@ -60,7 +60,7 @@ subroutine apply_one(x) !PARSE-TREE: OmpBeginDirective !PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = interchange !PARSE-TREE: | OmpClauseList -> OmpClause -> Apply -> OmpApplyClause -!PARSE-TREE: | | OmpLoopModifier +!PARSE-TREE: | | Modifier -> OmpLoopModifier !PARSE-TREE: | | | llvm::omp::LoopModifier = interchanged !PARSE-TREE: | | | Scalar -> Integer -> Constant -> Expr = '2_4' !PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '2' @@ -95,14 +95,14 @@ subroutine apply_inside_apply(x) !PARSE-TREE: | Scalar -> Integer -> Expr = '2_4' !PARSE-TREE: | | LiteralConstant -> IntLiteralConstant = '2' !PARSE-TREE: | OmpClause -> Apply -> OmpApplyClause -!PARSE-TREE: | | OmpLoopModifier +!PARSE-TREE: | | Modifier -> OmpLoopModifier !PARSE-TREE: | | | llvm::omp::LoopModifier = grid !PARSE-TREE: | | | Scalar -> Integer -> Constant -> Expr = '1_4' !PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '1' !PARSE-TREE: | | OmpDirectiveSpecification !PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = interchange !PARSE-TREE: | | | OmpClauseList -> OmpClause -> Apply -> OmpApplyClause -!PARSE-TREE: | | | | OmpLoopModifier +!PARSE-TREE: | | | | Modifier -> OmpLoopModifier !PARSE-TREE: | | | | | llvm::omp::LoopModifier = interchanged !PARSE-TREE: | | | | | Scalar -> Integer -> Constant -> Expr = '2_4' !PARSE-TREE: | | | | | | LiteralConstant -> IntLiteralConstant = '2' >From 11a1de748a870ce7398a83ab0b0841d3337c1e45 Mon Sep 17 00:00:00 2001 From: Ferran Toda <[email protected]> Date: Fri, 19 Jun 2026 14:14:35 +0000 Subject: [PATCH 4/8] format --- flang/include/flang/Parser/parse-tree.h | 4 +--- flang/lib/Parser/openmp-parsers.cpp | 3 ++- flang/lib/Semantics/check-omp-loop.cpp | 3 ++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index bf726a8451f25..306dbf3940b54 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -4511,9 +4511,7 @@ struct OmpContainsClause { struct OmpApplyClause { TUPLE_CLASS_BOILERPLATE(OmpApplyClause); MODIFIER_BOILERPLATE(OmpLoopModifier); - std::tuple<MODIFIERS(), - std::list<OmpDirectiveSpecification>> - t; + std::tuple<MODIFIERS(), std::list<OmpDirectiveSpecification>> t; }; // Ref: [4.5:46-50], [5.0:74-78], [5.1:92-96], [5.2:109] diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index 8690bffe244d6..105a72de5cb29 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -1189,7 +1189,8 @@ TYPE_PARSER(construct<OmpAffinityClause>( maybe(nonemptyList(Parser<OmpAffinityClause::Modifier>{}) / ":"), Parser<OmpObjectList>{})) -TYPE_PARSER(construct<OmpApplyClause>(maybe(nonemptyList(Parser<OmpApplyClause::Modifier>{} / ":")), +TYPE_PARSER(construct<OmpApplyClause>( + maybe(nonemptyList(Parser<OmpApplyClause::Modifier>{} / ":")), nonemptyList(OmpDirectiveSpecificationParser(/*allowCommas=*/false)))) // 2.4 Requires construct [OpenMP 5.0] diff --git a/flang/lib/Semantics/check-omp-loop.cpp b/flang/lib/Semantics/check-omp-loop.cpp index 0b0b6592befd9..06748e700dab4 100644 --- a/flang/lib/Semantics/check-omp-loop.cpp +++ b/flang/lib/Semantics/check-omp-loop.cpp @@ -908,7 +908,8 @@ void OmpStructureChecker::Enter(const parser::OmpLoopModifier &x) { void OmpStructureChecker::Enter(const parser::OmpClause::Apply &x) { EnterDirectiveNest(ApplyNest); CheckAllowedClause(llvm::omp::Clause::OMPC_apply); - OmpVerifyModifiers(x.v, llvm::omp::Clause::OMPC_apply, GetContext().clauseSource, context_); + OmpVerifyModifiers( + x.v, llvm::omp::Clause::OMPC_apply, GetContext().clauseSource, context_); } void OmpStructureChecker::Leave(const parser::OmpClause::Apply &x) { >From 9718ca8726375ac4c68801c65a454827abec5810 Mon Sep 17 00:00:00 2001 From: Ferran Toda <[email protected]> Date: Fri, 19 Jun 2026 14:15:41 +0000 Subject: [PATCH 5/8] remove optional property --- flang/include/flang/Semantics/openmp-modifiers.h | 2 +- flang/lib/Semantics/openmp-modifiers.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/flang/include/flang/Semantics/openmp-modifiers.h b/flang/include/flang/Semantics/openmp-modifiers.h index 1e549c288925b..66a4f3319c4d1 100644 --- a/flang/include/flang/Semantics/openmp-modifiers.h +++ b/flang/include/flang/Semantics/openmp-modifiers.h @@ -44,7 +44,7 @@ namespace Fortran::semantics { // or post-modifier (i.e. item: modifier). The default is pre-. // Add an additional property that reflects the type of modifier. -ENUM_CLASS(OmpProperty, Required, Unique, Exclusive, Ultimate, Post, Optional) +ENUM_CLASS(OmpProperty, Required, Unique, Exclusive, Ultimate, Post) using OmpProperties = common::EnumSet<OmpProperty, OmpProperty_enumSize>; using OmpClauses = common::EnumSet<llvm::omp::Clause, llvm::omp::Clause_enumSize>; diff --git a/flang/lib/Semantics/openmp-modifiers.cpp b/flang/lib/Semantics/openmp-modifiers.cpp index c261240480f63..fe8e087cd5a94 100644 --- a/flang/lib/Semantics/openmp-modifiers.cpp +++ b/flang/lib/Semantics/openmp-modifiers.cpp @@ -462,7 +462,7 @@ const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpLoopModifier>() { /*name=*/"loop-modifier", /*props=*/ { - {60, {OmpProperty::Optional}}, + {60, {}}, }, /*clauses=*/ { >From 796dabb9227c1708a686976dfd63e3b13dc9274b Mon Sep 17 00:00:00 2001 From: Ferran Toda <[email protected]> Date: Fri, 19 Jun 2026 15:11:05 +0000 Subject: [PATCH 6/8] fix tablegen tests --- llvm/test/TableGen/directive1.td | 70 ++++++++++++++++++++++++++++++++ llvm/test/TableGen/directive2.td | 59 +++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) diff --git a/llvm/test/TableGen/directive1.td b/llvm/test/TableGen/directive1.td index 7dca15e908665..a82ca6e2451ce 100644 --- a/llvm/test/TableGen/directive1.td +++ b/llvm/test/TableGen/directive1.td @@ -126,6 +126,34 @@ def TDL_DirA : Directive<[Spelling<"dira">]> { // CHECK-NEXT: constexpr auto TDLC_clauseb = Clause::TDLC_clauseb; // CHECK-NEXT: constexpr auto TDLC_clausec = Clause::TDLC_clausec; // CHECK-EMPTY: +// CHECK-NEXT: enum class LoopModifier { +// CHECK-NEXT: flattened, +// CHECK-NEXT: First_ = flattened, +// CHECK-NEXT: fused, +// CHECK-NEXT: grid, +// CHECK-NEXT: identity, +// CHECK-NEXT: interchanged, +// CHECK-NEXT: intratile, +// CHECK-NEXT: offsets, +// CHECK-NEXT: reversed, +// CHECK-NEXT: split, +// CHECK-NEXT: unrolled, +// CHECK-NEXT: Last_ = unrolled, +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: static constexpr std::size_t LoopModifier_enumSize = 10; +// CHECK-EMPTY: +// CHECK-NEXT: constexpr auto flattened = LoopModifier::flattened; +// CHECK-NEXT: constexpr auto fused = LoopModifier::fused; +// CHECK-NEXT: constexpr auto grid = LoopModifier::grid; +// CHECK-NEXT: constexpr auto identity = LoopModifier::identity; +// CHECK-NEXT: constexpr auto interchanged = LoopModifier::interchanged; +// CHECK-NEXT: constexpr auto intratile = LoopModifier::intratile; +// CHECK-NEXT: constexpr auto offsets = LoopModifier::offsets; +// CHECK-NEXT: constexpr auto reversed = LoopModifier::reversed; +// CHECK-NEXT: constexpr auto split = LoopModifier::split; +// CHECK-NEXT: constexpr auto unrolled = LoopModifier::unrolled; +// CHECK-EMPTY: // CHECK-NEXT: enum class AKind { // CHECK-NEXT: TDLCV_vala=1, // CHECK-NEXT: TDLCV_valb=2, @@ -194,6 +222,8 @@ def TDL_DirA : Directive<[Spelling<"dira">]> { // CHECK-NEXT: LLVM_ABI bool isAllowedClauseForDirective(Directive D, Clause C, unsigned Version); // CHECK-EMPTY: // CHECK-NEXT: constexpr std::size_t getMaxLeafCount() { return 0; } +// CHECK-NEXT: LLVM_ABI bool isAllowedLoopModifier(Directive D, LoopModifier LM); +// CHECK-NEXT: LLVM_ABI StringRef getLoopModifierName(LoopModifier LM, unsigned Ver = 0); // CHECK-NEXT: LLVM_ABI AKind getAKind(StringRef Str); // CHECK-NEXT: LLVM_ABI StringRef getTdlAKindName(AKind x); // CHECK-EMPTY: @@ -215,6 +245,10 @@ def TDL_DirA : Directive<[Spelling<"dira">]> { // CHECK-NEXT: static constexpr bool is_iterable = true; // CHECK-NEXT: }; // CHECK-EMPTY: +// CHECK-NEXT: template <> struct enum_iteration_traits<tdl::LoopModifier> { +// CHECK-NEXT: static constexpr bool is_iterable = true; +// CHECK-NEXT: }; +// CHECK-EMPTY: // CHECK-NEXT: } // namespace llvm // CHECK-EMPTY: // CHECK-NEXT: #endif // LLVM_Tdl_INC @@ -467,6 +501,42 @@ def TDL_DirA : Directive<[Spelling<"dira">]> { // IMPL-NEXT: llvm_unreachable("Invalid Tdl Directive kind"); // IMPL-NEXT: } // IMPL-EMPTY: +// IMPL-NEXT: bool llvm::tdl::isAllowedLoopModifier(llvm::tdl::Directive D, llvm::tdl::LoopModifier LM) { +// IMPL-NEXT: assert(unsigned(D) <= Directive_enumSize); +// IMPL-NEXT: switch (D) { +// IMPL-NEXT: case TDLD_dira: +// IMPL-NEXT: return false; +// IMPL-NEXT: break; +// IMPL-NEXT: } +// IMPL-NEXT: llvm_unreachable("Invalid Tdl Directive kind"); +// IMPL-NEXT: } +// IMPL-EMPTY: +// IMPL-NEXT: llvm::StringRef llvm::tdl::getLoopModifierName(llvm::tdl::LoopModifier Kind, unsigned Version) { +// IMPL-NEXT: switch (Kind) { +// IMPL-NEXT: case flattened: +// IMPL-NEXT: return "flattened"; +// IMPL-NEXT: case fused: +// IMPL-NEXT: return "fused"; +// IMPL-NEXT: case grid: +// IMPL-NEXT: return "grid"; +// IMPL-NEXT: case identity: +// IMPL-NEXT: return "identity"; +// IMPL-NEXT: case interchanged: +// IMPL-NEXT: return "interchanged"; +// IMPL-NEXT: case intratile: +// IMPL-NEXT: return "intratile"; +// IMPL-NEXT: case offsets: +// IMPL-NEXT: return "offsets"; +// IMPL-NEXT: case reversed: +// IMPL-NEXT: return "reversed"; +// IMPL-NEXT: case split: +// IMPL-NEXT: return "split"; +// IMPL-NEXT: case unrolled: +// IMPL-NEXT: return "unrolled"; +// IMPL-NEXT: } +// IMPL-NEXT: llvm_unreachable("Invalid LoopModifier kind"); +// IMPL-NEXT: } +// IMPL-EMPTY: // IMPL-NEXT: static_assert(sizeof(llvm::tdl::Directive) == sizeof(int)); // IMPL-NEXT: {{.*}} static const llvm::tdl::Directive LeafConstructTable[][2] = { // IMPL-NEXT: {llvm::tdl::TDLD_dira, static_cast<llvm::tdl::Directive>(0),}, diff --git a/llvm/test/TableGen/directive2.td b/llvm/test/TableGen/directive2.td index 31a3bc907988c..76252e5f92303 100644 --- a/llvm/test/TableGen/directive2.td +++ b/llvm/test/TableGen/directive2.td @@ -112,6 +112,23 @@ def TDL_DirA : Directive<[Spelling<"dira">]> { // CHECK-EMPTY: // CHECK-NEXT: static constexpr std::size_t Clause_enumSize = 4; // CHECK-EMPTY: +// CHECK-NEXT: enum class LoopModifier { +// CHECK-NEXT: flattened, +// CHECK-NEXT: First_ = flattened, +// CHECK-NEXT: fused, +// CHECK-NEXT: grid, +// CHECK-NEXT: identity, +// CHECK-NEXT: interchanged, +// CHECK-NEXT: intratile, +// CHECK-NEXT: offsets, +// CHECK-NEXT: reversed, +// CHECK-NEXT: split, +// CHECK-NEXT: unrolled, +// CHECK-NEXT: Last_ = unrolled, +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: static constexpr std::size_t LoopModifier_enumSize = 10; +// CHECK-EMPTY: // CHECK-NEXT: // Constexpr functions. // CHECK-EMPTY: // CHECK-NEXT: constexpr Association getDirectiveAssociation(Directive Dir) { @@ -170,6 +187,8 @@ def TDL_DirA : Directive<[Spelling<"dira">]> { // CHECK-NEXT: LLVM_ABI bool isAllowedClauseForDirective(Directive D, Clause C, unsigned Version); // CHECK-EMPTY: // CHECK-NEXT: constexpr std::size_t getMaxLeafCount() { return 0; } +// CHECK-NEXT: LLVM_ABI bool isAllowedLoopModifier(Directive D, LoopModifier LM); +// CHECK-NEXT: LLVM_ABI StringRef getLoopModifierName(LoopModifier LM, unsigned Ver = 0); // CHECK-EMPTY: // CHECK-NEXT: } // namespace tdl // CHECK-EMPTY: @@ -189,6 +208,10 @@ def TDL_DirA : Directive<[Spelling<"dira">]> { // CHECK-NEXT: static constexpr bool is_iterable = true; // CHECK-NEXT: }; // CHECK-EMPTY: +// CHECK-NEXT: template <> struct enum_iteration_traits<tdl::LoopModifier> { +// CHECK-NEXT: static constexpr bool is_iterable = true; +// CHECK-NEXT: }; +// CHECK-EMPTY: // CHECK-NEXT: } // namespace llvm // CHECK-EMPTY: // CHECK-NEXT: #endif // LLVM_Tdl_INC @@ -392,6 +415,42 @@ def TDL_DirA : Directive<[Spelling<"dira">]> { // IMPL-NEXT: llvm_unreachable("Invalid Tdl Directive kind"); // IMPL-NEXT: } // IMPL-EMPTY: +// IMPL-NEXT: bool llvm::tdl::isAllowedLoopModifier(llvm::tdl::Directive D, llvm::tdl::LoopModifier LM) { +// IMPL-NEXT: assert(unsigned(D) <= Directive_enumSize); +// IMPL-NEXT: switch (D) { +// IMPL-NEXT: case TDLD_dira: +// IMPL-NEXT: return false; +// IMPL-NEXT: break; +// IMPL-NEXT: } +// IMPL-NEXT: llvm_unreachable("Invalid Tdl Directive kind"); +// IMPL-NEXT: } +// IMPL-EMPTY: +// IMPL-NEXT: llvm::StringRef llvm::tdl::getLoopModifierName(llvm::tdl::LoopModifier Kind, unsigned Version) { +// IMPL-NEXT: switch (Kind) { +// IMPL-NEXT: case flattened: +// IMPL-NEXT: return "flattened"; +// IMPL-NEXT: case fused: +// IMPL-NEXT: return "fused"; +// IMPL-NEXT: case grid: +// IMPL-NEXT: return "grid"; +// IMPL-NEXT: case identity: +// IMPL-NEXT: return "identity"; +// IMPL-NEXT: case interchanged: +// IMPL-NEXT: return "interchanged"; +// IMPL-NEXT: case intratile: +// IMPL-NEXT: return "intratile"; +// IMPL-NEXT: case offsets: +// IMPL-NEXT: return "offsets"; +// IMPL-NEXT: case reversed: +// IMPL-NEXT: return "reversed"; +// IMPL-NEXT: case split: +// IMPL-NEXT: return "split"; +// IMPL-NEXT: case unrolled: +// IMPL-NEXT: return "unrolled"; +// IMPL-NEXT: } +// IMPL-NEXT: llvm_unreachable("Invalid LoopModifier kind"); +// IMPL-NEXT: } +// IMPL-EMPTY: // IMPL-NEXT: static_assert(sizeof(llvm::tdl::Directive) == sizeof(int)); // IMPL-NEXT: {{.*}} static const llvm::tdl::Directive LeafConstructTable[][2] = { // IMPL-NEXT: {llvm::tdl::TDLD_dira, static_cast<llvm::tdl::Directive>(0),}, >From d4cd6d9421220c990efd99a2fbd53dfd7c6aeb90 Mon Sep 17 00:00:00 2001 From: Ferran Toda <[email protected]> Date: Mon, 6 Jul 2026 14:56:24 +0000 Subject: [PATCH 7/8] CheckAllowedClause no longer needed --- flang/lib/Semantics/check-omp-loop.cpp | 1 - flang/lib/Semantics/check-omp-structure.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/flang/lib/Semantics/check-omp-loop.cpp b/flang/lib/Semantics/check-omp-loop.cpp index 06748e700dab4..b05ae4d0d8946 100644 --- a/flang/lib/Semantics/check-omp-loop.cpp +++ b/flang/lib/Semantics/check-omp-loop.cpp @@ -907,7 +907,6 @@ void OmpStructureChecker::Enter(const parser::OmpLoopModifier &x) { void OmpStructureChecker::Enter(const parser::OmpClause::Apply &x) { EnterDirectiveNest(ApplyNest); - CheckAllowedClause(llvm::omp::Clause::OMPC_apply); OmpVerifyModifiers( x.v, llvm::omp::Clause::OMPC_apply, GetContext().clauseSource, context_); } diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h index 4acfd5961d421..97906e636298e 100644 --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -146,6 +146,7 @@ class OmpStructureChecker : public OmpStructureCheckerBase { void Enter(const parser::OmpLoopModifier &); + void Enter(const parser::OmpClause::Apply &); void Leave(const parser::OmpClause::Apply &); template <typename A> void Enter(const parser::Statement<A> &); >From 81ce58125ccac8a5138e7d0798a848a4f3131644 Mon Sep 17 00:00:00 2001 From: Ferran Toda <[email protected]> Date: Tue, 7 Jul 2026 13:17:41 +0000 Subject: [PATCH 8/8] update clang unexpected apply error --- clang/test/OpenMP/unimplemented_clause_messages.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/clang/test/OpenMP/unimplemented_clause_messages.cpp b/clang/test/OpenMP/unimplemented_clause_messages.cpp index 172203ea5d040..0f51c916093ff 100644 --- a/clang/test/OpenMP/unimplemented_clause_messages.cpp +++ b/clang/test/OpenMP/unimplemented_clause_messages.cpp @@ -16,8 +16,7 @@ void test_induction_basic() { } void test_apply() { - // omp60-warning@+4{{extra tokens at the end of '#pragma omp tile' are ignored}} - // omp60-error@+3{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}} + // omp60-warning@+3{{extra tokens at the end of '#pragma omp tile' are ignored}} // omp51-error@+2{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}} // omp51-warning@+1{{extra tokens at the end of '#pragma omp tile' are ignored}} #pragma omp tile sizes(10) apply(intratile: unroll) @@ -26,8 +25,7 @@ void test_apply() { } void test_empty_apply() { - // omp60-warning@+4{{extra tokens at the end of '#pragma omp tile' are ignored}} - // omp60-error@+3{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}} + // omp60-warning@+3{{extra tokens at the end of '#pragma omp tile' are ignored}} // omp51-error@+2{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}} // omp51-warning@+1{{extra tokens at the end of '#pragma omp tile' are ignored}} #pragma omp tile sizes(10) apply() @@ -37,7 +35,6 @@ void test_empty_apply() { void test_nested_apply() { - // omp60-error@+5{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}} // omp60-warning@+4{{extra tokens at the end of '#pragma omp tile' are ignored}} //omp51-error@+3{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}} // omp51-warning@+2{{extra tokens at the end of '#pragma omp tile' are ignored}} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
