brintos

brintos / llvm-project-archived public Read only

0
0
Text · 70.5 KiB · dd0cb3c Raw
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