Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 909e38e

Browse files
kparzyszc-rhodes
authored andcommitted
[flang][OpenMP] Leave local automatic variables alone (llvm#178739)
There is code in resolve-directives.cpp that tries to apply DSA flags to symbols encountered inside constructs. This code was written with the assumption that all such symbols will be declared outside of the construct. When a symbol declared in a BLOCK construct nested in a construct was found, the code would attempt to either privatize or share it in the enclosing construct (where the symbol didn't exist) leading to trouble. BLOCK constructs (and thus the possibility of having local variables) was introduced in F2008. The first OpenMP spec that considered F2008 was 5.0, where the behavior of the BLOCK construct was explicitly left unspecified. From OpenMP 5.1 onwards, all local non-static variables are private in the construct enclosing the declaration. This PR extends this behavior retroactively to all prior OpenMP versions. Fixes llvm#178613 (cherry picked from commit 7ccdc06)
1 parent 275e5b4 commit 909e38e

2 files changed

Lines changed: 144 additions & 24 deletions

File tree

flang/lib/Semantics/resolve-directives.cpp

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,29 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
388388
explicit OmpAttributeVisitor(SemanticsContext &context)
389389
: DirectiveAttributeVisitor(context) {}
390390

391+
static bool HasStaticStorageDuration(const Symbol &symbol) {
392+
auto &ultSym = symbol.GetUltimate();
393+
// Module-scope variable
394+
return ultSym.owner().kind() == Scope::Kind::Module ||
395+
// Data statement variable
396+
ultSym.flags().test(Symbol::Flag::InDataStmt) ||
397+
// Save attribute variable
398+
ultSym.attrs().test(Attr::SAVE) ||
399+
// Referenced in a common block
400+
ultSym.flags().test(Symbol::Flag::InCommonBlock);
401+
}
402+
403+
// Recognize symbols that are not created as a part of the OpenMP data-
404+
// sharing processing, and that are declared inside of the construct.
405+
// These symbols are predetermined private, but they shouldn't be marked
406+
// in any special way, because there is nothing to be done for them.
407+
// They are not symbols for which private copies need to be created,
408+
// they are already themselves private.
409+
static bool IsLocalInsideScope(const Symbol &symbol, const Scope &scope) {
410+
return symbol.owner() != scope && scope.Contains(symbol.owner()) &&
411+
!HasStaticStorageDuration(symbol);
412+
}
413+
391414
template <typename A> void Walk(const A &x) { parser::Walk(x, *this); }
392415
template <typename A> bool Pre(const A &) { return true; }
393416
template <typename A> void Post(const A &) {}
@@ -2076,6 +2099,9 @@ void OmpAttributeVisitor::ResolveSeqLoopIndexInParallelOrTaskConstruct(
20762099
break;
20772100
}
20782101
}
2102+
if (IsLocalInsideScope(*iv.symbol, targetIt->scope)) {
2103+
return;
2104+
}
20792105
// If this symbol already has a data-sharing attribute then there is nothing
20802106
// to do here.
20812107
if (const Symbol * symbol{iv.symbol}) {
@@ -2400,14 +2426,14 @@ void OmpAttributeVisitor::PrivatizeAssociatedLoopIndexAndCheckLoopLevel(
24002426
}
24012427
}
24022428
// go through all the nested do-loops and resolve index variables
2403-
const parser::Name *iv{GetLoopIndex(*loop)};
2404-
if (iv) {
2405-
if (auto *symbol{ResolveOmp(*iv, ivDSA, currScope())}) {
2406-
SetSymbolDSA(*symbol, {Symbol::Flag::OmpPreDetermined, ivDSA});
2407-
iv->symbol = symbol; // adjust the symbol within region
2408-
AddToContextObjectWithDSA(*symbol, ivDSA);
2429+
if (const parser::Name *iv{GetLoopIndex(*loop)}) {
2430+
if (!iv->symbol || !IsLocalInsideScope(*iv->symbol, currScope())) {
2431+
if (auto *symbol{ResolveOmp(*iv, ivDSA, currScope())}) {
2432+
SetSymbolDSA(*symbol, {Symbol::Flag::OmpPreDetermined, ivDSA});
2433+
iv->symbol = symbol; // adjust the symbol within region
2434+
AddToContextObjectWithDSA(*symbol, ivDSA);
2435+
}
24092436
}
2410-
24112437
const auto &block{std::get<parser::Block>(loop->t)};
24122438
const auto it{block.begin()};
24132439
loop = it != block.end() ? GetDoConstructIf(*it) : nullptr;
@@ -2651,20 +2677,6 @@ static bool IsPrivatizable(const Symbol *sym) {
26512677
misc->kind() != MiscDetails::Kind::ConstructName));
26522678
}
26532679

2654-
static bool IsSymbolStaticStorageDuration(const Symbol &symbol) {
2655-
LLVM_DEBUG(llvm::dbgs() << "IsSymbolStaticStorageDuration(" << symbol.name()
2656-
<< "):\n");
2657-
auto ultSym = symbol.GetUltimate();
2658-
// Module-scope variable
2659-
return (ultSym.owner().kind() == Scope::Kind::Module) ||
2660-
// Data statement variable
2661-
(ultSym.flags().test(Symbol::Flag::InDataStmt)) ||
2662-
// Save attribute variable
2663-
(ultSym.attrs().test(Attr::SAVE)) ||
2664-
// Referenced in a common block
2665-
(ultSym.flags().test(Symbol::Flag::InCommonBlock));
2666-
}
2667-
26682680
static bool IsTargetCaptureImplicitlyFirstprivatizeable(const Symbol &symbol,
26692681
const Symbol::Flags &dsa, const Symbol::Flags &dataSharingAttributeFlags,
26702682
const Symbol::Flags &dataMappingAttributeFlags,
@@ -2823,7 +2835,9 @@ void OmpAttributeVisitor::CreateImplicitSymbols(const Symbol *symbol) {
28232835
bool targetDir = llvm::omp::allTargetSet.test(dirContext.directive);
28242836
bool parallelDir = llvm::omp::topParallelSet.test(dirContext.directive);
28252837
bool teamsDir = llvm::omp::allTeamsSet.test(dirContext.directive);
2826-
bool isStaticStorageDuration = IsSymbolStaticStorageDuration(*symbol);
2838+
bool isStaticStorageDuration = HasStaticStorageDuration(*symbol);
2839+
LLVM_DEBUG(llvm::dbgs()
2840+
<< "HasStaticStorageDuration(" << symbol->name() << "):\n");
28272841

28282842
if (dsa.any()) {
28292843
if (parallelDir || taskGenDir || teamsDir) {
@@ -2977,7 +2991,8 @@ void OmpAttributeVisitor::Post(const parser::Name &name) {
29772991
auto *symbol{name.symbol};
29782992

29792993
if (symbol && WithinConstruct()) {
2980-
if (IsPrivatizable(symbol) && !IsObjectWithDSA(*symbol)) {
2994+
if (IsPrivatizable(symbol) && !IsObjectWithDSA(*symbol) &&
2995+
!IsLocalInsideScope(*symbol, currScope())) {
29812996
// TODO: create a separate function to go through the rules for
29822997
// predetermined, explicitly determined, and implicitly
29832998
// determined data-sharing attributes (2.15.1.1).
@@ -3046,7 +3061,17 @@ void OmpAttributeVisitor::Post(const parser::Name &name) {
30463061
return;
30473062
}
30483063

3049-
CreateImplicitSymbols(symbol);
3064+
// We should only create any additional symbols, if the one mentioned
3065+
// in the source code was declared outside of the construct. This was
3066+
// always the case before Fortran 2008. F2008 introduced the BLOCK
3067+
// construct, and allowed local variable declarations.
3068+
// In OpenMP local (non-static) variables are always private in a given
3069+
// construct, if they are declared inside the construct. In those cases
3070+
// we don't need to do anything here (i.e. no flags are needed or
3071+
// anything else).
3072+
if (!IsLocalInsideScope(*symbol, currScope())) {
3073+
CreateImplicitSymbols(symbol);
3074+
}
30503075
} // within OpenMP construct
30513076
}
30523077

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
!RUN: %flang_fc1 -fdebug-unparse-with-symbols -fopenmp %s | FileCheck %s
2+
3+
!Make sure that the local `bbb`s are their own entities.
4+
5+
!CHECK-LABEL: !DEF: /f00 (Subroutine) Subprogram
6+
!CHECK-NEXT: subroutine f00
7+
!CHECK-NEXT: !DEF: /f00/i ObjectEntity INTEGER(4)
8+
!CHECK-NEXT: integer i
9+
!CHECK-NEXT: !$omp parallel
10+
!CHECK-NEXT: block
11+
!CHECK-NEXT: block
12+
!CHECK-NEXT: !DEF: /f00/OtherConstruct1/BlockConstruct1/BlockConstruct1/bbb ObjectEntity INTEGER(4)
13+
!CHECK-NEXT: integer bbb
14+
!CHECK-NEXT: !REF: /f00/OtherConstruct1/BlockConstruct1/BlockConstruct1/bbb
15+
!CHECK-NEXT: bbb = 1
16+
!CHECK-NEXT: end block
17+
!CHECK-NEXT: block
18+
!CHECK-NEXT: !DEF: /f00/OtherConstruct1/BlockConstruct1/BlockConstruct2/bbb ObjectEntity INTEGER(4)
19+
!CHECK-NEXT: integer bbb
20+
!CHECK-NEXT: !REF: /f00/OtherConstruct1/BlockConstruct1/BlockConstruct2/bbb
21+
!CHECK-NEXT: bbb = 2
22+
!CHECK-NEXT: end block
23+
!CHECK-NEXT: end block
24+
!CHECK-NEXT: !$omp end parallel
25+
!CHECK-NEXT: end subroutine
26+
27+
subroutine f00()
28+
integer :: i
29+
!$omp parallel
30+
block
31+
block
32+
integer :: bbb
33+
bbb = 1
34+
end block
35+
block
36+
integer :: bbb
37+
bbb = 2
38+
end block
39+
end block
40+
!$omp end parallel
41+
end subroutine
42+
43+
44+
!CHECK-LABEL: !DEF: /f01 (Subroutine) Subprogram
45+
!CHECK-NEXT: subroutine f01
46+
!CHECK-NEXT: !DEF: /f01/i ObjectEntity INTEGER(4)
47+
!CHECK-NEXT: integer i
48+
!CHECK-NEXT: !DEF: /f01/bbb ObjectEntity INTEGER(4)
49+
!CHECK-NEXT: integer bbb
50+
!CHECK-NEXT: !REF: /f01/bbb
51+
!CHECK-NEXT: bbb = 0
52+
!CHECK-NEXT: !$omp parallel
53+
!CHECK-NEXT: block
54+
!CHECK-NEXT: !DEF: /f01/OtherConstruct1/bbb (OmpShared) HostAssoc INTEGER(4)
55+
!CHECK-NEXT: bbb = 1234
56+
!CHECK-NEXT: block
57+
!CHECK-NEXT: !DEF: /f01/OtherConstruct1/BlockConstruct1/BlockConstruct1/bbb ObjectEntity INTEGER(4)
58+
!CHECK-NEXT: integer bbb
59+
!CHECK-NEXT: !REF: /f01/OtherConstruct1/BlockConstruct1/BlockConstruct1/bbb
60+
!CHECK-NEXT: bbb = 1
61+
!CHECK-NEXT: end block
62+
!CHECK-NEXT: block
63+
!CHECK-NEXT: !DEF: /f01/OtherConstruct1/BlockConstruct1/BlockConstruct2/bbb ObjectEntity INTEGER(4)
64+
!CHECK-NEXT: integer bbb
65+
!CHECK-NEXT: !REF: /f01/OtherConstruct1/BlockConstruct1/BlockConstruct2/bbb
66+
!CHECK-NEXT: bbb = 2
67+
!CHECK-NEXT: end block
68+
!CHECK-NEXT: end block
69+
!CHECK-NEXT: !$omp end parallel
70+
!CHECK-NEXT: !REF: /f01/bbb
71+
!CHECK-NEXT: print *, bbb
72+
!CHECK-NEXT: end subroutine
73+
74+
subroutine f01()
75+
integer :: i
76+
integer :: bbb
77+
78+
bbb = 0
79+
80+
!$omp parallel
81+
block
82+
bbb = 1234
83+
block
84+
integer :: bbb
85+
bbb = 1
86+
end block
87+
block
88+
integer :: bbb
89+
bbb = 2
90+
end block
91+
end block
92+
!$omp end parallel
93+
94+
print *, bbb
95+
end subroutine

0 commit comments

Comments
 (0)