[flang-commits] [flang] f4accbf - [flang][OpenMP] Support privatization for single construct
Peixin Qiao via flang-commits
flang-commits at lists.llvm.org
Wed Oct 5 05:23:39 PDT 2022
Author: Peixin Qiao
Date: 2022-10-05T20:22:33+08:00
New Revision: f4accbf55f4d0fcd6d7cc6f7632a0e4b69c9f3dd
URL: https://github.com/llvm/llvm-project/commit/f4accbf55f4d0fcd6d7cc6f7632a0e4b69c9f3dd
DIFF: https://github.com/llvm/llvm-project/commit/f4accbf55f4d0fcd6d7cc6f7632a0e4b69c9f3dd.diff
LOG: [flang][OpenMP] Support privatization for single construct
This supports the lowering of private and firstprivate clauses in single
construct. The alloca ops are emitted in the entry block according to
https://llvm.org/docs/Frontend/PerformanceTips.html#use-of-allocas, and
the load/store ops are emitted in the single region. The data race
problem is handled in OMPIRBuilder. That is, the barrier is emitted in
OMPIRBuilder.
Co-authored-by: Nimish Mishra <neelam.nimish at gmail.com>
Reviewed By: kiranchandramohan
Differential Revision: https://reviews.llvm.org/D128596
Added:
Modified:
flang/include/flang/Lower/AbstractConverter.h
flang/lib/Lower/Bridge.cpp
flang/lib/Lower/OpenMP.cpp
flang/test/Lower/OpenMP/single.f90
Removed:
################################################################################
diff --git a/flang/include/flang/Lower/AbstractConverter.h b/flang/include/flang/Lower/AbstractConverter.h
index 5a2a52335f6ce..6ab649ccf020a 100644
--- a/flang/include/flang/Lower/AbstractConverter.h
+++ b/flang/include/flang/Lower/AbstractConverter.h
@@ -18,6 +18,7 @@
#include "flang/Lower/PFTDefs.h"
#include "flang/Optimizer/Builder/BoxValue.h"
#include "flang/Semantics/symbol.h"
+#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/Operation.h"
#include "llvm/ADT/ArrayRef.h"
@@ -103,8 +104,9 @@ class AbstractConverter {
virtual bool
createHostAssociateVarClone(const Fortran::semantics::Symbol &sym) = 0;
- virtual void copyHostAssociateVar(const Fortran::semantics::Symbol &sym,
- mlir::Block *lastPrivBlock = nullptr) = 0;
+ virtual void copyHostAssociateVar(
+ const Fortran::semantics::Symbol &sym,
+ mlir::OpBuilder::InsertPoint *copyAssignIP = nullptr) = 0;
/// Collect the set of symbols with \p flag in \p eval
/// region if \p collectSymbols is true. Likewise, collect the
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 3748f72c1645f..bd1bddcc987b9 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -516,10 +516,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
return bindIfNewSymbol(sym, exv);
}
- // FIXME: Generalize this function, so that lastPrivBlock can be removed
- void
- copyHostAssociateVar(const Fortran::semantics::Symbol &sym,
- mlir::Block *lastPrivBlock = nullptr) override final {
+ void copyHostAssociateVar(
+ const Fortran::semantics::Symbol &sym,
+ mlir::OpBuilder::InsertPoint *copyAssignIP = nullptr) override final {
// 1) Fetch the original copy of the variable.
assert(sym.has<Fortran::semantics::HostAssocDetails>() &&
"No host-association found");
@@ -537,13 +536,14 @@ class FirConverter : public Fortran::lower::AbstractConverter {
// 3) Perform the assignment.
mlir::OpBuilder::InsertPoint insPt = builder->saveInsertionPoint();
- if (lastPrivBlock)
- builder->setInsertionPointToStart(lastPrivBlock);
+ if (copyAssignIP && copyAssignIP->isSet())
+ builder->restoreInsertionPoint(*copyAssignIP);
else
builder->setInsertionPointAfter(fir::getBase(exv).getDefiningOp());
fir::ExtendedValue lhs, rhs;
- if (lastPrivBlock) {
+ if (copyAssignIP && copyAssignIP->isSet() &&
+ sym.test(Fortran::semantics::Symbol::Flag::OmpLastPrivate)) {
// lastprivate case
lhs = hexv;
rhs = exv;
@@ -568,7 +568,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
builder->create<fir::StoreOp>(loc, loadVal, fir::getBase(lhs));
}
- if (lastPrivBlock)
+ if (copyAssignIP && copyAssignIP->isSet() &&
+ sym.test(Fortran::semantics::Symbol::Flag::OmpLastPrivate))
builder->restoreInsertionPoint(insPt);
}
diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp
index cf7b54d2c1dab..31709d68ee8ac 100644
--- a/flang/lib/Lower/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP.cpp
@@ -61,10 +61,11 @@ getOmpObjectSymbol(const Fortran::parser::OmpObject &ompObject) {
return sym;
}
-static void
-privatizeSymbol(Fortran::lower::AbstractConverter &converter,
- const Fortran::semantics::Symbol *sym,
- [[maybe_unused]] mlir::Block *lastPrivBlock = nullptr) {
+template <typename Op>
+static void privatizeSymbol(
+ Op &op, Fortran::lower::AbstractConverter &converter,
+ const Fortran::semantics::Symbol *sym,
+ [[maybe_unused]] mlir::OpBuilder::InsertPoint *lastPrivIP = nullptr) {
// Privatization for symbols which are pre-determined (like loop index
// variables) happen separately, for everything else privatize here.
if (sym->test(Fortran::semantics::Symbol::Flag::OmpPreDetermined))
@@ -72,10 +73,20 @@ privatizeSymbol(Fortran::lower::AbstractConverter &converter,
bool success = converter.createHostAssociateVarClone(*sym);
(void)success;
assert(success && "Privatization failed due to existing binding");
- if (sym->test(Fortran::semantics::Symbol::Flag::OmpFirstPrivate))
- converter.copyHostAssociateVar(*sym);
+ if (sym->test(Fortran::semantics::Symbol::Flag::OmpFirstPrivate)) {
+ fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
+ mlir::OpBuilder::InsertPoint firstPrivIP, insPt;
+ if (mlir::isa<mlir::omp::SingleOp>(op)) {
+ insPt = firOpBuilder.saveInsertionPoint();
+ firOpBuilder.setInsertionPointToStart(&op.getRegion().front());
+ firstPrivIP = firOpBuilder.saveInsertionPoint();
+ }
+ converter.copyHostAssociateVar(*sym, &firstPrivIP);
+ if (mlir::isa<mlir::omp::SingleOp>(op))
+ firOpBuilder.restoreInsertionPoint(insPt);
+ }
if (sym->test(Fortran::semantics::Symbol::Flag::OmpLastPrivate))
- converter.copyHostAssociateVar(*sym, lastPrivBlock);
+ converter.copyHostAssociateVar(*sym, lastPrivIP);
}
template <typename Op>
@@ -96,7 +107,7 @@ static bool privatizeVars(Op &op, Fortran::lower::AbstractConverter &converter,
};
// We need just one ICmpOp for multiple LastPrivate clauses.
mlir::arith::CmpIOp cmpOp;
- mlir::Block *lastPrivBlock = nullptr;
+ mlir::OpBuilder::InsertPoint lastPrivIP;
bool hasLastPrivateOp = false;
for (const Fortran::parser::OmpClause &clause : opClauseList.v) {
if (const auto &privateClause =
@@ -155,7 +166,8 @@ static bool privatizeVars(Op &op, Fortran::lower::AbstractConverter &converter,
}
mlir::scf::IfOp ifOp = firOpBuilder.create<mlir::scf::IfOp>(
wsLoopOp->getLoc(), cmpOp, /*else*/ false);
- lastPrivBlock = &ifOp.getThenRegion().front();
+ firOpBuilder.setInsertionPointToStart(&ifOp.getThenRegion().front());
+ lastPrivIP = firOpBuilder.saveInsertionPoint();
} else {
TODO(converter.getCurrentLocation(),
"lastprivate clause in constructs other than worksharing-loop");
@@ -207,7 +219,7 @@ static bool privatizeVars(Op &op, Fortran::lower::AbstractConverter &converter,
else
firOpBuilder.setInsertionPointToStart(firOpBuilder.getAllocaBlock());
for (auto sym : privatizedSymbols) {
- privatizeSymbol(converter, sym, lastPrivBlock);
+ privatizeSymbol(op, converter, sym, &lastPrivIP);
if (sym->test(Fortran::semantics::Symbol::Flag::OmpFirstPrivate) &&
sym->test(Fortran::semantics::Symbol::Flag::OmpLastPrivate))
needBarrier = true;
@@ -217,7 +229,7 @@ static bool privatizeVars(Op &op, Fortran::lower::AbstractConverter &converter,
if (!symbolsInNestedRegions.contains(sym) &&
!symbolsInParentRegions.contains(sym) &&
!privatizedSymbols.contains(sym))
- privatizeSymbol(converter, sym);
+ privatizeSymbol(op, converter, sym);
// Emit implicit barrier to synchronize threads and avoid data races on
// initialization of firstprivate variables and post-update of lastprivate
@@ -825,7 +837,8 @@ genOMP(Fortran::lower::AbstractConverter &converter,
} else if (blockDirective.v == llvm::omp::OMPD_single) {
auto singleOp = firOpBuilder.create<mlir::omp::SingleOp>(
currentLocation, allocateOperands, allocatorOperands, nowaitAttr);
- createBodyOfOp<omp::SingleOp>(singleOp, converter, currentLocation, eval);
+ createBodyOfOp<omp::SingleOp>(singleOp, converter, currentLocation, eval,
+ &opClauseList);
} else if (blockDirective.v == llvm::omp::OMPD_ordered) {
auto orderedOp = firOpBuilder.create<mlir::omp::OrderedRegionOp>(
currentLocation, /*simd=*/nullptr);
@@ -839,7 +852,7 @@ genOMP(Fortran::lower::AbstractConverter &converter,
allocatorOperands);
createBodyOfOp(taskOp, converter, currentLocation, eval, &opClauseList);
} else if (blockDirective.v == llvm::omp::OMPD_taskgroup) {
- // TODO: Add task_reduction support
+ // TODO: Add task_reduction support
auto taskGroupOp = firOpBuilder.create<mlir::omp::TaskGroupOp>(
currentLocation, /*task_reduction_vars=*/ValueRange(),
/*task_reductions=*/nullptr, allocateOperands, allocatorOperands);
diff --git a/flang/test/Lower/OpenMP/single.f90 b/flang/test/Lower/OpenMP/single.f90
index b655d78075bdd..fa34753910c59 100644
--- a/flang/test/Lower/OpenMP/single.f90
+++ b/flang/test/Lower/OpenMP/single.f90
@@ -1,25 +1,25 @@
-!RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | FileCheck %s --check-prefixes="FIRDialect,OMPDialect"
-!RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | fir-opt --cfg-conversion | fir-opt --fir-to-llvm-ir | FileCheck %s --check-prefixes="LLVMDialect,OMPDialect"
+!RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | FileCheck %s
+!RUN: bbc -emit-fir -fopenmp %s -o - | FileCheck %s
!===============================================================================
! Single construct
!===============================================================================
-!FIRDialect-LABEL: func @_QPomp_single
-!FIRDialect-SAME: (%[[x:.*]]: !fir.ref<i32> {fir.bindc_name = "x"})
+!CHECK-LABEL: func @_QPomp_single
+!CHECK-SAME: (%[[x:.*]]: !fir.ref<i32> {fir.bindc_name = "x"})
subroutine omp_single(x)
integer, intent(inout) :: x
- !OMPDialect: omp.parallel
+ !CHECK: omp.parallel
!$omp parallel
- !OMPDialect: omp.single
+ !CHECK: omp.single
!$omp single
- !FIRDialect: %[[xval:.*]] = fir.load %[[x]] : !fir.ref<i32>
- !FIRDialect: %[[res:.*]] = arith.addi %[[xval]], %{{.*}} : i32
- !FIRDialect: fir.store %[[res]] to %[[x]] : !fir.ref<i32>
+ !CHECK: %[[xval:.*]] = fir.load %[[x]] : !fir.ref<i32>
+ !CHECK: %[[res:.*]] = arith.addi %[[xval]], %{{.*}} : i32
+ !CHECK: fir.store %[[res]] to %[[x]] : !fir.ref<i32>
x = x + 12
- !OMPDialect: omp.terminator
+ !CHECK: omp.terminator
!$omp end single
- !OMPDialect: omp.terminator
+ !CHECK: omp.terminator
!$omp end parallel
end subroutine omp_single
@@ -27,21 +27,21 @@ end subroutine omp_single
! Single construct with nowait
!===============================================================================
-!FIRDialect-LABEL: func @_QPomp_single_nowait
-!FIRDialect-SAME: (%[[x:.*]]: !fir.ref<i32> {fir.bindc_name = "x"})
+!CHECK-LABEL: func @_QPomp_single_nowait
+!CHECK-SAME: (%[[x:.*]]: !fir.ref<i32> {fir.bindc_name = "x"})
subroutine omp_single_nowait(x)
integer, intent(inout) :: x
- !OMPDialect: omp.parallel
+ !CHECK: omp.parallel
!$omp parallel
- !OMPDialect: omp.single nowait
+ !CHECK: omp.single nowait
!$omp single
- !FIRDialect: %[[xval:.*]] = fir.load %[[x]] : !fir.ref<i32>
- !FIRDialect: %[[res:.*]] = arith.addi %[[xval]], %{{.*}} : i32
- !FIRDialect: fir.store %[[res]] to %[[x]] : !fir.ref<i32>
+ !CHECK: %[[xval:.*]] = fir.load %[[x]] : !fir.ref<i32>
+ !CHECK: %[[res:.*]] = arith.addi %[[xval]], %{{.*}} : i32
+ !CHECK: fir.store %[[res]] to %[[x]] : !fir.ref<i32>
x = x + 12
- !OMPDialect: omp.terminator
+ !CHECK: omp.terminator
!$omp end single nowait
- !OMPDialect: omp.terminator
+ !CHECK: omp.terminator
!$omp end parallel
end subroutine omp_single_nowait
@@ -49,21 +49,73 @@ end subroutine omp_single_nowait
! Single construct with allocate
!===============================================================================
-!FIRDialect-LABEL: func @_QPsingle_allocate
+!CHECK-LABEL: func @_QPsingle_allocate
subroutine single_allocate()
use omp_lib
integer :: x
- !OMPDialect: omp.parallel {
+ !CHECK: omp.parallel {
!$omp parallel
- !OMPDialect: omp.single allocate(
- !FIRDialect: %{{.+}} : i32 -> %{{.+}} : !fir.ref<i32>
- !LLVMDialect: %{{.+}} : i32 -> %{{.+}} : !llvm.ptr<i32>
- !OMPDialect: ) {
+ !CHECK: omp.single allocate(%{{.+}} : i32 -> %{{.+}} : !fir.ref<i32>) {
!$omp single allocate(omp_high_bw_mem_alloc: x) private(x)
- !FIRDialect: arith.addi
+ !CHECK: arith.addi
x = x + 12
- !OMPDialect: omp.terminator
+ !CHECK: omp.terminator
!$omp end single
- !OMPDialect: omp.terminator
+ !CHECK: omp.terminator
!$omp end parallel
end subroutine single_allocate
+
+!===============================================================================
+! Single construct with private/firstprivate
+!===============================================================================
+
+! CHECK-LABEL: func.func @_QPsingle_privatization(
+! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<f32> {fir.bindc_name = "x"},
+! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<f64> {fir.bindc_name = "y"}) {
+! CHECK: %[[VAL_2:.*]] = fir.alloca f32 {bindc_name = "x", pinned, uniq_name = "_QFsingle_privatizationEx"}
+! CHECK: %[[VAL_3:.*]] = fir.alloca f64 {bindc_name = "y", pinned, uniq_name = "_QFsingle_privatizationEy"}
+! CHECK: omp.single {
+! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_1]] : !fir.ref<f64>
+! CHECK: fir.store %[[VAL_4]] to %[[VAL_3]] : !fir.ref<f64>
+! CHECK: fir.call @_QPbar(%[[VAL_2]], %[[VAL_3]]) : (!fir.ref<f32>, !fir.ref<f64>) -> ()
+! CHECK: omp.terminator
+! CHECK: }
+! CHECK: return
+! CHECK: }
+
+subroutine single_privatization(x, y)
+ real :: x
+ real(8) :: y
+
+ !$omp single private(x) firstprivate(y)
+ call bar(x, y)
+ !$omp end single
+end subroutine
+
+! CHECK-LABEL: func.func @_QPsingle_privatization2(
+! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<f32> {fir.bindc_name = "x"},
+! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<f64> {fir.bindc_name = "y"}) {
+! CHECK: omp.parallel {
+! CHECK: %[[VAL_2:.*]] = fir.alloca f32 {bindc_name = "x", pinned, uniq_name = "_QFsingle_privatization2Ex"}
+! CHECK: %[[VAL_3:.*]] = fir.alloca f64 {bindc_name = "y", pinned, uniq_name = "_QFsingle_privatization2Ey"}
+! CHECK: omp.single {
+! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_1]] : !fir.ref<f64>
+! CHECK: fir.store %[[VAL_4]] to %[[VAL_3]] : !fir.ref<f64>
+! CHECK: fir.call @_QPbar(%[[VAL_2]], %[[VAL_3]]) : (!fir.ref<f32>, !fir.ref<f64>) -> ()
+! CHECK: omp.terminator
+! CHECK: }
+! CHECK: omp.terminator
+! CHECK: }
+! CHECK: return
+! CHECK: }
+
+subroutine single_privatization2(x, y)
+ real :: x
+ real(8) :: y
+
+ !$omp parallel
+ !$omp single private(x) firstprivate(y)
+ call bar(x, y)
+ !$omp end single
+ !$omp end parallel
+end subroutine
More information about the flang-commits
mailing list