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

Skip to content

Commit ece1c94

Browse files
kparzyszc-rhodes
authored andcommitted
[flang][OpenMP] Improve locality check when determining DSA (llvm#180583)
Follow-up to llvm#178739. The locality check assumed that immediately after the initial symbol resolution (i.e. prior to the OpenMP code in resolve-directives.cpp), the scope that owns a given symbol is the scope which owns the symbol's storage. Turns out that this isn't necessarily true as illustrated by the included testcase, roughly something like: ``` program main integer :: j ! host j (storage-owning) contains subroutine f !$omp parallel ! scope that owns j, but j is host-associated do j = ... end do !$omp end parallel end end program ``` In such cases, the locality should be checked for the symbol that owns storage, i.e. a clone of the symbol that is has been privatized or a symbol that is not host- or use-associated. This is similar to obtaning the ultimate symbol (i.e. from the end of association chain), except the chain traversal would stop at a privatized symbol, potentially before reaching the end. This fixes a few regressions in the Fujitsu test suite: Fujitsu/Fortran/0160/Fujitsu-Fortran-0160_0000.test Fujitsu/Fortran/0160/Fujitsu-Fortran-0160_0012.test Fujitsu/Fortran/0160/Fujitsu-Fortran-0160_0013.test Fujitsu/Fortran/0660/Fujitsu-Fortran-0660_0096.test Fujitsu/Fortran/0660/Fujitsu-Fortran-0660_0097.test Fujitsu/Fortran/1052/Fujitsu-Fortran-1052_0108.test Fujitsu/Fortran/1052/Fujitsu-Fortran-1052_0112.test (cherry picked from commit 0e7ddf3)
1 parent 909e38e commit ece1c94

3 files changed

Lines changed: 90 additions & 2 deletions

File tree

flang/lib/Semantics/resolve-directives.cpp

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -400,15 +400,51 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
400400
ultSym.flags().test(Symbol::Flag::InCommonBlock);
401401
}
402402

403+
static const Symbol &GetStorageOwner(const Symbol &symbol) {
404+
static auto getParent = [](const Symbol *s) -> const Symbol * {
405+
if (auto *details{s->detailsIf<UseDetails>()}) {
406+
return &details->symbol();
407+
} else if (auto *details{s->detailsIf<HostAssocDetails>()}) {
408+
return &details->symbol();
409+
} else {
410+
return nullptr;
411+
}
412+
};
413+
static auto isPrivate = [](const Symbol &symbol) {
414+
static const Symbol::Flags privatizing{Symbol::Flag::OmpPrivate,
415+
Symbol::Flag::OmpFirstPrivate, Symbol::Flag::OmpLastPrivate,
416+
Symbol::Flag::OmpLinear};
417+
return (symbol.flags() & privatizing).any();
418+
};
419+
420+
const Symbol *sym = &symbol;
421+
while (true) {
422+
if (isPrivate(*sym)) {
423+
return *sym;
424+
}
425+
if (const Symbol *parent{getParent(sym)}) {
426+
sym = parent;
427+
} else {
428+
return *sym;
429+
}
430+
}
431+
llvm_unreachable("Error while looking for storage owning symbol");
432+
}
433+
403434
// Recognize symbols that are not created as a part of the OpenMP data-
404435
// sharing processing, and that are declared inside of the construct.
405436
// These symbols are predetermined private, but they shouldn't be marked
406437
// in any special way, because there is nothing to be done for them.
407438
// They are not symbols for which private copies need to be created,
408439
// they are already themselves private.
409440
static bool IsLocalInsideScope(const Symbol &symbol, const Scope &scope) {
410-
return symbol.owner() != scope && scope.Contains(symbol.owner()) &&
411-
!HasStaticStorageDuration(symbol);
441+
// A symbol that is marked with a DSA will be cloned in the construct
442+
// scope and marked as host-associated. This applies to privatized symbols
443+
// as well even though they will have their own storage. They should be
444+
// considered local regardless of the status of the original symbol.
445+
const Symbol &actual{GetStorageOwner(symbol)};
446+
return actual.owner() != scope && scope.Contains(actual.owner()) &&
447+
!HasStaticStorageDuration(actual);
412448
}
413449

414450
template <typename A> void Walk(const A &x) { parser::Walk(x, *this); }
File renamed without changes.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
!RUN: %flang_fc1 -fdebug-unparse-with-symbols -fopenmp -fopenmp-version=60 %s | FileCheck %s
2+
3+
! Shortened version of Fujitsu/Fortran/0160/0160_0000.f90
4+
! Make sure that j is privatized.
5+
6+
!CHECK-LABEL: !DEF: /MAIN MainProgram
7+
!CHECK-NEXT: program MAIN
8+
!CHECK-NEXT: implicit none
9+
!CHECK-NEXT: !DEF: /MAIN/j ObjectEntity INTEGER(4)
10+
!CHECK-NEXT: !DEF: /MAIN/k ObjectEntity INTEGER(4)
11+
!CHECK-NEXT: !DEF: /MAIN/ndim ObjectEntity INTEGER(4)
12+
!CHECK-NEXT: integer j, k, ndim
13+
!CHECK-NEXT: !DEF: /MAIN/flux (Subroutine) Subprogram
14+
!CHECK-NEXT: call flux
15+
!CHECK-NEXT: contains
16+
!CHECK-NEXT: !REF: /MAIN/flux
17+
!CHECK-NEXT: subroutine flux
18+
!CHECK-NEXT: !$omp parallel
19+
!CHECK-NEXT: !$omp do
20+
!CHECK-NEXT: !DEF: /MAIN/flux/OtherConstruct1/OtherConstruct1/k (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
21+
!CHECK-NEXT: !DEF: /MAIN/flux/OtherConstruct1/OtherConstruct1/ndim HostAssoc INTEGER(4)
22+
!CHECK-NEXT: do k=-1,ndim+1
23+
!CHECK-NEXT: !DEF: /MAIN/flux/OtherConstruct1/OtherConstruct1/j (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
24+
!CHECK-NEXT: !REF: /MAIN/flux/OtherConstruct1/OtherConstruct1/ndim
25+
!CHECK-NEXT: do j=-1,ndim+1
26+
!CHECK-NEXT: end do
27+
!CHECK-NEXT: end do
28+
!CHECK-NEXT: !$omp end do
29+
!CHECK-NEXT: !$omp end parallel
30+
!CHECK-NEXT: end subroutine flux
31+
!CHECK-NEXT: end program MAIN
32+
33+
program main
34+
implicit none
35+
integer :: j, k, ndim
36+
37+
call flux()
38+
39+
contains
40+
41+
subroutine flux
42+
!$omp parallel
43+
!$omp do
44+
do k = -1, ndim + 1
45+
do j = -1, ndim + 1
46+
enddo
47+
enddo
48+
!$omp end do
49+
!$omp end parallel
50+
end subroutine flux
51+
52+
end program main

0 commit comments

Comments
 (0)