Author: Ferran Toda Date: 2026-07-09T10:51:35-05:00 New Revision: 3b2fe66a4eb5fc569cc9a9822440ebe3a1a36f34
URL: https://github.com/llvm/llvm-project/commit/3b2fe66a4eb5fc569cc9a9822440ebe3a1a36f34 DIFF: https://github.com/llvm/llvm-project/commit/3b2fe66a4eb5fc569cc9a9822440ebe3a1a36f34.diff LOG: [Flang][OpenMP] add Apply clause for OpenMP Flang (#204225) This patch adds a parser and basic checks for the Apply clause from OpenMP 6.0 in Flang. It is missing semantic checks for nesting loop transformations that are being worked on. Added: flang/test/Parser/OpenMP/apply01.f90 flang/test/Parser/OpenMP/apply02.f90 flang/test/Semantics/OpenMP/apply01.f90 flang/test/Semantics/OpenMP/apply02.f90 Modified: clang/test/OpenMP/unimplemented_clause_messages.cpp flang/include/flang/Parser/dump-parse-tree.h flang/include/flang/Parser/parse-tree.h flang/include/flang/Semantics/openmp-modifiers.h flang/lib/Parser/openmp-parsers.cpp flang/lib/Parser/unparse.cpp flang/lib/Semantics/check-omp-loop.cpp flang/lib/Semantics/check-omp-structure.h flang/lib/Semantics/check-omp-variant.cpp flang/lib/Semantics/openmp-modifiers.cpp llvm/include/llvm/Frontend/Directive/DirectiveBase.td llvm/include/llvm/Frontend/OpenMP/OMP.td llvm/include/llvm/TableGen/DirectiveEmitter.h llvm/test/TableGen/directive1.td llvm/test/TableGen/directive2.td llvm/utils/TableGen/Basic/DirectiveEmitter.cpp Removed: ################################################################################ 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}} diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h index ceba23d7d4706..030b0cc6f5301 100644 --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -556,6 +556,15 @@ 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::getLoopModifierName(x)) + .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 a6fecf61593cb..f1e483922eee4 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -4155,6 +4155,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 -> @@ -4485,6 +4503,16 @@ 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); + MODIFIER_BOILERPLATE(OmpLoopModifier); + std::tuple<MODIFIERS(), 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/include/flang/Semantics/openmp-modifiers.h b/flang/include/flang/Semantics/openmp-modifiers.h index 8dcac9b179924..66a4f3319c4d1 100644 --- a/flang/include/flang/Semantics/openmp-modifiers.h +++ b/flang/include/flang/Semantics/openmp-modifiers.h @@ -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 2c5f9c19a944e..105a72de5cb29 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -1133,6 +1133,20 @@ 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) || + "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 +1189,10 @@ TYPE_PARSER(construct<OmpAffinityClause>( maybe(nonemptyList(Parser<OmpAffinityClause::Modifier>{}) / ":"), Parser<OmpObjectList>{})) +TYPE_PARSER(construct<OmpApplyClause>( + maybe(nonemptyList(Parser<OmpApplyClause::Modifier>{} / ":")), + nonemptyList(OmpDirectiveSpecificationParser(/*allowCommas=*/false)))) + // 2.4 Requires construct [OpenMP 5.0] // atomic-default-mem-order-clause -> // acq_rel @@ -1483,6 +1501,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..c7fc6da4b8268 100644 --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2213,6 +2213,17 @@ 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::getLoopModifierName(std::get<llvm::omp::LoopModifier>(x.t))); + Walk("(", std::get<std::optional<std::list<ScalarIntConstantExpr>>>(x.t), + ")"); + } + void Unparse(const OmpApplyClause &x) { + 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) { 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..b05ae4d0d8946 100644 --- a/flang/lib/Semantics/check-omp-loop.cpp +++ b/flang/lib/Semantics/check-omp-loop.cpp @@ -869,6 +869,52 @@ 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::getLoopModifierName(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::OmpClause::Apply &x) { + EnterDirectiveNest(ApplyNest); + OmpVerifyModifiers( + x.v, llvm::omp::Clause::OMPC_apply, GetContext().clauseSource, context_); +} + +void OmpStructureChecker::Leave(const parser::OmpClause::Apply &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..97906e636298e 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::OmpClause::Apply &); + void Leave(const parser::OmpClause::Apply &); + 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/lib/Semantics/openmp-modifiers.cpp b/flang/lib/Semantics/openmp-modifiers.cpp index b6a6d476ceec6..fe8e087cd5a94 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, {}}, + }, + /*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 new file mode 100644 index 0000000000000..555ef769e22b3 --- /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: | | Modifier -> 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: | | 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: | | Modifier -> 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: | | 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: | | | | Modifier -> 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..e2160796bf40e --- /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: | | Modifier -> 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: | | Modifier -> 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: | | 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: | | | | Modifier -> 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 diff erent format for names of its directives enum. std::string getClangAccSpelling() const { StringRef Name = getSpellingForIdentifier(); 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),}, diff --git a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp index 55675fdec8448..93d83f909bfd2 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 getLoopModifierName(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"; @@ -384,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); @@ -416,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"; } @@ -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, @@ -1344,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 @@ -1360,6 +1413,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"); } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
