Skip to content
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

[Flang][OpenMP] Add support for lastprivate clause lowering. #1593

Open
wants to merge 1 commit into
base: fir-dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion flang/include/flang/Lower/AbstractConverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ class AbstractConverter {
virtual bool
createHostAssociateVarClone(const Fortran::semantics::Symbol &sym) = 0;

virtual void copyHostAssociateVar(const Fortran::semantics::Symbol &sym) = 0;
virtual void copyHostAssociateVar(const Fortran::semantics::Symbol &sym,
bool firstPrivate = false,
bool lastPrivate = false) = 0;

//===--------------------------------------------------------------------===//
// Expressions
Expand Down
37 changes: 30 additions & 7 deletions flang/lib/Lower/Bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -467,8 +467,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
return bindIfNewSymbol(sym, exv);
}

void
copyHostAssociateVar(const Fortran::semantics::Symbol &sym) override final {
void copyHostAssociateVar(const Fortran::semantics::Symbol &sym,
bool firstPrivate,
bool lastPrivate) override final {
// 1) Fetch the original copy of the variable.
assert(sym.has<Fortran::semantics::HostAssocDetails>() &&
"No host-association found");
Expand All @@ -477,25 +478,47 @@ class FirConverter : public Fortran::lower::AbstractConverter {
fir::ExtendedValue hexv = getExtendedValue(hsb);

// 2) Create a copy that will mask the original.
createHostAssociateVarClone(sym);
// Make sure you do not create multiple clones when a variable is
// both firstPrivate and lastPrivate, as in that case, a clone will
// already be created for you during the function call with firstPrivate.
if (!(firstPrivate && lastPrivate)) {
createHostAssociateVarClone(sym);
}

Fortran::lower::SymbolBox sb = lookupSymbol(sym);
fir::ExtendedValue exv = getExtendedValue(sb);

if (lastPrivate) {
// Copy back to the original value right before exiting the block.
builder->setInsertionPoint(
getSymbolAddress(sym).getParentBlock()->getTerminator());
}

fir::ExtendedValue lhs, rhs;

if (lastPrivate) {
lhs = hexv;
rhs = exv;
} else {
lhs = exv;
rhs = hexv;
}

// 3) Perform the assignment.
mlir::Location loc = genLocation(sym.name());
mlir::Type symType = genType(sym);
if (auto seqTy = symType.dyn_cast<fir::SequenceType>()) {
Fortran::lower::StatementContext stmtCtx;
Fortran::lower::createSomeArrayAssignment(*this, exv, hexv, localSymbols,
Fortran::lower::createSomeArrayAssignment(*this, lhs, rhs, localSymbols,
stmtCtx);
stmtCtx.finalize();
} else if (hexv.getBoxOf<fir::CharBoxValue>()) {
fir::factory::CharacterExprHelper{*builder, loc}.createAssign(exv, hexv);
fir::factory::CharacterExprHelper{*builder, loc}.createAssign(lhs, rhs);
} else if (hexv.getBoxOf<fir::MutableBoxValue>()) {
TODO(loc, "firstprivatisation of allocatable variables");
} else {
auto loadVal = builder->create<fir::LoadOp>(loc, fir::getBase(hexv));
builder->create<fir::StoreOp>(loc, loadVal, fir::getBase(exv));
auto loadVal = builder->create<fir::LoadOp>(loc, fir::getBase(rhs));
builder->create<fir::StoreOp>(loc, loadVal, fir::getBase(lhs));
}
}

Expand Down
12 changes: 11 additions & 1 deletion flang/lib/Lower/OpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,13 @@ static void createPrivateVarSyms(Fortran::lower::AbstractConverter &converter,
// variables) happen separately, for everything else privatize here.
if (sym->test(Fortran::semantics::Symbol::Flag::OmpPreDetermined))
continue;
bool firstPrivate = false;
if constexpr (std::is_same_v<T, Fortran::parser::OmpClause::Firstprivate>) {
converter.copyHostAssociateVar(*sym);
firstPrivate = true;
converter.copyHostAssociateVar(*sym, firstPrivate, /*lastPrivate*/ false);
}
if constexpr (std::is_same_v<T, Fortran::parser::OmpClause::Lastprivate>) {
converter.copyHostAssociateVar(*sym, firstPrivate, /*lastPrivate*/ true);
} else {
bool success = converter.createHostAssociateVarClone(*sym);
(void)success;
Expand All @@ -75,6 +80,10 @@ static void privatizeVars(Fortran::lower::AbstractConverter &converter,
std::get_if<Fortran::parser::OmpClause::Firstprivate>(
&clause.u)) {
createPrivateVarSyms(converter, firstPrivateClause);
} else if (const auto &lastPrivateClause =
std::get_if<Fortran::parser::OmpClause::Lastprivate>(
&clause.u)) {
createPrivateVarSyms(converter, lastPrivateClause);
}
}
firOpBuilder.restoreInsertionPoint(insPt);
Expand Down Expand Up @@ -714,6 +723,7 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,

createBodyOfOp<omp::WsLoopOp>(wsLoopOp, converter, currentLocation, eval,
&wsLoopOpClauseList, iv);

}

static void
Expand Down
68 changes: 68 additions & 0 deletions flang/test/Lower/OpenMP/omp-parallel-lastprivate-clause-scalar.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
! This test checks lowering of `FIRSTPRIVATE` clause for scalar types.

! RUN: bbc -fopenmp -emit-fir %s -o - | FileCheck %s --check-prefix=FIRDialect

!FIRDialect: func @_QPlastprivate_character(%[[ARG1:.*]]: !fir.boxchar<1>{{.*}}) {
!FIRDialect-DAG: %[[ARG1_UNBOX:.*]]:2 = fir.unboxchar
!FIRDialect: omp.parallel {
!FIRDialect-DAG: %[[ARG1_PVT:.*]] = fir.alloca !fir.char<1,5> {bindc_name = "arg1",
! Check that we are accessing the clone inside the loop
!FIRDialect-DAG: %[[ARG1_PVT_REF:.*]] = fir.convert %[[ARG1_PVT]] : (!fir.ref<!fir.char<1,5>>) -> !fir.ref<i8>

! Check we are copying back the last iterated value back to the clone before exiting
!FIRDialect-DAG: %[[LOCAL_VAR:.*]] = fir.alloca i32 {adapt.valuebyref, pinned}
!FIRDialect-DAG: omp.wsloop (%[[INDX_WS:.*]]) : {{.*}} {
!FIRDialect-DAG: fir.store %[[INDX_WS]] to %[[LOCAL_VAR]] : !fir.ref<i32>
!FIRDialect-DAG: %[[ADDR:.*]] = fir.address_of(@_QQcl.63) : !fir.ref<!fir.char<1>>

! Testing string copy
!FIRDialect-DAG: %[[CVT:.*]] = fir.convert %[[ARG1_UNBOX]]#0 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<i8>
!FIRDialect-DAG: %[[CVT1:.*]] = fir.convert %[[ARG1_PVT]] : (!fir.ref<!fir.char<1,5>>) -> !fir.ref<i8>
!FIRDialect-DAG: fir.call @llvm.memmove.p0i8.p0i8.i64(%[[CVT]], %[[CVT1]]{{.*}})

!FIRDialect: %[[THIRTY_TWO:.*]] = arith.constant 32 : i8
!FIRDialect-DAG: %[[UNDEF:.*]] = fir.undefined !fir.char<1>
!FIRDialect-DAG: %[[INSERT:.*]] = fir.insert_value %[[UNDEF]], %[[THIRTY_TWO]], [0 : index] : (!fir.char<1>, i8) -> !fir.char<1>
!FIRDialect-DAG: %[[ONE_3:.*]] = arith.constant 1 : index

!FIRDialect: fir.do_loop %[[INDX_WS]] = {{.*}} {
!FIRDialect-DAG: %[[CVT_2:.*]] = fir.convert %[[ARG1_UNBOX]]#0 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<!fir.array<?x!fir.char<1>>>
!FIRDialect-DAG: %[[COORD:.*]] = fir.coordinate_of %[[CVT_2]], %[[INDX_WS]] : (!fir.ref<!fir.array<?x!fir.char<1>>>, index) -> !fir.ref<!fir.char<1>>
!FIRDialect-DAG: fir.store %[[INSERT]] to %[[COORD]] : !fir.ref<!fir.char<1>>
!FIRDialect-DAG: }


subroutine lastprivate_character(arg1)
character(5) :: arg1

!$OMP PARALLEL
!$OMP DO LASTPRIVATE(arg1)
do n = 1, 5
arg1(n:n) = 'c'
print *, arg1
end do
!$OMP END DO
!$OMP END PARALLEL

end subroutine

!FIRDialect: func @_QPlastprivate_int(%[[ARG1:.*]]: !fir.ref<i32> {fir.bindc_name = "arg1"}) {
!FIRDialect-DAG: omp.parallel {
!FIRDialect-DAG: %[[CLONE:.*]] = fir.alloca i32 {bindc_name = "arg1"
!FIRDialect: omp.yield
!FIRDialect: %[[CLONE_LD:.*]] = fir.load %[[CLONE]] : !fir.ref<i32>
!FIRDialect-DAG: fir.store %[[CLONE_LD]] to %[[ARG1]] : !fir.ref<i32>
!FIRDialect-DAG: omp.terminator

subroutine lastprivate_int(arg1)
integer :: arg1
!$OMP PARALLEL
!$OMP DO LASTPRIVATE(arg1)
do n = 1, 5
arg1 = 2
print *, arg1
end do
!$OMP END DO
!$OMP END PARALLEL
print *, arg1
end subroutine