[flang-commits] [flang] [llvm] [Flang][OpenMP] add Apply clause for OpenMP Flang (PR #204225)
Ferran Toda via flang-commits
flang-commits at lists.llvm.org
Fri Jun 19 07:16:37 PDT 2026
https://github.com/NouTimbaler updated https://github.com/llvm/llvm-project/pull/204225
>From 1b8fe1def9fc0160d4b2d660b13662af78943f35 Mon Sep 17 00:00:00 2001
From: Ferran Toda <ferran.todacasaban at bsc.es>
Date: Tue, 16 Jun 2026 17:42:05 +0000
Subject: [PATCH 1/5] apply parsing and basic checks
---
flang/include/flang/Parser/dump-parse-tree.h | 8 +
flang/include/flang/Parser/parse-tree.h | 29 ++++
flang/lib/Parser/openmp-parsers.cpp | 17 +++
flang/lib/Parser/unparse.cpp | 10 ++
flang/lib/Semantics/check-omp-loop.cpp | 45 ++++++
flang/lib/Semantics/check-omp-structure.h | 6 +
flang/lib/Semantics/check-omp-variant.cpp | 4 +-
flang/test/Parser/OpenMP/apply01.f90 | 137 ++++++++++++++++++
flang/test/Parser/OpenMP/apply02.f90 | 114 +++++++++++++++
flang/test/Semantics/OpenMP/apply01.f90 | 34 +++++
flang/test/Semantics/OpenMP/apply02.f90 | 34 +++++
.../llvm/Frontend/Directive/DirectiveBase.td | 24 +++
llvm/include/llvm/Frontend/OpenMP/OMP.td | 55 +++++++
llvm/include/llvm/TableGen/DirectiveEmitter.h | 12 ++
.../utils/TableGen/Basic/DirectiveEmitter.cpp | 60 +++++++-
15 files changed, 586 insertions(+), 3 deletions(-)
create mode 100644 flang/test/Parser/OpenMP/apply01.f90
create mode 100644 flang/test/Parser/OpenMP/apply02.f90
create mode 100644 flang/test/Semantics/OpenMP/apply01.f90
create mode 100644 flang/test/Semantics/OpenMP/apply02.f90
diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index 1205101c21fcf..b3e674603d4fa 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -556,6 +556,14 @@ class ParseTreeDumper {
NODE_ENUM(OmpAlwaysModifier, Value)
NODE(parser, OmpAppendArgsClause)
NODE(OmpAppendArgsClause, OmpAppendOp)
+ NODE(parser, OmpLoopModifier)
+
+ static std::string GetNodeName(const llvm::omp::LoopModifier &x) {
+ return llvm::Twine(
+ "llvm::omp::LoopModifier = ", llvm::omp::getOpenMPLoopModifierName(x))
+ .str();
+ }
+ NODE(parser, OmpApplyClause)
NODE(parser, OmpArgument)
NODE(parser, OmpArgumentList)
NODE(parser, OmpAssumeDirective)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index ee6288539395c..ea05c03d009f7 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -4353,6 +4353,24 @@ struct OmpxHoldModifier {
WRAPPER_CLASS_BOILERPLATE(OmpxHoldModifier, Value);
};
+// Ref: [6.0:372-373]
+//
+// loop-modifier ->
+// FLATTENED |
+// FUSED | GRID | IDENTITY |
+// INTERCHANGED |
+// INTRATILE | OFFSETS |
+// REVERSED | SPLIT |
+// UNROLLED
+// [( ScalarIntConstantExpr-list )]
+struct OmpLoopModifier {
+ TUPLE_CLASS_BOILERPLATE(OmpLoopModifier);
+ std::tuple<llvm::omp::LoopModifier,
+ std::optional<std::list<ScalarIntConstantExpr>>>
+ t;
+ CharBlock source;
+};
+
// context-selector
using OmpContextSelector = traits::OmpContextSelectorSpecification;
} // namespace modifier
@@ -4480,6 +4498,17 @@ struct OmpContainsClause {
WRAPPER_CLASS_BOILERPLATE(OmpContainsClause, OmpDirectiveList);
};
+// Ref: [6.0:372-373]
+//
+// apply-clause ->
+// APPLY( [loop-modifier :] directive-specification-list )
+struct OmpApplyClause {
+ TUPLE_CLASS_BOILERPLATE(OmpApplyClause);
+ std::tuple<std::optional<OmpLoopModifier>,
+ std::list<OmpDirectiveSpecification>>
+ t;
+};
+
// Ref: [4.5:46-50], [5.0:74-78], [5.1:92-96], [5.2:109]
//
// When used as a data-sharing clause:
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index 7016c688a572d..aedca5e582100 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -1101,6 +1101,18 @@ TYPE_PARSER(construct<OmpAdjustArgsClause::OmpAdjustOp>(
"NEED_DEVICE_PTR" >>
pure(OmpAdjustArgsClause::OmpAdjustOp::Value::Need_Device_Ptr)))
+TYPE_PARSER(sourced(construct<OmpLoopModifier>(
+ "FUSED" >> pure(llvm::omp::LoopModifier::OMPLM_fused) ||
+ "GRID" >> pure(llvm::omp::LoopModifier::OMPLM_grid) ||
+ "IDENTITY" >> pure(llvm::omp::LoopModifier::OMPLM_identity) ||
+ "INTERCHANGED" >> pure(llvm::omp::LoopModifier::OMPLM_interchanged) ||
+ "INTRATILE" >> pure(llvm::omp::LoopModifier::OMPLM_intratile) ||
+ "OFFSETS" >> pure(llvm::omp::LoopModifier::OMPLM_offsets) ||
+ "REVERSED" >> pure(llvm::omp::LoopModifier::OMPLM_reversed) ||
+ "SPLIT" >> pure(llvm::omp::LoopModifier::OMPLM_split) ||
+ "UNROLLED" >> pure(llvm::omp::LoopModifier::OMPLM_unrolled),
+ maybe(parenthesized(nonemptyList(scalarIntConstantExpr))))))
+
// --- Parsers for clauses --------------------------------------------
// Declaration of the ODS parser. This type must be complete for some of
@@ -1143,6 +1155,9 @@ TYPE_PARSER(construct<OmpAffinityClause>(
maybe(nonemptyList(Parser<OmpAffinityClause::Modifier>{}) / ":"),
Parser<OmpObjectList>{}))
+TYPE_PARSER(construct<OmpApplyClause>(maybe(Parser<OmpLoopModifier>{} / ":"),
+ nonemptyList(OmpDirectiveSpecificationParser(/*allowCommas=*/false))))
+
// 2.4 Requires construct [OpenMP 5.0]
// atomic-default-mem-order-clause ->
// acq_rel
@@ -1457,6 +1472,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 42f042e470e81..e1b02f4c70e8e 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2213,6 +2213,16 @@ class UnparseVisitor {
}
void Unparse(const OmpAppendArgsClause &x) { Walk(x.v, ","); }
void Unparse(const OmpArgumentList &x) { Walk(x.v, ", "); }
+ void Unparse(const OmpLoopModifier &x) {
+ Word(llvm::omp::getOpenMPLoopModifierName(
+ std::get<llvm::omp::LoopModifier>(x.t)));
+ Walk("(", std::get<std::optional<std::list<ScalarIntConstantExpr>>>(x.t),
+ ")");
+ }
+ void Unparse(const OmpApplyClause &x) {
+ Walk(std::get<std::optional<OmpLoopModifier>>(x.t), ": ");
+ Walk(std::get<std::list<OmpDirectiveSpecification>>(x.t));
+ }
void Unparse(const OmpAttachModifier &x) {
Word("ATTACH(");
Walk(x.v);
diff --git a/flang/lib/Semantics/check-omp-loop.cpp b/flang/lib/Semantics/check-omp-loop.cpp
index 689e3a0da89ca..99778afb4938e 100644
--- a/flang/lib/Semantics/check-omp-loop.cpp
+++ b/flang/lib/Semantics/check-omp-loop.cpp
@@ -879,6 +879,51 @@ void OmpStructureChecker::Enter(const parser::DoConstruct &x) {
constructStack_.push_back(&x);
}
+void OmpStructureChecker::Enter(const parser::OmpLoopModifier &x) {
+ DirectiveContext &dirCtx = GetContext();
+ llvm::omp::Directive dir{dirCtx.directive};
+ unsigned version{context_.langOptions().OpenMPVersion};
+ auto &m{std::get<llvm::omp::LoopModifier>(x.t)};
+ if (!llvm::omp::isAllowedLoopModifier(dir, m)) {
+ llvm::StringRef name = llvm::omp::getOpenMPLoopModifierName(m);
+ context_.Say(x.source,
+ "%s modifier is not allowed on %s directive"_err_en_US,
+ parser::ToUpperCaseLetters(name),
+ parser::omp::GetUpperName(dir, version));
+ }
+ if (const auto &il{
+ std::get<std::optional<std::list<parser::ScalarIntConstantExpr>>>(
+ x.t)}) {
+ int64_t last = -1;
+ for (auto &i : il.value()) {
+ if (const auto v{GetIntValue(i)}) {
+ if (*v <= 0) {
+ context_.Say(x.source,
+ "The loop modifier indexes of the %s clause must be constant positive integer expressions"_err_en_US,
+ parser::ToUpperCaseLetters(
+ getClauseName(llvm::omp::Clause::OMPC_apply).str()));
+ } else if (*v <= last) {
+ context_.Say(x.source,
+ "The loop modifier indexes of the %s clause must be in ascending order"_err_en_US,
+ parser::ToUpperCaseLetters(
+ getClauseName(llvm::omp::Clause::OMPC_apply).str()));
+ } else {
+ last = *v;
+ }
+ }
+ }
+ }
+}
+
+void OmpStructureChecker::Enter(const parser::OmpApplyClause &x) {
+ EnterDirectiveNest(ApplyNest);
+ CheckAllowedClause(llvm::omp::Clause::OMPC_apply);
+}
+
+void OmpStructureChecker::Leave(const parser::OmpApplyClause &x) {
+ ExitDirectiveNest(ApplyNest);
+}
+
void OmpStructureChecker::Leave(const parser::DoConstruct &x) {
assert(!constructStack_.empty() && "Expecting non-empty construct stack");
#ifndef NDEBUG
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 9fca5ff0f5fca..ea358430c1e2d 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -173,6 +173,11 @@ class OmpStructureChecker : public OmpStructureCheckerBase {
void Enter(const parser::OmpContextSelector &);
void Leave(const parser::OmpContextSelector &);
+ void Enter(const parser::OmpLoopModifier &);
+
+ void Enter(const parser::OmpApplyClause &);
+ void Leave(const parser::OmpApplyClause &);
+
template <typename A> void Enter(const parser::Statement<A> &);
void Leave(const parser::GotoStmt &);
void Leave(const parser::ComputedGotoStmt &);
@@ -399,6 +404,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 8ab160496b64a..1832acf687c24 100644
--- a/flang/lib/Semantics/check-omp-variant.cpp
+++ b/flang/lib/Semantics/check-omp-variant.cpp
@@ -549,7 +549,7 @@ void OmpStructureChecker::Enter(const parser::OmpDirectiveSpecification &x) {
// METADIRECTIVE.
// In other cases it's a part of other constructs that handle directive
// context stack by themselves.
- if (!GetDirectiveNest(MetadirectiveNest)) {
+ if (!GetDirectiveNest(MetadirectiveNest) && !GetDirectiveNest(ApplyNest)) {
return;
}
@@ -578,7 +578,7 @@ void OmpStructureChecker::Enter(const parser::OmpDirectiveSpecification &x) {
}
void OmpStructureChecker::Leave(const parser::OmpDirectiveSpecification &x) {
- if (GetDirectiveNest(MetadirectiveNest)) {
+ if (GetDirectiveNest(MetadirectiveNest) || GetDirectiveNest(ApplyNest)) {
dirContext_.pop_back();
}
}
diff --git a/flang/test/Parser/OpenMP/apply01.f90 b/flang/test/Parser/OpenMP/apply01.f90
new file mode 100644
index 0000000000000..c1c5d4be2d0eb
--- /dev/null
+++ b/flang/test/Parser/OpenMP/apply01.f90
@@ -0,0 +1,137 @@
+!RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=60 %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s
+!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=60 %s | FileCheck --check-prefix="PARSE-TREE" %s
+
+subroutine apply_1(x)
+ implicit none
+ integer :: x, i, j
+
+ !$omp interchange apply(nothing, reverse)
+ do i = 1,10
+ do j = 1,10
+ x = x + 1
+ end do
+ end do
+end
+
+!UNPARSE: !$OMP INTERCHANGE APPLY(NOTHING, REVERSE)
+!UNPARSE: DO i=1_4,10_4
+!UNPARSE: DO j=1_4,10_4
+!UNPARSE: x=x+1_4
+!UNPARSE: END DO
+!UNPARSE: END DO
+
+!PARSE-TREE: OmpBeginDirective
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = interchange
+!PARSE-TREE: | OmpClauseList -> OmpClause -> Apply -> OmpApplyClause
+!PARSE-TREE: | | OmpDirectiveSpecification
+!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = nothing
+!PARSE-TREE: | | | OmpClauseList ->
+!PARSE-TREE: | | | Flags = {}
+!PARSE-TREE: | | OmpDirectiveSpecification
+!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = reverse
+!PARSE-TREE: | | | OmpClauseList ->
+!PARSE-TREE: | | | Flags = {}
+
+subroutine apply_modifier(x)
+ implicit none
+ integer :: x, i
+
+ !$omp tile sizes(2) apply(grid: reverse)
+ do i = 1, 10
+ x = x + 1
+ end do
+end
+
+!UNPARSE: !$OMP TILE SIZES(2_4) APPLY(GRID: REVERSE)
+!UNPARSE: DO i=1_4,10_4
+!UNPARSE: x=x+1_4
+!UNPARSE: END DO
+
+!PARSE-TREE: OmpBeginDirective
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = tile
+!PARSE-TREE: | OmpClauseList -> OmpClause -> Sizes -> Scalar -> Integer -> Expr = '2_4'
+!PARSE-TREE: | | LiteralConstant -> IntLiteralConstant = '2'
+!PARSE-TREE: | OmpClause -> Apply -> OmpApplyClause
+!PARSE-TREE: | | OmpLoopModifier
+!PARSE-TREE: | | | llvm::omp::LoopModifier = grid
+!PARSE-TREE: | | OmpDirectiveSpecification
+!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = reverse
+!PARSE-TREE: | | | OmpClauseList ->
+!PARSE-TREE: | | | Flags = {}
+
+subroutine apply_2_clauses(x)
+ implicit none
+ integer :: x, i
+
+ !$omp tile sizes(2) apply(intratile: unroll) apply(grid: reverse)
+ do i = 1, 10
+ x = x + 1
+ end do
+end
+
+!UNPARSE: !$OMP TILE SIZES(2_4) APPLY(INTRATILE: UNROLL) APPLY(GRID: REVERSE)
+!UNPARSE: DO i=1_4,10_4
+!UNPARSE: x=x+1_4
+!UNPARSE: END DO
+
+!PARSE-TREE: OmpBeginDirective
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = tile
+!PARSE-TREE: | OmpClauseList -> OmpClause -> Sizes -> Scalar -> Integer -> Expr = '2_4'
+!PARSE-TREE: | | LiteralConstant -> IntLiteralConstant = '2'
+!PARSE-TREE: | OmpClause -> Apply -> OmpApplyClause
+!PARSE-TREE: | | OmpLoopModifier
+!PARSE-TREE: | | | llvm::omp::LoopModifier = intratile
+!PARSE-TREE: | | OmpDirectiveSpecification
+!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = unroll
+!PARSE-TREE: | | | OmpClauseList ->
+!PARSE-TREE: | | | Flags = {}
+!PARSE-TREE: | OmpClause -> Apply -> OmpApplyClause
+!PARSE-TREE: | | OmpLoopModifier
+!PARSE-TREE: | | | llvm::omp::LoopModifier = grid
+!PARSE-TREE: | | OmpDirectiveSpecification
+!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = reverse
+!PARSE-TREE: | | | OmpClauseList ->
+!PARSE-TREE: | | | Flags = {}
+
+
+subroutine apply_inside_apply(x)
+ implicit none
+ integer :: x, i, j
+
+ !$omp fuse apply(fused: tile sizes(2) apply(grid: reverse))
+ do i = 1, 10
+ x = x + 1
+ end do
+ do j = 1, 10
+ x = x - 1
+ end do
+ !$omp end fuse
+end
+
+!UNPARSE: !$OMP FUSE APPLY(FUSED: TILE SIZES(2_4) APPLY(GRID: REVERSE))
+!UNPARSE: DO i=1_4,10_4
+!UNPARSE: x=x+1_4
+!UNPARSE: END DO
+!UNPARSE: DO j=1_4,10_4
+!UNPARSE: x=x-1_4
+!UNPARSE: END DO
+!UNPARSE: !$OMP END FUSE
+
+!PARSE-TREE: OmpBeginDirective
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = fuse
+!PARSE-TREE: | OmpClauseList -> OmpClause -> Apply -> OmpApplyClause
+!PARSE-TREE: | | OmpLoopModifier
+!PARSE-TREE: | | | llvm::omp::LoopModifier = fused
+!PARSE-TREE: | | OmpDirectiveSpecification
+!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = tile
+!PARSE-TREE: | | | OmpClauseList -> OmpClause -> Sizes -> Scalar -> Integer -> Expr = '2_4'
+!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '2'
+!PARSE-TREE: | | | OmpClause -> Apply -> OmpApplyClause
+!PARSE-TREE: | | | | OmpLoopModifier
+!PARSE-TREE: | | | | | llvm::omp::LoopModifier = grid
+!PARSE-TREE: | | | | OmpDirectiveSpecification
+!PARSE-TREE: | | | | | OmpDirectiveName -> llvm::omp::Directive = reverse
+!PARSE-TREE: | | | | | OmpClauseList ->
+!PARSE-TREE: | | | | | Flags = {}
+!PARSE-TREE: | | | Flags = {}
+
diff --git a/flang/test/Parser/OpenMP/apply02.f90 b/flang/test/Parser/OpenMP/apply02.f90
new file mode 100644
index 0000000000000..803f0ac73d25a
--- /dev/null
+++ b/flang/test/Parser/OpenMP/apply02.f90
@@ -0,0 +1,114 @@
+!RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=60 %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s
+!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=60 %s | FileCheck --check-prefix="PARSE-TREE" %s
+
+subroutine apply_all(x)
+ implicit none
+ integer :: x, i, j
+
+ !$omp interchange apply(interchanged(1,2): nothing, reverse)
+ do i = 1,10
+ do j = 1,10
+ x = x + 1
+ end do
+ end do
+end
+
+!UNPARSE: !$OMP INTERCHANGE APPLY(INTERCHANGED(1_4, 2_4): NOTHING, REVERSE)
+!UNPARSE: DO i=1_4,10_4
+!UNPARSE: DO j=1_4,10_4
+!UNPARSE: x=x+1_4
+!UNPARSE: END DO
+!UNPARSE: END DO
+
+!PARSE-TREE: OmpBeginDirective
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = interchange
+!PARSE-TREE: | OmpClauseList -> OmpClause -> Apply -> OmpApplyClause
+!PARSE-TREE: | | OmpLoopModifier
+!PARSE-TREE: | | | llvm::omp::LoopModifier = interchanged
+!PARSE-TREE: | | | Scalar -> Integer -> Constant -> Expr = '1_4'
+!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '1'
+!PARSE-TREE: | | | Scalar -> Integer -> Constant -> Expr = '2_4'
+!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '2'
+!PARSE-TREE: | | OmpDirectiveSpecification
+!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = nothing
+!PARSE-TREE: | | | OmpClauseList ->
+!PARSE-TREE: | | | Flags = {}
+!PARSE-TREE: | | OmpDirectiveSpecification
+!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = reverse
+!PARSE-TREE: | | | OmpClauseList ->
+!PARSE-TREE: | | | Flags = {}
+
+subroutine apply_one(x)
+ implicit none
+ integer :: x, i, j
+
+ !$omp interchange apply(interchanged(2): reverse)
+ do i = 1,10
+ do j = 1,10
+ x = x + 1
+ end do
+ end do
+end
+
+!UNPARSE: !$OMP INTERCHANGE APPLY(INTERCHANGED(2_4): REVERSE)
+!UNPARSE: DO i=1_4,10_4
+!UNPARSE: DO j=1_4,10_4
+!UNPARSE: x=x+1_4
+!UNPARSE: END DO
+!UNPARSE: END DO
+
+!PARSE-TREE: OmpBeginDirective
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = interchange
+!PARSE-TREE: | OmpClauseList -> OmpClause -> Apply -> OmpApplyClause
+!PARSE-TREE: | | OmpLoopModifier
+!PARSE-TREE: | | | llvm::omp::LoopModifier = interchanged
+!PARSE-TREE: | | | Scalar -> Integer -> Constant -> Expr = '2_4'
+!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '2'
+!PARSE-TREE: | | OmpDirectiveSpecification
+!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = reverse
+!PARSE-TREE: | | | OmpClauseList ->
+!PARSE-TREE: | | | Flags = {}
+
+subroutine apply_inside_apply(x)
+ implicit none
+ integer :: x, i, j
+
+ !$omp tile sizes(2,2) apply(grid(1): interchange apply(interchanged(2): reverse))
+ do i = 1,10
+ do j = 1,10
+ x = x + 1
+ end do
+ end do
+end
+
+!UNPARSE: !$OMP TILE SIZES(2_4,2_4) APPLY(GRID(1_4): INTERCHANGE APPLY(INTERCHANGED(2_4): REVERSE))
+!UNPARSE: DO i=1_4,10_4
+!UNPARSE: DO j=1_4,10_4
+!UNPARSE: x=x+1_4
+!UNPARSE: END DO
+!UNPARSE: END DO
+
+!PARSE-TREE: OmpBeginDirective
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = tile
+!PARSE-TREE: | OmpClauseList -> OmpClause -> Sizes -> Scalar -> Integer -> Expr = '2_4'
+!PARSE-TREE: | | LiteralConstant -> IntLiteralConstant = '2'
+!PARSE-TREE: | Scalar -> Integer -> Expr = '2_4'
+!PARSE-TREE: | | LiteralConstant -> IntLiteralConstant = '2'
+!PARSE-TREE: | OmpClause -> Apply -> OmpApplyClause
+!PARSE-TREE: | | OmpLoopModifier
+!PARSE-TREE: | | | llvm::omp::LoopModifier = grid
+!PARSE-TREE: | | | Scalar -> Integer -> Constant -> Expr = '1_4'
+!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '1'
+!PARSE-TREE: | | OmpDirectiveSpecification
+!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = interchange
+!PARSE-TREE: | | | OmpClauseList -> OmpClause -> Apply -> OmpApplyClause
+!PARSE-TREE: | | | | OmpLoopModifier
+!PARSE-TREE: | | | | | llvm::omp::LoopModifier = interchanged
+!PARSE-TREE: | | | | | Scalar -> Integer -> Constant -> Expr = '2_4'
+!PARSE-TREE: | | | | | | LiteralConstant -> IntLiteralConstant = '2'
+!PARSE-TREE: | | | | OmpDirectiveSpecification
+!PARSE-TREE: | | | | | OmpDirectiveName -> llvm::omp::Directive = reverse
+!PARSE-TREE: | | | | | OmpClauseList ->
+!PARSE-TREE: | | | | | Flags = {}
+!PARSE-TREE: | | | Flags = {}
+
diff --git a/flang/test/Semantics/OpenMP/apply01.f90 b/flang/test/Semantics/OpenMP/apply01.f90
new file mode 100644
index 0000000000000..f146c4e7730d8
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/apply01.f90
@@ -0,0 +1,34 @@
+! Testing the Semantics of tile
+!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=60
+
+
+subroutine wrong_modifier(x)
+ implicit none
+ integer i, j, x
+
+ !ERROR: INTERCHANGED modifier is not allowed on TILE directive
+ !$omp tile sizes(2,2) apply(interchanged: nothing, reverse)
+ do i = 1, 10
+ do j = 1, 10
+ x = x + 1
+ end do
+ end do
+
+ !ERROR: INTERCHANGED modifier is not allowed on TILE directive
+ !ERROR: FUSED modifier is not allowed on TILE directive
+ !$omp tile sizes(2,2) apply(interchanged: nothing, reverse) apply(fused: reverse)
+ do i = 1, 10
+ do j = 1, 10
+ x = x + 1
+ end do
+ end do
+
+ !ERROR: INTRATILE modifier is not allowed on UNROLL directive
+ !$omp tile sizes(2,2) apply(grid: nothing, unroll partial(2) apply(intratile: reverse))
+ do i = 1, 10
+ do j = 1, 10
+ x = x + 1
+ end do
+ end do
+end subroutine
+
diff --git a/flang/test/Semantics/OpenMP/apply02.f90 b/flang/test/Semantics/OpenMP/apply02.f90
new file mode 100644
index 0000000000000..81fc436f96fe6
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/apply02.f90
@@ -0,0 +1,34 @@
+! Testing the Semantics of tile
+!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=60
+
+
+subroutine wrong_modifier(x)
+ implicit none
+ integer i, j, x
+
+ !ERROR: Must be a constant value
+ !$omp tile sizes(2,2) apply(grid(x): unroll)
+ do i = 1, 10
+ do j = 1, 10
+ x = x + 1
+ end do
+ end do
+
+ !ERROR: The loop modifier indexes of the APPLY clause must be constant positive integer expressions
+ !$omp tile sizes(2,2) apply(grid(-1): unroll)
+ do i = 1, 10
+ do j = 1, 10
+ x = x + 1
+ end do
+ end do
+
+ !ERROR: The loop modifier indexes of the APPLY clause must be in ascending order
+ !$omp tile sizes(2,2) apply(grid(2,1): unroll, nothing)
+ do i = 1, 10
+ do j = 1, 10
+ x = x + 1
+ end do
+ end do
+
+end subroutine
+
diff --git a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
index 2aa0649479023..56d5457481bc3 100644
--- a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
+++ b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
@@ -33,6 +33,10 @@ class DirectiveLanguage {
// enum.
string clausePrefix = "";
+ // Optional prefix used for the generation of the enumerator in the
+ // LoopModifier enum.
+ string loopModifierPrefix = "";
+
// Make the enum values available in the namespace. This allows us to
// write something like Enum_X if we have a `using namespace cppNamespace`.
bit makeEnumAvailableInNamespace = false;
@@ -201,6 +205,23 @@ class SourceLanguage<string n> {
def L_C : SourceLanguage<"C"> {}
def L_Fortran : SourceLanguage<"Fortran"> {}
+// Loop Modifier for Apply clause
+class LoopModifier<list<Spelling> ss> {
+ // Spellings of the loop modifer.
+ list<Spelling> spellings = ss;
+}
+
+def LM_Flattened: LoopModifier<[Spelling<"flattened">]> {}
+def LM_Fused: LoopModifier<[Spelling<"fused">]> {}
+def LM_Grid: LoopModifier<[Spelling<"grid">]> {}
+def LM_Identity: LoopModifier<[Spelling<"identity">]> {}
+def LM_Interchanged: LoopModifier<[Spelling<"interchanged">]> {}
+def LM_Intratile: LoopModifier<[Spelling<"intratile">]> {}
+def LM_Offsets: LoopModifier<[Spelling<"offsets">]> {}
+def LM_Reversed: LoopModifier<[Spelling<"reversed">]> {}
+def LM_Split: LoopModifier<[Spelling<"split">]> {}
+def LM_Unrolled: LoopModifier<[Spelling<"unrolled">]> {}
+
// Information about a specific directive.
class Directive<list<Spelling> ss> {
// Spellings of the directive.
@@ -235,6 +256,9 @@ class Directive<list<Spelling> ss> {
// The category of the directive.
Category category = ?;
+ // List of allowed loop modifiers for the apply clause.
+ list<LoopModifier> allowedLoopModifiers = [];
+
// The languages that allow this directive. Default: all languages.
list<SourceLanguage> languages = [L_C, L_Fortran];
}
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index e1e66df72dfc5..11a0354ba54f6 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";
@@ -939,6 +941,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 = [
@@ -980,19 +985,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 = [
@@ -1043,8 +1060,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 = [
@@ -1100,8 +1123,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 allowedClauses = [
@@ -1409,6 +1438,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>,
];
@@ -1417,15 +1449,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>,
];
@@ -1434,6 +1480,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;
@@ -1441,12 +1490,18 @@ def OMP_Unknown : Directive<[Spelling<"unknown">]> {
let category = CA_Utility;
}
def OMP_Unroll : Directive<[Spelling<"unroll">]> {
+ let allowedClauses = [
+ VersionedClause<OMPC_Apply, 60>,
+ ];
let allowedOnceClauses = [
VersionedClause<OMPC_Full, 51>,
VersionedClause<OMPC_Partial, 51>,
];
let association = AS_LoopNest;
let category = CA_Executable;
+ let allowedLoopModifiers = [
+ LM_Unrolled,
+ ];
}
def OMP_Workshare : Directive<[Spelling<"workshare">]> {
let allowedOnceClauses = [
diff --git a/llvm/include/llvm/TableGen/DirectiveEmitter.h b/llvm/include/llvm/TableGen/DirectiveEmitter.h
index 2080f75eb8cfc..d111f666ff31a 100644
--- a/llvm/include/llvm/TableGen/DirectiveEmitter.h
+++ b/llvm/include/llvm/TableGen/DirectiveEmitter.h
@@ -48,6 +48,10 @@ class DirectiveLanguage {
return Def->getValueAsString("clausePrefix");
}
+ StringRef getLoopModifierPrefix() const {
+ return Def->getValueAsString("loopModifierPrefix");
+ }
+
StringRef getClauseEnumSetClass() const {
return Def->getValueAsString("clauseEnumSetClass");
}
@@ -84,6 +88,10 @@ class DirectiveLanguage {
return Records.getAllDerivedDefinitions("Clause");
}
+ ArrayRef<const Record *> getLoopModifiers() const {
+ return Records.getAllDerivedDefinitions("LoopModifier");
+ }
+
bool HasValidityErrors() const;
private:
@@ -262,6 +270,10 @@ class Directive : public BaseRecord {
return Def->getValueAsListOfDefs("languages");
}
+ std::vector<const Record *> getAllowedLoopModifiers() const {
+ return Def->getValueAsListOfDefs("allowedLoopModifiers");
+ }
+
// Clang uses a different format for names of its directives enum.
std::string getClangAccSpelling() const {
StringRef Name = getSpellingForIdentifier();
diff --git a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
index e091cda694f99..07157fc23a9ab 100644
--- a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
@@ -311,6 +311,11 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
DirLang.getClausePrefix(),
DirLang.hasMakeEnumAvailableInNamespace());
+ // Emit LoopModifier
+ generateEnumClass(DirLang.getLoopModifiers(), OS, "LoopModifier",
+ DirLang.getLoopModifierPrefix(),
+ DirLang.hasMakeEnumAvailableInNamespace());
+
// Emit ClauseVals enumeration
std::string EnumHelperFuncs;
generateClauseEnumVal(DirLang.getClauses(), OS, DirLang, EnumHelperFuncs);
@@ -354,11 +359,16 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
OS << "\n";
OS << "constexpr std::size_t getMaxLeafCount() { return "
<< getMaxLeafCount(DirLang) << "; }\n";
+ OS << "LLVM_ABI bool isAllowedLoopModifier(Directive D, LoopModifier "
+ "LM);\n";
+ OS << "LLVM_ABI StringRef get" << Lang
+ << "LoopModifierName(LoopModifier LM, unsigned Ver = 0);\n";
OS << EnumHelperFuncs;
} // close DirLangNS
// These specializations need to be in ::llvm.
- for (StringRef Enum : {"Association", "Category", "Directive", "Clause"}) {
+ for (StringRef Enum :
+ {"Association", "Category", "Directive", "Clause", "LoopModifier"}) {
OS << "\n";
OS << "template <> struct enum_iteration_traits<"
<< DirLang.getCppNamespace() << "::" << Enum << "> {\n";
@@ -909,6 +919,47 @@ static void generateGetDirectiveLanguages(const DirectiveLanguage &DirLang,
OS << "}\n";
}
+// Generate the isAllowedLoopModifier function implementation.
+static void generateIsAllowedLoopModifier(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
+ std::string Qual = getQualifier(DirLang);
+
+ OS << "\n";
+ OS << "bool " << Qual << "isAllowedLoopModifier(" << Qual << "Directive D, "
+ << Qual << "LoopModifier LM) {\n";
+ OS << " assert(unsigned(D) <= Directive_enumSize);\n";
+
+ OS << " switch (D) {\n";
+
+ StringRef DPrefix = DirLang.getDirectivePrefix();
+ StringRef LMPrefix = DirLang.getLoopModifierPrefix();
+ for (const Record *R : DirLang.getDirectives()) {
+ Directive Dir(R);
+ OS << " case " << getIdentifierName(R, DPrefix) << ":\n";
+ if (Dir.getAllowedLoopModifiers().empty()) {
+ OS << " return false;\n";
+ } else {
+ OS << " switch (LM) {\n";
+
+ for (const Record *LMR : Dir.getAllowedLoopModifiers()) {
+ std::string Name = getIdentifierName(LMR, LMPrefix);
+ OS << " case LoopModifier::" << Name << ":\n";
+ OS << " return true;\n";
+ }
+
+ OS << " default:\n";
+ OS << " return false;\n";
+ OS << " }\n"; // End of modifier switch
+ }
+ OS << " break;\n";
+ }
+
+ OS << " }\n"; // End of directives switch
+ OS << " llvm_unreachable(\"Invalid " << DirLang.getName()
+ << " Directive kind\");\n";
+ OS << "}\n"; // End of function isAllowedLoopModifier
+}
+
// Generate a simple enum set with the give clauses.
static void generateClauseSet(ArrayRef<const Record *> VerClauses,
raw_ostream &OS, StringRef ClauseSetPrefix,
@@ -1360,6 +1411,13 @@ void emitDirectivesBasicImpl(const DirectiveLanguage &DirLang,
// isAllowedClauseForDirective(Directive D, Clause C, unsigned Version)
generateIsAllowedClause(DirLang, OS);
+ // isAllowedLoopModifier(Directive D, LoopModifier LM)
+ generateIsAllowedLoopModifier(DirLang, OS);
+
+ // getLoopModifierName(LoopModifier Kind)
+ generateGetName(DirLang.getLoopModifiers(), OS, "LoopModifier", DirLang,
+ DirLang.getLoopModifierPrefix());
+
// Leaf table for getLeafConstructs, etc.
emitLeafTable(DirLang, OS, "LeafConstructTable");
}
>From 1c4fb4e98a1c069b9b1cb4815223ae3d8eba90b5 Mon Sep 17 00:00:00 2001
From: Ferran Toda <ferran.todacasaban at bsc.es>
Date: Wed, 17 Jun 2026 14:05:23 +0000
Subject: [PATCH 2/5] remove lang name from function
---
flang/include/flang/Parser/dump-parse-tree.h | 2 +-
flang/lib/Parser/unparse.cpp | 4 ++--
flang/lib/Semantics/check-omp-loop.cpp | 2 +-
.../utils/TableGen/Basic/DirectiveEmitter.cpp | 22 ++++++++++---------
4 files changed, 16 insertions(+), 14 deletions(-)
diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index b3e674603d4fa..d895b9bb53d70 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -560,7 +560,7 @@ class ParseTreeDumper {
static std::string GetNodeName(const llvm::omp::LoopModifier &x) {
return llvm::Twine(
- "llvm::omp::LoopModifier = ", llvm::omp::getOpenMPLoopModifierName(x))
+ "llvm::omp::LoopModifier = ", llvm::omp::getLoopModifierName(x))
.str();
}
NODE(parser, OmpApplyClause)
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index e1b02f4c70e8e..05b9de704d5b6 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2214,8 +2214,8 @@ class UnparseVisitor {
void Unparse(const OmpAppendArgsClause &x) { Walk(x.v, ","); }
void Unparse(const OmpArgumentList &x) { Walk(x.v, ", "); }
void Unparse(const OmpLoopModifier &x) {
- Word(llvm::omp::getOpenMPLoopModifierName(
- std::get<llvm::omp::LoopModifier>(x.t)));
+ Word(
+ llvm::omp::getLoopModifierName(std::get<llvm::omp::LoopModifier>(x.t)));
Walk("(", std::get<std::optional<std::list<ScalarIntConstantExpr>>>(x.t),
")");
}
diff --git a/flang/lib/Semantics/check-omp-loop.cpp b/flang/lib/Semantics/check-omp-loop.cpp
index 99778afb4938e..009ea6acfd6e6 100644
--- a/flang/lib/Semantics/check-omp-loop.cpp
+++ b/flang/lib/Semantics/check-omp-loop.cpp
@@ -885,7 +885,7 @@ void OmpStructureChecker::Enter(const parser::OmpLoopModifier &x) {
unsigned version{context_.langOptions().OpenMPVersion};
auto &m{std::get<llvm::omp::LoopModifier>(x.t)};
if (!llvm::omp::isAllowedLoopModifier(dir, m)) {
- llvm::StringRef name = llvm::omp::getOpenMPLoopModifierName(m);
+ llvm::StringRef name = llvm::omp::getLoopModifierName(m);
context_.Say(x.source,
"%s modifier is not allowed on %s directive"_err_en_US,
parser::ToUpperCaseLetters(name),
diff --git a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
index 07157fc23a9ab..20fb878f08ec6 100644
--- a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
@@ -361,8 +361,8 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
<< getMaxLeafCount(DirLang) << "; }\n";
OS << "LLVM_ABI bool isAllowedLoopModifier(Directive D, LoopModifier "
"LM);\n";
- OS << "LLVM_ABI StringRef get" << Lang
- << "LoopModifierName(LoopModifier LM, unsigned Ver = 0);\n";
+ OS << "LLVM_ABI StringRef getLoopModifierName(LoopModifier LM, unsigned "
+ "Ver = 0);\n";
OS << EnumHelperFuncs;
} // close DirLangNS
@@ -394,12 +394,11 @@ orderSpellings(ArrayRef<Spelling::Value> Spellings) {
// Generate function implementation for get<Enum>Name(StringRef Str)
static void generateGetName(ArrayRef<const Record *> Records, raw_ostream &OS,
StringRef Enum, const DirectiveLanguage &DirLang,
- StringRef Prefix) {
- StringRef Lang = DirLang.getName();
+ StringRef LangName, StringRef Prefix) {
std::string Qual = getQualifier(DirLang);
OS << "\n";
- OS << "llvm::StringRef " << Qual << "get" << Lang << Enum << "Name(" << Qual
- << Enum << " Kind, unsigned Version) {\n";
+ OS << "llvm::StringRef " << Qual << "get" << LangName << Enum << "Name("
+ << Qual << Enum << " Kind, unsigned Version) {\n";
OS << " switch (Kind) {\n";
for (const Record *R : Records) {
BaseRecord Rec(R);
@@ -426,7 +425,8 @@ static void generateGetName(ArrayRef<const Record *> Records, raw_ostream &OS,
}
}
OS << " }\n"; // switch
- OS << " llvm_unreachable(\"Invalid " << Lang << " " << Enum << " kind\");\n";
+ OS << " llvm_unreachable(\"Invalid " << LangName << " " << Enum
+ << " kind\");\n";
OS << "}\n";
}
@@ -1395,14 +1395,16 @@ void emitDirectivesBasicImpl(const DirectiveLanguage &DirLang,
/*ImplicitAsUnknown=*/false);
// getDirectiveName(Directive Kind)
- generateGetName(DirLang.getDirectives(), OS, "Directive", DirLang, DPrefix);
+ generateGetName(DirLang.getDirectives(), OS, "Directive", DirLang,
+ DirLang.getName(), DPrefix);
// getClauseKind(StringRef Str)
generateGetKind(DirLang.getClauses(), OS, "Clause", DirLang, CPrefix,
/*ImplicitAsUnknown=*/true);
// getClauseName(Clause Kind)
- generateGetName(DirLang.getClauses(), OS, "Clause", DirLang, CPrefix);
+ generateGetName(DirLang.getClauses(), OS, "Clause", DirLang,
+ DirLang.getName(), CPrefix);
// <enumClauseValue> get<enumClauseValue>(StringRef Str) ; string -> value
// StringRef get<enumClauseValue>Name(<enumClauseValue>) ; value -> string
@@ -1415,7 +1417,7 @@ void emitDirectivesBasicImpl(const DirectiveLanguage &DirLang,
generateIsAllowedLoopModifier(DirLang, OS);
// getLoopModifierName(LoopModifier Kind)
- generateGetName(DirLang.getLoopModifiers(), OS, "LoopModifier", DirLang,
+ generateGetName(DirLang.getLoopModifiers(), OS, "LoopModifier", DirLang, "",
DirLang.getLoopModifierPrefix());
// Leaf table for getLeafConstructs, etc.
>From ff7686d1f09b567455049bb7d313c9c295d7c3b4 Mon Sep 17 00:00:00 2001
From: Ferran Toda <ferran.todacasaban at bsc.es>
Date: Thu, 18 Jun 2026 15:30:49 +0000
Subject: [PATCH 3/5] using modifier mechanisms
---
flang/include/flang/Parser/dump-parse-tree.h | 1 +
flang/include/flang/Parser/parse-tree.h | 39 ++++++++++---------
.../flang/Semantics/openmp-modifiers.h | 3 +-
flang/lib/Parser/openmp-parsers.cpp | 4 +-
flang/lib/Parser/unparse.cpp | 3 +-
flang/lib/Semantics/check-omp-loop.cpp | 5 ++-
flang/lib/Semantics/check-omp-structure.cpp | 1 -
flang/lib/Semantics/check-omp-structure.h | 3 +-
flang/lib/Semantics/openmp-modifiers.cpp | 16 ++++++++
flang/test/Parser/OpenMP/apply01.f90 | 10 ++---
flang/test/Parser/OpenMP/apply02.f90 | 8 ++--
11 files changed, 57 insertions(+), 36 deletions(-)
diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index d895b9bb53d70..ef8680ad93d8d 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -564,6 +564,7 @@ class ParseTreeDumper {
.str();
}
NODE(parser, OmpApplyClause)
+ NODE(OmpApplyClause, Modifier)
NODE(parser, OmpArgument)
NODE(parser, OmpArgumentList)
NODE(parser, OmpAssumeDirective)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index ea05c03d009f7..9fa9cb7cd2772 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -4150,6 +4150,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 ->
@@ -4353,24 +4371,6 @@ struct OmpxHoldModifier {
WRAPPER_CLASS_BOILERPLATE(OmpxHoldModifier, Value);
};
-// Ref: [6.0:372-373]
-//
-// loop-modifier ->
-// FLATTENED |
-// FUSED | GRID | IDENTITY |
-// INTERCHANGED |
-// INTRATILE | OFFSETS |
-// REVERSED | SPLIT |
-// UNROLLED
-// [( ScalarIntConstantExpr-list )]
-struct OmpLoopModifier {
- TUPLE_CLASS_BOILERPLATE(OmpLoopModifier);
- std::tuple<llvm::omp::LoopModifier,
- std::optional<std::list<ScalarIntConstantExpr>>>
- t;
- CharBlock source;
-};
-
// context-selector
using OmpContextSelector = traits::OmpContextSelectorSpecification;
} // namespace modifier
@@ -4504,7 +4504,8 @@ struct OmpContainsClause {
// APPLY( [loop-modifier :] directive-specification-list )
struct OmpApplyClause {
TUPLE_CLASS_BOILERPLATE(OmpApplyClause);
- std::tuple<std::optional<OmpLoopModifier>,
+ MODIFIER_BOILERPLATE(OmpLoopModifier);
+ std::tuple<MODIFIERS(),
std::list<OmpDirectiveSpecification>>
t;
};
diff --git a/flang/include/flang/Semantics/openmp-modifiers.h b/flang/include/flang/Semantics/openmp-modifiers.h
index 8dcac9b179924..1e549c288925b 100644
--- a/flang/include/flang/Semantics/openmp-modifiers.h
+++ b/flang/include/flang/Semantics/openmp-modifiers.h
@@ -44,7 +44,7 @@ namespace Fortran::semantics {
// or post-modifier (i.e. item: modifier). The default is pre-.
// Add an additional property that reflects the type of modifier.
-ENUM_CLASS(OmpProperty, Required, Unique, Exclusive, Ultimate, Post)
+ENUM_CLASS(OmpProperty, Required, Unique, Exclusive, Ultimate, Post, Optional)
using OmpProperties = common::EnumSet<OmpProperty, OmpProperty_enumSize>;
using OmpClauses =
common::EnumSet<llvm::omp::Clause, llvm::omp::Clause_enumSize>;
@@ -90,6 +90,7 @@ DECLARE_DESCRIPTOR(parser::OmpInteropType);
DECLARE_DESCRIPTOR(parser::OmpIterator);
DECLARE_DESCRIPTOR(parser::OmpLastprivateModifier);
DECLARE_DESCRIPTOR(parser::OmpLinearModifier);
+DECLARE_DESCRIPTOR(parser::OmpLoopModifier);
DECLARE_DESCRIPTOR(parser::OmpLowerBound);
DECLARE_DESCRIPTOR(parser::OmpMapper);
DECLARE_DESCRIPTOR(parser::OmpMapType);
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index aedca5e582100..4615067af7d80 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -1101,6 +1101,8 @@ TYPE_PARSER(construct<OmpAdjustArgsClause::OmpAdjustOp>(
"NEED_DEVICE_PTR" >>
pure(OmpAdjustArgsClause::OmpAdjustOp::Value::Need_Device_Ptr)))
+TYPE_PARSER(construct<OmpApplyClause::Modifier>(Parser<OmpLoopModifier>{}))
+
TYPE_PARSER(sourced(construct<OmpLoopModifier>(
"FUSED" >> pure(llvm::omp::LoopModifier::OMPLM_fused) ||
"GRID" >> pure(llvm::omp::LoopModifier::OMPLM_grid) ||
@@ -1155,7 +1157,7 @@ TYPE_PARSER(construct<OmpAffinityClause>(
maybe(nonemptyList(Parser<OmpAffinityClause::Modifier>{}) / ":"),
Parser<OmpObjectList>{}))
-TYPE_PARSER(construct<OmpApplyClause>(maybe(Parser<OmpLoopModifier>{} / ":"),
+TYPE_PARSER(construct<OmpApplyClause>(maybe(nonemptyList(Parser<OmpApplyClause::Modifier>{} / ":")),
nonemptyList(OmpDirectiveSpecificationParser(/*allowCommas=*/false))))
// 2.4 Requires construct [OpenMP 5.0]
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 05b9de704d5b6..2b15666962a67 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2220,7 +2220,8 @@ class UnparseVisitor {
")");
}
void Unparse(const OmpApplyClause &x) {
- Walk(std::get<std::optional<OmpLoopModifier>>(x.t), ": ");
+ using Modifier = OmpApplyClause::Modifier;
+ Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");
Walk(std::get<std::list<OmpDirectiveSpecification>>(x.t));
}
void Unparse(const OmpAttachModifier &x) {
diff --git a/flang/lib/Semantics/check-omp-loop.cpp b/flang/lib/Semantics/check-omp-loop.cpp
index 009ea6acfd6e6..95d55c7b94c71 100644
--- a/flang/lib/Semantics/check-omp-loop.cpp
+++ b/flang/lib/Semantics/check-omp-loop.cpp
@@ -915,12 +915,13 @@ void OmpStructureChecker::Enter(const parser::OmpLoopModifier &x) {
}
}
-void OmpStructureChecker::Enter(const parser::OmpApplyClause &x) {
+void OmpStructureChecker::Enter(const parser::OmpClause::Apply &x) {
EnterDirectiveNest(ApplyNest);
CheckAllowedClause(llvm::omp::Clause::OMPC_apply);
+ OmpVerifyModifiers(x.v, llvm::omp::Clause::OMPC_apply, GetContext().clauseSource, context_);
}
-void OmpStructureChecker::Leave(const parser::OmpApplyClause &x) {
+void OmpStructureChecker::Leave(const parser::OmpClause::Apply &x) {
ExitDirectiveNest(ApplyNest);
}
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 7c531ae0046ae..be959bd3d5f5f 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -5972,7 +5972,6 @@ CHECK_SIMPLE_CLAUSE(AcqRel, OMPC_acq_rel)
CHECK_SIMPLE_CLAUSE(Acquire, OMPC_acquire)
CHECK_SIMPLE_CLAUSE(AdjustArgs, OMPC_adjust_args)
CHECK_SIMPLE_CLAUSE(AppendArgs, OMPC_append_args)
-CHECK_SIMPLE_CLAUSE(Apply, OMPC_apply)
CHECK_SIMPLE_CLAUSE(Bind, OMPC_bind)
CHECK_SIMPLE_CLAUSE(Capture, OMPC_capture)
CHECK_SIMPLE_CLAUSE(Collector, OMPC_collector)
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index ea358430c1e2d..a9aec01af354e 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -175,8 +175,7 @@ class OmpStructureChecker : public OmpStructureCheckerBase {
void Enter(const parser::OmpLoopModifier &);
- void Enter(const parser::OmpApplyClause &);
- void Leave(const parser::OmpApplyClause &);
+ void Leave(const parser::OmpClause::Apply &);
template <typename A> void Enter(const parser::Statement<A> &);
void Leave(const parser::GotoStmt &);
diff --git a/flang/lib/Semantics/openmp-modifiers.cpp b/flang/lib/Semantics/openmp-modifiers.cpp
index b6a6d476ceec6..c261240480f63 100644
--- a/flang/lib/Semantics/openmp-modifiers.cpp
+++ b/flang/lib/Semantics/openmp-modifiers.cpp
@@ -456,6 +456,22 @@ const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpLinearModifier>() {
return desc;
}
+template <>
+const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpLoopModifier>() {
+ static const OmpModifierDescriptor desc{
+ /*name=*/"loop-modifier",
+ /*props=*/
+ {
+ {60, {OmpProperty::Optional}},
+ },
+ /*clauses=*/
+ {
+ {60, {Clause::OMPC_apply}},
+ },
+ };
+ return desc;
+}
+
template <>
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpLowerBound>() {
static const OmpModifierDescriptor desc{
diff --git a/flang/test/Parser/OpenMP/apply01.f90 b/flang/test/Parser/OpenMP/apply01.f90
index c1c5d4be2d0eb..555ef769e22b3 100644
--- a/flang/test/Parser/OpenMP/apply01.f90
+++ b/flang/test/Parser/OpenMP/apply01.f90
@@ -52,7 +52,7 @@ subroutine apply_modifier(x)
!PARSE-TREE: | OmpClauseList -> OmpClause -> Sizes -> Scalar -> Integer -> Expr = '2_4'
!PARSE-TREE: | | LiteralConstant -> IntLiteralConstant = '2'
!PARSE-TREE: | OmpClause -> Apply -> OmpApplyClause
-!PARSE-TREE: | | OmpLoopModifier
+!PARSE-TREE: | | Modifier -> OmpLoopModifier
!PARSE-TREE: | | | llvm::omp::LoopModifier = grid
!PARSE-TREE: | | OmpDirectiveSpecification
!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = reverse
@@ -79,14 +79,14 @@ subroutine apply_2_clauses(x)
!PARSE-TREE: | OmpClauseList -> OmpClause -> Sizes -> Scalar -> Integer -> Expr = '2_4'
!PARSE-TREE: | | LiteralConstant -> IntLiteralConstant = '2'
!PARSE-TREE: | OmpClause -> Apply -> OmpApplyClause
-!PARSE-TREE: | | OmpLoopModifier
+!PARSE-TREE: | | Modifier -> OmpLoopModifier
!PARSE-TREE: | | | llvm::omp::LoopModifier = intratile
!PARSE-TREE: | | OmpDirectiveSpecification
!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = unroll
!PARSE-TREE: | | | OmpClauseList ->
!PARSE-TREE: | | | Flags = {}
!PARSE-TREE: | OmpClause -> Apply -> OmpApplyClause
-!PARSE-TREE: | | OmpLoopModifier
+!PARSE-TREE: | | Modifier -> OmpLoopModifier
!PARSE-TREE: | | | llvm::omp::LoopModifier = grid
!PARSE-TREE: | | OmpDirectiveSpecification
!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = reverse
@@ -120,14 +120,14 @@ subroutine apply_inside_apply(x)
!PARSE-TREE: OmpBeginDirective
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = fuse
!PARSE-TREE: | OmpClauseList -> OmpClause -> Apply -> OmpApplyClause
-!PARSE-TREE: | | OmpLoopModifier
+!PARSE-TREE: | | Modifier -> OmpLoopModifier
!PARSE-TREE: | | | llvm::omp::LoopModifier = fused
!PARSE-TREE: | | OmpDirectiveSpecification
!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = tile
!PARSE-TREE: | | | OmpClauseList -> OmpClause -> Sizes -> Scalar -> Integer -> Expr = '2_4'
!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '2'
!PARSE-TREE: | | | OmpClause -> Apply -> OmpApplyClause
-!PARSE-TREE: | | | | OmpLoopModifier
+!PARSE-TREE: | | | | Modifier -> OmpLoopModifier
!PARSE-TREE: | | | | | llvm::omp::LoopModifier = grid
!PARSE-TREE: | | | | OmpDirectiveSpecification
!PARSE-TREE: | | | | | OmpDirectiveName -> llvm::omp::Directive = reverse
diff --git a/flang/test/Parser/OpenMP/apply02.f90 b/flang/test/Parser/OpenMP/apply02.f90
index 803f0ac73d25a..e2160796bf40e 100644
--- a/flang/test/Parser/OpenMP/apply02.f90
+++ b/flang/test/Parser/OpenMP/apply02.f90
@@ -23,7 +23,7 @@ subroutine apply_all(x)
!PARSE-TREE: OmpBeginDirective
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = interchange
!PARSE-TREE: | OmpClauseList -> OmpClause -> Apply -> OmpApplyClause
-!PARSE-TREE: | | OmpLoopModifier
+!PARSE-TREE: | | Modifier -> OmpLoopModifier
!PARSE-TREE: | | | llvm::omp::LoopModifier = interchanged
!PARSE-TREE: | | | Scalar -> Integer -> Constant -> Expr = '1_4'
!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '1'
@@ -60,7 +60,7 @@ subroutine apply_one(x)
!PARSE-TREE: OmpBeginDirective
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = interchange
!PARSE-TREE: | OmpClauseList -> OmpClause -> Apply -> OmpApplyClause
-!PARSE-TREE: | | OmpLoopModifier
+!PARSE-TREE: | | Modifier -> OmpLoopModifier
!PARSE-TREE: | | | llvm::omp::LoopModifier = interchanged
!PARSE-TREE: | | | Scalar -> Integer -> Constant -> Expr = '2_4'
!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '2'
@@ -95,14 +95,14 @@ subroutine apply_inside_apply(x)
!PARSE-TREE: | Scalar -> Integer -> Expr = '2_4'
!PARSE-TREE: | | LiteralConstant -> IntLiteralConstant = '2'
!PARSE-TREE: | OmpClause -> Apply -> OmpApplyClause
-!PARSE-TREE: | | OmpLoopModifier
+!PARSE-TREE: | | Modifier -> OmpLoopModifier
!PARSE-TREE: | | | llvm::omp::LoopModifier = grid
!PARSE-TREE: | | | Scalar -> Integer -> Constant -> Expr = '1_4'
!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '1'
!PARSE-TREE: | | OmpDirectiveSpecification
!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = interchange
!PARSE-TREE: | | | OmpClauseList -> OmpClause -> Apply -> OmpApplyClause
-!PARSE-TREE: | | | | OmpLoopModifier
+!PARSE-TREE: | | | | Modifier -> OmpLoopModifier
!PARSE-TREE: | | | | | llvm::omp::LoopModifier = interchanged
!PARSE-TREE: | | | | | Scalar -> Integer -> Constant -> Expr = '2_4'
!PARSE-TREE: | | | | | | LiteralConstant -> IntLiteralConstant = '2'
>From 71bd484d147b5bcf4c673a183b34450b2dd46e18 Mon Sep 17 00:00:00 2001
From: Ferran Toda <ferran.todacasaban at bsc.es>
Date: Fri, 19 Jun 2026 14:14:35 +0000
Subject: [PATCH 4/5] format
---
flang/include/flang/Parser/parse-tree.h | 4 +---
flang/lib/Parser/openmp-parsers.cpp | 3 ++-
flang/lib/Semantics/check-omp-loop.cpp | 3 ++-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 9fa9cb7cd2772..8c398fa1c4606 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -4505,9 +4505,7 @@ struct OmpContainsClause {
struct OmpApplyClause {
TUPLE_CLASS_BOILERPLATE(OmpApplyClause);
MODIFIER_BOILERPLATE(OmpLoopModifier);
- std::tuple<MODIFIERS(),
- std::list<OmpDirectiveSpecification>>
- t;
+ std::tuple<MODIFIERS(), std::list<OmpDirectiveSpecification>> t;
};
// Ref: [4.5:46-50], [5.0:74-78], [5.1:92-96], [5.2:109]
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index 4615067af7d80..05b4d5cf46f79 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -1157,7 +1157,8 @@ TYPE_PARSER(construct<OmpAffinityClause>(
maybe(nonemptyList(Parser<OmpAffinityClause::Modifier>{}) / ":"),
Parser<OmpObjectList>{}))
-TYPE_PARSER(construct<OmpApplyClause>(maybe(nonemptyList(Parser<OmpApplyClause::Modifier>{} / ":")),
+TYPE_PARSER(construct<OmpApplyClause>(
+ maybe(nonemptyList(Parser<OmpApplyClause::Modifier>{} / ":")),
nonemptyList(OmpDirectiveSpecificationParser(/*allowCommas=*/false))))
// 2.4 Requires construct [OpenMP 5.0]
diff --git a/flang/lib/Semantics/check-omp-loop.cpp b/flang/lib/Semantics/check-omp-loop.cpp
index 95d55c7b94c71..b4bfa6bae3db6 100644
--- a/flang/lib/Semantics/check-omp-loop.cpp
+++ b/flang/lib/Semantics/check-omp-loop.cpp
@@ -918,7 +918,8 @@ void OmpStructureChecker::Enter(const parser::OmpLoopModifier &x) {
void OmpStructureChecker::Enter(const parser::OmpClause::Apply &x) {
EnterDirectiveNest(ApplyNest);
CheckAllowedClause(llvm::omp::Clause::OMPC_apply);
- OmpVerifyModifiers(x.v, llvm::omp::Clause::OMPC_apply, GetContext().clauseSource, context_);
+ OmpVerifyModifiers(
+ x.v, llvm::omp::Clause::OMPC_apply, GetContext().clauseSource, context_);
}
void OmpStructureChecker::Leave(const parser::OmpClause::Apply &x) {
>From ea08d4e7d84b20ae5260e5963c692e1d7b247e49 Mon Sep 17 00:00:00 2001
From: Ferran Toda <ferran.todacasaban at bsc.es>
Date: Fri, 19 Jun 2026 14:15:41 +0000
Subject: [PATCH 5/5] remove optional property
---
flang/include/flang/Semantics/openmp-modifiers.h | 2 +-
flang/lib/Semantics/openmp-modifiers.cpp | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/flang/include/flang/Semantics/openmp-modifiers.h b/flang/include/flang/Semantics/openmp-modifiers.h
index 1e549c288925b..66a4f3319c4d1 100644
--- a/flang/include/flang/Semantics/openmp-modifiers.h
+++ b/flang/include/flang/Semantics/openmp-modifiers.h
@@ -44,7 +44,7 @@ namespace Fortran::semantics {
// or post-modifier (i.e. item: modifier). The default is pre-.
// Add an additional property that reflects the type of modifier.
-ENUM_CLASS(OmpProperty, Required, Unique, Exclusive, Ultimate, Post, Optional)
+ENUM_CLASS(OmpProperty, Required, Unique, Exclusive, Ultimate, Post)
using OmpProperties = common::EnumSet<OmpProperty, OmpProperty_enumSize>;
using OmpClauses =
common::EnumSet<llvm::omp::Clause, llvm::omp::Clause_enumSize>;
diff --git a/flang/lib/Semantics/openmp-modifiers.cpp b/flang/lib/Semantics/openmp-modifiers.cpp
index c261240480f63..fe8e087cd5a94 100644
--- a/flang/lib/Semantics/openmp-modifiers.cpp
+++ b/flang/lib/Semantics/openmp-modifiers.cpp
@@ -462,7 +462,7 @@ const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpLoopModifier>() {
/*name=*/"loop-modifier",
/*props=*/
{
- {60, {OmpProperty::Optional}},
+ {60, {}},
},
/*clauses=*/
{
More information about the flang-commits
mailing list