[Flang][OpenMP] Fix copyin allocatable lowering to MLIR (#122097)
Fixes https://github.com/llvm/llvm-project/issues/113191
Issue: [flang][OpenMP] Runtime segfault when an allocatable variable is
used with copyin
Rootcause: The value of the threadprivate variable is not being copied
from the primary thread to the other threads within a parallel region.
As a result it tries to access a null pointer inside a parallel region
which causes segfault.
Fix: When allocatables used with copyin clause need to ensure that, on
entry to any parallel region each thread’s copy of a variable will
acquire the allocation status of the primary thread, before copying the
value of a threadprivate variable of the primary thread to the
threadprivate variable of each other member of the team.
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 700ca56..d92dc0c 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -1290,9 +1290,30 @@
auto loadVal = builder->create<fir::LoadOp>(loc, rhs);
builder->create<fir::StoreOp>(loc, loadVal, lhs);
} else if (isAllocatable &&
- (flags.test(Fortran::semantics::Symbol::Flag::OmpFirstPrivate) ||
- flags.test(Fortran::semantics::Symbol::Flag::OmpCopyIn))) {
- // For firstprivate and copyin allocatable variables, RHS must be copied
+ flags.test(Fortran::semantics::Symbol::Flag::OmpCopyIn)) {
+ // For copyin allocatable variables, RHS must be copied to lhs
+ // only when rhs is allocated.
+ hlfir::Entity temp =
+ hlfir::derefPointersAndAllocatables(loc, *builder, rhs);
+ mlir::Value addr = hlfir::genVariableRawAddress(loc, *builder, temp);
+ mlir::Value isAllocated = builder->genIsNotNullAddr(loc, addr);
+ builder->genIfThenElse(loc, isAllocated)
+ .genThen([&]() { copyData(lhs, rhs); })
+ .genElse([&]() {
+ fir::ExtendedValue hexv = symBoxToExtendedValue(dst);
+ hexv.match(
+ [&](const fir::MutableBoxValue &new_box) -> void {
+ // if the allocation status of original list item is
+ // unallocated, unallocate the copy if it is allocated, else
+ // do nothing.
+ Fortran::lower::genDeallocateIfAllocated(*this, new_box, loc);
+ },
+ [&](const auto &) -> void {});
+ })
+ .end();
+ } else if (isAllocatable &&
+ flags.test(Fortran::semantics::Symbol::Flag::OmpFirstPrivate)) {
+ // For firstprivate allocatable variables, RHS must be copied
// only when LHS is allocated.
hlfir::Entity temp =
hlfir::derefPointersAndAllocatables(loc, *builder, lhs);