1725 lines · cpp
1//===-- ClauseProcessor.cpp -------------------------------------*- 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 13#include "ClauseProcessor.h"14#include "Utils.h"15 16#include "flang/Lower/ConvertCall.h"17#include "flang/Lower/ConvertExprToHLFIR.h"18#include "flang/Lower/OpenMP/Clauses.h"19#include "flang/Lower/PFTBuilder.h"20#include "flang/Lower/Support/ReductionProcessor.h"21#include "flang/Optimizer/Dialect/FIRType.h"22#include "flang/Parser/tools.h"23#include "flang/Semantics/tools.h"24#include "flang/Utils/OpenMP.h"25#include "llvm/Frontend/OpenMP/OMP.h.inc"26#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"27 28namespace Fortran {29namespace lower {30namespace omp {31 32using ReductionModifier =33 Fortran::lower::omp::clause::Reduction::ReductionModifier;34 35mlir::omp::ReductionModifier translateReductionModifier(ReductionModifier mod) {36 switch (mod) {37 case ReductionModifier::Default:38 return mlir::omp::ReductionModifier::defaultmod;39 case ReductionModifier::Inscan:40 return mlir::omp::ReductionModifier::inscan;41 case ReductionModifier::Task:42 return mlir::omp::ReductionModifier::task;43 }44 return mlir::omp::ReductionModifier::defaultmod;45}46 47/// Check for unsupported map operand types.48static void checkMapType(mlir::Location location, mlir::Type type) {49 if (auto refType = mlir::dyn_cast<fir::ReferenceType>(type))50 type = refType.getElementType();51 if (auto boxType = mlir::dyn_cast_or_null<fir::BoxType>(type))52 if (!mlir::isa<fir::PointerType>(boxType.getElementType()))53 TODO(location, "OMPD_target_data MapOperand BoxType");54}55 56static mlir::omp::ScheduleModifier57translateScheduleModifier(const omp::clause::Schedule::OrderingModifier &m) {58 switch (m) {59 case omp::clause::Schedule::OrderingModifier::Monotonic:60 return mlir::omp::ScheduleModifier::monotonic;61 case omp::clause::Schedule::OrderingModifier::Nonmonotonic:62 return mlir::omp::ScheduleModifier::nonmonotonic;63 }64 return mlir::omp::ScheduleModifier::none;65}66 67static mlir::omp::ScheduleModifier68getScheduleModifier(const omp::clause::Schedule &clause) {69 using Schedule = omp::clause::Schedule;70 const auto &modifier =71 std::get<std::optional<Schedule::OrderingModifier>>(clause.t);72 if (modifier)73 return translateScheduleModifier(*modifier);74 return mlir::omp::ScheduleModifier::none;75}76 77static mlir::omp::ScheduleModifier78getSimdModifier(const omp::clause::Schedule &clause) {79 using Schedule = omp::clause::Schedule;80 const auto &modifier =81 std::get<std::optional<Schedule::ChunkModifier>>(clause.t);82 if (modifier && *modifier == Schedule::ChunkModifier::Simd)83 return mlir::omp::ScheduleModifier::simd;84 return mlir::omp::ScheduleModifier::none;85}86 87static void88genAllocateClause(lower::AbstractConverter &converter,89 const omp::clause::Allocate &clause,90 llvm::SmallVectorImpl<mlir::Value> &allocatorOperands,91 llvm::SmallVectorImpl<mlir::Value> &allocateOperands) {92 fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();93 mlir::Location currentLocation = converter.getCurrentLocation();94 lower::StatementContext stmtCtx;95 96 auto &objects = std::get<omp::ObjectList>(clause.t);97 98 using Allocate = omp::clause::Allocate;99 // ALIGN in this context is unimplemented100 if (std::get<std::optional<Allocate::AlignModifier>>(clause.t))101 TODO(currentLocation, "OmpAllocateClause ALIGN modifier");102 103 // Check if allocate clause has allocator specified. If so, add it104 // to list of allocators, otherwise, add default allocator to105 // list of allocators.106 using ComplexModifier = Allocate::AllocatorComplexModifier;107 if (auto &mod = std::get<std::optional<ComplexModifier>>(clause.t)) {108 mlir::Value operand = fir::getBase(converter.genExprValue(mod->v, stmtCtx));109 allocatorOperands.append(objects.size(), operand);110 } else {111 mlir::Value operand = firOpBuilder.createIntegerConstant(112 currentLocation, firOpBuilder.getI32Type(), 1);113 allocatorOperands.append(objects.size(), operand);114 }115 116 genObjectList(objects, converter, allocateOperands);117}118 119static mlir::omp::ClauseBindKindAttr120genBindKindAttr(fir::FirOpBuilder &firOpBuilder,121 const omp::clause::Bind &clause) {122 mlir::omp::ClauseBindKind bindKind;123 switch (clause.v) {124 case omp::clause::Bind::Binding::Teams:125 bindKind = mlir::omp::ClauseBindKind::Teams;126 break;127 case omp::clause::Bind::Binding::Parallel:128 bindKind = mlir::omp::ClauseBindKind::Parallel;129 break;130 case omp::clause::Bind::Binding::Thread:131 bindKind = mlir::omp::ClauseBindKind::Thread;132 break;133 }134 return mlir::omp::ClauseBindKindAttr::get(firOpBuilder.getContext(),135 bindKind);136}137 138static mlir::omp::ClauseProcBindKindAttr139genProcBindKindAttr(fir::FirOpBuilder &firOpBuilder,140 const omp::clause::ProcBind &clause) {141 mlir::omp::ClauseProcBindKind procBindKind;142 switch (clause.v) {143 case omp::clause::ProcBind::AffinityPolicy::Master:144 procBindKind = mlir::omp::ClauseProcBindKind::Master;145 break;146 case omp::clause::ProcBind::AffinityPolicy::Close:147 procBindKind = mlir::omp::ClauseProcBindKind::Close;148 break;149 case omp::clause::ProcBind::AffinityPolicy::Spread:150 procBindKind = mlir::omp::ClauseProcBindKind::Spread;151 break;152 case omp::clause::ProcBind::AffinityPolicy::Primary:153 procBindKind = mlir::omp::ClauseProcBindKind::Primary;154 break;155 }156 return mlir::omp::ClauseProcBindKindAttr::get(firOpBuilder.getContext(),157 procBindKind);158}159 160static mlir::omp::ClauseTaskDependAttr161genDependKindAttr(lower::AbstractConverter &converter,162 const omp::clause::DependenceType kind) {163 fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();164 mlir::Location currentLocation = converter.getCurrentLocation();165 166 mlir::omp::ClauseTaskDepend pbKind;167 switch (kind) {168 case omp::clause::DependenceType::In:169 pbKind = mlir::omp::ClauseTaskDepend::taskdependin;170 break;171 case omp::clause::DependenceType::Out:172 pbKind = mlir::omp::ClauseTaskDepend::taskdependout;173 break;174 case omp::clause::DependenceType::Inout:175 pbKind = mlir::omp::ClauseTaskDepend::taskdependinout;176 break;177 case omp::clause::DependenceType::Mutexinoutset:178 pbKind = mlir::omp::ClauseTaskDepend::taskdependmutexinoutset;179 break;180 case omp::clause::DependenceType::Inoutset:181 pbKind = mlir::omp::ClauseTaskDepend::taskdependinoutset;182 break;183 case omp::clause::DependenceType::Depobj:184 TODO(currentLocation, "DEPOBJ dependence-type");185 break;186 case omp::clause::DependenceType::Sink:187 case omp::clause::DependenceType::Source:188 llvm_unreachable("unhandled parser task dependence type");189 break;190 }191 return mlir::omp::ClauseTaskDependAttr::get(firOpBuilder.getContext(),192 pbKind);193}194 195static mlir::Value196getIfClauseOperand(lower::AbstractConverter &converter,197 const omp::clause::If &clause,198 omp::clause::If::DirectiveNameModifier directiveName,199 mlir::Location clauseLocation) {200 // Only consider the clause if it's intended for the given directive.201 auto &directive =202 std::get<std::optional<omp::clause::If::DirectiveNameModifier>>(clause.t);203 if (directive && directive.value() != directiveName)204 return nullptr;205 206 lower::StatementContext stmtCtx;207 fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();208 mlir::Value ifVal = fir::getBase(209 converter.genExprValue(std::get<omp::SomeExpr>(clause.t), stmtCtx));210 return firOpBuilder.createConvert(clauseLocation, firOpBuilder.getI1Type(),211 ifVal);212}213 214static void addUseDeviceClause(215 lower::AbstractConverter &converter, const omp::ObjectList &objects,216 llvm::SmallVectorImpl<mlir::Value> &operands,217 llvm::SmallVectorImpl<const semantics::Symbol *> &useDeviceSyms) {218 genObjectList(objects, converter, operands);219 for (mlir::Value &operand : operands)220 checkMapType(operand.getLoc(), operand.getType());221 222 for (const omp::Object &object : objects)223 useDeviceSyms.push_back(object.sym());224}225 226//===----------------------------------------------------------------------===//227// ClauseProcessor unique clauses228//===----------------------------------------------------------------------===//229 230bool ClauseProcessor::processBare(mlir::omp::BareClauseOps &result) const {231 return markClauseOccurrence<omp::clause::OmpxBare>(result.bare);232}233 234bool ClauseProcessor::processBind(mlir::omp::BindClauseOps &result) const {235 if (auto *clause = findUniqueClause<omp::clause::Bind>()) {236 fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();237 result.bindKind = genBindKindAttr(firOpBuilder, *clause);238 return true;239 }240 return false;241}242 243bool ClauseProcessor::processCancelDirectiveName(244 mlir::omp::CancelDirectiveNameClauseOps &result) const {245 using ConstructType = mlir::omp::ClauseCancellationConstructType;246 mlir::MLIRContext *context = &converter.getMLIRContext();247 248 ConstructType directive;249 if (auto *clause = findUniqueClause<omp::CancellationConstructType>()) {250 switch (clause->v) {251 case llvm::omp::OMP_CANCELLATION_CONSTRUCT_Parallel:252 directive = mlir::omp::ClauseCancellationConstructType::Parallel;253 break;254 case llvm::omp::OMP_CANCELLATION_CONSTRUCT_Loop:255 directive = mlir::omp::ClauseCancellationConstructType::Loop;256 break;257 case llvm::omp::OMP_CANCELLATION_CONSTRUCT_Sections:258 directive = mlir::omp::ClauseCancellationConstructType::Sections;259 break;260 case llvm::omp::OMP_CANCELLATION_CONSTRUCT_Taskgroup:261 directive = mlir::omp::ClauseCancellationConstructType::Taskgroup;262 break;263 case llvm::omp::OMP_CANCELLATION_CONSTRUCT_None:264 llvm_unreachable("OMP_CANCELLATION_CONSTRUCT_None");265 break;266 }267 } else {268 llvm_unreachable("cancel construct missing cancellation construct type");269 }270 271 result.cancelDirective =272 mlir::omp::ClauseCancellationConstructTypeAttr::get(context, directive);273 return true;274}275 276bool ClauseProcessor::processCollapse(277 mlir::Location currentLocation, lower::pft::Evaluation &eval,278 mlir::omp::LoopRelatedClauseOps &loopResult,279 mlir::omp::CollapseClauseOps &collapseResult,280 llvm::SmallVectorImpl<const semantics::Symbol *> &iv) const {281 282 int64_t numCollapse = collectLoopRelatedInfo(converter, currentLocation, eval,283 clauses, loopResult, iv);284 fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();285 collapseResult.collapseNumLoops = firOpBuilder.getI64IntegerAttr(numCollapse);286 return numCollapse > 1;287}288 289bool ClauseProcessor::processDevice(lower::StatementContext &stmtCtx,290 mlir::omp::DeviceClauseOps &result) const {291 const parser::CharBlock *source = nullptr;292 if (auto *clause = findUniqueClause<omp::clause::Device>(&source)) {293 mlir::Location clauseLocation = converter.genLocation(*source);294 if (auto deviceModifier =295 std::get<std::optional<omp::clause::Device::DeviceModifier>>(296 clause->t)) {297 if (deviceModifier == omp::clause::Device::DeviceModifier::Ancestor) {298 TODO(clauseLocation, "OMPD_target Device Modifier Ancestor");299 }300 }301 const auto &deviceExpr = std::get<omp::SomeExpr>(clause->t);302 result.device = fir::getBase(converter.genExprValue(deviceExpr, stmtCtx));303 return true;304 }305 return false;306}307 308bool ClauseProcessor::processDeviceType(309 mlir::omp::DeviceTypeClauseOps &result) const {310 if (auto *clause = findUniqueClause<omp::clause::DeviceType>()) {311 // Case: declare target ... device_type(any | host | nohost)312 switch (clause->v) {313 case omp::clause::DeviceType::DeviceTypeDescription::Nohost:314 result.deviceType = mlir::omp::DeclareTargetDeviceType::nohost;315 break;316 case omp::clause::DeviceType::DeviceTypeDescription::Host:317 result.deviceType = mlir::omp::DeclareTargetDeviceType::host;318 break;319 case omp::clause::DeviceType::DeviceTypeDescription::Any:320 result.deviceType = mlir::omp::DeclareTargetDeviceType::any;321 break;322 }323 return true;324 }325 return false;326}327 328bool ClauseProcessor::processDistSchedule(329 lower::StatementContext &stmtCtx,330 mlir::omp::DistScheduleClauseOps &result) const {331 if (auto *clause = findUniqueClause<omp::clause::DistSchedule>()) {332 result.distScheduleStatic = converter.getFirOpBuilder().getUnitAttr();333 const auto &chunkSize = std::get<std::optional<ExprTy>>(clause->t);334 if (chunkSize)335 result.distScheduleChunkSize =336 fir::getBase(converter.genExprValue(*chunkSize, stmtCtx));337 return true;338 }339 return false;340}341 342bool ClauseProcessor::processExclusive(343 mlir::Location currentLocation,344 mlir::omp::ExclusiveClauseOps &result) const {345 if (auto *clause = findUniqueClause<omp::clause::Exclusive>()) {346 for (const Object &object : clause->v) {347 const semantics::Symbol *symbol = object.sym();348 mlir::Value symVal = converter.getSymbolAddress(*symbol);349 result.exclusiveVars.push_back(symVal);350 }351 return true;352 }353 return false;354}355 356bool ClauseProcessor::processFilter(lower::StatementContext &stmtCtx,357 mlir::omp::FilterClauseOps &result) const {358 if (auto *clause = findUniqueClause<omp::clause::Filter>()) {359 result.filteredThreadId =360 fir::getBase(converter.genExprValue(clause->v, stmtCtx));361 return true;362 }363 return false;364}365 366bool ClauseProcessor::processFinal(lower::StatementContext &stmtCtx,367 mlir::omp::FinalClauseOps &result) const {368 const parser::CharBlock *source = nullptr;369 if (auto *clause = findUniqueClause<omp::clause::Final>(&source)) {370 fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();371 mlir::Location clauseLocation = converter.genLocation(*source);372 373 mlir::Value finalVal =374 fir::getBase(converter.genExprValue(clause->v, stmtCtx));375 result.final = firOpBuilder.createConvert(376 clauseLocation, firOpBuilder.getI1Type(), finalVal);377 return true;378 }379 return false;380}381 382bool ClauseProcessor::processHint(mlir::omp::HintClauseOps &result) const {383 if (auto *clause = findUniqueClause<omp::clause::Hint>()) {384 fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();385 int64_t hintValue = *evaluate::ToInt64(clause->v);386 result.hint = firOpBuilder.getI64IntegerAttr(hintValue);387 return true;388 }389 return false;390}391 392bool ClauseProcessor::processInclusive(393 mlir::Location currentLocation,394 mlir::omp::InclusiveClauseOps &result) const {395 if (auto *clause = findUniqueClause<omp::clause::Inclusive>()) {396 for (const Object &object : clause->v) {397 const semantics::Symbol *symbol = object.sym();398 mlir::Value symVal = converter.getSymbolAddress(*symbol);399 result.inclusiveVars.push_back(symVal);400 }401 return true;402 }403 return false;404}405 406bool ClauseProcessor::processInitializer(407 lower::SymMap &symMap, const parser::OmpClause::Initializer &inp,408 ReductionProcessor::GenInitValueCBTy &genInitValueCB) const {409 if (auto *clause = findUniqueClause<omp::clause::Initializer>()) {410 genInitValueCB = [&, clause](fir::FirOpBuilder &builder, mlir::Location loc,411 mlir::Type type, mlir::Value ompOrig) {412 lower::SymMapScope scope(symMap);413 const parser::OmpInitializerExpression &iexpr = inp.v.v;414 const parser::OmpStylizedInstance &styleInstance = iexpr.v.front();415 const std::list<parser::OmpStylizedDeclaration> &declList =416 std::get<std::list<parser::OmpStylizedDeclaration>>(styleInstance.t);417 mlir::Value ompPrivVar;418 for (const parser::OmpStylizedDeclaration &decl : declList) {419 auto &name = std::get<parser::ObjectName>(decl.var.t);420 assert(name.symbol && "Name does not have a symbol");421 mlir::Value addr = builder.createTemporary(loc, ompOrig.getType());422 fir::StoreOp::create(builder, loc, ompOrig, addr);423 fir::FortranVariableFlagsEnum extraFlags = {};424 fir::FortranVariableFlagsAttr attributes =425 Fortran::lower::translateSymbolAttributes(builder.getContext(),426 *name.symbol, extraFlags);427 auto declareOp = hlfir::DeclareOp::create(428 builder, loc, addr, name.ToString(), nullptr, {}, nullptr, nullptr,429 0, attributes);430 if (name.ToString() == "omp_priv")431 ompPrivVar = declareOp.getResult(0);432 symMap.addVariableDefinition(*name.symbol, declareOp);433 }434 // Lower the expression/function call435 lower::StatementContext stmtCtx;436 mlir::Value result = common::visit(437 common::visitors{438 [&](const evaluate::ProcedureRef &procRef) -> mlir::Value {439 convertCallToHLFIR(loc, converter, procRef, std::nullopt,440 symMap, stmtCtx);441 auto privVal = fir::LoadOp::create(builder, loc, ompPrivVar);442 return privVal;443 },444 [&](const auto &expr) -> mlir::Value {445 mlir::Value exprResult = fir::getBase(convertExprToValue(446 loc, converter, clause->v, symMap, stmtCtx));447 // Conversion can either give a value or a refrence to a value,448 // we need to return the reduction type, so an optional load may449 // be generated.450 if (auto refType = llvm::dyn_cast<fir::ReferenceType>(451 exprResult.getType()))452 if (ompPrivVar.getType() == refType)453 exprResult = fir::LoadOp::create(builder, loc, exprResult);454 return exprResult;455 }},456 clause->v.u);457 stmtCtx.finalizeAndPop();458 return result;459 };460 return true;461 }462 return false;463}464 465bool ClauseProcessor::processMergeable(466 mlir::omp::MergeableClauseOps &result) const {467 return markClauseOccurrence<omp::clause::Mergeable>(result.mergeable);468}469 470bool ClauseProcessor::processNogroup(471 mlir::omp::NogroupClauseOps &result) const {472 return markClauseOccurrence<omp::clause::Nogroup>(result.nogroup);473}474 475bool ClauseProcessor::processNowait(mlir::omp::NowaitClauseOps &result) const {476 return markClauseOccurrence<omp::clause::Nowait>(result.nowait);477}478 479bool ClauseProcessor::processNumTasks(480 lower::StatementContext &stmtCtx,481 mlir::omp::NumTasksClauseOps &result) const {482 using NumTasks = omp::clause::NumTasks;483 if (auto *clause = findUniqueClause<NumTasks>()) {484 fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();485 mlir::MLIRContext *context = firOpBuilder.getContext();486 const auto &modifier =487 std::get<std::optional<NumTasks::Prescriptiveness>>(clause->t);488 if (modifier && *modifier == NumTasks::Prescriptiveness::Strict) {489 result.numTasksMod = mlir::omp::ClauseNumTasksTypeAttr::get(490 context, mlir::omp::ClauseNumTasksType::Strict);491 }492 const auto &numtasksExpr = std::get<omp::SomeExpr>(clause->t);493 result.numTasks =494 fir::getBase(converter.genExprValue(numtasksExpr, stmtCtx));495 return true;496 }497 return false;498}499 500bool ClauseProcessor::processSizes(StatementContext &stmtCtx,501 mlir::omp::SizesClauseOps &result) const {502 if (auto *clause = findUniqueClause<omp::clause::Sizes>()) {503 result.sizes.reserve(clause->v.size());504 for (const ExprTy &vv : clause->v)505 result.sizes.push_back(fir::getBase(converter.genExprValue(vv, stmtCtx)));506 507 return true;508 }509 510 return false;511}512 513bool ClauseProcessor::processNumTeams(514 lower::StatementContext &stmtCtx,515 mlir::omp::NumTeamsClauseOps &result) const {516 // TODO Get lower and upper bounds for num_teams when parser is updated to517 // accept both.518 if (auto *clause = findUniqueClause<omp::clause::NumTeams>()) {519 // The num_teams directive accepts a list of team lower/upper bounds.520 // This is an extension to support grid specification for ompx_bare.521 // Here, only expect a single element in the list.522 assert(clause->v.size() == 1);523 // auto lowerBound = std::get<std::optional<ExprTy>>(clause->v[0]->t);524 auto &upperBound = std::get<ExprTy>(clause->v[0].t);525 result.numTeamsUpper =526 fir::getBase(converter.genExprValue(upperBound, stmtCtx));527 return true;528 }529 return false;530}531 532bool ClauseProcessor::processNumThreads(533 lower::StatementContext &stmtCtx,534 mlir::omp::NumThreadsClauseOps &result) const {535 if (auto *clause = findUniqueClause<omp::clause::NumThreads>()) {536 // OMPIRBuilder expects `NUM_THREADS` clause as a `Value`.537 result.numThreads =538 fir::getBase(converter.genExprValue(clause->v, stmtCtx));539 return true;540 }541 return false;542}543 544bool ClauseProcessor::processOrder(mlir::omp::OrderClauseOps &result) const {545 using Order = omp::clause::Order;546 if (auto *clause = findUniqueClause<Order>()) {547 fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();548 result.order = mlir::omp::ClauseOrderKindAttr::get(549 firOpBuilder.getContext(), mlir::omp::ClauseOrderKind::Concurrent);550 const auto &modifier =551 std::get<std::optional<Order::OrderModifier>>(clause->t);552 if (modifier && *modifier == Order::OrderModifier::Unconstrained) {553 result.orderMod = mlir::omp::OrderModifierAttr::get(554 firOpBuilder.getContext(), mlir::omp::OrderModifier::unconstrained);555 } else {556 // "If order-modifier is not unconstrained, the behavior is as if the557 // reproducible modifier is present."558 result.orderMod = mlir::omp::OrderModifierAttr::get(559 firOpBuilder.getContext(), mlir::omp::OrderModifier::reproducible);560 }561 return true;562 }563 return false;564}565 566bool ClauseProcessor::processOrdered(567 mlir::omp::OrderedClauseOps &result) const {568 if (auto *clause = findUniqueClause<omp::clause::Ordered>()) {569 fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();570 int64_t orderedClauseValue = 0l;571 if (clause->v.has_value())572 orderedClauseValue = *evaluate::ToInt64(*clause->v);573 result.ordered = firOpBuilder.getI64IntegerAttr(orderedClauseValue);574 return true;575 }576 return false;577}578 579bool ClauseProcessor::processPriority(580 lower::StatementContext &stmtCtx,581 mlir::omp::PriorityClauseOps &result) const {582 if (auto *clause = findUniqueClause<omp::clause::Priority>()) {583 result.priority = fir::getBase(converter.genExprValue(clause->v, stmtCtx));584 return true;585 }586 return false;587}588 589bool ClauseProcessor::processDetach(mlir::omp::DetachClauseOps &result) const {590 if (auto *clause = findUniqueClause<omp::clause::Detach>()) {591 semantics::Symbol *sym = clause->v.sym();592 mlir::Value symVal = converter.getSymbolAddress(*sym);593 result.eventHandle = symVal;594 return true;595 }596 return false;597}598 599bool ClauseProcessor::processProcBind(600 mlir::omp::ProcBindClauseOps &result) const {601 if (auto *clause = findUniqueClause<omp::clause::ProcBind>()) {602 fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();603 result.procBindKind = genProcBindKindAttr(firOpBuilder, *clause);604 return true;605 }606 return false;607}608 609bool ClauseProcessor::processTileSizes(610 lower::pft::Evaluation &eval, mlir::omp::LoopNestOperands &result) const {611 auto *ompCons{eval.getIf<parser::OpenMPConstruct>()};612 collectTileSizesFromOpenMPConstruct(ompCons, result.tileSizes, semaCtx);613 return !result.tileSizes.empty();614}615 616bool ClauseProcessor::processSafelen(617 mlir::omp::SafelenClauseOps &result) const {618 if (auto *clause = findUniqueClause<omp::clause::Safelen>()) {619 fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();620 const std::optional<std::int64_t> safelenVal = evaluate::ToInt64(clause->v);621 result.safelen = firOpBuilder.getI64IntegerAttr(*safelenVal);622 return true;623 }624 return false;625}626 627bool ClauseProcessor::processSchedule(628 lower::StatementContext &stmtCtx,629 mlir::omp::ScheduleClauseOps &result) const {630 if (auto *clause = findUniqueClause<omp::clause::Schedule>()) {631 fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();632 mlir::MLIRContext *context = firOpBuilder.getContext();633 const auto &scheduleType = std::get<omp::clause::Schedule::Kind>(clause->t);634 635 mlir::omp::ClauseScheduleKind scheduleKind;636 switch (scheduleType) {637 case omp::clause::Schedule::Kind::Static:638 scheduleKind = mlir::omp::ClauseScheduleKind::Static;639 break;640 case omp::clause::Schedule::Kind::Dynamic:641 scheduleKind = mlir::omp::ClauseScheduleKind::Dynamic;642 break;643 case omp::clause::Schedule::Kind::Guided:644 scheduleKind = mlir::omp::ClauseScheduleKind::Guided;645 break;646 case omp::clause::Schedule::Kind::Auto:647 scheduleKind = mlir::omp::ClauseScheduleKind::Auto;648 break;649 case omp::clause::Schedule::Kind::Runtime:650 scheduleKind = mlir::omp::ClauseScheduleKind::Runtime;651 break;652 }653 654 result.scheduleKind =655 mlir::omp::ClauseScheduleKindAttr::get(context, scheduleKind);656 657 mlir::omp::ScheduleModifier scheduleMod = getScheduleModifier(*clause);658 if (scheduleMod != mlir::omp::ScheduleModifier::none)659 result.scheduleMod =660 mlir::omp::ScheduleModifierAttr::get(context, scheduleMod);661 662 if (getSimdModifier(*clause) != mlir::omp::ScheduleModifier::none)663 result.scheduleSimd = firOpBuilder.getUnitAttr();664 665 if (const auto &chunkExpr = std::get<omp::MaybeExpr>(clause->t))666 result.scheduleChunk =667 fir::getBase(converter.genExprValue(*chunkExpr, stmtCtx));668 669 return true;670 }671 return false;672}673 674bool ClauseProcessor::processSimdlen(675 mlir::omp::SimdlenClauseOps &result) const {676 if (auto *clause = findUniqueClause<omp::clause::Simdlen>()) {677 fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();678 const std::optional<std::int64_t> simdlenVal = evaluate::ToInt64(clause->v);679 result.simdlen = firOpBuilder.getI64IntegerAttr(*simdlenVal);680 return true;681 }682 return false;683}684 685bool ClauseProcessor::processThreadLimit(686 lower::StatementContext &stmtCtx,687 mlir::omp::ThreadLimitClauseOps &result) const {688 if (auto *clause = findUniqueClause<omp::clause::ThreadLimit>()) {689 result.threadLimit =690 fir::getBase(converter.genExprValue(clause->v, stmtCtx));691 return true;692 }693 return false;694}695 696bool ClauseProcessor::processUntied(mlir::omp::UntiedClauseOps &result) const {697 return markClauseOccurrence<omp::clause::Untied>(result.untied);698}699 700//===----------------------------------------------------------------------===//701// ClauseProcessor repeatable clauses702//===----------------------------------------------------------------------===//703static llvm::StringMap<bool> getTargetFeatures(mlir::ModuleOp module) {704 llvm::StringMap<bool> featuresMap;705 llvm::SmallVector<llvm::StringRef> targetFeaturesVec;706 if (mlir::LLVM::TargetFeaturesAttr features =707 fir::getTargetFeatures(module)) {708 llvm::ArrayRef<mlir::StringAttr> featureAttrs = features.getFeatures();709 for (auto &featureAttr : featureAttrs) {710 llvm::StringRef featureKeyString = featureAttr.strref();711 featuresMap[featureKeyString.substr(1)] = (featureKeyString[0] == '+');712 }713 }714 return featuresMap;715}716 717static void718addAlignedClause(lower::AbstractConverter &converter,719 const omp::clause::Aligned &clause,720 llvm::SmallVectorImpl<mlir::Value> &alignedVars,721 llvm::SmallVectorImpl<mlir::Attribute> &alignments) {722 using Aligned = omp::clause::Aligned;723 lower::StatementContext stmtCtx;724 mlir::IntegerAttr alignmentValueAttr;725 int64_t alignment = 0;726 fir::FirOpBuilder &builder = converter.getFirOpBuilder();727 728 if (auto &alignmentValueParserExpr =729 std::get<std::optional<Aligned::Alignment>>(clause.t)) {730 mlir::Value operand = fir::getBase(731 converter.genExprValue(*alignmentValueParserExpr, stmtCtx));732 alignment = *fir::getIntIfConstant(operand);733 } else {734 llvm::StringMap<bool> featuresMap = getTargetFeatures(builder.getModule());735 llvm::Triple triple = fir::getTargetTriple(builder.getModule());736 alignment =737 llvm::OpenMPIRBuilder::getOpenMPDefaultSimdAlign(triple, featuresMap);738 }739 740 // The default alignment for some targets is equal to 0.741 // Do not generate alignment assumption if alignment is less than or equal to742 // 0 or not a power of two743 if (alignment > 0 && ((alignment & (alignment - 1)) == 0)) {744 auto &objects = std::get<omp::ObjectList>(clause.t);745 if (!objects.empty())746 genObjectList(objects, converter, alignedVars);747 alignmentValueAttr = builder.getI64IntegerAttr(alignment);748 // All the list items in a aligned clause will have same alignment749 for (std::size_t i = 0; i < objects.size(); i++)750 alignments.push_back(alignmentValueAttr);751 }752}753 754bool ClauseProcessor::processAligned(755 mlir::omp::AlignedClauseOps &result) const {756 return findRepeatableClause<omp::clause::Aligned>(757 [&](const omp::clause::Aligned &clause, const parser::CharBlock &) {758 addAlignedClause(converter, clause, result.alignedVars,759 result.alignments);760 });761}762 763bool ClauseProcessor::processAllocate(764 mlir::omp::AllocateClauseOps &result) const {765 return findRepeatableClause<omp::clause::Allocate>(766 [&](const omp::clause::Allocate &clause, const parser::CharBlock &) {767 genAllocateClause(converter, clause, result.allocatorVars,768 result.allocateVars);769 });770}771 772bool ClauseProcessor::processCopyin() const {773 fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();774 mlir::OpBuilder::InsertPoint insPt = firOpBuilder.saveInsertionPoint();775 firOpBuilder.setInsertionPointToStart(firOpBuilder.getAllocaBlock());776 auto checkAndCopyHostAssociateVar =777 [&](semantics::Symbol *sym,778 mlir::OpBuilder::InsertPoint *copyAssignIP = nullptr) {779 assert(sym->has<semantics::HostAssocDetails>() &&780 "No host-association found");781 if (converter.isPresentShallowLookup(*sym))782 converter.copyHostAssociateVar(*sym, copyAssignIP);783 };784 bool hasCopyin = findRepeatableClause<omp::clause::Copyin>(785 [&](const omp::clause::Copyin &clause, const parser::CharBlock &) {786 for (const omp::Object &object : clause.v) {787 semantics::Symbol *sym = object.sym();788 assert(sym && "Expecting symbol");789 if (const auto *commonDetails =790 sym->detailsIf<semantics::CommonBlockDetails>()) {791 for (const auto &mem : commonDetails->objects())792 checkAndCopyHostAssociateVar(&*mem, &insPt);793 break;794 }795 796 assert(sym->has<semantics::HostAssocDetails>() &&797 "No host-association found");798 checkAndCopyHostAssociateVar(sym);799 }800 });801 802 // [OMP 5.0, 2.19.6.1] The copy is done after the team is formed and prior to803 // the execution of the associated structured block. Emit implicit barrier to804 // synchronize threads and avoid data races on propagation master's thread805 // values of threadprivate variables to local instances of that variables of806 // all other implicit threads.807 808 // All copies are inserted at either "insPt" (i.e. immediately before it),809 // or at some earlier point (as determined by "copyHostAssociateVar").810 // Unless the insertion point is given to "copyHostAssociateVar" explicitly,811 // it will not restore the builder's insertion point. Since the copies may be812 // inserted in any order (not following the execution order), make sure the813 // barrier is inserted following all of them.814 firOpBuilder.restoreInsertionPoint(insPt);815 if (hasCopyin)816 mlir::omp::BarrierOp::create(firOpBuilder, converter.getCurrentLocation());817 return hasCopyin;818}819 820/// Class that extracts information from the specified type.821class TypeInfo {822public:823 TypeInfo(mlir::Type ty) { typeScan(ty); }824 825 // Returns the length of character types.826 std::optional<fir::CharacterType::LenType> getCharLength() const {827 return charLen;828 }829 830 // Returns the shape of array types.831 llvm::ArrayRef<int64_t> getShape() const { return shape; }832 833 // Is the type inside a box?834 bool isBox() const { return inBox; }835 836 bool isBoxChar() const { return inBoxChar; }837 838private:839 void typeScan(mlir::Type type);840 841 std::optional<fir::CharacterType::LenType> charLen;842 llvm::SmallVector<int64_t> shape;843 bool inBox = false;844 bool inBoxChar = false;845};846 847void TypeInfo::typeScan(mlir::Type ty) {848 if (auto sty = mlir::dyn_cast<fir::SequenceType>(ty)) {849 assert(shape.empty() && !sty.getShape().empty());850 shape = llvm::SmallVector<int64_t>(sty.getShape());851 typeScan(sty.getEleTy());852 } else if (auto bty = mlir::dyn_cast<fir::BoxType>(ty)) {853 inBox = true;854 typeScan(bty.getEleTy());855 } else if (auto cty = mlir::dyn_cast<fir::ClassType>(ty)) {856 inBox = true;857 typeScan(cty.getEleTy());858 } else if (auto cty = mlir::dyn_cast<fir::CharacterType>(ty)) {859 charLen = cty.getLen();860 } else if (auto cty = mlir::dyn_cast<fir::BoxCharType>(ty)) {861 inBoxChar = true;862 typeScan(cty.getEleTy());863 } else if (auto hty = mlir::dyn_cast<fir::HeapType>(ty)) {864 typeScan(hty.getEleTy());865 } else if (auto pty = mlir::dyn_cast<fir::PointerType>(ty)) {866 typeScan(pty.getEleTy());867 } else {868 // The scan ends when reaching any built-in, record or boxproc type.869 assert(ty.isIntOrIndexOrFloat() || mlir::isa<mlir::ComplexType>(ty) ||870 mlir::isa<fir::LogicalType>(ty) || mlir::isa<fir::RecordType>(ty) ||871 mlir::isa<fir::BoxProcType>(ty));872 }873}874 875// Create a function that performs a copy between two variables, compatible876// with their types and attributes.877static mlir::func::FuncOp878createCopyFunc(mlir::Location loc, lower::AbstractConverter &converter,879 mlir::Type varType, fir::FortranVariableFlagsEnum varAttrs) {880 fir::FirOpBuilder &builder = converter.getFirOpBuilder();881 mlir::ModuleOp module = builder.getModule();882 mlir::Type eleTy = mlir::cast<fir::ReferenceType>(varType).getEleTy();883 TypeInfo typeInfo(eleTy);884 std::string copyFuncName =885 fir::getTypeAsString(eleTy, builder.getKindMap(), "_copy");886 887 if (auto decl = module.lookupSymbol<mlir::func::FuncOp>(copyFuncName))888 return decl;889 890 // create function891 mlir::OpBuilder::InsertionGuard guard(builder);892 mlir::OpBuilder modBuilder(module.getBodyRegion());893 llvm::SmallVector<mlir::Type> argsTy = {varType, varType};894 auto funcType = mlir::FunctionType::get(builder.getContext(), argsTy, {});895 mlir::func::FuncOp funcOp =896 mlir::func::FuncOp::create(modBuilder, loc, copyFuncName, funcType);897 funcOp.setVisibility(mlir::SymbolTable::Visibility::Private);898 fir::factory::setInternalLinkage(funcOp);899 builder.createBlock(&funcOp.getRegion(), funcOp.getRegion().end(), argsTy,900 {loc, loc});901 builder.setInsertionPointToStart(&funcOp.getRegion().back());902 // generate body903 fir::FortranVariableFlagsAttr attrs;904 if (varAttrs != fir::FortranVariableFlagsEnum::None)905 attrs = fir::FortranVariableFlagsAttr::get(builder.getContext(), varAttrs);906 mlir::Value shape;907 if (!typeInfo.isBox() && !typeInfo.getShape().empty()) {908 llvm::SmallVector<mlir::Value> extents;909 for (auto extent : typeInfo.getShape())910 extents.push_back(911 builder.createIntegerConstant(loc, builder.getIndexType(), extent));912 shape = fir::ShapeOp::create(builder, loc, extents);913 }914 mlir::Value dst = funcOp.getArgument(0);915 mlir::Value src = funcOp.getArgument(1);916 llvm::SmallVector<mlir::Value> typeparams;917 if (typeInfo.isBoxChar()) {918 // fir.boxchar will be passed here as fir.ref<fir.boxchar>919 auto loadDst = fir::LoadOp::create(builder, loc, dst);920 auto loadSrc = fir::LoadOp::create(builder, loc, src);921 // get the actual fir.ref<fir.char> type922 mlir::Type refType =923 fir::ReferenceType::get(mlir::cast<fir::BoxCharType>(eleTy).getEleTy());924 auto unboxedDst = fir::UnboxCharOp::create(builder, loc, refType,925 builder.getIndexType(), loadDst);926 auto unboxedSrc = fir::UnboxCharOp::create(builder, loc, refType,927 builder.getIndexType(), loadSrc);928 // Add length to type parameters929 typeparams.push_back(unboxedDst.getResult(1));930 dst = unboxedDst.getResult(0);931 src = unboxedSrc.getResult(0);932 } else if (typeInfo.getCharLength().has_value()) {933 mlir::Value charLen = builder.createIntegerConstant(934 loc, builder.getCharacterLengthType(), *typeInfo.getCharLength());935 typeparams.push_back(charLen);936 }937 auto declDst = hlfir::DeclareOp::create(938 builder, loc, dst, copyFuncName + "_dst", shape, typeparams,939 /*dummy_scope=*/nullptr, /*storage=*/nullptr,940 /*storage_offset=*/0, attrs);941 auto declSrc = hlfir::DeclareOp::create(942 builder, loc, src, copyFuncName + "_src", shape, typeparams,943 /*dummy_scope=*/nullptr, /*storage=*/nullptr,944 /*storage_offset=*/0, attrs);945 converter.copyVar(loc, declDst.getBase(), declSrc.getBase(), varAttrs);946 mlir::func::ReturnOp::create(builder, loc);947 return funcOp;948}949 950bool ClauseProcessor::processCopyprivate(951 mlir::Location currentLocation,952 mlir::omp::CopyprivateClauseOps &result) const {953 auto addCopyPrivateVar = [&](semantics::Symbol *sym) {954 mlir::Value symVal = converter.getSymbolAddress(*sym);955 auto declOp = symVal.getDefiningOp<hlfir::DeclareOp>();956 if (!declOp)957 fir::emitFatalError(currentLocation,958 "COPYPRIVATE is supported only in HLFIR mode");959 symVal = declOp.getBase();960 mlir::Type symType = symVal.getType();961 fir::FortranVariableFlagsEnum attrs =962 declOp.getFortranAttrs().has_value()963 ? *declOp.getFortranAttrs()964 : fir::FortranVariableFlagsEnum::None;965 mlir::Value cpVar = symVal;966 967 // CopyPrivate variables must be passed by reference. However, in the case968 // of assumed shapes/vla the type is not a !fir.ref, but a !fir.box.969 // In the case of character types, the passed in type can also be970 // !fir.boxchar. In these cases to retrieve the appropriate971 // !fir.ref<!fir.box<...>> or !fir.ref<!fir.boxchar<..>> to access the data972 // we need we must perform an alloca and then store to it and retrieve the973 // data from the new alloca.974 if (mlir::isa<fir::BaseBoxType>(symType) ||975 mlir::isa<fir::BoxCharType>(symType)) {976 fir::FirOpBuilder &builder = converter.getFirOpBuilder();977 auto alloca = fir::AllocaOp::create(builder, currentLocation, symType);978 fir::StoreOp::create(builder, currentLocation, symVal, alloca);979 cpVar = alloca;980 }981 982 result.copyprivateVars.push_back(cpVar);983 mlir::func::FuncOp funcOp =984 createCopyFunc(currentLocation, converter, cpVar.getType(), attrs);985 result.copyprivateSyms.push_back(mlir::SymbolRefAttr::get(funcOp));986 };987 988 bool hasCopyPrivate = findRepeatableClause<clause::Copyprivate>(989 [&](const clause::Copyprivate &clause, const parser::CharBlock &) {990 for (const Object &object : clause.v) {991 semantics::Symbol *sym = object.sym();992 if (const auto *commonDetails =993 sym->detailsIf<semantics::CommonBlockDetails>()) {994 for (const auto &mem : commonDetails->objects())995 addCopyPrivateVar(&*mem);996 break;997 }998 addCopyPrivateVar(sym);999 }1000 });1001 1002 return hasCopyPrivate;1003}1004 1005template <typename T>1006static bool isVectorSubscript(const evaluate::Expr<T> &expr) {1007 if (std::optional<evaluate::DataRef> dataRef{evaluate::ExtractDataRef(expr)})1008 if (const auto *arrayRef = std::get_if<evaluate::ArrayRef>(&dataRef->u))1009 for (const evaluate::Subscript &subscript : arrayRef->subscript())1010 if (std::holds_alternative<evaluate::IndirectSubscriptIntegerExpr>(1011 subscript.u))1012 if (subscript.Rank() > 0)1013 return true;1014 return false;1015}1016 1017bool ClauseProcessor::processDefaultMap(lower::StatementContext &stmtCtx,1018 DefaultMapsTy &result) const {1019 auto process = [&](const omp::clause::Defaultmap &clause,1020 const parser::CharBlock &) {1021 using Defmap = omp::clause::Defaultmap;1022 clause::Defaultmap::VariableCategory variableCategory =1023 Defmap::VariableCategory::All;1024 // Variable Category is optional, if not specified defaults to all.1025 // Multiples of the same category are illegal as are any other1026 // defaultmaps being specified when a user specified all is in place,1027 // however, this should be handled earlier during semantics.1028 if (auto varCat =1029 std::get<std::optional<Defmap::VariableCategory>>(clause.t))1030 variableCategory = varCat.value();1031 auto behaviour = std::get<Defmap::ImplicitBehavior>(clause.t);1032 result[variableCategory] = behaviour;1033 };1034 return findRepeatableClause<omp::clause::Defaultmap>(process);1035}1036 1037bool ClauseProcessor::processDepend(lower::SymMap &symMap,1038 lower::StatementContext &stmtCtx,1039 mlir::omp::DependClauseOps &result) const {1040 auto process = [&](const omp::clause::Depend &clause,1041 const parser::CharBlock &) {1042 using Depend = omp::clause::Depend;1043 if (!std::holds_alternative<Depend::TaskDep>(clause.u)) {1044 TODO(converter.getCurrentLocation(),1045 "DEPEND clause with SINK or SOURCE is not supported yet");1046 }1047 auto &taskDep = std::get<Depend::TaskDep>(clause.u);1048 auto depType = std::get<clause::DependenceType>(taskDep.t);1049 auto &objects = std::get<omp::ObjectList>(taskDep.t);1050 fir::FirOpBuilder &builder = converter.getFirOpBuilder();1051 1052 if (std::get<std::optional<omp::clause::Iterator>>(taskDep.t)) {1053 TODO(converter.getCurrentLocation(),1054 "Support for iterator modifiers is not implemented yet");1055 }1056 mlir::omp::ClauseTaskDependAttr dependTypeOperand =1057 genDependKindAttr(converter, depType);1058 result.dependKinds.append(objects.size(), dependTypeOperand);1059 1060 for (const omp::Object &object : objects) {1061 assert(object.ref() && "Expecting designator");1062 mlir::Value dependVar;1063 SomeExpr expr = *object.ref();1064 1065 if (evaluate::IsArrayElement(expr) || evaluate::ExtractSubstring(expr)) {1066 // Array Section or character (sub)string1067 if (isVectorSubscript(expr)) {1068 // OpenMP needs the address of the first indexed element (required by1069 // the standard to be the lowest index) to identify the dependency. We1070 // don't need an accurate length for the array section because the1071 // OpenMP standard forbids overlapping array sections.1072 dependVar = genVectorSubscriptedDesignatorFirstElementAddress(1073 converter.getCurrentLocation(), converter, expr, symMap, stmtCtx);1074 } else {1075 // Ordinary array section e.g. A(1:512:2)1076 hlfir::EntityWithAttributes entity = convertExprToHLFIR(1077 converter.getCurrentLocation(), converter, expr, symMap, stmtCtx);1078 dependVar = entity.getBase();1079 }1080 } else if (evaluate::isStructureComponent(expr) ||1081 evaluate::ExtractComplexPart(expr)) {1082 SomeExpr expr = *object.ref();1083 hlfir::EntityWithAttributes entity = convertExprToHLFIR(1084 converter.getCurrentLocation(), converter, expr, symMap, stmtCtx);1085 dependVar = entity.getBase();1086 } else {1087 semantics::Symbol *sym = object.sym();1088 dependVar = converter.getSymbolAddress(*sym);1089 }1090 1091 // If we pass a mutable box e.g. !fir.ref<!fir.box<!fir.heap<...>>> then1092 // the runtime will use the address of the box not the address of the1093 // data. Flang generates a lot of memcpys between different box1094 // allocations so this is not a reliable way to identify the dependency.1095 if (auto ref = mlir::dyn_cast<fir::ReferenceType>(dependVar.getType()))1096 if (fir::isa_box_type(ref.getElementType()))1097 dependVar = fir::LoadOp::create(1098 builder, converter.getCurrentLocation(), dependVar);1099 1100 // The openmp dialect doesn't know what to do with boxes (and it would1101 // break layering to teach it about them). The dependency variable can be1102 // a box because it was an array section or because the original symbol1103 // was mapped to a box.1104 // Getting the address of the box data is okay because all the runtime1105 // ultimately cares about is the base address of the array.1106 if (fir::isa_box_type(dependVar.getType()))1107 dependVar = fir::BoxAddrOp::create(1108 builder, converter.getCurrentLocation(), dependVar);1109 1110 result.dependVars.push_back(dependVar);1111 }1112 };1113 1114 return findRepeatableClause<omp::clause::Depend>(process);1115}1116 1117bool ClauseProcessor::processGrainsize(1118 lower::StatementContext &stmtCtx,1119 mlir::omp::GrainsizeClauseOps &result) const {1120 using Grainsize = omp::clause::Grainsize;1121 if (auto *clause = findUniqueClause<Grainsize>()) {1122 fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();1123 mlir::MLIRContext *context = firOpBuilder.getContext();1124 const auto &modifier =1125 std::get<std::optional<Grainsize::Prescriptiveness>>(clause->t);1126 if (modifier && *modifier == Grainsize::Prescriptiveness::Strict) {1127 result.grainsizeMod = mlir::omp::ClauseGrainsizeTypeAttr::get(1128 context, mlir::omp::ClauseGrainsizeType::Strict);1129 }1130 const auto &grainsizeExpr = std::get<omp::SomeExpr>(clause->t);1131 result.grainsize =1132 fir::getBase(converter.genExprValue(grainsizeExpr, stmtCtx));1133 return true;1134 }1135 return false;1136}1137 1138bool ClauseProcessor::processHasDeviceAddr(1139 lower::StatementContext &stmtCtx, mlir::omp::HasDeviceAddrClauseOps &result,1140 llvm::SmallVectorImpl<const semantics::Symbol *> &hasDeviceSyms) const {1141 // For HAS_DEVICE_ADDR objects, implicitly map the top-level entities.1142 // Their address (or the whole descriptor, if the entity had one) will be1143 // passed to the target region.1144 std::map<Object, OmpMapParentAndMemberData> parentMemberIndices;1145 bool clauseFound = findRepeatableClause<omp::clause::HasDeviceAddr>(1146 [&](const omp::clause::HasDeviceAddr &clause,1147 const parser::CharBlock &source) {1148 mlir::Location location = converter.genLocation(source);1149 mlir::omp::ClauseMapFlags mapTypeBits =1150 mlir::omp::ClauseMapFlags::to | mlir::omp::ClauseMapFlags::implicit;1151 omp::ObjectList baseObjects;1152 llvm::transform(clause.v, std::back_inserter(baseObjects),1153 [&](const omp::Object &object) {1154 if (auto maybeBase = getBaseObject(object, semaCtx))1155 return *maybeBase;1156 return object;1157 });1158 processMapObjects(stmtCtx, location, baseObjects, mapTypeBits,1159 parentMemberIndices, result.hasDeviceAddrVars,1160 hasDeviceSyms);1161 });1162 1163 insertChildMapInfoIntoParent(converter, semaCtx, stmtCtx, parentMemberIndices,1164 result.hasDeviceAddrVars, hasDeviceSyms);1165 return clauseFound;1166}1167 1168bool ClauseProcessor::processIf(1169 omp::clause::If::DirectiveNameModifier directiveName,1170 mlir::omp::IfClauseOps &result) const {1171 bool found = false;1172 findRepeatableClause<omp::clause::If>([&](const omp::clause::If &clause,1173 const parser::CharBlock &source) {1174 mlir::Location clauseLocation = converter.genLocation(source);1175 mlir::Value operand =1176 getIfClauseOperand(converter, clause, directiveName, clauseLocation);1177 // Assume that, at most, a single 'if' clause will be applicable to the1178 // given directive.1179 if (operand) {1180 result.ifExpr = operand;1181 found = true;1182 }1183 });1184 return found;1185}1186 1187template <typename T>1188void collectReductionSyms(1189 const T &reduction,1190 llvm::SmallVectorImpl<const semantics::Symbol *> &reductionSyms) {1191 const auto &objectList{std::get<omp::ObjectList>(reduction.t)};1192 for (const Object &object : objectList) {1193 const semantics::Symbol *symbol = object.sym();1194 reductionSyms.push_back(symbol);1195 }1196}1197 1198bool ClauseProcessor::processInReduction(1199 mlir::Location currentLocation, mlir::omp::InReductionClauseOps &result,1200 llvm::SmallVectorImpl<const semantics::Symbol *> &outReductionSyms) const {1201 return findRepeatableClause<omp::clause::InReduction>(1202 [&](const omp::clause::InReduction &clause, const parser::CharBlock &) {1203 llvm::SmallVector<mlir::Value> inReductionVars;1204 llvm::SmallVector<bool> inReduceVarByRef;1205 llvm::SmallVector<mlir::Attribute> inReductionDeclSymbols;1206 llvm::SmallVector<const semantics::Symbol *> inReductionSyms;1207 collectReductionSyms(clause, inReductionSyms);1208 1209 ReductionProcessor rp;1210 if (!rp.processReductionArguments<mlir::omp::DeclareReductionOp>(1211 currentLocation, converter,1212 std::get<typename omp::clause::ReductionOperatorList>(clause.t),1213 inReductionVars, inReduceVarByRef, inReductionDeclSymbols,1214 inReductionSyms))1215 TODO(currentLocation, "Lowering unrecognised reduction type");1216 1217 // Copy local lists into the output.1218 llvm::copy(inReductionVars, std::back_inserter(result.inReductionVars));1219 llvm::copy(inReduceVarByRef,1220 std::back_inserter(result.inReductionByref));1221 llvm::copy(inReductionDeclSymbols,1222 std::back_inserter(result.inReductionSyms));1223 llvm::copy(inReductionSyms, std::back_inserter(outReductionSyms));1224 });1225}1226 1227bool ClauseProcessor::processIsDevicePtr(1228 mlir::omp::IsDevicePtrClauseOps &result,1229 llvm::SmallVectorImpl<const semantics::Symbol *> &isDeviceSyms) const {1230 return findRepeatableClause<omp::clause::IsDevicePtr>(1231 [&](const omp::clause::IsDevicePtr &devPtrClause,1232 const parser::CharBlock &) {1233 addUseDeviceClause(converter, devPtrClause.v, result.isDevicePtrVars,1234 isDeviceSyms);1235 });1236}1237 1238bool ClauseProcessor::processLinear(mlir::omp::LinearClauseOps &result) const {1239 lower::StatementContext stmtCtx;1240 return findRepeatableClause<1241 omp::clause::Linear>([&](const omp::clause::Linear &clause,1242 const parser::CharBlock &) {1243 auto &objects = std::get<omp::ObjectList>(clause.t);1244 for (const omp::Object &object : objects) {1245 semantics::Symbol *sym = object.sym();1246 const mlir::Value variable = converter.getSymbolAddress(*sym);1247 result.linearVars.push_back(variable);1248 }1249 if (objects.size()) {1250 if (auto &mod =1251 std::get<std::optional<omp::clause::Linear::StepComplexModifier>>(1252 clause.t)) {1253 mlir::Value operand =1254 fir::getBase(converter.genExprValue(toEvExpr(*mod), stmtCtx));1255 result.linearStepVars.append(objects.size(), operand);1256 } else if (std::get<std::optional<omp::clause::Linear::LinearModifier>>(1257 clause.t)) {1258 mlir::Location currentLocation = converter.getCurrentLocation();1259 TODO(currentLocation, "Linear modifiers not yet implemented");1260 } else {1261 // If nothing is present, add the default step of 1.1262 fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();1263 mlir::Location currentLocation = converter.getCurrentLocation();1264 mlir::Value operand = firOpBuilder.createIntegerConstant(1265 currentLocation, firOpBuilder.getI32Type(), 1);1266 result.linearStepVars.append(objects.size(), operand);1267 }1268 }1269 });1270}1271 1272bool ClauseProcessor::processLink(1273 llvm::SmallVectorImpl<DeclareTargetCaptureInfo> &result) const {1274 return findRepeatableClause<omp::clause::Link>(1275 [&](const omp::clause::Link &clause, const parser::CharBlock &) {1276 // Case: declare target link(var1, var2)...1277 gatherFuncAndVarSyms(1278 clause.v, mlir::omp::DeclareTargetCaptureClause::link, result,1279 /*automap=*/false);1280 });1281}1282 1283void ClauseProcessor::processMapObjects(1284 lower::StatementContext &stmtCtx, mlir::Location clauseLocation,1285 const omp::ObjectList &objects, mlir::omp::ClauseMapFlags mapTypeBits,1286 std::map<Object, OmpMapParentAndMemberData> &parentMemberIndices,1287 llvm::SmallVectorImpl<mlir::Value> &mapVars,1288 llvm::SmallVectorImpl<const semantics::Symbol *> &mapSyms,1289 llvm::StringRef mapperIdNameRef) const {1290 fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();1291 1292 auto getSymbolDerivedType = [](const semantics::Symbol &symbol)1293 -> const semantics::DerivedTypeSpec * {1294 const semantics::Symbol &ultimate = symbol.GetUltimate();1295 if (const semantics::DeclTypeSpec *declType = ultimate.GetType())1296 if (const auto *derived = declType->AsDerived())1297 return derived;1298 return nullptr;1299 };1300 1301 auto addImplicitMapper = [&](const omp::Object &object,1302 std::string &mapperIdName,1303 bool allowGenerate) -> mlir::FlatSymbolRefAttr {1304 if (mapperIdName.empty())1305 return mlir::FlatSymbolRefAttr();1306 1307 if (converter.getModuleOp().lookupSymbol(mapperIdName))1308 return mlir::FlatSymbolRefAttr::get(&converter.getMLIRContext(),1309 mapperIdName);1310 1311 if (!allowGenerate)1312 return mlir::FlatSymbolRefAttr();1313 1314 const semantics::DerivedTypeSpec *typeSpec =1315 getSymbolDerivedType(*object.sym());1316 if (!typeSpec && object.sym()->owner().IsDerivedType())1317 typeSpec = object.sym()->owner().derivedTypeSpec();1318 1319 if (!typeSpec)1320 return mlir::FlatSymbolRefAttr();1321 1322 mlir::Type type = converter.genType(*typeSpec);1323 auto recordType = mlir::dyn_cast<fir::RecordType>(type);1324 if (!recordType)1325 return mlir::FlatSymbolRefAttr();1326 1327 return getOrGenImplicitDefaultDeclareMapper(converter, clauseLocation,1328 recordType, mapperIdName);1329 };1330 1331 auto getDefaultMapperID =1332 [&](const semantics::DerivedTypeSpec *typeSpec) -> std::string {1333 if (mlir::isa<mlir::omp::DeclareMapperOp>(1334 firOpBuilder.getRegion().getParentOp()) ||1335 !typeSpec)1336 return {};1337 1338 std::string mapperIdName =1339 typeSpec->name().ToString() + llvm::omp::OmpDefaultMapperName;1340 if (auto *sym = converter.getCurrentScope().FindSymbol(mapperIdName)) {1341 mapperIdName =1342 converter.mangleName(mapperIdName, sym->GetUltimate().owner());1343 } else {1344 mapperIdName = converter.mangleName(mapperIdName, *typeSpec->GetScope());1345 }1346 1347 // Make sure we don't return a mapper to self.1348 if (auto declMapOp = mlir::dyn_cast<mlir::omp::DeclareMapperOp>(1349 firOpBuilder.getRegion().getParentOp()))1350 if (mapperIdName == declMapOp.getSymName())1351 return {};1352 return mapperIdName;1353 };1354 1355 // Create the mapper symbol from its name, if specified.1356 mlir::FlatSymbolRefAttr mapperId;1357 if (!mapperIdNameRef.empty() && !objects.empty() &&1358 mapperIdNameRef != "__implicit_mapper") {1359 std::string mapperIdName = mapperIdNameRef.str();1360 const omp::Object &object = objects.front();1361 if (mapperIdNameRef == "default") {1362 const semantics::DerivedTypeSpec *typeSpec =1363 getSymbolDerivedType(*object.sym());1364 if (!typeSpec && object.sym()->owner().IsDerivedType())1365 typeSpec = object.sym()->owner().derivedTypeSpec();1366 mapperIdName = getDefaultMapperID(typeSpec);1367 }1368 assert(converter.getModuleOp().lookupSymbol(mapperIdName) &&1369 "mapper not found");1370 mapperId =1371 mlir::FlatSymbolRefAttr::get(&converter.getMLIRContext(), mapperIdName);1372 }1373 1374 for (const omp::Object &object : objects) {1375 llvm::SmallVector<mlir::Value> bounds;1376 std::stringstream asFortran;1377 std::optional<omp::Object> parentObj;1378 1379 fir::factory::AddrAndBoundsInfo info =1380 lower::gatherDataOperandAddrAndBounds<mlir::omp::MapBoundsOp,1381 mlir::omp::MapBoundsType>(1382 converter, firOpBuilder, semaCtx, stmtCtx, *object.sym(),1383 object.ref(), clauseLocation, asFortran, bounds,1384 treatIndexAsSection);1385 1386 mlir::Value baseOp = info.rawInput;1387 if (object.sym()->owner().IsDerivedType()) {1388 omp::ObjectList objectList = gatherObjectsOf(object, semaCtx);1389 assert(!objectList.empty() &&1390 "could not find parent objects of derived type member");1391 parentObj = objectList[0];1392 parentMemberIndices.emplace(parentObj.value(),1393 OmpMapParentAndMemberData{});1394 1395 if (isMemberOrParentAllocatableOrPointer(object, semaCtx)) {1396 llvm::SmallVector<int64_t> indices;1397 generateMemberPlacementIndices(object, indices, semaCtx);1398 baseOp = createParentSymAndGenIntermediateMaps(1399 clauseLocation, converter, semaCtx, stmtCtx, objectList, indices,1400 parentMemberIndices[parentObj.value()], asFortran.str(),1401 mapTypeBits);1402 }1403 }1404 1405 const semantics::DerivedTypeSpec *objectTypeSpec =1406 getSymbolDerivedType(*object.sym());1407 1408 if (mapperIdNameRef == "__implicit_mapper") {1409 if (parentObj.has_value()) {1410 mapperId = mlir::FlatSymbolRefAttr();1411 } else if (objectTypeSpec) {1412 std::string mapperIdName = getDefaultMapperID(objectTypeSpec);1413 bool needsDefaultMapper =1414 semantics::IsAllocatableOrObjectPointer(object.sym()) ||1415 requiresImplicitDefaultDeclareMapper(*objectTypeSpec);1416 if (!mapperIdName.empty())1417 mapperId = addImplicitMapper(object, mapperIdName,1418 /*allowGenerate=*/needsDefaultMapper);1419 else1420 mapperId = mlir::FlatSymbolRefAttr();1421 } else {1422 mapperId = mlir::FlatSymbolRefAttr();1423 }1424 }1425 1426 // Explicit map captures are captured ByRef by default,1427 // optimisation passes may alter this to ByCopy or other capture1428 // types to optimise1429 auto location = mlir::NameLoc::get(1430 mlir::StringAttr::get(firOpBuilder.getContext(), asFortran.str()),1431 baseOp.getLoc());1432 mlir::omp::MapInfoOp mapOp = utils::openmp::createMapInfoOp(1433 firOpBuilder, location, baseOp,1434 /*varPtrPtr=*/mlir::Value{}, asFortran.str(), bounds,1435 /*members=*/{}, /*membersIndex=*/mlir::ArrayAttr{}, mapTypeBits,1436 mlir::omp::VariableCaptureKind::ByRef, baseOp.getType(),1437 /*partialMap=*/false, mapperId);1438 1439 if (parentObj.has_value()) {1440 parentMemberIndices[parentObj.value()].addChildIndexAndMapToParent(1441 object, mapOp, semaCtx);1442 } else {1443 mapVars.push_back(mapOp);1444 mapSyms.push_back(object.sym());1445 }1446 }1447}1448 1449bool ClauseProcessor::processMap(1450 mlir::Location currentLocation, lower::StatementContext &stmtCtx,1451 mlir::omp::MapClauseOps &result, llvm::omp::Directive directive,1452 llvm::SmallVectorImpl<const semantics::Symbol *> *mapSyms) const {1453 // We always require tracking of symbols, even if the caller does not,1454 // so we create an optionally used local set of symbols when the mapSyms1455 // argument is not present.1456 llvm::SmallVector<const semantics::Symbol *> localMapSyms;1457 llvm::SmallVectorImpl<const semantics::Symbol *> *ptrMapSyms =1458 mapSyms ? mapSyms : &localMapSyms;1459 std::map<Object, OmpMapParentAndMemberData> parentMemberIndices;1460 1461 auto process = [&](const omp::clause::Map &clause,1462 const parser::CharBlock &source) {1463 using Map = omp::clause::Map;1464 mlir::Location clauseLocation = converter.genLocation(source);1465 const auto &[mapType, typeMods, attachMod, refMod, mappers, iterator,1466 objects] = clause.t;1467 if (attachMod)1468 TODO(currentLocation, "ATTACH modifier is not implemented yet");1469 mlir::omp::ClauseMapFlags mapTypeBits = mlir::omp::ClauseMapFlags::none;1470 std::string mapperIdName = "__implicit_mapper";1471 // If the map type is specified, then process it else set the appropriate1472 // default value1473 Map::MapType type;1474 if (directive == llvm::omp::Directive::OMPD_target_enter_data &&1475 semaCtx.langOptions().OpenMPVersion >= 52)1476 type = mapType.value_or(Map::MapType::To);1477 else if (directive == llvm::omp::Directive::OMPD_target_exit_data &&1478 semaCtx.langOptions().OpenMPVersion >= 52)1479 type = mapType.value_or(Map::MapType::From);1480 else1481 type = mapType.value_or(Map::MapType::Tofrom);1482 1483 switch (type) {1484 case Map::MapType::To:1485 mapTypeBits |= mlir::omp::ClauseMapFlags::to;1486 break;1487 case Map::MapType::From:1488 mapTypeBits |= mlir::omp::ClauseMapFlags::from;1489 break;1490 case Map::MapType::Tofrom:1491 mapTypeBits |=1492 mlir::omp::ClauseMapFlags::to | mlir::omp::ClauseMapFlags::from;1493 break;1494 case Map::MapType::Storage:1495 mapTypeBits |= mlir::omp::ClauseMapFlags::storage;1496 break;1497 }1498 1499 if (typeMods) {1500 // TODO: Still requires "self" modifier, an OpenMP 6.0+ feature1501 if (llvm::is_contained(*typeMods, Map::MapTypeModifier::Always))1502 mapTypeBits |= mlir::omp::ClauseMapFlags::always;1503 if (llvm::is_contained(*typeMods, Map::MapTypeModifier::Present))1504 mapTypeBits |= mlir::omp::ClauseMapFlags::present;1505 if (llvm::is_contained(*typeMods, Map::MapTypeModifier::Close))1506 mapTypeBits |= mlir::omp::ClauseMapFlags::close;1507 if (llvm::is_contained(*typeMods, Map::MapTypeModifier::Delete))1508 mapTypeBits |= mlir::omp::ClauseMapFlags::del;1509 if (llvm::is_contained(*typeMods, Map::MapTypeModifier::OmpxHold))1510 mapTypeBits |= mlir::omp::ClauseMapFlags::ompx_hold;1511 }1512 1513 if (iterator) {1514 TODO(currentLocation,1515 "Support for iterator modifiers is not implemented yet");1516 }1517 if (mappers) {1518 assert(mappers->size() == 1 && "more than one mapper");1519 const semantics::Symbol *mapperSym = mappers->front().v.id().symbol;1520 mapperIdName = mapperSym->name().ToString();1521 if (mapperIdName != "default") {1522 // Mangle with the ultimate owner so that use-associated mapper1523 // identifiers resolve to the same symbol as their defining scope.1524 const semantics::Symbol &ultimate = mapperSym->GetUltimate();1525 mapperIdName = converter.mangleName(mapperIdName, ultimate.owner());1526 }1527 }1528 1529 processMapObjects(stmtCtx, clauseLocation,1530 std::get<omp::ObjectList>(clause.t), mapTypeBits,1531 parentMemberIndices, result.mapVars, *ptrMapSyms,1532 mapperIdName);1533 };1534 1535 bool clauseFound = findRepeatableClause<omp::clause::Map>(process);1536 insertChildMapInfoIntoParent(converter, semaCtx, stmtCtx, parentMemberIndices,1537 result.mapVars, *ptrMapSyms);1538 1539 return clauseFound;1540}1541 1542bool ClauseProcessor::processMotionClauses(lower::StatementContext &stmtCtx,1543 mlir::omp::MapClauseOps &result) {1544 std::map<Object, OmpMapParentAndMemberData> parentMemberIndices;1545 llvm::SmallVector<const semantics::Symbol *> mapSymbols;1546 1547 auto callbackFn = [&](const auto &clause, const parser::CharBlock &source) {1548 mlir::Location clauseLocation = converter.genLocation(source);1549 const auto &[expectation, mapper, iterator, objects] = clause.t;1550 1551 // TODO Support motion modifiers: mapper, iterator.1552 if (mapper) {1553 TODO(clauseLocation, "Mapper modifier is not supported yet");1554 } else if (iterator) {1555 TODO(clauseLocation, "Iterator modifier is not supported yet");1556 }1557 1558 mlir::omp::ClauseMapFlags mapTypeBits =1559 std::is_same_v<llvm::remove_cvref_t<decltype(clause)>, omp::clause::To>1560 ? mlir::omp::ClauseMapFlags::to1561 : mlir::omp::ClauseMapFlags::from;1562 if (expectation && *expectation == omp::clause::To::Expectation::Present)1563 mapTypeBits |= mlir::omp::ClauseMapFlags::present;1564 processMapObjects(stmtCtx, clauseLocation, objects, mapTypeBits,1565 parentMemberIndices, result.mapVars, mapSymbols);1566 };1567 1568 bool clauseFound = findRepeatableClause<omp::clause::To>(callbackFn);1569 clauseFound =1570 findRepeatableClause<omp::clause::From>(callbackFn) || clauseFound;1571 1572 insertChildMapInfoIntoParent(converter, semaCtx, stmtCtx, parentMemberIndices,1573 result.mapVars, mapSymbols);1574 1575 return clauseFound;1576}1577 1578bool ClauseProcessor::processNontemporal(1579 mlir::omp::NontemporalClauseOps &result) const {1580 return findRepeatableClause<omp::clause::Nontemporal>(1581 [&](const omp::clause::Nontemporal &clause, const parser::CharBlock &) {1582 for (const Object &object : clause.v) {1583 semantics::Symbol *sym = object.sym();1584 mlir::Value symVal = converter.getSymbolAddress(*sym);1585 result.nontemporalVars.push_back(symVal);1586 }1587 });1588}1589 1590bool ClauseProcessor::processReduction(1591 mlir::Location currentLocation, mlir::omp::ReductionClauseOps &result,1592 llvm::SmallVectorImpl<const semantics::Symbol *> &outReductionSyms) const {1593 return findRepeatableClause<omp::clause::Reduction>(1594 [&](const omp::clause::Reduction &clause, const parser::CharBlock &) {1595 llvm::SmallVector<mlir::Value> reductionVars;1596 llvm::SmallVector<bool> reduceVarByRef;1597 llvm::SmallVector<mlir::Attribute> reductionDeclSymbols;1598 llvm::SmallVector<const semantics::Symbol *> reductionSyms;1599 collectReductionSyms(clause, reductionSyms);1600 1601 auto mod = std::get<std::optional<ReductionModifier>>(clause.t);1602 if (mod.has_value()) {1603 if (mod.value() == ReductionModifier::Task)1604 TODO(currentLocation, "Reduction modifier `task` is not supported");1605 else1606 result.reductionMod = mlir::omp::ReductionModifierAttr::get(1607 converter.getFirOpBuilder().getContext(),1608 translateReductionModifier(mod.value()));1609 }1610 1611 ReductionProcessor rp;1612 if (!rp.processReductionArguments<mlir::omp::DeclareReductionOp>(1613 currentLocation, converter,1614 std::get<typename omp::clause::ReductionOperatorList>(clause.t),1615 reductionVars, reduceVarByRef, reductionDeclSymbols,1616 reductionSyms))1617 TODO(currentLocation, "Lowering unrecognised reduction type");1618 // Copy local lists into the output.1619 llvm::copy(reductionVars, std::back_inserter(result.reductionVars));1620 llvm::copy(reduceVarByRef, std::back_inserter(result.reductionByref));1621 llvm::copy(reductionDeclSymbols,1622 std::back_inserter(result.reductionSyms));1623 llvm::copy(reductionSyms, std::back_inserter(outReductionSyms));1624 });1625}1626 1627bool ClauseProcessor::processTaskReduction(1628 mlir::Location currentLocation, mlir::omp::TaskReductionClauseOps &result,1629 llvm::SmallVectorImpl<const semantics::Symbol *> &outReductionSyms) const {1630 return findRepeatableClause<omp::clause::TaskReduction>(1631 [&](const omp::clause::TaskReduction &clause, const parser::CharBlock &) {1632 llvm::SmallVector<mlir::Value> taskReductionVars;1633 llvm::SmallVector<bool> taskReduceVarByRef;1634 llvm::SmallVector<mlir::Attribute> taskReductionDeclSymbols;1635 llvm::SmallVector<const semantics::Symbol *> taskReductionSyms;1636 collectReductionSyms(clause, taskReductionSyms);1637 1638 ReductionProcessor rp;1639 if (!rp.processReductionArguments<mlir::omp::DeclareReductionOp>(1640 currentLocation, converter,1641 std::get<typename omp::clause::ReductionOperatorList>(clause.t),1642 taskReductionVars, taskReduceVarByRef, taskReductionDeclSymbols,1643 taskReductionSyms))1644 TODO(currentLocation, "Lowering unrecognised reduction type");1645 // Copy local lists into the output.1646 llvm::copy(taskReductionVars,1647 std::back_inserter(result.taskReductionVars));1648 llvm::copy(taskReduceVarByRef,1649 std::back_inserter(result.taskReductionByref));1650 llvm::copy(taskReductionDeclSymbols,1651 std::back_inserter(result.taskReductionSyms));1652 llvm::copy(taskReductionSyms, std::back_inserter(outReductionSyms));1653 });1654}1655 1656bool ClauseProcessor::processTo(1657 llvm::SmallVectorImpl<DeclareTargetCaptureInfo> &result) const {1658 return findRepeatableClause<omp::clause::To>(1659 [&](const omp::clause::To &clause, const parser::CharBlock &) {1660 // Case: declare target to(func, var1, var2)...1661 gatherFuncAndVarSyms(std::get<ObjectList>(clause.t),1662 mlir::omp::DeclareTargetCaptureClause::to, result,1663 /*automap=*/false);1664 });1665}1666 1667bool ClauseProcessor::processEnter(1668 llvm::SmallVectorImpl<DeclareTargetCaptureInfo> &result) const {1669 return findRepeatableClause<omp::clause::Enter>(1670 [&](const omp::clause::Enter &clause, const parser::CharBlock &source) {1671 bool automap =1672 std::get<std::optional<omp::clause::Enter::Modifier>>(clause.t)1673 .has_value();1674 // Case: declare target enter(func, var1, var2)...1675 gatherFuncAndVarSyms(std::get<ObjectList>(clause.t),1676 mlir::omp::DeclareTargetCaptureClause::enter,1677 result, automap);1678 });1679}1680 1681bool ClauseProcessor::processUseDeviceAddr(1682 lower::StatementContext &stmtCtx, mlir::omp::UseDeviceAddrClauseOps &result,1683 llvm::SmallVectorImpl<const semantics::Symbol *> &useDeviceSyms) const {1684 std::map<Object, OmpMapParentAndMemberData> parentMemberIndices;1685 bool clauseFound = findRepeatableClause<omp::clause::UseDeviceAddr>(1686 [&](const omp::clause::UseDeviceAddr &clause,1687 const parser::CharBlock &source) {1688 mlir::Location location = converter.genLocation(source);1689 mlir::omp::ClauseMapFlags mapTypeBits =1690 mlir::omp::ClauseMapFlags::return_param;1691 processMapObjects(stmtCtx, location, clause.v, mapTypeBits,1692 parentMemberIndices, result.useDeviceAddrVars,1693 useDeviceSyms);1694 });1695 1696 insertChildMapInfoIntoParent(converter, semaCtx, stmtCtx, parentMemberIndices,1697 result.useDeviceAddrVars, useDeviceSyms);1698 return clauseFound;1699}1700 1701bool ClauseProcessor::processUseDevicePtr(1702 lower::StatementContext &stmtCtx, mlir::omp::UseDevicePtrClauseOps &result,1703 llvm::SmallVectorImpl<const semantics::Symbol *> &useDeviceSyms) const {1704 std::map<Object, OmpMapParentAndMemberData> parentMemberIndices;1705 1706 bool clauseFound = findRepeatableClause<omp::clause::UseDevicePtr>(1707 [&](const omp::clause::UseDevicePtr &clause,1708 const parser::CharBlock &source) {1709 mlir::Location location = converter.genLocation(source);1710 mlir::omp::ClauseMapFlags mapTypeBits =1711 mlir::omp::ClauseMapFlags::return_param;1712 processMapObjects(stmtCtx, location, clause.v, mapTypeBits,1713 parentMemberIndices, result.useDevicePtrVars,1714 useDeviceSyms);1715 });1716 1717 insertChildMapInfoIntoParent(converter, semaCtx, stmtCtx, parentMemberIndices,1718 result.useDevicePtrVars, useDeviceSyms);1719 return clauseFound;1720}1721 1722} // namespace omp1723} // namespace lower1724} // namespace Fortran1725