Skip to content

Commit 5968560

Browse files
committed
[flang][mlir][OpenMP] Add support for COPYPRIVATE
Add initial handling of OpenMP COPYPRIVATE clause in Flang. MLIR's omp.single operation was modified to support an optional CopyPrivateVarList. It consists of pairs of variables and functions. When present, each thread variable is updated with the variable value of the thread that executed the single region, using the specified functions to perform the copy. When lowering COPYPRIVATE, Flang then generates the copy function needed by each variable and builds the appropriate CopyPrivateVarList. The translation to LLVM IR is done in OMPIRBuilder, by calling createCopyPrivate() for each variable in the list, which generates calls to __kmpc_copyprivate. Fixes #63933
1 parent b522675 commit 5968560

File tree

11 files changed

+498
-83
lines changed

11 files changed

+498
-83
lines changed

flang/include/flang/Lower/AbstractConverter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ class AbstractConverter {
118118
const Fortran::semantics::Symbol &sym,
119119
mlir::OpBuilder::InsertPoint *copyAssignIP = nullptr) = 0;
120120

121+
virtual void copyVar(mlir::Location loc, mlir::Value dst,
122+
mlir::Value src) = 0;
123+
121124
/// For a given symbol, check if it is present in the inner-most
122125
/// level of the symbol map.
123126
virtual bool isPresentShallowLookup(Fortran::semantics::Symbol &sym) = 0;

flang/lib/Lower/Bridge.cpp

Lines changed: 79 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,11 @@ class FirConverter : public Fortran::lower::AbstractConverter {
740740
});
741741
}
742742

743+
void copyVar(mlir::Location loc, mlir::Value dst,
744+
mlir::Value src) override final {
745+
copyVarHLFIR(loc, dst, src);
746+
}
747+
743748
void copyHostAssociateVar(
744749
const Fortran::semantics::Symbol &sym,
745750
mlir::OpBuilder::InsertPoint *copyAssignIP = nullptr) override final {
@@ -774,64 +779,7 @@ class FirConverter : public Fortran::lower::AbstractConverter {
774779
rhs_sb = &hsb;
775780
}
776781

777-
mlir::Location loc = genLocation(sym.name());
778-
779-
if (lowerToHighLevelFIR()) {
780-
hlfir::Entity lhs{lhs_sb->getAddr()};
781-
hlfir::Entity rhs{rhs_sb->getAddr()};
782-
// Temporary_lhs is set to true in hlfir.assign below to avoid user
783-
// assignment to be used and finalization to be called on the LHS.
784-
// This may or may not be correct but mimics the current behaviour
785-
// without HLFIR.
786-
auto copyData = [&](hlfir::Entity l, hlfir::Entity r) {
787-
// Dereference RHS and load it if trivial scalar.
788-
r = hlfir::loadTrivialScalar(loc, *builder, r);
789-
builder->create<hlfir::AssignOp>(
790-
loc, r, l,
791-
/*isWholeAllocatableAssignment=*/false,
792-
/*keepLhsLengthInAllocatableAssignment=*/false,
793-
/*temporary_lhs=*/true);
794-
};
795-
if (lhs.isAllocatable()) {
796-
// Deep copy allocatable if it is allocated.
797-
// Note that when allocated, the RHS is already allocated with the LHS
798-
// shape for copy on entry in createHostAssociateVarClone.
799-
// For lastprivate, this assumes that the RHS was not reallocated in
800-
// the OpenMP region.
801-
lhs = hlfir::derefPointersAndAllocatables(loc, *builder, lhs);
802-
mlir::Value addr = hlfir::genVariableRawAddress(loc, *builder, lhs);
803-
mlir::Value isAllocated = builder->genIsNotNullAddr(loc, addr);
804-
builder->genIfThen(loc, isAllocated)
805-
.genThen([&]() {
806-
// Copy the DATA, not the descriptors.
807-
copyData(lhs, rhs);
808-
})
809-
.end();
810-
} else if (lhs.isPointer()) {
811-
// Set LHS target to the target of RHS (do not copy the RHS
812-
// target data into the LHS target storage).
813-
auto loadVal = builder->create<fir::LoadOp>(loc, rhs);
814-
builder->create<fir::StoreOp>(loc, loadVal, lhs);
815-
} else {
816-
// Non ALLOCATABLE/POINTER variable. Simple DATA copy.
817-
copyData(lhs, rhs);
818-
}
819-
} else {
820-
fir::ExtendedValue lhs = symBoxToExtendedValue(*lhs_sb);
821-
fir::ExtendedValue rhs = symBoxToExtendedValue(*rhs_sb);
822-
mlir::Type symType = genType(sym);
823-
if (auto seqTy = symType.dyn_cast<fir::SequenceType>()) {
824-
Fortran::lower::StatementContext stmtCtx;
825-
Fortran::lower::createSomeArrayAssignment(*this, lhs, rhs, localSymbols,
826-
stmtCtx);
827-
stmtCtx.finalizeAndReset();
828-
} else if (lhs.getBoxOf<fir::CharBoxValue>()) {
829-
fir::factory::CharacterExprHelper{*builder, loc}.createAssign(lhs, rhs);
830-
} else {
831-
auto loadVal = builder->create<fir::LoadOp>(loc, fir::getBase(rhs));
832-
builder->create<fir::StoreOp>(loc, loadVal, fir::getBase(lhs));
833-
}
834-
}
782+
copyVar(sym, *lhs_sb, *rhs_sb);
835783

836784
if (copyAssignIP && copyAssignIP->isSet() &&
837785
sym.test(Fortran::semantics::Symbol::Flag::OmpLastPrivate)) {
@@ -1089,6 +1037,79 @@ class FirConverter : public Fortran::lower::AbstractConverter {
10891037
return true;
10901038
}
10911039

1040+
void copyVar(const Fortran::semantics::Symbol &sym,
1041+
const Fortran::lower::SymbolBox &lhs_sb,
1042+
const Fortran::lower::SymbolBox &rhs_sb) {
1043+
mlir::Location loc = genLocation(sym.name());
1044+
if (lowerToHighLevelFIR())
1045+
copyVarHLFIR(loc, lhs_sb.getAddr(), rhs_sb.getAddr());
1046+
else
1047+
copyVarFIR(loc, sym, lhs_sb, rhs_sb);
1048+
}
1049+
1050+
void copyVarHLFIR(mlir::Location loc, mlir::Value dst, mlir::Value src) {
1051+
assert(lowerToHighLevelFIR());
1052+
hlfir::Entity lhs{dst};
1053+
hlfir::Entity rhs{src};
1054+
// Temporary_lhs is set to true in hlfir.assign below to avoid user
1055+
// assignment to be used and finalization to be called on the LHS.
1056+
// This may or may not be correct but mimics the current behaviour
1057+
// without HLFIR.
1058+
auto copyData = [&](hlfir::Entity l, hlfir::Entity r) {
1059+
// Dereference RHS and load it if trivial scalar.
1060+
r = hlfir::loadTrivialScalar(loc, *builder, r);
1061+
builder->create<hlfir::AssignOp>(
1062+
loc, r, l,
1063+
/*isWholeAllocatableAssignment=*/false,
1064+
/*keepLhsLengthInAllocatableAssignment=*/false,
1065+
/*temporary_lhs=*/true);
1066+
};
1067+
if (lhs.isAllocatable()) {
1068+
// Deep copy allocatable if it is allocated.
1069+
// Note that when allocated, the RHS is already allocated with the LHS
1070+
// shape for copy on entry in createHostAssociateVarClone.
1071+
// For lastprivate, this assumes that the RHS was not reallocated in
1072+
// the OpenMP region.
1073+
lhs = hlfir::derefPointersAndAllocatables(loc, *builder, lhs);
1074+
mlir::Value addr = hlfir::genVariableRawAddress(loc, *builder, lhs);
1075+
mlir::Value isAllocated = builder->genIsNotNullAddr(loc, addr);
1076+
builder->genIfThen(loc, isAllocated)
1077+
.genThen([&]() {
1078+
// Copy the DATA, not the descriptors.
1079+
copyData(lhs, rhs);
1080+
})
1081+
.end();
1082+
} else if (lhs.isPointer()) {
1083+
// Set LHS target to the target of RHS (do not copy the RHS
1084+
// target data into the LHS target storage).
1085+
auto loadVal = builder->create<fir::LoadOp>(loc, rhs);
1086+
builder->create<fir::StoreOp>(loc, loadVal, lhs);
1087+
} else {
1088+
// Non ALLOCATABLE/POINTER variable. Simple DATA copy.
1089+
copyData(lhs, rhs);
1090+
}
1091+
}
1092+
1093+
void copyVarFIR(mlir::Location loc, const Fortran::semantics::Symbol &sym,
1094+
const Fortran::lower::SymbolBox &lhs_sb,
1095+
const Fortran::lower::SymbolBox &rhs_sb) {
1096+
assert(!lowerToHighLevelFIR());
1097+
fir::ExtendedValue lhs = symBoxToExtendedValue(lhs_sb);
1098+
fir::ExtendedValue rhs = symBoxToExtendedValue(rhs_sb);
1099+
mlir::Type symType = genType(sym);
1100+
if (auto seqTy = symType.dyn_cast<fir::SequenceType>()) {
1101+
Fortran::lower::StatementContext stmtCtx;
1102+
Fortran::lower::createSomeArrayAssignment(*this, lhs, rhs, localSymbols,
1103+
stmtCtx);
1104+
stmtCtx.finalizeAndReset();
1105+
} else if (lhs.getBoxOf<fir::CharBoxValue>()) {
1106+
fir::factory::CharacterExprHelper{*builder, loc}.createAssign(lhs, rhs);
1107+
} else {
1108+
auto loadVal = builder->create<fir::LoadOp>(loc, fir::getBase(rhs));
1109+
builder->create<fir::StoreOp>(loc, loadVal, fir::getBase(lhs));
1110+
}
1111+
}
1112+
10921113
/// Map a block argument to a result or dummy symbol. This is not the
10931114
/// definitive mapping. The specification expression have not been lowered
10941115
/// yet. The final mapping will be done using this pre-mapping in

0 commit comments

Comments
 (0)