|
22 | 22 | #include "flang/Optimizer/Builder/BoxValue.h"
|
23 | 23 | #include "flang/Optimizer/Builder/FIRBuilder.h"
|
24 | 24 | #include "flang/Optimizer/Builder/Todo.h"
|
| 25 | +#include "flang/Optimizer/Dialect/FIRType.h" |
25 | 26 | #include "flang/Optimizer/HLFIR/HLFIROps.h"
|
26 | 27 | #include "flang/Parser/dump-parse-tree.h"
|
27 | 28 | #include "flang/Parser/parse-tree.h"
|
@@ -592,6 +593,10 @@ class ClauseProcessor {
|
592 | 593 | processAllocate(llvm::SmallVectorImpl<mlir::Value> &allocatorOperands,
|
593 | 594 | llvm::SmallVectorImpl<mlir::Value> &allocateOperands) const;
|
594 | 595 | bool processCopyin() const;
|
| 596 | + bool processCopyPrivate( |
| 597 | + mlir::Location currentLocation, |
| 598 | + llvm::SmallVectorImpl<mlir::Value> ©PrivateVars, |
| 599 | + llvm::SmallVectorImpl<mlir::Attribute> ©PrivateFuncs) const; |
595 | 600 | bool processDepend(llvm::SmallVectorImpl<mlir::Attribute> &dependTypeOperands,
|
596 | 601 | llvm::SmallVectorImpl<mlir::Value> &dependOperands) const;
|
597 | 602 | bool
|
@@ -1160,6 +1165,102 @@ class ReductionProcessor {
|
1160 | 1165 | }
|
1161 | 1166 | };
|
1162 | 1167 |
|
| 1168 | +/// Class that extracts information from the specified type. |
| 1169 | +class TypeInfo { |
| 1170 | +public: |
| 1171 | + TypeInfo(mlir::Type ty) { typeScan(ty); } |
| 1172 | + |
| 1173 | + // Returns the length of character types. |
| 1174 | + std::optional<fir::CharacterType::LenType> getCharLength() const { |
| 1175 | + return charLen; |
| 1176 | + } |
| 1177 | + |
| 1178 | + // Returns the shape of array types. |
| 1179 | + const llvm::SmallVector<int64_t> &getShape() const { return shape; } |
| 1180 | + |
| 1181 | + // Is the type inside a box? |
| 1182 | + bool isBox() const { return inBox; } |
| 1183 | + |
| 1184 | +private: |
| 1185 | + void typeScan(mlir::Type type); |
| 1186 | + |
| 1187 | + std::optional<fir::CharacterType::LenType> charLen; |
| 1188 | + llvm::SmallVector<int64_t> shape; |
| 1189 | + bool inBox = false; |
| 1190 | +}; |
| 1191 | + |
| 1192 | +void TypeInfo::typeScan(mlir::Type ty) { |
| 1193 | + if (auto sty = mlir::dyn_cast<fir::SequenceType>(ty)) { |
| 1194 | + assert(shape.empty() && !sty.getShape().empty()); |
| 1195 | + shape = llvm::SmallVector<int64_t>(sty.getShape()); |
| 1196 | + typeScan(sty.getEleTy()); |
| 1197 | + } else if (auto bty = mlir::dyn_cast<fir::BoxType>(ty)) { |
| 1198 | + inBox = true; |
| 1199 | + typeScan(bty.getEleTy()); |
| 1200 | + } else if (auto cty = mlir::dyn_cast<fir::CharacterType>(ty)) { |
| 1201 | + charLen = cty.getLen(); |
| 1202 | + } else if (auto hty = mlir::dyn_cast<fir::HeapType>(ty)) { |
| 1203 | + typeScan(hty.getEleTy()); |
| 1204 | + } else if (auto pty = mlir::dyn_cast<fir::PointerType>(ty)) { |
| 1205 | + typeScan(pty.getEleTy()); |
| 1206 | + } |
| 1207 | +} |
| 1208 | + |
| 1209 | +// Create a function that performs a copy between two variables, compatible |
| 1210 | +// with their types and attributes. |
| 1211 | +static mlir::func::FuncOp |
| 1212 | +createCopyFunc(mlir::Location loc, Fortran::lower::AbstractConverter &converter, |
| 1213 | + mlir::Type varType, fir::FortranVariableFlagsEnum varAttrs) { |
| 1214 | + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); |
| 1215 | + mlir::ModuleOp module = builder.getModule(); |
| 1216 | + mlir::Type eleTy = mlir::cast<fir::ReferenceType>(varType).getEleTy(); |
| 1217 | + TypeInfo typeInfo(eleTy); |
| 1218 | + std::string copyFuncName = |
| 1219 | + fir::getTypeAsString(eleTy, builder.getKindMap(), "_copy"); |
| 1220 | + |
| 1221 | + if (auto decl = module.lookupSymbol<mlir::func::FuncOp>(copyFuncName)) |
| 1222 | + return decl; |
| 1223 | + |
| 1224 | + // create function |
| 1225 | + mlir::OpBuilder::InsertionGuard guard(builder); |
| 1226 | + mlir::OpBuilder modBuilder(module.getBodyRegion()); |
| 1227 | + llvm::SmallVector<mlir::Type> argsTy = {varType, varType}; |
| 1228 | + auto funcType = mlir::FunctionType::get(builder.getContext(), argsTy, {}); |
| 1229 | + mlir::func::FuncOp funcOp = |
| 1230 | + modBuilder.create<mlir::func::FuncOp>(loc, copyFuncName, funcType); |
| 1231 | + funcOp.setVisibility(mlir::SymbolTable::Visibility::Private); |
| 1232 | + builder.createBlock(&funcOp.getRegion(), funcOp.getRegion().end(), argsTy, |
| 1233 | + {loc, loc}); |
| 1234 | + builder.setInsertionPointToStart(&funcOp.getRegion().back()); |
| 1235 | + // generate body |
| 1236 | + fir::FortranVariableFlagsAttr attrs; |
| 1237 | + if (varAttrs != fir::FortranVariableFlagsEnum::None) |
| 1238 | + attrs = fir::FortranVariableFlagsAttr::get(builder.getContext(), varAttrs); |
| 1239 | + llvm::SmallVector<mlir::Value> typeparams; |
| 1240 | + if (typeInfo.getCharLength().has_value()) { |
| 1241 | + mlir::Value charLen = builder.createIntegerConstant( |
| 1242 | + loc, builder.getCharacterLengthType(), *typeInfo.getCharLength()); |
| 1243 | + typeparams.push_back(charLen); |
| 1244 | + } |
| 1245 | + mlir::Value shape; |
| 1246 | + if (!typeInfo.isBox() && !typeInfo.getShape().empty()) { |
| 1247 | + llvm::SmallVector<mlir::Value> extents; |
| 1248 | + for (auto extent : typeInfo.getShape()) |
| 1249 | + extents.push_back( |
| 1250 | + builder.createIntegerConstant(loc, builder.getIndexType(), extent)); |
| 1251 | + shape = builder.create<fir::ShapeOp>(loc, extents); |
| 1252 | + } |
| 1253 | + auto declDst = builder.create<hlfir::DeclareOp>(loc, funcOp.getArgument(0), |
| 1254 | + copyFuncName + "_dst", shape, |
| 1255 | + typeparams, attrs); |
| 1256 | + auto declSrc = builder.create<hlfir::DeclareOp>(loc, funcOp.getArgument(1), |
| 1257 | + copyFuncName + "_src", shape, |
| 1258 | + typeparams, attrs); |
| 1259 | + converter.copyVar(loc, declDst.getBase(), declSrc.getBase()); |
| 1260 | + builder.create<mlir::func::ReturnOp>(loc); |
| 1261 | + return funcOp; |
| 1262 | +} |
| 1263 | + |
1163 | 1264 | static mlir::omp::ScheduleModifier
|
1164 | 1265 | translateScheduleModifier(const Fortran::parser::OmpScheduleModifierType &m) {
|
1165 | 1266 | switch (m.v) {
|
@@ -1740,6 +1841,62 @@ bool ClauseProcessor::processCopyin() const {
|
1740 | 1841 | return hasCopyin;
|
1741 | 1842 | }
|
1742 | 1843 |
|
| 1844 | +bool ClauseProcessor::processCopyPrivate( |
| 1845 | + mlir::Location currentLocation, |
| 1846 | + llvm::SmallVectorImpl<mlir::Value> ©PrivateVars, |
| 1847 | + llvm::SmallVectorImpl<mlir::Attribute> ©PrivateFuncs) const { |
| 1848 | + auto addCopyPrivateVar = [&](Fortran::semantics::Symbol *sym) { |
| 1849 | + mlir::Value symVal = converter.getSymbolAddress(*sym); |
| 1850 | + auto declOp = symVal.getDefiningOp<hlfir::DeclareOp>(); |
| 1851 | + if (!declOp) |
| 1852 | + fir::emitFatalError(currentLocation, |
| 1853 | + "COPYPRIVATE is supported only in HLFIR mode"); |
| 1854 | + symVal = declOp.getBase(); |
| 1855 | + mlir::Type symType = symVal.getType(); |
| 1856 | + fir::FortranVariableFlagsEnum attrs = |
| 1857 | + declOp.getFortranAttrs().has_value() |
| 1858 | + ? *declOp.getFortranAttrs() |
| 1859 | + : fir::FortranVariableFlagsEnum::None; |
| 1860 | + mlir::Value cpVar = symVal; |
| 1861 | + |
| 1862 | + // CopyPrivate variables must be passed by reference. However, in the case |
| 1863 | + // of assumed shapes/vla the type is not a !fir.ref, but a !fir.box. |
| 1864 | + // In these cases to retrieve the appropriate !fir.ref<!fir.box<...>> to |
| 1865 | + // access the data we need we must perform an alloca and then store to it |
| 1866 | + // and retrieve the data from the new alloca. |
| 1867 | + if (mlir::isa<fir::BaseBoxType>(symType)) { |
| 1868 | + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); |
| 1869 | + auto alloca = builder.create<fir::AllocaOp>(currentLocation, symType); |
| 1870 | + builder.create<fir::StoreOp>(currentLocation, symVal, alloca); |
| 1871 | + cpVar = alloca; |
| 1872 | + } |
| 1873 | + |
| 1874 | + copyPrivateVars.push_back(cpVar); |
| 1875 | + mlir::func::FuncOp funcOp = |
| 1876 | + createCopyFunc(currentLocation, converter, cpVar.getType(), attrs); |
| 1877 | + copyPrivateFuncs.push_back(mlir::SymbolRefAttr::get(funcOp)); |
| 1878 | + }; |
| 1879 | + |
| 1880 | + bool hasCopyPrivate = findRepeatableClause<ClauseTy::Copyprivate>( |
| 1881 | + [&](const ClauseTy::Copyprivate *copyPrivateClause, |
| 1882 | + const Fortran::parser::CharBlock &) { |
| 1883 | + const Fortran::parser::OmpObjectList &ompObjectList = |
| 1884 | + copyPrivateClause->v; |
| 1885 | + for (const Fortran::parser::OmpObject &ompObject : ompObjectList.v) { |
| 1886 | + Fortran::semantics::Symbol *sym = getOmpObjectSymbol(ompObject); |
| 1887 | + if (const auto *commonDetails = |
| 1888 | + sym->detailsIf<Fortran::semantics::CommonBlockDetails>()) { |
| 1889 | + for (const auto &mem : commonDetails->objects()) |
| 1890 | + addCopyPrivateVar(&*mem); |
| 1891 | + break; |
| 1892 | + } |
| 1893 | + addCopyPrivateVar(sym); |
| 1894 | + } |
| 1895 | + }); |
| 1896 | + |
| 1897 | + return hasCopyPrivate; |
| 1898 | +} |
| 1899 | + |
1743 | 1900 | bool ClauseProcessor::processDepend(
|
1744 | 1901 | llvm::SmallVectorImpl<mlir::Attribute> &dependTypeOperands,
|
1745 | 1902 | llvm::SmallVectorImpl<mlir::Value> &dependOperands) const {
|
@@ -2482,19 +2639,24 @@ genSingleOp(Fortran::lower::AbstractConverter &converter,
|
2482 | 2639 | const Fortran::parser::OmpClauseList &endClauseList) {
|
2483 | 2640 | llvm::SmallVector<mlir::Value> allocateOperands, allocatorOperands;
|
2484 | 2641 | llvm::SmallVector<mlir::Value> copyPrivateVars;
|
| 2642 | + llvm::SmallVector<mlir::Attribute> copyPrivateFuncs; |
2485 | 2643 | mlir::UnitAttr nowaitAttr;
|
2486 | 2644 |
|
2487 | 2645 | ClauseProcessor cp(converter, beginClauseList);
|
2488 | 2646 | cp.processAllocate(allocatorOperands, allocateOperands);
|
2489 |
| - cp.processTODO<Fortran::parser::OmpClause::Copyprivate>( |
2490 |
| - currentLocation, llvm::omp::Directive::OMPD_single); |
2491 | 2647 |
|
2492 |
| - ClauseProcessor(converter, endClauseList).processNowait(nowaitAttr); |
| 2648 | + ClauseProcessor ecp(converter, endClauseList); |
| 2649 | + ecp.processNowait(nowaitAttr); |
| 2650 | + ecp.processCopyPrivate(currentLocation, copyPrivateVars, copyPrivateFuncs); |
2493 | 2651 |
|
2494 | 2652 | return genOpWithBody<mlir::omp::SingleOp>(
|
2495 | 2653 | converter, eval, genNested, currentLocation,
|
2496 | 2654 | /*outerCombined=*/false, &beginClauseList, allocateOperands,
|
2497 |
| - allocatorOperands, copyPrivateVars, /*copyPrivateFuncs=*/nullptr, |
| 2655 | + allocatorOperands, copyPrivateVars, |
| 2656 | + copyPrivateFuncs.empty() |
| 2657 | + ? nullptr |
| 2658 | + : mlir::ArrayAttr::get(converter.getFirOpBuilder().getContext(), |
| 2659 | + copyPrivateFuncs), |
2498 | 2660 | nowaitAttr);
|
2499 | 2661 | }
|
2500 | 2662 |
|
@@ -3369,7 +3531,8 @@ genOMP(Fortran::lower::AbstractConverter &converter,
|
3369 | 3531 |
|
3370 | 3532 | for (const auto &clause : endClauseList.v) {
|
3371 | 3533 | mlir::Location clauseLocation = converter.genLocation(clause.source);
|
3372 |
| - if (!std::get_if<Fortran::parser::OmpClause::Nowait>(&clause.u)) |
| 3534 | + if (!std::get_if<Fortran::parser::OmpClause::Nowait>(&clause.u) && |
| 3535 | + !std::get_if<Fortran::parser::OmpClause::Copyprivate>(&clause.u)) |
3373 | 3536 | TODO(clauseLocation, "OpenMP Block construct clause");
|
3374 | 3537 | }
|
3375 | 3538 |
|
|
0 commit comments