From 5197006c80b1a1d3a1cfb0038423cd8b756baed2 Mon Sep 17 00:00:00 2001 From: Jack Styles Date: Tue, 10 Jun 2025 09:55:40 +0100 Subject: [PATCH 1/3] [Flang][OpenMP] Add Parsing support for Indirect Clause As part of OpenMP Version 5.1, support for the `indirect` clause was added for the `declare target` directive. This clause should follow an `enter` clause, and allows procedure calls to be done indirectly through OpenMP. This adds Parsing support for the clause, along with semantics checks. Currently, lowering for the clause is not supported so a TODO message will be outputted to the user. It also performs version checking as `indirect` is only support in OpenMP 5.1 or greater. See also: #110008 --- flang/include/flang/Parser/dump-parse-tree.h | 1 + flang/include/flang/Parser/parse-tree.h | 5 ++ flang/lib/Lower/OpenMP/Clauses.cpp | 4 +- flang/lib/Parser/openmp-parsers.cpp | 2 + flang/lib/Semantics/check-omp-structure.cpp | 9 ++++ flang/lib/Semantics/check-omp-structure.h | 1 + .../Lower/OpenMP/Todo/omp-clause-indirect.f90 | 34 ++++++++++++ .../OpenMP/declare-target-indirect-tree.f90 | 53 +++++++++++++++++++ flang/test/Semantics/indirect01.f90 | 34 ++++++++++++ flang/test/Semantics/indirect02.f90 | 36 +++++++++++++ llvm/include/llvm/Frontend/OpenMP/ClauseT.h | 2 +- llvm/include/llvm/Frontend/OpenMP/OMP.td | 1 + 12 files changed, 179 insertions(+), 3 deletions(-) create mode 100644 flang/test/Lower/OpenMP/Todo/omp-clause-indirect.f90 create mode 100644 flang/test/Parser/OpenMP/declare-target-indirect-tree.f90 create mode 100644 flang/test/Semantics/indirect01.f90 create mode 100644 flang/test/Semantics/indirect02.f90 diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h index df9278697346f..64228c2295151 100644 --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -574,6 +574,7 @@ class ParseTreeDumper { NODE_ENUM(OmpDependenceType, Value) NODE(parser, OmpTaskDependenceType) NODE_ENUM(OmpTaskDependenceType, Value) + NODE(parser, OmpIndirectClause) NODE(parser, OmpIterationOffset) NODE(parser, OmpIteration) NODE(parser, OmpIterationVector) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index c99006f0c1c22..bce2606029c4d 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -4300,6 +4300,11 @@ struct OmpHoldsClause { WRAPPER_CLASS_BOILERPLATE(OmpHoldsClause, common::Indirection); }; +// Ref: [5.2: 209] +struct OmpIndirectClause { + WRAPPER_CLASS_BOILERPLATE(OmpIndirectClause, std::optional); +}; + // Ref: [5.2:72-73], in 4.5-5.1 it's scattered over individual directives // that allow the IF clause. // diff --git a/flang/lib/Lower/OpenMP/Clauses.cpp b/flang/lib/Lower/OpenMP/Clauses.cpp index f3088b18b77ff..c628de208d3c7 100644 --- a/flang/lib/Lower/OpenMP/Clauses.cpp +++ b/flang/lib/Lower/OpenMP/Clauses.cpp @@ -906,8 +906,8 @@ Inclusive make(const parser::OmpClause::Inclusive &inp, Indirect make(const parser::OmpClause::Indirect &inp, semantics::SemanticsContext &semaCtx) { - // inp -> empty - llvm_unreachable("Empty: indirect"); + // inp.v.v -> std::optional + return Indirect{maybeApply(makeExprFn(semaCtx), inp.v.v)}; } Init make(const parser::OmpClause::Init &inp, diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index 08326fad8c143..e7bc1c66b458c 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -996,6 +996,8 @@ TYPE_PARSER( // "IF" >> construct(construct( parenthesized(Parser{}))) || "INBRANCH" >> construct(construct()) || + "INDIRECT" >> construct(construct( + maybe(parenthesized(scalarLogicalExpr)))) || "INIT" >> construct(construct( parenthesized(Parser{}))) || "INCLUSIVE" >> construct(construct( diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index bdd078c33da92..5bbd1085c00a8 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -1812,15 +1812,24 @@ void OmpStructureChecker::Leave(const parser::OmpDeclareTargetWithClause &x) { const parser::OmpClause *toClause = FindClause(llvm::omp::Clause::OMPC_to); const parser::OmpClause *linkClause = FindClause(llvm::omp::Clause::OMPC_link); + const parser::OmpClause *indirectClause = FindClause(llvm::omp::Clause::OMPC_indirect); if (!enterClause && !toClause && !linkClause) { context_.Say(x.source, "If the DECLARE TARGET directive has a clause, it must contain at least one ENTER clause or LINK clause"_err_en_US); } + if (indirectClause && !enterClause) { + context_.Say(x.source, + "The INDIRECT clause cannot be used without the ENTER clause with the DECLARE TARGET directive."_err_en_US); + } unsigned version{context_.langOptions().OpenMPVersion}; if (toClause && version >= 52) { context_.Warn(common::UsageWarning::OpenMPUsage, toClause->source, "The usage of TO clause on DECLARE TARGET directive has been deprecated. Use ENTER clause instead."_warn_en_US); } + if(indirectClause && version < 51) { + context_.Say(x.source, + "The usage of INDIRECT clause on DECLARE TARGET directive is only supported on OpenMP Version 5.1 or greater"_err_en_US); + } } } diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h index 1a8059d8548ed..a964124beb0f9 100644 --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -243,6 +243,7 @@ class OmpStructureChecker void CheckSymbolNames( const parser::CharBlock &source, const parser::OmpObjectList &objList); void CheckIntentInPointer(SymbolSourceMap &, const llvm::omp::Clause); + void MakeScalarLogicalTrue(const parser::OmpClause *clause); void CheckProcedurePointer(SymbolSourceMap &, const llvm::omp::Clause); void CheckCrayPointee(const parser::OmpObjectList &objectList, llvm::StringRef clause, bool suggestToUseCrayPointer = true); diff --git a/flang/test/Lower/OpenMP/Todo/omp-clause-indirect.f90 b/flang/test/Lower/OpenMP/Todo/omp-clause-indirect.f90 new file mode 100644 index 0000000000000..d441cac47f5da --- /dev/null +++ b/flang/test/Lower/OpenMP/Todo/omp-clause-indirect.f90 @@ -0,0 +1,34 @@ +! This test checks the lowering of OpenMP Indirect Clause when used with the Declare Target directive + +! RUN: not flang -fc1 -emit-fir -fopenmp -fopenmp-version=52 %s 2>&1 | FileCheck %s + +module functions + implicit none + + interface + function func() result(i) + character(1) :: i + end function + end interface + +contains + function func1() result(i) + !CHECK: not yet implemented: Unhandled clause INDIRECT in DECLARE TARGET construct + !$omp declare target enter(func1) indirect(.true.) + character(1) :: i + i = 'a' + return + end function +end module + +program main + use functions + implicit none + procedure (func), pointer :: ptr1=>func1 + character(1) :: val1 + + !$omp target map(from: val1) + val1 = ptr1() + !$omp end target + +end program diff --git a/flang/test/Parser/OpenMP/declare-target-indirect-tree.f90 b/flang/test/Parser/OpenMP/declare-target-indirect-tree.f90 new file mode 100644 index 0000000000000..b76b7eb49e418 --- /dev/null +++ b/flang/test/Parser/OpenMP/declare-target-indirect-tree.f90 @@ -0,0 +1,53 @@ +! REQUIRES: openmp_runtime + +! RUN: %flang_fc1 %openmp_flags -fopenmp-version=52 -fdebug-dump-parse-tree %s | FileCheck %s +! RUN: %flang_fc1 %openmp_flags -fdebug-unparse -fopenmp-version=52 %s | FileCheck %s --check-prefix="UNPARSE" + +module functions + implicit none + + interface + function func() result(i) + character(1) :: i + end function + end interface + +contains + function func1() result(i) + !$omp declare target enter(func1) indirect(.true.) + !CHECK: | | | | | OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> Enter -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'func1' + !CHECK-NEXT: | | | | | OmpClause -> Indirect -> OmpIndirectClause -> Scalar -> Logical -> Expr = '.true._4' + !CHECK-NEXT: | | | | | | LiteralConstant -> LogicalLiteralConstant + !CHECK-NEXT: | | | | | | | bool = 'true' + character(1) :: i + i = 'a' + return + end function + + function func2() result(i) + !$omp declare target enter(func2) indirect + !CHECK: | | | | | OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> Enter -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'func2' + !CHECK-NEXT: | | | | | OmpClause -> Indirect -> OmpIndirectClause -> + character(1) :: i + i = 'b' + return + end function +end module + +program main + use functions + implicit none + procedure (func), pointer :: ptr1=>func1, ptr2=>func2 + character(1) :: val1, val2 + + !$omp target map(from: val1) + val1 = ptr1() + !$omp end target + !$omp target map(from: val2) + val2 = ptr2() + !$omp end target + +end program + +!UNPARSE: !$OMP DECLARE TARGET ENTER(func1) INDIRECT(.true._4) +!UNPARSE: !$OMP DECLARE TARGET ENTER(func2) INDIRECT() \ No newline at end of file diff --git a/flang/test/Semantics/indirect01.f90 b/flang/test/Semantics/indirect01.f90 new file mode 100644 index 0000000000000..59850662275d9 --- /dev/null +++ b/flang/test/Semantics/indirect01.f90 @@ -0,0 +1,34 @@ +! This test checks the lowering of OpenMP Indirect Clause when used with the Declare Target directive + +! RUN: not flang -fopenmp -fopenmp-version=52 %s 2>&1 | FileCheck %s + +module functions + implicit none + + interface + function func() result(i) + character(1) :: i + end function + end interface + +contains + function func1() result(i) + !CHECK: The INDIRECT clause cannot be used without the ENTER clause with the DECLARE TARGET directive. + !$omp declare target indirect(.true.) + character(1) :: i + i = 'a' + return + end function +end module + +program main + use functions + implicit none + procedure (func), pointer :: ptr1=>func1 + character(1) :: val1 + + !$omp target map(from: val1) + val1 = ptr1() + !$omp end target + +end program diff --git a/flang/test/Semantics/indirect02.f90 b/flang/test/Semantics/indirect02.f90 new file mode 100644 index 0000000000000..1b8b7dcadecf4 --- /dev/null +++ b/flang/test/Semantics/indirect02.f90 @@ -0,0 +1,36 @@ +! This test checks the lowering of OpenMP Indirect Clause when used with the Declare Target directive + +! RUN: not flang -fopenmp -fopenmp-version=50 %s 2>&1 | FileCheck %s --check-prefix="CHECK-50" +! RUN: not flang -fopenmp -fopenmp-version=52 %s 2>&1 | FileCheck %s --check-prefix="CHECK-52" + +module functions + implicit none + + interface + function func() result(i) + character(1) :: i + end function + end interface + +contains + function func1() result(i) + !CHECK-50: The usage of INDIRECT clause on DECLARE TARGET directive is only supported on OpenMP Version 5.1 or greater + !CHECK-52: not yet implemented: Unhandled clause INDIRECT in DECLARE TARGET construct + !$omp declare target enter(func1) indirect(.true.) + character(1) :: i + i = 'a' + return + end function +end module + +program main + use functions + implicit none + procedure (func), pointer :: ptr1=>func1 + character(1) :: val1 + + !$omp target map(from: val1) + val1 = ptr1() + !$omp end target + +end program diff --git a/llvm/include/llvm/Frontend/OpenMP/ClauseT.h b/llvm/include/llvm/Frontend/OpenMP/ClauseT.h index e0714e812e5cd..de888ff86fe91 100644 --- a/llvm/include/llvm/Frontend/OpenMP/ClauseT.h +++ b/llvm/include/llvm/Frontend/OpenMP/ClauseT.h @@ -701,7 +701,7 @@ template // struct IndirectT { using InvokedByFptr = E; using WrapperTrait = std::true_type; - InvokedByFptr v; + OPT(InvokedByFptr) v; }; // V5.2: [14.1.2] `init` clause diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td index 027692275b63b..cbd26eb985165 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMP.td +++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -246,6 +246,7 @@ def OMPC_Inclusive : Clause<[Spelling<"inclusive">]> { let flangClass = "OmpObjectList"; } def OMPC_Indirect : Clause<[Spelling<"indirect">]> { + let flangClass = "OmpIndirectClause"; } def OMPC_Init : Clause<[Spelling<"init">]> { let clangClass = "OMPInitClause"; From 6203920b8a4034ef8f84cb44c74b36e4081e6c3f Mon Sep 17 00:00:00 2001 From: Jack Styles Date: Tue, 10 Jun 2025 12:04:23 +0100 Subject: [PATCH 2/3] Apply formatting changes --- flang/include/flang/Parser/parse-tree.h | 3 ++- flang/lib/Parser/openmp-parsers.cpp | 2 +- flang/lib/Semantics/check-omp-structure.cpp | 7 ++++--- flang/test/Parser/OpenMP/declare-target-indirect-tree.f90 | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index bce2606029c4d..09634766493e2 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -4302,7 +4302,8 @@ struct OmpHoldsClause { // Ref: [5.2: 209] struct OmpIndirectClause { - WRAPPER_CLASS_BOILERPLATE(OmpIndirectClause, std::optional); + WRAPPER_CLASS_BOILERPLATE( + OmpIndirectClause, std::optional); }; // Ref: [5.2:72-73], in 4.5-5.1 it's scattered over individual directives diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index e7bc1c66b458c..1c16218047ed1 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -997,7 +997,7 @@ TYPE_PARSER( // parenthesized(Parser{}))) || "INBRANCH" >> construct(construct()) || "INDIRECT" >> construct(construct( - maybe(parenthesized(scalarLogicalExpr)))) || + maybe(parenthesized(scalarLogicalExpr)))) || "INIT" >> construct(construct( parenthesized(Parser{}))) || "INCLUSIVE" >> construct(construct( diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index 5bbd1085c00a8..c8d06244844f0 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -1812,7 +1812,8 @@ void OmpStructureChecker::Leave(const parser::OmpDeclareTargetWithClause &x) { const parser::OmpClause *toClause = FindClause(llvm::omp::Clause::OMPC_to); const parser::OmpClause *linkClause = FindClause(llvm::omp::Clause::OMPC_link); - const parser::OmpClause *indirectClause = FindClause(llvm::omp::Clause::OMPC_indirect); + const parser::OmpClause *indirectClause = + FindClause(llvm::omp::Clause::OMPC_indirect); if (!enterClause && !toClause && !linkClause) { context_.Say(x.source, "If the DECLARE TARGET directive has a clause, it must contain at least one ENTER clause or LINK clause"_err_en_US); @@ -1826,9 +1827,9 @@ void OmpStructureChecker::Leave(const parser::OmpDeclareTargetWithClause &x) { context_.Warn(common::UsageWarning::OpenMPUsage, toClause->source, "The usage of TO clause on DECLARE TARGET directive has been deprecated. Use ENTER clause instead."_warn_en_US); } - if(indirectClause && version < 51) { + if (indirectClause && version < 51) { context_.Say(x.source, - "The usage of INDIRECT clause on DECLARE TARGET directive is only supported on OpenMP Version 5.1 or greater"_err_en_US); + "The usage of INDIRECT clause on DECLARE TARGET directive is only supported on OpenMP Version 5.1 or greater"_err_en_US); } } } diff --git a/flang/test/Parser/OpenMP/declare-target-indirect-tree.f90 b/flang/test/Parser/OpenMP/declare-target-indirect-tree.f90 index b76b7eb49e418..df85942ec15a5 100644 --- a/flang/test/Parser/OpenMP/declare-target-indirect-tree.f90 +++ b/flang/test/Parser/OpenMP/declare-target-indirect-tree.f90 @@ -50,4 +50,4 @@ program main end program !UNPARSE: !$OMP DECLARE TARGET ENTER(func1) INDIRECT(.true._4) -!UNPARSE: !$OMP DECLARE TARGET ENTER(func2) INDIRECT() \ No newline at end of file +!UNPARSE: !$OMP DECLARE TARGET ENTER(func2) INDIRECT() From fbd1152610dab1aeb2dfb7b6216b4a1fb5baaaf3 Mon Sep 17 00:00:00 2001 From: Jack Styles Date: Tue, 10 Jun 2025 15:34:35 +0100 Subject: [PATCH 3/3] Responding to review comments The following has been completed: - Removed unneeded function declartion - Updated logic for version checking to use the `CheckAllowedClause` function. --- flang/lib/Semantics/check-omp-structure.cpp | 5 ++--- flang/lib/Semantics/check-omp-structure.h | 1 - flang/test/Semantics/indirect02.f90 | 2 +- llvm/include/llvm/Frontend/OpenMP/OMP.td | 4 ++-- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index c8d06244844f0..8c3e7fa6445a4 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -1827,9 +1827,8 @@ void OmpStructureChecker::Leave(const parser::OmpDeclareTargetWithClause &x) { context_.Warn(common::UsageWarning::OpenMPUsage, toClause->source, "The usage of TO clause on DECLARE TARGET directive has been deprecated. Use ENTER clause instead."_warn_en_US); } - if (indirectClause && version < 51) { - context_.Say(x.source, - "The usage of INDIRECT clause on DECLARE TARGET directive is only supported on OpenMP Version 5.1 or greater"_err_en_US); + if (indirectClause) { + CheckAllowedClause(llvm::omp::Clause::OMPC_indirect); } } } diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h index a964124beb0f9..1a8059d8548ed 100644 --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -243,7 +243,6 @@ class OmpStructureChecker void CheckSymbolNames( const parser::CharBlock &source, const parser::OmpObjectList &objList); void CheckIntentInPointer(SymbolSourceMap &, const llvm::omp::Clause); - void MakeScalarLogicalTrue(const parser::OmpClause *clause); void CheckProcedurePointer(SymbolSourceMap &, const llvm::omp::Clause); void CheckCrayPointee(const parser::OmpObjectList &objectList, llvm::StringRef clause, bool suggestToUseCrayPointer = true); diff --git a/flang/test/Semantics/indirect02.f90 b/flang/test/Semantics/indirect02.f90 index 1b8b7dcadecf4..273f8856626b7 100644 --- a/flang/test/Semantics/indirect02.f90 +++ b/flang/test/Semantics/indirect02.f90 @@ -14,7 +14,7 @@ function func() result(i) contains function func1() result(i) - !CHECK-50: The usage of INDIRECT clause on DECLARE TARGET directive is only supported on OpenMP Version 5.1 or greater + !CHECK-50: INDIRECT clause is not allowed on directive DECLARE TARGET in OpenMP v5.0, try -fopenmp-version=51 !CHECK-52: not yet implemented: Unhandled clause INDIRECT in DECLARE TARGET construct !$omp declare target enter(func1) indirect(.true.) character(1) :: i diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td index cbd26eb985165..a87111cb5a11d 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMP.td +++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -647,7 +647,7 @@ def OMP_EndAssumes : Directive<[Spelling<"end assumes">]> { def OMP_BeginDeclareTarget : Directive<[Spelling<"begin declare target">]> { let allowedClauses = [ VersionedClause, - VersionedClause, + VersionedClause, VersionedClause, VersionedClause, ]; @@ -725,7 +725,7 @@ def OMP_DeclareSimd : Directive<[Spelling<"declare simd">]> { def OMP_DeclareTarget : Directive<[Spelling<"declare target">]> { let allowedClauses = [ VersionedClause, - VersionedClause, + VersionedClause, VersionedClause, VersionedClause, ];