From 2e2676f155a90df30c36e3385b8bb5f902486e3f Mon Sep 17 00:00:00 2001 From: Andrew Gozillon Date: Thu, 9 Nov 2023 12:44:36 -0600 Subject: [PATCH] Minor quick and lazy update (code that'll be deprecated by rebase on IFA PR) to support target loops Handling of implicits for target parallel do/parallel distribtue do, to test a larger subset of milestone 3a/3b. This will be deprecated in favour of IFA so not a lot of effort put into removing obvious code duplication. --- flang/include/flang/Lower/OpenMP.h | 7 ++ flang/lib/Lower/Bridge.cpp | 5 + flang/lib/Lower/OpenMP.cpp | 165 +++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+) diff --git a/flang/include/flang/Lower/OpenMP.h b/flang/include/flang/Lower/OpenMP.h index 537c822c397e..0413c00ce093 100644 --- a/flang/include/flang/Lower/OpenMP.h +++ b/flang/include/flang/Lower/OpenMP.h @@ -30,6 +30,7 @@ namespace Fortran { namespace parser { struct OpenMPConstruct; struct OpenMPBlockConstruct; +struct OpenMPLoopConstruct; struct OpenMPDeclarativeConstruct; struct OmpEndLoopDirective; struct OmpClauseList; @@ -67,6 +68,12 @@ void genImplicitMapsForTarget( Fortran::lower::pft::Evaluation &eval, const Fortran::parser::OpenMPBlockConstruct &ompBlock); +void genImplicitMapsForTarget( + Fortran::lower::AbstractConverter &converter, + Fortran::semantics::SemanticsContext &semanticsContext, + Fortran::lower::pft::Evaluation &eval, + const Fortran::parser::OpenMPLoopConstruct &ompLoop); + mlir::Operation *findReductionChain(mlir::Value, mlir::Value * = nullptr); fir::ConvertOp getConvertFromReductionOp(mlir::Operation *, mlir::Value); void updateReduction(mlir::Operation *, fir::FirOpBuilder &, mlir::Value, diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index f6eadf0dc2ea..ae12c35c3651 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -2432,6 +2432,11 @@ class FirConverter : public Fortran::lower::AbstractConverter { *ompBlock); } + if (ompLoop) { + genImplicitMapsForTarget(*this, bridge.getSemanticsContext(), *curEval, + *ompLoop); + } + localSymbols.popScope(); builder->restoreInsertionPoint(insertPt); diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp index a8d3b18f6e23..8f5047bc3451 100644 --- a/flang/lib/Lower/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP.cpp @@ -2590,6 +2590,171 @@ genEnterExitDataOp(Fortran::lower::AbstractConverter &converter, deviceOperand, nowaitAttr, mapOperands); } +void Fortran::lower::genImplicitMapsForTarget( + Fortran::lower::AbstractConverter &converter, + Fortran::semantics::SemanticsContext &semanticsContext, + Fortran::lower::pft::Evaluation &eval, + const Fortran::parser::OpenMPLoopConstruct &ompLoop) { + llvm::SmallVector> + targetSyms; + + auto printList = [&](const Fortran::semantics::Symbol &sym) { + for (auto syms : targetSyms) + if (*std::get<0>(syms) == sym) + return; + // skip these, declare target should be handled elsewhere via a provided + // explicit map and functions and subroutines are not symbols that are + // required to be mapped + if (sym.test(Fortran::semantics::Symbol::Flag::Function) || + sym.test(Fortran::semantics::Symbol::Flag::Subroutine) || + sym.test(Fortran::semantics::Symbol::Flag::OmpDeclareTarget)) + return; + + targetSyms.push_back( + std::pair( + &sym, converter.getSymbolAddress(sym))); + }; + + Fortran::lower::pft::visitAllSymbols(eval, printList); + + auto isScalarType = [&](mlir::Type type) { + if (type.isa()) + type = type.cast().getEleTy(); + + if (type.isa() || type.isa() || + type.isa() || type.isa() || + type.isa() || type.isa() || + type.isa()) + return true; + return false; + }; + + const auto &beginLoopDirective = + std::get(ompLoop.t); + const auto &directive = + std::get(beginLoopDirective.t); + fir::FirOpBuilder builder = converter.getFirOpBuilder(); + + if (llvm::omp::Directive::OMPD_target_parallel_do == directive.v + || llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do == directive.v) { + if (auto tarOp = mlir::dyn_cast( + builder.getInsertionPoint()->getParentOfType())) { + // NOTE: It is possible to use Fortran::lower::pft::visitAllSymbols, + // here to access individual symbolic/semantic information for each + // implicit map operand where neccessary (need to retrieve the + // symbol name from the op to find the matching semantic symbol) + llvm::SetVector operandSet; + mlir::getUsedValuesDefinedAbove(tarOp.getRegion(), operandSet); + + // filter out uses already being mapped (explicit maps) + bool removed = false; + for (llvm::SetVector::iterator iter = operandSet.begin(); + iter != operandSet.end();) { + for (auto mapValue : tarOp.getMapOperands()) { + if (auto mapOp = mlir::dyn_cast_if_present( + mapValue.getDefiningOp())) { + mlir::Value underlyingValue = mapOp.getVarPtr(); + + // If we have a box, we have some value chasing to do, as the + // original symbol/used value is hidden by the box which + // contains more information on the underlying operation. + if (auto boxAddr = mlir::dyn_cast_if_present( + mapOp.getVarPtr().getDefiningOp())) { + if (auto load = mlir::dyn_cast_if_present( + boxAddr.getVal().getDefiningOp())) { + underlyingValue = load.getMemref(); + } + } + + if (underlyingValue == *iter) { + iter = operandSet.erase(iter); + removed = true; + break; + } + } + } + if (!removed) + iter++; + else + removed = false; + } + + builder.setInsertionPoint(tarOp); + + llvm::SmallVector impMapOps; + for (auto value : operandSet) { + llvm::omp::OpenMPOffloadMappingFlags mapTypeBits = + llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_NONE; + + const Fortran::semantics::Symbol *sym = nullptr; + for (auto &tarSym : targetSyms) { + if (std::get<1>(tarSym) == value) { + sym = std::get<0>(tarSym); + } + } + + bool isScalar = isScalarType(value.getType()); + + // Default implicit map cases, only handle two for the moment + if (isScalar) { + mapTypeBits = + llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM | + llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_LITERAL | + llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT; + } else { // non-scalar values + mapTypeBits |= + llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT | + llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO | + llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM | + llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM; + } + + mlir::Value baseAddr; + llvm::SmallVector bounds; + if (sym) { + baseAddr = getDataOperandBaseAddr(converter, builder, *sym, + converter.getCurrentLocation()); + if (fir::unwrapRefType(baseAddr.getType()).isa()) + bounds = genBoundsOpsFromBox( + builder, converter.getCurrentLocation(), converter, + converter.getSymbolExtendedValue(*sym), baseAddr); + if (fir::unwrapRefType(baseAddr.getType()).isa()) + bounds = genBaseBoundsOps( + builder, converter.getCurrentLocation(), converter, + converter.getSymbolExtendedValue(*sym), baseAddr); + } + uint64_t mapType = static_cast< + std::underlying_type_t>( + mapTypeBits); + + // compare implicit mapped vs explicit mapped bounds out + if (sym && Fortran::semantics::IsAllocatableOrPointer(*sym)) { + mlir::Value descriptor = converter.getSymbolAddress(*sym); + impMapOps.push_back(createMapInfoOp( + builder, tarOp->getLoc(), descriptor, nullptr, + sym->name().ToString(), mlir::SmallVector{}, + static_cast< + std::underlying_type_t>( + mapTypeBits), + mlir::omp::VariableCaptureKind::ByRef, true, + descriptor.getType())); + } else { + impMapOps.push_back(createMapInfoOp( + builder, tarOp->getLoc(), baseAddr ? baseAddr : value, nullptr, + sym ? sym->name().ToString() : "", bounds, mapType, + isScalar ? mlir::omp::VariableCaptureKind::ByCopy + : mlir::omp::VariableCaptureKind::ByRef, + false, value.getType())); + } + } + + tarOp.getMapOperandsMutable().append(impMapOps); + } + } +} + void Fortran::lower::genImplicitMapsForTarget( Fortran::lower::AbstractConverter &converter, Fortran::semantics::SemanticsContext &semanticsContext,