Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 18 additions & 7 deletions flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "flang/Semantics/tools.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/SmallSet.h"
#include <variant>

namespace Fortran {
namespace lower {
Expand All @@ -44,6 +45,13 @@ bool DataSharingProcessor::OMPConstructSymbolVisitor::isSymbolDefineBy(
[](const auto &functionParserNode) { return false; }});
}

bool DataSharingProcessor::OMPConstructSymbolVisitor::
isSymbolDefineByNestedDeclaration(const semantics::Symbol *symbol) const {
return symDefMap.count(symbol) &&
std::holds_alternative<const parser::DeclarationConstruct *>(
symDefMap.at(symbol));
}

static bool isConstructWithTopLevelTarget(lower::pft::Evaluation &eval) {
const auto *ompEval = eval.getIf<parser::OpenMPConstruct>();
if (ompEval) {
Expand Down Expand Up @@ -550,17 +558,20 @@ void DataSharingProcessor::collectSymbols(
return false;
}

return sym->test(semantics::Symbol::Flag::OmpImplicit);
}

if (collectPreDetermined) {
// Collect pre-determined symbols only if they are defined by the current
// OpenMP evaluation. If `sym` is not defined by the current OpenMP
// Collect implicit symbols only if they are not defined by a nested
// `DeclarationConstruct`. If `sym` is not defined by the current OpenMP
// evaluation then it is defined by a block nested within the OpenMP
// construct. This, in turn, means that the private allocation for the
// symbol will be emitted as part of the nested block and there is no need
// to privatize it within the OpenMP construct.
return visitor.isSymbolDefineBy(sym, eval) &&
return !visitor.isSymbolDefineByNestedDeclaration(sym) &&
sym->test(semantics::Symbol::Flag::OmpImplicit);
}

if (collectPreDetermined) {
// Similar to implicit symbols, collect pre-determined symbols only if
// they are not defined by a nested `DeclarationConstruct`
return !visitor.isSymbolDefineByNestedDeclaration(sym) &&
sym->test(semantics::Symbol::Flag::OmpPreDetermined);
Comment on lines +574 to 575
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's because I'm not very familiar with this logic, but wouldn't the visitor.isSymbolDefineBy(sym, eval) check need to be preserved? E.g.: visitor.isSymbolDefineBy(sym, eval) && !visitor.isSymbolDefineByNestedDeclaration(sym) && sym->test(semantics::Symbol::Flag::OmpPreDetermined).

Copy link
Member Author

@ergawy ergawy Aug 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The symbol and its defining construct are added only once to symDefMap. So, if we have a block and within that block a DeclarationConstruct, the symbol will be paired with the DeclarationConstruct. If the symbol is later referenced by the eval for which we are doing the privatization, symDefMap will not be updated again.

So the map track the first time we encounter a symbol and the context/construct where we did so.

Therefore, I think, isSymbolDefineByNestedDeclaration is both more accurate and sufficient as a check.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@skatrak you were right, the check should be maintained. Removing it triggered a regression in Fujitsu. OpenMP newbie here 🤦!

I am working on a PR with a lit test.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened #154070.

}

Expand Down
5 changes: 5 additions & 0 deletions flang/lib/Lower/OpenMP/DataSharingProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ class DataSharingProcessor {
bool isSymbolDefineBy(const semantics::Symbol *symbol,
lower::pft::Evaluation &eval) const;

// Given a \p symbol, returns true if it is defined by a nested
// `DeclarationConstruct`.
bool
isSymbolDefineByNestedDeclaration(const semantics::Symbol *symbol) const;

private:
using ConstructPtr = std::variant<const parser::OpenMPConstruct *,
const parser::DeclarationConstruct *>;
Expand Down
31 changes: 31 additions & 0 deletions flang/test/Lower/OpenMP/block_implicit_privatization.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
! Fixes a bug when a block variable is marked as implicit private. In such
! case, we can simply ignore privatizing that symbol within the context of the
! currrent OpenMP construct since the "private" allocation for the symbol will
! be emitted within the nested block anyway.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: For this comment, I suggest rewording slightly to something like "When a block variable is marked as implicit private, we can simply ignore privatizing...". Otherwise, it sounds like a unit test is somehow fixing an issue.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


! RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s

subroutine block_implicit_privatization
implicit none
integer :: i

!$omp task
do i=1,10
block
integer :: j
j = 0
end block
end do
!$omp end task
end subroutine

! CHECK-LABEL: func.func @_QPblock_implicit_privatization() {
! CHECK: %[[I_DECL:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "{{.*}}Ei"}
! CHECK: omp.task private(@{{.*}}Ei_private_i32 %[[I_DECL]]#0 -> %{{.*}} : !fir.ref<i32>) {
! CHECK: fir.do_loop {{.*}} {
! Verify that `j` is allocated whithin the same scope of its block (i.e. inside
! the `task` loop).
! CHECK: fir.alloca i32 {bindc_name = "j", {{.*}}}
! CHECK: }
! CHECK: }
! CHECK: }