[flang-commits] [flang] 3b2fe66 - [Flang][OpenMP] add Apply clause for OpenMP Flang (#204225)
via flang-commits
flang-commits at lists.llvm.org
Thu Jul 9 08:51:42 PDT 2026
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 at +4{{extra tokens at the end of '#pragma omp tile' are ignored}}
- // omp60-error at +3{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}}
+ // omp60-warning at +3{{extra tokens at the end of '#pragma omp tile' are ignored}}
// omp51-error at +2{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}}
// omp51-warning at +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 at +4{{extra tokens at the end of '#pragma omp tile' are ignored}}
- // omp60-error at +3{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}}
+ // omp60-warning at +3{{extra tokens at the end of '#pragma omp tile' are ignored}}
// omp51-error at +2{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}}
// omp51-warning at +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 at +5{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}}
// omp60-warning at +4{{extra tokens at the end of '#pragma omp tile' are ignored}}
//omp51-error at +3{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}}
// omp51-warning at +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");
}
More information about the flang-commits
mailing list