261 lines · c
1//===-- Lower/OpenMP/ClauseProcessor.h --------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/10//11//===----------------------------------------------------------------------===//12#ifndef FORTRAN_LOWER_CLAUSEPROCESSOR_H13#define FORTRAN_LOWER_CLAUSEPROCESSOR_H14 15#include "ClauseFinder.h"16#include "Utils.h"17#include "flang/Lower/AbstractConverter.h"18#include "flang/Lower/Bridge.h"19#include "flang/Lower/DirectivesCommon.h"20#include "flang/Lower/OpenMP/Clauses.h"21#include "flang/Lower/Support/ReductionProcessor.h"22#include "flang/Optimizer/Builder/Todo.h"23#include "flang/Parser/parse-tree.h"24#include "mlir/Dialect/OpenMP/OpenMPDialect.h"25 26namespace fir {27class FirOpBuilder;28} // namespace fir29 30namespace Fortran {31namespace lower {32namespace omp {33 34// Container type for tracking user specified Defaultmaps for a target region35using DefaultMapsTy = std::map<clause::Defaultmap::VariableCategory,36 clause::Defaultmap::ImplicitBehavior>;37 38/// Class that handles the processing of OpenMP clauses.39///40/// Its `process<ClauseName>()` methods perform MLIR code generation for their41/// corresponding clause if it is present in the clause list. Otherwise, they42/// will return `false` to signal that the clause was not found.43///44/// The intended use of this class is to move clause processing outside of45/// construct processing, since the same clauses can appear attached to46/// different constructs and constructs can be combined, so that code47/// duplication is minimized.48///49/// Each construct-lowering function only calls the `process<ClauseName>()`50/// methods that relate to clauses that can impact the lowering of that51/// construct.52class ClauseProcessor {53public:54 ClauseProcessor(lower::AbstractConverter &converter,55 semantics::SemanticsContext &semaCtx,56 const List<Clause> &clauses)57 : converter(converter), semaCtx(semaCtx), clauses(clauses) {}58 59 // 'Unique' clauses: They can appear at most once in the clause list.60 bool processBare(mlir::omp::BareClauseOps &result) const;61 bool processBind(mlir::omp::BindClauseOps &result) const;62 bool processCancelDirectiveName(63 mlir::omp::CancelDirectiveNameClauseOps &result) const;64 bool65 processCollapse(mlir::Location currentLocation, lower::pft::Evaluation &eval,66 mlir::omp::LoopRelatedClauseOps &loopResult,67 mlir::omp::CollapseClauseOps &collapseResult,68 llvm::SmallVectorImpl<const semantics::Symbol *> &iv) const;69 bool processSizes(StatementContext &stmtCtx,70 mlir::omp::SizesClauseOps &result) const;71 bool processDevice(lower::StatementContext &stmtCtx,72 mlir::omp::DeviceClauseOps &result) const;73 bool processDeviceType(mlir::omp::DeviceTypeClauseOps &result) const;74 bool processDistSchedule(lower::StatementContext &stmtCtx,75 mlir::omp::DistScheduleClauseOps &result) const;76 bool processExclusive(mlir::Location currentLocation,77 mlir::omp::ExclusiveClauseOps &result) const;78 bool processFilter(lower::StatementContext &stmtCtx,79 mlir::omp::FilterClauseOps &result) const;80 bool processFinal(lower::StatementContext &stmtCtx,81 mlir::omp::FinalClauseOps &result) const;82 bool processGrainsize(lower::StatementContext &stmtCtx,83 mlir::omp::GrainsizeClauseOps &result) const;84 bool processHasDeviceAddr(85 lower::StatementContext &stmtCtx,86 mlir::omp::HasDeviceAddrClauseOps &result,87 llvm::SmallVectorImpl<const semantics::Symbol *> &hasDeviceSyms) const;88 bool processHint(mlir::omp::HintClauseOps &result) const;89 bool processInclusive(mlir::Location currentLocation,90 mlir::omp::InclusiveClauseOps &result) const;91 bool processInitializer(92 lower::SymMap &symMap, const parser::OmpClause::Initializer &inp,93 ReductionProcessor::GenInitValueCBTy &genInitValueCB) const;94 bool processMergeable(mlir::omp::MergeableClauseOps &result) const;95 bool processNogroup(mlir::omp::NogroupClauseOps &result) const;96 bool processNowait(mlir::omp::NowaitClauseOps &result) const;97 bool processNumTasks(lower::StatementContext &stmtCtx,98 mlir::omp::NumTasksClauseOps &result) const;99 bool processNumTeams(lower::StatementContext &stmtCtx,100 mlir::omp::NumTeamsClauseOps &result) const;101 bool processNumThreads(lower::StatementContext &stmtCtx,102 mlir::omp::NumThreadsClauseOps &result) const;103 bool processOrder(mlir::omp::OrderClauseOps &result) const;104 bool processOrdered(mlir::omp::OrderedClauseOps &result) const;105 bool processPriority(lower::StatementContext &stmtCtx,106 mlir::omp::PriorityClauseOps &result) const;107 bool processProcBind(mlir::omp::ProcBindClauseOps &result) const;108 bool processTileSizes(lower::pft::Evaluation &eval,109 mlir::omp::LoopNestOperands &result) const;110 bool processSafelen(mlir::omp::SafelenClauseOps &result) const;111 bool processSchedule(lower::StatementContext &stmtCtx,112 mlir::omp::ScheduleClauseOps &result) const;113 bool processSimdlen(mlir::omp::SimdlenClauseOps &result) const;114 bool processThreadLimit(lower::StatementContext &stmtCtx,115 mlir::omp::ThreadLimitClauseOps &result) const;116 bool processUntied(mlir::omp::UntiedClauseOps &result) const;117 118 bool processDetach(mlir::omp::DetachClauseOps &result) const;119 // 'Repeatable' clauses: They can appear multiple times in the clause list.120 bool processAligned(mlir::omp::AlignedClauseOps &result) const;121 bool processAllocate(mlir::omp::AllocateClauseOps &result) const;122 bool processCopyin() const;123 bool processCopyprivate(mlir::Location currentLocation,124 mlir::omp::CopyprivateClauseOps &result) const;125 bool processDefaultMap(lower::StatementContext &stmtCtx,126 DefaultMapsTy &result) const;127 bool processDepend(lower::SymMap &symMap, lower::StatementContext &stmtCtx,128 mlir::omp::DependClauseOps &result) const;129 bool130 processEnter(llvm::SmallVectorImpl<DeclareTargetCaptureInfo> &result) const;131 bool processIf(omp::clause::If::DirectiveNameModifier directiveName,132 mlir::omp::IfClauseOps &result) const;133 bool processInReduction(134 mlir::Location currentLocation, mlir::omp::InReductionClauseOps &result,135 llvm::SmallVectorImpl<const semantics::Symbol *> &outReductionSyms) const;136 bool processIsDevicePtr(137 mlir::omp::IsDevicePtrClauseOps &result,138 llvm::SmallVectorImpl<const semantics::Symbol *> &isDeviceSyms) const;139 bool processLinear(mlir::omp::LinearClauseOps &result) const;140 bool141 processLink(llvm::SmallVectorImpl<DeclareTargetCaptureInfo> &result) const;142 143 // This method is used to process a map clause.144 // The optional parameter mapSyms is used to store the original Fortran symbol145 // for the map operands. It may be used later on to create the block_arguments146 // for some of the directives that require it.147 bool processMap(mlir::Location currentLocation,148 lower::StatementContext &stmtCtx,149 mlir::omp::MapClauseOps &result,150 llvm::omp::Directive directive = llvm::omp::OMPD_unknown,151 llvm::SmallVectorImpl<const semantics::Symbol *> *mapSyms =152 nullptr) const;153 bool processMotionClauses(lower::StatementContext &stmtCtx,154 mlir::omp::MapClauseOps &result);155 bool processNontemporal(mlir::omp::NontemporalClauseOps &result) const;156 bool processReduction(157 mlir::Location currentLocation, mlir::omp::ReductionClauseOps &result,158 llvm::SmallVectorImpl<const semantics::Symbol *> &reductionSyms) const;159 bool processTaskReduction(160 mlir::Location currentLocation, mlir::omp::TaskReductionClauseOps &result,161 llvm::SmallVectorImpl<const semantics::Symbol *> &outReductionSyms) const;162 bool processTo(llvm::SmallVectorImpl<DeclareTargetCaptureInfo> &result) const;163 bool processUseDeviceAddr(164 lower::StatementContext &stmtCtx,165 mlir::omp::UseDeviceAddrClauseOps &result,166 llvm::SmallVectorImpl<const semantics::Symbol *> &useDeviceSyms) const;167 bool processUseDevicePtr(168 lower::StatementContext &stmtCtx,169 mlir::omp::UseDevicePtrClauseOps &result,170 llvm::SmallVectorImpl<const semantics::Symbol *> &useDeviceSyms) const;171 172 // Call this method for these clauses that should be supported but are not173 // implemented yet. It triggers a compilation error if any of the given174 // clauses is found.175 template <typename... Ts>176 void processTODO(mlir::Location currentLocation,177 llvm::omp::Directive directive) const;178 179private:180 using ClauseIterator = List<Clause>::const_iterator;181 182 /// Return the first instance of the given clause found in the clause list or183 /// `nullptr` if not present. If more than one instance is expected, use184 /// `findRepeatableClause` instead.185 template <typename T>186 const T *findUniqueClause(const parser::CharBlock **source = nullptr) const;187 188 /// Call `callbackFn` for each occurrence of the given clause. Return `true`189 /// if at least one instance was found.190 template <typename T>191 bool findRepeatableClause(192 std::function<void(const T &, const parser::CharBlock &source)>193 callbackFn) const;194 195 /// Set the `result` to a new `mlir::UnitAttr` if the clause is present.196 template <typename T>197 bool markClauseOccurrence(mlir::UnitAttr &result) const;198 199 void processMapObjects(200 lower::StatementContext &stmtCtx, mlir::Location clauseLocation,201 const omp::ObjectList &objects, mlir::omp::ClauseMapFlags mapTypeBits,202 std::map<Object, OmpMapParentAndMemberData> &parentMemberIndices,203 llvm::SmallVectorImpl<mlir::Value> &mapVars,204 llvm::SmallVectorImpl<const semantics::Symbol *> &mapSyms,205 llvm::StringRef mapperIdNameRef = "") const;206 207 lower::AbstractConverter &converter;208 semantics::SemanticsContext &semaCtx;209 List<Clause> clauses;210};211 212template <typename... Ts>213void ClauseProcessor::processTODO(mlir::Location currentLocation,214 llvm::omp::Directive directive) const {215 auto checkUnhandledClause = [&](llvm::omp::Clause id, const auto *x) {216 if (!x)217 return;218 unsigned version = semaCtx.langOptions().OpenMPVersion;219 bool isSimdDirective = llvm::omp::getOpenMPDirectiveName(directive, version)220 .upper()221 .find("SIMD") != llvm::StringRef::npos;222 if (!semaCtx.langOptions().OpenMPSimd || isSimdDirective)223 TODO(currentLocation,224 "Unhandled clause " + llvm::omp::getOpenMPClauseName(id).upper() +225 " in " +226 llvm::omp::getOpenMPDirectiveName(directive, version).upper() +227 " construct");228 };229 230 for (ClauseIterator it = clauses.begin(); it != clauses.end(); ++it)231 (checkUnhandledClause(it->id, std::get_if<Ts>(&it->u)), ...);232}233 234template <typename T>235const T *236ClauseProcessor::findUniqueClause(const parser::CharBlock **source) const {237 return ClauseFinder::findUniqueClause<T>(clauses, source);238}239 240template <typename T>241bool ClauseProcessor::findRepeatableClause(242 std::function<void(const T &, const parser::CharBlock &source)> callbackFn)243 const {244 return ClauseFinder::findRepeatableClause<T>(clauses, callbackFn);245}246 247template <typename T>248bool ClauseProcessor::markClauseOccurrence(mlir::UnitAttr &result) const {249 if (findUniqueClause<T>()) {250 result = converter.getFirOpBuilder().getUnitAttr();251 return true;252 }253 return false;254}255 256} // namespace omp257} // namespace lower258} // namespace Fortran259 260#endif // FORTRAN_LOWER_CLAUSEPROCESSOR_H261