Skip to content

[flang][OpenMP] Set isNewBlock directly on OpenMP constructs #144593

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

kparzysz
Copy link
Contributor

When the PFT builder decides that an evaluation needs a new block it checks if the evaluation has nested evaluations. In such case it sets the flag on the first nested evaluation. This works under the assuption that such an evaluation only serves as a container, and does not, by itself, generate any code.

This fails for OpenMP constructs that contain nested evaluations because the top-level evaluation does generate code that wraps the code from the nested evaluations. In such cases, the code for the top-level evaluation may be emitted in a wrong place.

When setting the isNewBlock flag, recognize OpenMP directives, and treat them accordingly.

This fixes #139071

When the PFT builder decides that an evaluation needs a new block
it checks if the evaluation has nested evaluations. In such case it
sets the flag on the first nested evaluation. This works under the
assuption that such an evaluation only serves as a container, and
does not, by itself, generate any code.

This fails for OpenMP constructs that contain nested evaluations
because the top-level evaluation does generate code that wraps the
code from the nested evaluations. In such cases, the code for the
top-level evaluation may be emitted in a wrong place.

When setting the `isNewBlock` flag, recognize OpenMP directives,
and treat them accordingly.

This fixes llvm#139071
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:fir-hlfir flang:openmp labels Jun 17, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 17, 2025

@llvm/pr-subscribers-flang-openmp

@llvm/pr-subscribers-flang-fir-hlfir

Author: Krzysztof Parzyszek (kparzysz)

Changes

When the PFT builder decides that an evaluation needs a new block it checks if the evaluation has nested evaluations. In such case it sets the flag on the first nested evaluation. This works under the assuption that such an evaluation only serves as a container, and does not, by itself, generate any code.

This fails for OpenMP constructs that contain nested evaluations because the top-level evaluation does generate code that wraps the code from the nested evaluations. In such cases, the code for the top-level evaluation may be emitted in a wrong place.

When setting the isNewBlock flag, recognize OpenMP directives, and treat them accordingly.

This fixes #139071


Full diff: https://github.com/llvm/llvm-project/pull/144593.diff

3 Files Affected:

  • (modified) flang/include/flang/Lower/PFTBuilder.h (+10)
  • (modified) flang/lib/Lower/PFTBuilder.cpp (+3-1)
  • (added) flang/test/Lower/OpenMP/multiple-entry-points.f90 (+46)
diff --git a/flang/include/flang/Lower/PFTBuilder.h b/flang/include/flang/Lower/PFTBuilder.h
index 42d6546b77553..ac87fcd7c3b9b 100644
--- a/flang/include/flang/Lower/PFTBuilder.h
+++ b/flang/include/flang/Lower/PFTBuilder.h
@@ -184,6 +184,11 @@ static constexpr bool isExecutableDirective{common::HasMember<
     A, std::tuple<parser::CompilerDirective, parser::OpenACCConstruct,
                   parser::OpenMPConstruct, parser::CUFKernelDoConstruct>>};
 
+template <typename A>
+static constexpr bool isOpenMPDirective{
+    common::HasMember<A, std::tuple<parser::OpenMPConstruct,
+                                    parser::OpenMPDeclarativeConstruct>>};
+
 template <typename A>
 static constexpr bool isFunctionLike{common::HasMember<
     A, std::tuple<parser::MainProgram, parser::FunctionSubprogram,
@@ -267,6 +272,11 @@ struct Evaluation : EvaluationVariant {
       return pft::isExecutableDirective<std::decay_t<decltype(r)>>;
     }});
   }
+  constexpr bool isOpenMPDirective() const {
+    return visit(common::visitors{[](auto &r) {
+      return pft::isOpenMPDirective<std::decay_t<decltype(r)>>;
+    }});
+  }
 
   /// Return the predicate:  "This is a non-initial, non-terminal construct
   /// statement."  For an IfConstruct, this is ElseIfStmt and ElseStmt.
diff --git a/flang/lib/Lower/PFTBuilder.cpp b/flang/lib/Lower/PFTBuilder.cpp
index 2cc458cb6130d..68023610c3c50 100644
--- a/flang/lib/Lower/PFTBuilder.cpp
+++ b/flang/lib/Lower/PFTBuilder.cpp
@@ -1096,7 +1096,9 @@ class PFTBuilder {
 
     // The first executable statement in the subprogram is preceded by a
     // branch to the entry point, so it starts a new block.
-    if (initialEval->hasNestedEvaluations())
+    // OpenMP directives can generate code around the nested evaluations.
+    if (initialEval->hasNestedEvaluations() &&
+        !initialEval->isOpenMPDirective())
       initialEval = &initialEval->getFirstNestedEvaluation();
     else if (initialEval->isA<Fortran::parser::EntryStmt>())
       initialEval = initialEval->lexicalSuccessor;
diff --git a/flang/test/Lower/OpenMP/multiple-entry-points.f90 b/flang/test/Lower/OpenMP/multiple-entry-points.f90
new file mode 100644
index 0000000000000..2b8caa79eaa15
--- /dev/null
+++ b/flang/test/Lower/OpenMP/multiple-entry-points.f90
@@ -0,0 +1,46 @@
+!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s
+
+! Check the first entry point
+!CHECK: func.func @_QPprocess_a
+!CHECK: omp.parallel
+!CHECK: omp.wsloop
+!CHECK: %[[V0:[0-9]+]] = fir.load %{{[0-9]+}} : !fir.ref<f32>
+!CHECK: %[[V1:[a-z_0-9]+]] = arith.constant 2.000000e+00 : f32
+!CHECK:   = arith.mulf %[[V0]], %[[V1]] fastmath<contract> : f32
+!CHECK: omp.terminator
+!CHECK-NOT: omp
+!CHECK: return
+
+! Check the second entry point
+!CHECK: func.func @_QPprocess_b
+!CHECK: omp.parallel
+!CHECK: fir.do_loop
+!CHECK: %[[V3:[0-9]+]] = fir.load %[[V2:[0-9]+]]#0 : !fir.ref<i32>
+!CHECK: %[[V4:[0-9]+]] = fir.load %[[V2]]#0 : !fir.ref<i32>
+!CHECK:   = arith.muli %[[V3]], %[[V4]] : i32
+!CHECK: omp.terminator
+!CHECK-NOT: omp
+!CHECK: return
+
+subroutine process_a(n, a)
+  integer, intent(in) :: n
+  real, intent(inout) :: a(n)
+  integer :: i
+
+  !$omp parallel do
+  do i = 1, n
+    a(i) = a(i) * 2.0
+  end do
+  !$omp end parallel do
+
+  return
+
+  entry process_b(n, b)
+    
+  !$omp parallel
+  do i = 1, n
+    a(i) = i * i
+  end do
+  !$omp end parallel
+
+end subroutine process_a

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:fir-hlfir flang:openmp flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[flang][OpenMP] Lowering of OpenMP construct fails in a procedure with alternate entries
2 participants