Skip to content

Commit 31387d6

Browse files
authored
[flang][OpenMP] Don't privatize implicit symbols declare by nested BLOCKs (#152973)
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.
1 parent 12400a9 commit 31387d6

File tree

3 files changed

+54
-7
lines changed

3 files changed

+54
-7
lines changed

flang/lib/Lower/OpenMP/DataSharingProcessor.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "flang/Semantics/tools.h"
3131
#include "llvm/ADT/Sequence.h"
3232
#include "llvm/ADT/SmallSet.h"
33+
#include <variant>
3334

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

48+
bool DataSharingProcessor::OMPConstructSymbolVisitor::
49+
isSymbolDefineByNestedDeclaration(const semantics::Symbol *symbol) const {
50+
return symDefMap.count(symbol) &&
51+
std::holds_alternative<const parser::DeclarationConstruct *>(
52+
symDefMap.at(symbol));
53+
}
54+
4755
static bool isConstructWithTopLevelTarget(lower::pft::Evaluation &eval) {
4856
const auto *ompEval = eval.getIf<parser::OpenMPConstruct>();
4957
if (ompEval) {
@@ -550,17 +558,20 @@ void DataSharingProcessor::collectSymbols(
550558
return false;
551559
}
552560

553-
return sym->test(semantics::Symbol::Flag::OmpImplicit);
554-
}
555-
556-
if (collectPreDetermined) {
557-
// Collect pre-determined symbols only if they are defined by the current
558-
// OpenMP evaluation. If `sym` is not defined by the current OpenMP
561+
// Collect implicit symbols only if they are not defined by a nested
562+
// `DeclarationConstruct`. If `sym` is not defined by the current OpenMP
559563
// evaluation then it is defined by a block nested within the OpenMP
560564
// construct. This, in turn, means that the private allocation for the
561565
// symbol will be emitted as part of the nested block and there is no need
562566
// to privatize it within the OpenMP construct.
563-
return visitor.isSymbolDefineBy(sym, eval) &&
567+
return !visitor.isSymbolDefineByNestedDeclaration(sym) &&
568+
sym->test(semantics::Symbol::Flag::OmpImplicit);
569+
}
570+
571+
if (collectPreDetermined) {
572+
// Similar to implicit symbols, collect pre-determined symbols only if
573+
// they are not defined by a nested `DeclarationConstruct`
574+
return !visitor.isSymbolDefineByNestedDeclaration(sym) &&
564575
sym->test(semantics::Symbol::Flag::OmpPreDetermined);
565576
}
566577

flang/lib/Lower/OpenMP/DataSharingProcessor.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@ class DataSharingProcessor {
7777
bool isSymbolDefineBy(const semantics::Symbol *symbol,
7878
lower::pft::Evaluation &eval) const;
7979

80+
// Given a \p symbol, returns true if it is defined by a nested
81+
// `DeclarationConstruct`.
82+
bool
83+
isSymbolDefineByNestedDeclaration(const semantics::Symbol *symbol) const;
84+
8085
private:
8186
using ConstructPtr = std::variant<const parser::OpenMPConstruct *,
8287
const parser::DeclarationConstruct *>;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
! When a block variable is marked as implicit private, we can simply ignore
2+
! privatizing that symbol within the context of the currrent OpenMP construct
3+
! since the "private" allocation for the symbol will be emitted within the nested
4+
! block anyway.
5+
6+
! RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s
7+
8+
subroutine block_implicit_privatization
9+
implicit none
10+
integer :: i
11+
12+
!$omp task
13+
do i=1,10
14+
block
15+
integer :: j
16+
j = 0
17+
end block
18+
end do
19+
!$omp end task
20+
end subroutine
21+
22+
! CHECK-LABEL: func.func @_QPblock_implicit_privatization() {
23+
! CHECK: %[[I_DECL:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "{{.*}}Ei"}
24+
! CHECK: omp.task private(@{{.*}}Ei_private_i32 %[[I_DECL]]#0 -> %{{.*}} : !fir.ref<i32>) {
25+
! CHECK: fir.do_loop {{.*}} {
26+
! Verify that `j` is allocated whithin the same scope of its block (i.e. inside
27+
! the `task` loop).
28+
! CHECK: fir.alloca i32 {bindc_name = "j", {{.*}}}
29+
! CHECK: }
30+
! CHECK: }
31+
! CHECK: }

0 commit comments

Comments
 (0)