Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
24 changes: 16 additions & 8 deletions flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ namespace lower {
namespace omp {
bool DataSharingProcessor::OMPConstructSymbolVisitor::isSymbolDefineBy(
const semantics::Symbol *symbol, lower::pft::Evaluation &eval) const {
return eval.visit(
common::visitors{[&](const parser::OpenMPConstruct &functionParserNode) {
return symDefMap.count(symbol) &&
symDefMap.at(symbol) == &functionParserNode;
},
[](const auto &functionParserNode) { return false; }});
return eval.visit(common::visitors{
[&](const parser::OpenMPConstruct &functionParserNode) {
return symDefMap.count(symbol) &&
symDefMap.at(symbol) == ConstructPtr(&functionParserNode);
},
[](const auto &functionParserNode) { return false; }});
}

static bool isConstructWithTopLevelTarget(lower::pft::Evaluation &eval) {
Expand Down Expand Up @@ -553,8 +553,16 @@ void DataSharingProcessor::collectSymbols(
return sym->test(semantics::Symbol::Flag::OmpImplicit);
}

if (collectPreDetermined)
return sym->test(semantics::Symbol::Flag::OmpPreDetermined);
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
// 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) &&
sym->test(semantics::Symbol::Flag::OmpPreDetermined);
Comment on lines +563 to +564
Copy link
Contributor

Choose a reason for hiding this comment

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

If it doesn't break things, consider making this change for implicit symbols too, as they seem to have the same issue. Reproducer:

subroutine sub
  implicit none
  integer :: i

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

Copy link
Member Author

Choose a reason for hiding this comment

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

It breaks 2 tests:

  Flang :: Lower/OpenMP/implicit-dsa.f90
  Flang :: Lower/OpenMP/target.f90

So I will do that in a follow up PR.

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 in #152973.

}

return !sym->test(semantics::Symbol::Flag::OmpImplicit) &&
!sym->test(semantics::Symbol::Flag::OmpPreDetermined);
Expand Down
19 changes: 15 additions & 4 deletions flang/lib/Lower/OpenMP/DataSharingProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "flang/Parser/parse-tree.h"
#include "flang/Semantics/symbol.h"
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
#include <variant>

namespace mlir {
namespace omp {
Expand Down Expand Up @@ -58,20 +59,30 @@ class DataSharingProcessor {
}

void Post(const parser::Name &name) {
auto *current = !constructs.empty() ? constructs.back() : nullptr;
auto current = !constructs.empty() ? constructs.back() : ConstructPtr();
symDefMap.try_emplace(name.symbol, current);
}

llvm::SmallVector<const parser::OpenMPConstruct *> constructs;
llvm::DenseMap<semantics::Symbol *, const parser::OpenMPConstruct *>
symDefMap;
bool Pre(const parser::DeclarationConstruct &decl) {
constructs.push_back(&decl);
return true;
}

void Post(const parser::DeclarationConstruct &decl) {
constructs.pop_back();
}

/// Given a \p symbol and an \p eval, returns true if eval is the OMP
/// construct that defines symbol.
bool isSymbolDefineBy(const semantics::Symbol *symbol,
lower::pft::Evaluation &eval) const;

private:
using ConstructPtr = std::variant<const parser::OpenMPConstruct *,
const parser::DeclarationConstruct *>;
llvm::SmallVector<ConstructPtr> constructs;
llvm::DenseMap<semantics::Symbol *, ConstructPtr> symDefMap;

unsigned version;
};

Expand Down
32 changes: 32 additions & 0 deletions flang/test/Lower/OpenMP/block_predetermined_privatization.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
! Fixes a bug when a block variable is marked as pre-determined 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.

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

subroutine block_predetermined_privatization
implicit none
integer :: i

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

! CHECK-LABEL: func.func @_QPblock_predetermined_privatization() {
! CHECK: %[[I_DECL:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "{{.*}}Ei"}
! CHECK: omp.parallel 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 `parallel` loop).
! CHECK: fir.alloca i32 {bindc_name = "j", {{.*}}}
! CHECK: }
! CHECK: }
! CHECK: }