|
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"
|
@@ -598,6 +599,10 @@ class ClauseProcessor {
|
598 | 599 | processAllocate(llvm::SmallVectorImpl<mlir::Value> &allocatorOperands,
|
599 | 600 | llvm::SmallVectorImpl<mlir::Value> &allocateOperands) const;
|
600 | 601 | bool processCopyin() const;
|
| 602 | + bool processCopyPrivate( |
| 603 | + mlir::Location currentLocation, |
| 604 | + llvm::SmallVectorImpl<mlir::Value> ©PrivateVars, |
| 605 | + llvm::SmallVectorImpl<mlir::Attribute> ©PrivateFuncs) const; |
601 | 606 | bool processDepend(llvm::SmallVectorImpl<mlir::Attribute> &dependTypeOperands,
|
602 | 607 | llvm::SmallVectorImpl<mlir::Value> &dependOperands) const;
|
603 | 608 | bool
|
@@ -1178,6 +1183,102 @@ class ReductionProcessor {
|
1178 | 1183 | }
|
1179 | 1184 | };
|
1180 | 1185 |
|
| 1186 | +/// Class that extracts information from the specified type. |
| 1187 | +class TypeInfo { |
| 1188 | +public: |
| 1189 | + TypeInfo(mlir::Type ty) { typeScan(ty); } |
| 1190 | + |
| 1191 | + // Returns the length of character types. |
| 1192 | + std::optional<fir::CharacterType::LenType> getCharLength() const { |
| 1193 | + return charLen; |
| 1194 | + } |
| 1195 | + |
| 1196 | + // Returns the shape of array types. |
| 1197 | + const llvm::SmallVector<int64_t> &getShape() const { return shape; } |
| 1198 | + |
| 1199 | + // Is the type inside a box? |
| 1200 | + bool isBox() const { return inBox; } |
| 1201 | + |
| 1202 | +private: |
| 1203 | + void typeScan(mlir::Type type); |
| 1204 | + |
| 1205 | + std::optional<fir::CharacterType::LenType> charLen; |
| 1206 | + llvm::SmallVector<int64_t> shape; |
| 1207 | + bool inBox = false; |
| 1208 | +}; |
| 1209 | + |
| 1210 | +void TypeInfo::typeScan(mlir::Type ty) { |
| 1211 | + if (auto sty = mlir::dyn_cast<fir::SequenceType>(ty)) { |
| 1212 | + assert(shape.empty() && !sty.getShape().empty()); |
| 1213 | + shape = llvm::SmallVector<int64_t>(sty.getShape()); |
| 1214 | + typeScan(sty.getEleTy()); |
| 1215 | + } else if (auto bty = mlir::dyn_cast<fir::BoxType>(ty)) { |
| 1216 | + inBox = true; |
| 1217 | + typeScan(bty.getEleTy()); |
| 1218 | + } else if (auto cty = mlir::dyn_cast<fir::CharacterType>(ty)) { |
| 1219 | + charLen = cty.getLen(); |
| 1220 | + } else if (auto hty = mlir::dyn_cast<fir::HeapType>(ty)) { |
| 1221 | + typeScan(hty.getEleTy()); |
| 1222 | + } else if (auto pty = mlir::dyn_cast<fir::PointerType>(ty)) { |
| 1223 | + typeScan(pty.getEleTy()); |
| 1224 | + } |
| 1225 | +} |
| 1226 | + |
| 1227 | +// Create a function that performs a copy between two variables, compatible |
| 1228 | +// with their types and attributes. |
| 1229 | +static mlir::func::FuncOp |
| 1230 | +createCopyFunc(mlir::Location loc, Fortran::lower::AbstractConverter &converter, |
| 1231 | + mlir::Type varType, fir::FortranVariableFlagsEnum varAttrs) { |
| 1232 | + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); |
| 1233 | + mlir::ModuleOp module = builder.getModule(); |
| 1234 | + mlir::Type eleTy = mlir::cast<fir::ReferenceType>(varType).getEleTy(); |
| 1235 | + TypeInfo typeInfo(eleTy); |
| 1236 | + std::string copyFuncName = |
| 1237 | + fir::getTypeAsString(eleTy, builder.getKindMap(), "_copy"); |
| 1238 | + |
| 1239 | + if (auto decl = module.lookupSymbol<mlir::func::FuncOp>(copyFuncName)) |
| 1240 | + return decl; |
| 1241 | + |
| 1242 | + // create function |
| 1243 | + mlir::OpBuilder::InsertionGuard guard(builder); |
| 1244 | + mlir::OpBuilder modBuilder(module.getBodyRegion()); |
| 1245 | + llvm::SmallVector<mlir::Type> argsTy = {varType, varType}; |
| 1246 | + auto funcType = mlir::FunctionType::get(builder.getContext(), argsTy, {}); |
| 1247 | + mlir::func::FuncOp funcOp = |
| 1248 | + modBuilder.create<mlir::func::FuncOp>(loc, copyFuncName, funcType); |
| 1249 | + funcOp.setVisibility(mlir::SymbolTable::Visibility::Private); |
| 1250 | + builder.createBlock(&funcOp.getRegion(), funcOp.getRegion().end(), argsTy, |
| 1251 | + {loc, loc}); |
| 1252 | + builder.setInsertionPointToStart(&funcOp.getRegion().back()); |
| 1253 | + // generate body |
| 1254 | + fir::FortranVariableFlagsAttr attrs; |
| 1255 | + if (varAttrs != fir::FortranVariableFlagsEnum::None) |
| 1256 | + attrs = fir::FortranVariableFlagsAttr::get(builder.getContext(), varAttrs); |
| 1257 | + llvm::SmallVector<mlir::Value> typeparams; |
| 1258 | + if (typeInfo.getCharLength().has_value()) { |
| 1259 | + mlir::Value charLen = builder.createIntegerConstant( |
| 1260 | + loc, builder.getCharacterLengthType(), *typeInfo.getCharLength()); |
| 1261 | + typeparams.push_back(charLen); |
| 1262 | + } |
| 1263 | + mlir::Value shape; |
| 1264 | + if (!typeInfo.isBox() && !typeInfo.getShape().empty()) { |
| 1265 | + llvm::SmallVector<mlir::Value> extents; |
| 1266 | + for (auto extent : typeInfo.getShape()) |
| 1267 | + extents.push_back( |
| 1268 | + builder.createIntegerConstant(loc, builder.getIndexType(), extent)); |
| 1269 | + shape = builder.create<fir::ShapeOp>(loc, extents); |
| 1270 | + } |
| 1271 | + auto declDst = builder.create<hlfir::DeclareOp>(loc, funcOp.getArgument(0), |
| 1272 | + copyFuncName + "_dst", shape, |
| 1273 | + typeparams, attrs); |
| 1274 | + auto declSrc = builder.create<hlfir::DeclareOp>(loc, funcOp.getArgument(1), |
| 1275 | + copyFuncName + "_src", shape, |
| 1276 | + typeparams, attrs); |
| 1277 | + converter.copyVar(loc, declDst.getBase(), declSrc.getBase()); |
| 1278 | + builder.create<mlir::func::ReturnOp>(loc); |
| 1279 | + return funcOp; |
| 1280 | +} |
| 1281 | + |
1181 | 1282 | static mlir::omp::ScheduleModifier
|
1182 | 1283 | translateScheduleModifier(const Fortran::parser::OmpScheduleModifierType &m) {
|
1183 | 1284 | switch (m.v) {
|
@@ -1758,6 +1859,62 @@ bool ClauseProcessor::processCopyin() const {
|
1758 | 1859 | return hasCopyin;
|
1759 | 1860 | }
|
1760 | 1861 |
|
| 1862 | +bool ClauseProcessor::processCopyPrivate( |
| 1863 | + mlir::Location currentLocation, |
| 1864 | + llvm::SmallVectorImpl<mlir::Value> ©PrivateVars, |
| 1865 | + llvm::SmallVectorImpl<mlir::Attribute> ©PrivateFuncs) const { |
| 1866 | + auto addCopyPrivateVar = [&](Fortran::semantics::Symbol *sym) { |
| 1867 | + mlir::Value symVal = converter.getSymbolAddress(*sym); |
| 1868 | + auto declOp = symVal.getDefiningOp<hlfir::DeclareOp>(); |
| 1869 | + if (!declOp) |
| 1870 | + fir::emitFatalError(currentLocation, |
| 1871 | + "COPYPRIVATE is supported only in HLFIR mode"); |
| 1872 | + symVal = declOp.getBase(); |
| 1873 | + mlir::Type symType = symVal.getType(); |
| 1874 | + fir::FortranVariableFlagsEnum attrs = |
| 1875 | + declOp.getFortranAttrs().has_value() |
| 1876 | + ? *declOp.getFortranAttrs() |
| 1877 | + : fir::FortranVariableFlagsEnum::None; |
| 1878 | + mlir::Value cpVar = symVal; |
| 1879 | + |
| 1880 | + // CopyPrivate variables must be passed by reference. However, in the case |
| 1881 | + // of assumed shapes/vla the type is not a !fir.ref, but a !fir.box. |
| 1882 | + // In these cases to retrieve the appropriate !fir.ref<!fir.box<...>> to |
| 1883 | + // access the data we need we must perform an alloca and then store to it |
| 1884 | + // and retrieve the data from the new alloca. |
| 1885 | + if (mlir::isa<fir::BaseBoxType>(symType)) { |
| 1886 | + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); |
| 1887 | + auto alloca = builder.create<fir::AllocaOp>(currentLocation, symType); |
| 1888 | + builder.create<fir::StoreOp>(currentLocation, symVal, alloca); |
| 1889 | + cpVar = alloca; |
| 1890 | + } |
| 1891 | + |
| 1892 | + copyPrivateVars.push_back(cpVar); |
| 1893 | + mlir::func::FuncOp funcOp = |
| 1894 | + createCopyFunc(currentLocation, converter, cpVar.getType(), attrs); |
| 1895 | + copyPrivateFuncs.push_back(mlir::SymbolRefAttr::get(funcOp)); |
| 1896 | + }; |
| 1897 | + |
| 1898 | + bool hasCopyPrivate = findRepeatableClause<ClauseTy::Copyprivate>( |
| 1899 | + [&](const ClauseTy::Copyprivate *copyPrivateClause, |
| 1900 | + const Fortran::parser::CharBlock &) { |
| 1901 | + const Fortran::parser::OmpObjectList &ompObjectList = |
| 1902 | + copyPrivateClause->v; |
| 1903 | + for (const Fortran::parser::OmpObject &ompObject : ompObjectList.v) { |
| 1904 | + Fortran::semantics::Symbol *sym = getOmpObjectSymbol(ompObject); |
| 1905 | + if (const auto *commonDetails = |
| 1906 | + sym->detailsIf<Fortran::semantics::CommonBlockDetails>()) { |
| 1907 | + for (const auto &mem : commonDetails->objects()) |
| 1908 | + addCopyPrivateVar(&*mem); |
| 1909 | + break; |
| 1910 | + } |
| 1911 | + addCopyPrivateVar(sym); |
| 1912 | + } |
| 1913 | + }); |
| 1914 | + |
| 1915 | + return hasCopyPrivate; |
| 1916 | +} |
| 1917 | + |
1761 | 1918 | bool ClauseProcessor::processDepend(
|
1762 | 1919 | llvm::SmallVectorImpl<mlir::Attribute> &dependTypeOperands,
|
1763 | 1920 | llvm::SmallVectorImpl<mlir::Value> &dependOperands) const {
|
@@ -2666,21 +2823,26 @@ genSingleOp(Fortran::lower::AbstractConverter &converter,
|
2666 | 2823 | const Fortran::parser::OmpClauseList &endClauseList) {
|
2667 | 2824 | llvm::SmallVector<mlir::Value> allocateOperands, allocatorOperands;
|
2668 | 2825 | llvm::SmallVector<mlir::Value> copyPrivateVars;
|
| 2826 | + llvm::SmallVector<mlir::Attribute> copyPrivateFuncs; |
2669 | 2827 | mlir::UnitAttr nowaitAttr;
|
2670 | 2828 |
|
2671 | 2829 | ClauseProcessor cp(converter, semaCtx, beginClauseList);
|
2672 | 2830 | cp.processAllocate(allocatorOperands, allocateOperands);
|
2673 |
| - cp.processTODO<Fortran::parser::OmpClause::Copyprivate>( |
2674 |
| - currentLocation, llvm::omp::Directive::OMPD_single); |
2675 | 2831 |
|
2676 |
| - ClauseProcessor(converter, semaCtx, endClauseList).processNowait(nowaitAttr); |
| 2832 | + ClauseProcessor ecp(converter, semaCtx, endClauseList); |
| 2833 | + ecp.processNowait(nowaitAttr); |
| 2834 | + ecp.processCopyPrivate(currentLocation, copyPrivateVars, copyPrivateFuncs); |
2677 | 2835 |
|
2678 | 2836 | return genOpWithBody<mlir::omp::SingleOp>(
|
2679 | 2837 | OpWithBodyGenInfo(converter, semaCtx, currentLocation, eval)
|
2680 | 2838 | .setGenNested(genNested)
|
2681 | 2839 | .setClauses(&beginClauseList),
|
2682 | 2840 | allocateOperands, allocatorOperands, copyPrivateVars,
|
2683 |
| - /*copyPrivateFuncs=*/nullptr, nowaitAttr); |
| 2841 | + copyPrivateFuncs.empty() |
| 2842 | + ? nullptr |
| 2843 | + : mlir::ArrayAttr::get(converter.getFirOpBuilder().getContext(), |
| 2844 | + copyPrivateFuncs), |
| 2845 | + nowaitAttr); |
2684 | 2846 | }
|
2685 | 2847 |
|
2686 | 2848 | static mlir::omp::TaskOp
|
@@ -3708,7 +3870,8 @@ genOMP(Fortran::lower::AbstractConverter &converter,
|
3708 | 3870 |
|
3709 | 3871 | for (const auto &clause : endClauseList.v) {
|
3710 | 3872 | mlir::Location clauseLocation = converter.genLocation(clause.source);
|
3711 |
| - if (!std::get_if<Fortran::parser::OmpClause::Nowait>(&clause.u)) |
| 3873 | + if (!std::get_if<Fortran::parser::OmpClause::Nowait>(&clause.u) && |
| 3874 | + !std::get_if<Fortran::parser::OmpClause::Copyprivate>(&clause.u)) |
3712 | 3875 | TODO(clauseLocation, "OpenMP Block construct clause");
|
3713 | 3876 | }
|
3714 | 3877 |
|
|
0 commit comments