Skip to content

Commit

Permalink
[flang][OpenMP] Fix privatization of threadprivate common block (#77821)
Browse files Browse the repository at this point in the history
In some cases, when privatizing a threadprivate common block, the
original symbol will correspond to the common block, instead of
its threadprivate version. This can happen, for instance, with a
common block, declared in a separate module, used by a parent
procedure and privatized in its child procedure. In this case,
symbol lookup won't find a symbol in the parent procedure, but
only in the module where the common block was defined.

Fixes #65028
  • Loading branch information
luporl committed Feb 6, 2024
1 parent e686695 commit 48927e9
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 9 deletions.
34 changes: 25 additions & 9 deletions flang/lib/Lower/OpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2143,25 +2143,41 @@ static fir::ExtendedValue getExtendedValue(fir::ExtendedValue base,
});
}

#ifndef NDEBUG
static bool isThreadPrivate(Fortran::lower::SymbolRef sym) {
if (const auto *details =
sym->detailsIf<Fortran::semantics::CommonBlockDetails>()) {
for (const auto &obj : details->objects())
if (!obj->test(Fortran::semantics::Symbol::Flag::OmpThreadprivate))
return false;
return true;
}
return sym->test(Fortran::semantics::Symbol::Flag::OmpThreadprivate);
}
#endif

static void threadPrivatizeVars(Fortran::lower::AbstractConverter &converter,
Fortran::lower::pft::Evaluation &eval) {
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
mlir::Location currentLocation = converter.getCurrentLocation();
mlir::OpBuilder::InsertPoint insPt = firOpBuilder.saveInsertionPoint();
firOpBuilder.setInsertionPointToStart(firOpBuilder.getAllocaBlock());

// Get the original ThreadprivateOp corresponding to the symbol and use the
// symbol value from that operation to create one ThreadprivateOp copy
// operation inside the parallel region.
// If the symbol corresponds to the original ThreadprivateOp, use the symbol
// value from that operation to create one ThreadprivateOp copy operation
// inside the parallel region.
// In some cases, however, the symbol will correspond to the original,
// non-threadprivate variable. This can happen, for instance, with a common
// block, declared in a separate module, used by a parent procedure and
// privatized in its child procedure.
auto genThreadprivateOp = [&](Fortran::lower::SymbolRef sym) -> mlir::Value {
mlir::Value symOriThreadprivateValue = converter.getSymbolAddress(sym);
mlir::Operation *op = symOriThreadprivateValue.getDefiningOp();
assert(isThreadPrivate(sym));
mlir::Value symValue = converter.getSymbolAddress(sym);
mlir::Operation *op = symValue.getDefiningOp();
if (auto declOp = mlir::dyn_cast<hlfir::DeclareOp>(op))
op = declOp.getMemref().getDefiningOp();
assert(mlir::isa<mlir::omp::ThreadprivateOp>(op) &&
"Threadprivate operation not created");
mlir::Value symValue =
mlir::dyn_cast<mlir::omp::ThreadprivateOp>(op).getSymAddr();
if (mlir::isa<mlir::omp::ThreadprivateOp>(op))
symValue = mlir::dyn_cast<mlir::omp::ThreadprivateOp>(op).getSymAddr();
return firOpBuilder.create<mlir::omp::ThreadprivateOp>(
currentLocation, symValue.getType(), symValue);
};
Expand Down
29 changes: 29 additions & 0 deletions flang/test/Lower/OpenMP/threadprivate-commonblock-use.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
! This test checks lowering of OpenMP Threadprivate Directive.
! Test for common block, defined in one module, used in a subroutine of
! another module and privatized in a nested subroutine.

!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s

!CHECK: fir.global common @cmn_(dense<0> : vector<4xi8>) : !fir.array<4xi8>
module m0
common /cmn/ k1
!$omp threadprivate(/cmn/)
end

module m1
contains
subroutine ss1
use m0
contains
!CHECK-LABEL: func @_QMm1Fss1Pss2
!CHECK: %[[CMN:.*]] = fir.address_of(@cmn_) : !fir.ref<!fir.array<4xi8>>
!CHECK: omp.parallel
!CHECK: %{{.*}} = omp.threadprivate %[[CMN]] : !fir.ref<!fir.array<4xi8>> -> !fir.ref<!fir.array<4xi8>>
subroutine ss2
!$omp parallel copyin (k1)
!$omp end parallel
end subroutine ss2
end subroutine ss1
end

end

0 comments on commit 48927e9

Please sign in to comment.