-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[flang][OpenMP] Fix detecting nested OpenMP constructs #143383
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Recognize privatizing OpenMP constructs, and only exclude symbols from non-privatizing ones.
@llvm/pr-subscribers-flang-fir-hlfir Author: Krzysztof Parzyszek (kparzysz) ChangesRecognize privatizing OpenMP constructs, and only exclude symbols from non-privatizing ones. Full diff: https://github.com/llvm/llvm-project/pull/143383.diff 4 Files Affected:
diff --git a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
index 8b334d7a392ac..f8c68bfc3056a 100644
--- a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
@@ -388,19 +388,43 @@ getSource(const semantics::SemanticsContext &semaCtx,
return source;
}
+bool DataSharingProcessor::isOpenMPPrivatizingConstruct(
+ const parser::OpenMPConstruct &omp) {
+ return common::visit(
+ [](auto &&s) {
+ using BareS = llvm::remove_cvref_t<decltype(s)>;
+ return std::is_same_v<BareS, parser::OpenMPBlockConstruct> ||
+ std::is_same_v<BareS, parser::OpenMPLoopConstruct> ||
+ std::is_same_v<BareS, parser::OpenMPSectionsConstruct>;
+ },
+ omp.u);
+}
+
+bool DataSharingProcessor::isOpenMPPrivatizingEvaluation(
+ const pft::Evaluation &eval) const {
+ return eval.visit([](auto &&s) {
+ using BareS = llvm::remove_cvref_t<decltype(s)>;
+ if constexpr (std::is_same_v<BareS, parser::OpenMPConstruct>) {
+ return isOpenMPPrivatizingConstruct(s);
+ } else {
+ return false;
+ }
+ });
+}
+
void DataSharingProcessor::collectSymbolsInNestedRegions(
lower::pft::Evaluation &eval, semantics::Symbol::Flag flag,
llvm::SetVector<const semantics::Symbol *> &symbolsInNestedRegions) {
- for (lower::pft::Evaluation &nestedEval : eval.getNestedEvaluations()) {
- if (nestedEval.hasNestedEvaluations()) {
- if (nestedEval.isConstruct())
- // Recursively look for OpenMP constructs within `nestedEval`'s region
- collectSymbolsInNestedRegions(nestedEval, flag, symbolsInNestedRegions);
- else {
- converter.collectSymbolSet(nestedEval, symbolsInNestedRegions, flag,
- /*collectSymbols=*/true,
- /*collectHostAssociatedSymbols=*/false);
- }
+ if (!eval.hasNestedEvaluations())
+ return;
+ for (pft::Evaluation &nestedEval : eval.getNestedEvaluations()) {
+ if (isOpenMPPrivatizingEvaluation(nestedEval)) {
+ converter.collectSymbolSet(nestedEval, symbolsInNestedRegions, flag,
+ /*collectSymbols=*/true,
+ /*collectHostAssociatedSymbols=*/false);
+ } else {
+ // Recursively look for OpenMP constructs within `nestedEval`'s region
+ collectSymbolsInNestedRegions(nestedEval, flag, symbolsInNestedRegions);
}
}
}
diff --git a/flang/lib/Lower/OpenMP/DataSharingProcessor.h b/flang/lib/Lower/OpenMP/DataSharingProcessor.h
index 8a7dbb2ae30b7..fded04c839fb4 100644
--- a/flang/lib/Lower/OpenMP/DataSharingProcessor.h
+++ b/flang/lib/Lower/OpenMP/DataSharingProcessor.h
@@ -45,20 +45,22 @@ class DataSharingProcessor {
bool Pre(const parser::OpenMPConstruct &omp) {
// Skip constructs that may not have privatizations.
- if (!std::holds_alternative<parser::OpenMPCriticalConstruct>(omp.u))
- currentConstruct = &omp;
+ if (isOpenMPPrivatizingConstruct(omp))
+ constructs.push_back(&omp);
return true;
}
void Post(const parser::OpenMPConstruct &omp) {
- currentConstruct = nullptr;
+ if (isOpenMPPrivatizingConstruct(omp))
+ constructs.pop_back();
}
void Post(const parser::Name &name) {
- symDefMap.try_emplace(name.symbol, currentConstruct);
+ auto *current = !constructs.empty() ? constructs.back() : nullptr;
+ symDefMap.try_emplace(name.symbol, current);
}
- const parser::OpenMPConstruct *currentConstruct = nullptr;
+ llvm::SmallVector<const parser::OpenMPConstruct *> constructs;
llvm::DenseMap<semantics::Symbol *, const parser::OpenMPConstruct *>
symDefMap;
@@ -113,6 +115,9 @@ class DataSharingProcessor {
mlir::OpBuilder::InsertPoint *lastPrivIP);
void insertDeallocs();
+ static bool isOpenMPPrivatizingConstruct(const parser::OpenMPConstruct &omp);
+ bool isOpenMPPrivatizingEvaluation(const pft::Evaluation &eval) const;
+
public:
DataSharingProcessor(lower::AbstractConverter &converter,
semantics::SemanticsContext &semaCtx,
diff --git a/flang/test/Lower/OpenMP/atomic-privatize.f90 b/flang/test/Lower/OpenMP/atomic-privatize.f90
new file mode 100644
index 0000000000000..f922095264fca
--- /dev/null
+++ b/flang/test/Lower/OpenMP/atomic-privatize.f90
@@ -0,0 +1,25 @@
+! Testcase adopted from the Fujitsu test suite:
+! https://github.com/fujitsu/compiler-test-suite/blob/main/Fortran/0407/0407_0006.f90
+
+!RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=60 %s -o - | FileCheck %s
+
+! Make sure that the variable in the atomic construct is privatized at
+! the task level
+
+!CHECK: omp.task private(@_QFfredEprv_firstprivate_i32 %{{[0-9]+}}#0 -> %arg0
+!CHECK: %[[DECL:[0-9]+]]:2 = hlfir.declare %arg0 {uniq_name = "_QFfredEprv"}
+!CHECK: omp.atomic.update %[[DECL]]#0
+
+integer function fred
+ integer :: prv
+
+ prv = 1
+ !$omp parallel shared(prv)
+ !$omp task default(firstprivate)
+ !$omp atomic
+ prv = prv + 1
+ !$omp end task
+ !$omp end parallel
+ fred = prv
+end
+
diff --git a/flang/test/Lower/OpenMP/sections-predetermined-private.f90 b/flang/test/Lower/OpenMP/sections-predetermined-private.f90
index 9c2e2e127aa78..3ca3b2219c91b 100644
--- a/flang/test/Lower/OpenMP/sections-predetermined-private.f90
+++ b/flang/test/Lower/OpenMP/sections-predetermined-private.f90
@@ -11,7 +11,7 @@
end
! CHECK-LABEL: func.func @_QQmain() {
! CHECK: omp.parallel {
-! CHECK: %[[VAL_3:.*]] = fir.alloca i32 {bindc_name = "i", pinned}
+! CHECK: %[[VAL_3:.*]] = fir.alloca i32 {bindc_name = "i", pinned, uniq_name = "_QFEi"}
! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_3]] {uniq_name = "_QFEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: omp.sections {
! CHECK: omp.section {
|
@llvm/pr-subscribers-flang-openmp Author: Krzysztof Parzyszek (kparzysz) ChangesRecognize privatizing OpenMP constructs, and only exclude symbols from non-privatizing ones. Full diff: https://github.com/llvm/llvm-project/pull/143383.diff 4 Files Affected:
diff --git a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
index 8b334d7a392ac..f8c68bfc3056a 100644
--- a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
@@ -388,19 +388,43 @@ getSource(const semantics::SemanticsContext &semaCtx,
return source;
}
+bool DataSharingProcessor::isOpenMPPrivatizingConstruct(
+ const parser::OpenMPConstruct &omp) {
+ return common::visit(
+ [](auto &&s) {
+ using BareS = llvm::remove_cvref_t<decltype(s)>;
+ return std::is_same_v<BareS, parser::OpenMPBlockConstruct> ||
+ std::is_same_v<BareS, parser::OpenMPLoopConstruct> ||
+ std::is_same_v<BareS, parser::OpenMPSectionsConstruct>;
+ },
+ omp.u);
+}
+
+bool DataSharingProcessor::isOpenMPPrivatizingEvaluation(
+ const pft::Evaluation &eval) const {
+ return eval.visit([](auto &&s) {
+ using BareS = llvm::remove_cvref_t<decltype(s)>;
+ if constexpr (std::is_same_v<BareS, parser::OpenMPConstruct>) {
+ return isOpenMPPrivatizingConstruct(s);
+ } else {
+ return false;
+ }
+ });
+}
+
void DataSharingProcessor::collectSymbolsInNestedRegions(
lower::pft::Evaluation &eval, semantics::Symbol::Flag flag,
llvm::SetVector<const semantics::Symbol *> &symbolsInNestedRegions) {
- for (lower::pft::Evaluation &nestedEval : eval.getNestedEvaluations()) {
- if (nestedEval.hasNestedEvaluations()) {
- if (nestedEval.isConstruct())
- // Recursively look for OpenMP constructs within `nestedEval`'s region
- collectSymbolsInNestedRegions(nestedEval, flag, symbolsInNestedRegions);
- else {
- converter.collectSymbolSet(nestedEval, symbolsInNestedRegions, flag,
- /*collectSymbols=*/true,
- /*collectHostAssociatedSymbols=*/false);
- }
+ if (!eval.hasNestedEvaluations())
+ return;
+ for (pft::Evaluation &nestedEval : eval.getNestedEvaluations()) {
+ if (isOpenMPPrivatizingEvaluation(nestedEval)) {
+ converter.collectSymbolSet(nestedEval, symbolsInNestedRegions, flag,
+ /*collectSymbols=*/true,
+ /*collectHostAssociatedSymbols=*/false);
+ } else {
+ // Recursively look for OpenMP constructs within `nestedEval`'s region
+ collectSymbolsInNestedRegions(nestedEval, flag, symbolsInNestedRegions);
}
}
}
diff --git a/flang/lib/Lower/OpenMP/DataSharingProcessor.h b/flang/lib/Lower/OpenMP/DataSharingProcessor.h
index 8a7dbb2ae30b7..fded04c839fb4 100644
--- a/flang/lib/Lower/OpenMP/DataSharingProcessor.h
+++ b/flang/lib/Lower/OpenMP/DataSharingProcessor.h
@@ -45,20 +45,22 @@ class DataSharingProcessor {
bool Pre(const parser::OpenMPConstruct &omp) {
// Skip constructs that may not have privatizations.
- if (!std::holds_alternative<parser::OpenMPCriticalConstruct>(omp.u))
- currentConstruct = &omp;
+ if (isOpenMPPrivatizingConstruct(omp))
+ constructs.push_back(&omp);
return true;
}
void Post(const parser::OpenMPConstruct &omp) {
- currentConstruct = nullptr;
+ if (isOpenMPPrivatizingConstruct(omp))
+ constructs.pop_back();
}
void Post(const parser::Name &name) {
- symDefMap.try_emplace(name.symbol, currentConstruct);
+ auto *current = !constructs.empty() ? constructs.back() : nullptr;
+ symDefMap.try_emplace(name.symbol, current);
}
- const parser::OpenMPConstruct *currentConstruct = nullptr;
+ llvm::SmallVector<const parser::OpenMPConstruct *> constructs;
llvm::DenseMap<semantics::Symbol *, const parser::OpenMPConstruct *>
symDefMap;
@@ -113,6 +115,9 @@ class DataSharingProcessor {
mlir::OpBuilder::InsertPoint *lastPrivIP);
void insertDeallocs();
+ static bool isOpenMPPrivatizingConstruct(const parser::OpenMPConstruct &omp);
+ bool isOpenMPPrivatizingEvaluation(const pft::Evaluation &eval) const;
+
public:
DataSharingProcessor(lower::AbstractConverter &converter,
semantics::SemanticsContext &semaCtx,
diff --git a/flang/test/Lower/OpenMP/atomic-privatize.f90 b/flang/test/Lower/OpenMP/atomic-privatize.f90
new file mode 100644
index 0000000000000..f922095264fca
--- /dev/null
+++ b/flang/test/Lower/OpenMP/atomic-privatize.f90
@@ -0,0 +1,25 @@
+! Testcase adopted from the Fujitsu test suite:
+! https://github.com/fujitsu/compiler-test-suite/blob/main/Fortran/0407/0407_0006.f90
+
+!RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=60 %s -o - | FileCheck %s
+
+! Make sure that the variable in the atomic construct is privatized at
+! the task level
+
+!CHECK: omp.task private(@_QFfredEprv_firstprivate_i32 %{{[0-9]+}}#0 -> %arg0
+!CHECK: %[[DECL:[0-9]+]]:2 = hlfir.declare %arg0 {uniq_name = "_QFfredEprv"}
+!CHECK: omp.atomic.update %[[DECL]]#0
+
+integer function fred
+ integer :: prv
+
+ prv = 1
+ !$omp parallel shared(prv)
+ !$omp task default(firstprivate)
+ !$omp atomic
+ prv = prv + 1
+ !$omp end task
+ !$omp end parallel
+ fred = prv
+end
+
diff --git a/flang/test/Lower/OpenMP/sections-predetermined-private.f90 b/flang/test/Lower/OpenMP/sections-predetermined-private.f90
index 9c2e2e127aa78..3ca3b2219c91b 100644
--- a/flang/test/Lower/OpenMP/sections-predetermined-private.f90
+++ b/flang/test/Lower/OpenMP/sections-predetermined-private.f90
@@ -11,7 +11,7 @@
end
! CHECK-LABEL: func.func @_QQmain() {
! CHECK: omp.parallel {
-! CHECK: %[[VAL_3:.*]] = fir.alloca i32 {bindc_name = "i", pinned}
+! CHECK: %[[VAL_3:.*]] = fir.alloca i32 {bindc_name = "i", pinned, uniq_name = "_QFEi"}
! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_3]] {uniq_name = "_QFEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: omp.sections {
! CHECK: omp.section {
|
This issue was exposed by #137852 With the PR in place, the atomic construct contains a nested evaluation (an assignment), which causes the code to exclude variables defined in it. This, in turn, caused the The PFT tree with the new atomic code:
The generated MLIR for the OpenMP constructs:
The expected MLIR is (note the "private" clause on the "omp.task" construct):
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks for the fix
Recognize privatizing OpenMP constructs, and only exclude symbols from non-privatizing ones.
Recognize privatizing OpenMP constructs, and only exclude symbols from non-privatizing ones.
Recognize privatizing OpenMP constructs, and only exclude symbols from non-privatizing ones.