14d4af15cSKareem Ergawy //===-- ClauseProcessor.cpp -------------------------------------*- C++ -*-===// 24d4af15cSKareem Ergawy // 34d4af15cSKareem Ergawy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 44d4af15cSKareem Ergawy // See https://llvm.org/LICENSE.txt for license information. 54d4af15cSKareem Ergawy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 64d4af15cSKareem Ergawy // 74d4af15cSKareem Ergawy //===----------------------------------------------------------------------===// 84d4af15cSKareem Ergawy // 94d4af15cSKareem Ergawy // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ 104d4af15cSKareem Ergawy // 114d4af15cSKareem Ergawy //===----------------------------------------------------------------------===// 124d4af15cSKareem Ergawy 134d4af15cSKareem Ergawy #include "ClauseProcessor.h" 14f9e55796SKrzysztof Parzyszek #include "Clauses.h" 154d4af15cSKareem Ergawy 164d4af15cSKareem Ergawy #include "flang/Lower/PFTBuilder.h" 174d4af15cSKareem Ergawy #include "flang/Parser/tools.h" 184d4af15cSKareem Ergawy #include "flang/Semantics/tools.h" 197ffeaf0eSharishch4 #include "llvm/Frontend/OpenMP/OMPIRBuilder.h" 204d4af15cSKareem Ergawy 214d4af15cSKareem Ergawy namespace Fortran { 224d4af15cSKareem Ergawy namespace lower { 234d4af15cSKareem Ergawy namespace omp { 244d4af15cSKareem Ergawy 254d4af15cSKareem Ergawy /// Check for unsupported map operand types. 264d4af15cSKareem Ergawy static void checkMapType(mlir::Location location, mlir::Type type) { 27fac349a1SChristian Sigg if (auto refType = mlir::dyn_cast<fir::ReferenceType>(type)) 284d4af15cSKareem Ergawy type = refType.getElementType(); 29fac349a1SChristian Sigg if (auto boxType = mlir::dyn_cast_or_null<fir::BoxType>(type)) 30fac349a1SChristian Sigg if (!mlir::isa<fir::PointerType>(boxType.getElementType())) 314d4af15cSKareem Ergawy TODO(location, "OMPD_target_data MapOperand BoxType"); 324d4af15cSKareem Ergawy } 334d4af15cSKareem Ergawy 344d4af15cSKareem Ergawy static mlir::omp::ScheduleModifier 35148a5579SKrzysztof Parzyszek translateScheduleModifier(const omp::clause::Schedule::OrderingModifier &m) { 36f9e55796SKrzysztof Parzyszek switch (m) { 37148a5579SKrzysztof Parzyszek case omp::clause::Schedule::OrderingModifier::Monotonic: 384d4af15cSKareem Ergawy return mlir::omp::ScheduleModifier::monotonic; 39148a5579SKrzysztof Parzyszek case omp::clause::Schedule::OrderingModifier::Nonmonotonic: 404d4af15cSKareem Ergawy return mlir::omp::ScheduleModifier::nonmonotonic; 414d4af15cSKareem Ergawy } 424d4af15cSKareem Ergawy return mlir::omp::ScheduleModifier::none; 434d4af15cSKareem Ergawy } 444d4af15cSKareem Ergawy 454d4af15cSKareem Ergawy static mlir::omp::ScheduleModifier 46f9e55796SKrzysztof Parzyszek getScheduleModifier(const omp::clause::Schedule &clause) { 47148a5579SKrzysztof Parzyszek using Schedule = omp::clause::Schedule; 48148a5579SKrzysztof Parzyszek const auto &modifier = 49148a5579SKrzysztof Parzyszek std::get<std::optional<Schedule::OrderingModifier>>(clause.t); 50148a5579SKrzysztof Parzyszek if (modifier) 51148a5579SKrzysztof Parzyszek return translateScheduleModifier(*modifier); 524d4af15cSKareem Ergawy return mlir::omp::ScheduleModifier::none; 534d4af15cSKareem Ergawy } 544d4af15cSKareem Ergawy 554d4af15cSKareem Ergawy static mlir::omp::ScheduleModifier 56f9e55796SKrzysztof Parzyszek getSimdModifier(const omp::clause::Schedule &clause) { 57148a5579SKrzysztof Parzyszek using Schedule = omp::clause::Schedule; 58148a5579SKrzysztof Parzyszek const auto &modifier = 59148a5579SKrzysztof Parzyszek std::get<std::optional<Schedule::ChunkModifier>>(clause.t); 60148a5579SKrzysztof Parzyszek if (modifier && *modifier == Schedule::ChunkModifier::Simd) 614d4af15cSKareem Ergawy return mlir::omp::ScheduleModifier::simd; 624d4af15cSKareem Ergawy return mlir::omp::ScheduleModifier::none; 634d4af15cSKareem Ergawy } 644d4af15cSKareem Ergawy 654d4af15cSKareem Ergawy static void 667a66e420SKrzysztof Parzyszek genAllocateClause(lower::AbstractConverter &converter, 6763e70c05SKrzysztof Parzyszek const omp::clause::Allocate &clause, 684d4af15cSKareem Ergawy llvm::SmallVectorImpl<mlir::Value> &allocatorOperands, 694d4af15cSKareem Ergawy llvm::SmallVectorImpl<mlir::Value> &allocateOperands) { 704d4af15cSKareem Ergawy fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); 714d4af15cSKareem Ergawy mlir::Location currentLocation = converter.getCurrentLocation(); 727a66e420SKrzysztof Parzyszek lower::StatementContext stmtCtx; 734d4af15cSKareem Ergawy 74148a5579SKrzysztof Parzyszek auto &objects = std::get<omp::ObjectList>(clause.t); 754d4af15cSKareem Ergawy 76148a5579SKrzysztof Parzyszek using Allocate = omp::clause::Allocate; 77148a5579SKrzysztof Parzyszek // ALIGN in this context is unimplemented 78148a5579SKrzysztof Parzyszek if (std::get<std::optional<Allocate::AlignModifier>>(clause.t)) 794d4af15cSKareem Ergawy TODO(currentLocation, "OmpAllocateClause ALIGN modifier"); 804d4af15cSKareem Ergawy 814d4af15cSKareem Ergawy // Check if allocate clause has allocator specified. If so, add it 824d4af15cSKareem Ergawy // to list of allocators, otherwise, add default allocator to 834d4af15cSKareem Ergawy // list of allocators. 84148a5579SKrzysztof Parzyszek using ComplexModifier = Allocate::AllocatorComplexModifier; 85cdbd2287SKrzysztof Parzyszek if (auto &mod = std::get<std::optional<ComplexModifier>>(clause.t)) { 86148a5579SKrzysztof Parzyszek mlir::Value operand = fir::getBase(converter.genExprValue(mod->v, stmtCtx)); 87148a5579SKrzysztof Parzyszek allocatorOperands.append(objects.size(), operand); 884d4af15cSKareem Ergawy } else { 8963e70c05SKrzysztof Parzyszek mlir::Value operand = firOpBuilder.createIntegerConstant( 904d4af15cSKareem Ergawy currentLocation, firOpBuilder.getI32Type(), 1); 91148a5579SKrzysztof Parzyszek allocatorOperands.append(objects.size(), operand); 924d4af15cSKareem Ergawy } 93148a5579SKrzysztof Parzyszek 94148a5579SKrzysztof Parzyszek genObjectList(objects, converter, allocateOperands); 954d4af15cSKareem Ergawy } 964d4af15cSKareem Ergawy 97b4c0ef18SKareem Ergawy static mlir::omp::ClauseBindKindAttr 98b4c0ef18SKareem Ergawy genBindKindAttr(fir::FirOpBuilder &firOpBuilder, 99b4c0ef18SKareem Ergawy const omp::clause::Bind &clause) { 100b4c0ef18SKareem Ergawy mlir::omp::ClauseBindKind bindKind; 101b4c0ef18SKareem Ergawy switch (clause.v) { 102b4c0ef18SKareem Ergawy case omp::clause::Bind::Binding::Teams: 103b4c0ef18SKareem Ergawy bindKind = mlir::omp::ClauseBindKind::Teams; 104b4c0ef18SKareem Ergawy break; 105b4c0ef18SKareem Ergawy case omp::clause::Bind::Binding::Parallel: 106b4c0ef18SKareem Ergawy bindKind = mlir::omp::ClauseBindKind::Parallel; 107b4c0ef18SKareem Ergawy break; 108b4c0ef18SKareem Ergawy case omp::clause::Bind::Binding::Thread: 109b4c0ef18SKareem Ergawy bindKind = mlir::omp::ClauseBindKind::Thread; 110b4c0ef18SKareem Ergawy break; 111b4c0ef18SKareem Ergawy } 112b4c0ef18SKareem Ergawy return mlir::omp::ClauseBindKindAttr::get(firOpBuilder.getContext(), 113b4c0ef18SKareem Ergawy bindKind); 114b4c0ef18SKareem Ergawy } 115b4c0ef18SKareem Ergawy 116f9e55796SKrzysztof Parzyszek static mlir::omp::ClauseProcBindKindAttr 117f9e55796SKrzysztof Parzyszek genProcBindKindAttr(fir::FirOpBuilder &firOpBuilder, 118f9e55796SKrzysztof Parzyszek const omp::clause::ProcBind &clause) { 1194d4af15cSKareem Ergawy mlir::omp::ClauseProcBindKind procBindKind; 120f9e55796SKrzysztof Parzyszek switch (clause.v) { 121148a5579SKrzysztof Parzyszek case omp::clause::ProcBind::AffinityPolicy::Master: 1224d4af15cSKareem Ergawy procBindKind = mlir::omp::ClauseProcBindKind::Master; 1234d4af15cSKareem Ergawy break; 124148a5579SKrzysztof Parzyszek case omp::clause::ProcBind::AffinityPolicy::Close: 1254d4af15cSKareem Ergawy procBindKind = mlir::omp::ClauseProcBindKind::Close; 1264d4af15cSKareem Ergawy break; 127148a5579SKrzysztof Parzyszek case omp::clause::ProcBind::AffinityPolicy::Spread: 1284d4af15cSKareem Ergawy procBindKind = mlir::omp::ClauseProcBindKind::Spread; 1294d4af15cSKareem Ergawy break; 130148a5579SKrzysztof Parzyszek case omp::clause::ProcBind::AffinityPolicy::Primary: 1314d4af15cSKareem Ergawy procBindKind = mlir::omp::ClauseProcBindKind::Primary; 1324d4af15cSKareem Ergawy break; 1334d4af15cSKareem Ergawy } 1344d4af15cSKareem Ergawy return mlir::omp::ClauseProcBindKindAttr::get(firOpBuilder.getContext(), 1354d4af15cSKareem Ergawy procBindKind); 1364d4af15cSKareem Ergawy } 1374d4af15cSKareem Ergawy 1384d4af15cSKareem Ergawy static mlir::omp::ClauseTaskDependAttr 13929d4d7f6SKrzysztof Parzyszek genDependKindAttr(lower::AbstractConverter &converter, 140f87737f3SKrzysztof Parzyszek const omp::clause::DependenceType kind) { 14129d4d7f6SKrzysztof Parzyszek fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); 14229d4d7f6SKrzysztof Parzyszek mlir::Location currentLocation = converter.getCurrentLocation(); 14329d4d7f6SKrzysztof Parzyszek 1444d4af15cSKareem Ergawy mlir::omp::ClauseTaskDepend pbKind; 145148a5579SKrzysztof Parzyszek switch (kind) { 146f87737f3SKrzysztof Parzyszek case omp::clause::DependenceType::In: 1474d4af15cSKareem Ergawy pbKind = mlir::omp::ClauseTaskDepend::taskdependin; 1484d4af15cSKareem Ergawy break; 149f87737f3SKrzysztof Parzyszek case omp::clause::DependenceType::Out: 1504d4af15cSKareem Ergawy pbKind = mlir::omp::ClauseTaskDepend::taskdependout; 1514d4af15cSKareem Ergawy break; 152f87737f3SKrzysztof Parzyszek case omp::clause::DependenceType::Inout: 1534d4af15cSKareem Ergawy pbKind = mlir::omp::ClauseTaskDepend::taskdependinout; 1544d4af15cSKareem Ergawy break; 155f87737f3SKrzysztof Parzyszek case omp::clause::DependenceType::Mutexinoutset: 156cbe583b0SThirumalai Shaktivel pbKind = mlir::omp::ClauseTaskDepend::taskdependmutexinoutset; 157cbe583b0SThirumalai Shaktivel break; 158f87737f3SKrzysztof Parzyszek case omp::clause::DependenceType::Inoutset: 159cbe583b0SThirumalai Shaktivel pbKind = mlir::omp::ClauseTaskDepend::taskdependinoutset; 160cbe583b0SThirumalai Shaktivel break; 161f87737f3SKrzysztof Parzyszek case omp::clause::DependenceType::Depobj: 162cbe583b0SThirumalai Shaktivel TODO(currentLocation, "DEPOBJ dependence-type"); 163dcd62070SKiran Chandramohan break; 164f87737f3SKrzysztof Parzyszek case omp::clause::DependenceType::Sink: 165f87737f3SKrzysztof Parzyszek case omp::clause::DependenceType::Source: 166148a5579SKrzysztof Parzyszek llvm_unreachable("unhandled parser task dependence type"); 1674d4af15cSKareem Ergawy break; 1684d4af15cSKareem Ergawy } 1694d4af15cSKareem Ergawy return mlir::omp::ClauseTaskDependAttr::get(firOpBuilder.getContext(), 1704d4af15cSKareem Ergawy pbKind); 1714d4af15cSKareem Ergawy } 1724d4af15cSKareem Ergawy 17363e70c05SKrzysztof Parzyszek static mlir::Value 1747a66e420SKrzysztof Parzyszek getIfClauseOperand(lower::AbstractConverter &converter, 17563e70c05SKrzysztof Parzyszek const omp::clause::If &clause, 17663e70c05SKrzysztof Parzyszek omp::clause::If::DirectiveNameModifier directiveName, 1774d4af15cSKareem Ergawy mlir::Location clauseLocation) { 1784d4af15cSKareem Ergawy // Only consider the clause if it's intended for the given directive. 17963e70c05SKrzysztof Parzyszek auto &directive = 18063e70c05SKrzysztof Parzyszek std::get<std::optional<omp::clause::If::DirectiveNameModifier>>(clause.t); 1814d4af15cSKareem Ergawy if (directive && directive.value() != directiveName) 1824d4af15cSKareem Ergawy return nullptr; 1834d4af15cSKareem Ergawy 1847a66e420SKrzysztof Parzyszek lower::StatementContext stmtCtx; 1854d4af15cSKareem Ergawy fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); 1864d4af15cSKareem Ergawy mlir::Value ifVal = fir::getBase( 18763e70c05SKrzysztof Parzyszek converter.genExprValue(std::get<omp::SomeExpr>(clause.t), stmtCtx)); 1884d4af15cSKareem Ergawy return firOpBuilder.createConvert(clauseLocation, firOpBuilder.getI1Type(), 1894d4af15cSKareem Ergawy ifVal); 1904d4af15cSKareem Ergawy } 1914d4af15cSKareem Ergawy 19278eac466SSergio Afonso static void addUseDeviceClause( 1937a66e420SKrzysztof Parzyszek lower::AbstractConverter &converter, const omp::ObjectList &objects, 1944d4af15cSKareem Ergawy llvm::SmallVectorImpl<mlir::Value> &operands, 1957a66e420SKrzysztof Parzyszek llvm::SmallVectorImpl<const semantics::Symbol *> &useDeviceSyms) { 19663e70c05SKrzysztof Parzyszek genObjectList(objects, converter, operands); 19788478a89SSergio Afonso for (mlir::Value &operand : operands) 1984d4af15cSKareem Ergawy checkMapType(operand.getLoc(), operand.getType()); 19988478a89SSergio Afonso 20063e70c05SKrzysztof Parzyszek for (const omp::Object &object : objects) 2018b18f2feSKrzysztof Parzyszek useDeviceSyms.push_back(object.sym()); 2024d4af15cSKareem Ergawy } 2034d4af15cSKareem Ergawy 2047a66e420SKrzysztof Parzyszek static void convertLoopBounds(lower::AbstractConverter &converter, 20573402634SSergio Afonso mlir::Location loc, 2062f3d0619SSergio Afonso mlir::omp::LoopRelatedClauseOps &result, 20773402634SSergio Afonso std::size_t loopVarTypeSize) { 20873402634SSergio Afonso fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); 20973402634SSergio Afonso // The types of lower bound, upper bound, and step are converted into the 21073402634SSergio Afonso // type of the loop variable if necessary. 21173402634SSergio Afonso mlir::Type loopVarType = getLoopVarType(converter, loopVarTypeSize); 21246ecd7bbSSergio Afonso for (unsigned it = 0; it < (unsigned)result.loopLowerBounds.size(); it++) { 21346ecd7bbSSergio Afonso result.loopLowerBounds[it] = firOpBuilder.createConvert( 21446ecd7bbSSergio Afonso loc, loopVarType, result.loopLowerBounds[it]); 21546ecd7bbSSergio Afonso result.loopUpperBounds[it] = firOpBuilder.createConvert( 21646ecd7bbSSergio Afonso loc, loopVarType, result.loopUpperBounds[it]); 21746ecd7bbSSergio Afonso result.loopSteps[it] = 21846ecd7bbSSergio Afonso firOpBuilder.createConvert(loc, loopVarType, result.loopSteps[it]); 21973402634SSergio Afonso } 22073402634SSergio Afonso } 22173402634SSergio Afonso 2224d4af15cSKareem Ergawy //===----------------------------------------------------------------------===// 2234d4af15cSKareem Ergawy // ClauseProcessor unique clauses 2244d4af15cSKareem Ergawy //===----------------------------------------------------------------------===// 2254d4af15cSKareem Ergawy 2267c9404c2SIvan R. Ivanov bool ClauseProcessor::processBare(mlir::omp::BareClauseOps &result) const { 2277c9404c2SIvan R. Ivanov return markClauseOccurrence<omp::clause::OmpxBare>(result.bare); 2287c9404c2SIvan R. Ivanov } 2297c9404c2SIvan R. Ivanov 230b4c0ef18SKareem Ergawy bool ClauseProcessor::processBind(mlir::omp::BindClauseOps &result) const { 231b4c0ef18SKareem Ergawy if (auto *clause = findUniqueClause<omp::clause::Bind>()) { 232b4c0ef18SKareem Ergawy fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); 233b4c0ef18SKareem Ergawy result.bindKind = genBindKindAttr(firOpBuilder, *clause); 234b4c0ef18SKareem Ergawy return true; 235b4c0ef18SKareem Ergawy } 236b4c0ef18SKareem Ergawy return false; 237b4c0ef18SKareem Ergawy } 238b4c0ef18SKareem Ergawy 2394d4af15cSKareem Ergawy bool ClauseProcessor::processCollapse( 2407a66e420SKrzysztof Parzyszek mlir::Location currentLocation, lower::pft::Evaluation &eval, 2412f3d0619SSergio Afonso mlir::omp::LoopRelatedClauseOps &result, 2427a66e420SKrzysztof Parzyszek llvm::SmallVectorImpl<const semantics::Symbol *> &iv) const { 2434d4af15cSKareem Ergawy bool found = false; 2444d4af15cSKareem Ergawy fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); 2454d4af15cSKareem Ergawy 2464d4af15cSKareem Ergawy // Collect the loops to collapse. 2477a66e420SKrzysztof Parzyszek lower::pft::Evaluation *doConstructEval = &eval.getFirstNestedEvaluation(); 2487a66e420SKrzysztof Parzyszek if (doConstructEval->getIf<parser::DoConstruct>()->IsDoConcurrent()) { 2494d4af15cSKareem Ergawy TODO(currentLocation, "Do Concurrent in Worksharing loop construct"); 2504d4af15cSKareem Ergawy } 2514d4af15cSKareem Ergawy 2524d4af15cSKareem Ergawy std::int64_t collapseValue = 1l; 253f9e55796SKrzysztof Parzyszek if (auto *clause = findUniqueClause<omp::clause::Collapse>()) { 2547a66e420SKrzysztof Parzyszek collapseValue = evaluate::ToInt64(clause->v).value(); 2554d4af15cSKareem Ergawy found = true; 2564d4af15cSKareem Ergawy } 2574d4af15cSKareem Ergawy 25873402634SSergio Afonso std::size_t loopVarTypeSize = 0; 2594d4af15cSKareem Ergawy do { 2607a66e420SKrzysztof Parzyszek lower::pft::Evaluation *doLoop = 2614d4af15cSKareem Ergawy &doConstructEval->getFirstNestedEvaluation(); 2627a66e420SKrzysztof Parzyszek auto *doStmt = doLoop->getIf<parser::NonLabelDoStmt>(); 2634d4af15cSKareem Ergawy assert(doStmt && "Expected do loop to be in the nested evaluation"); 2644d4af15cSKareem Ergawy const auto &loopControl = 2657a66e420SKrzysztof Parzyszek std::get<std::optional<parser::LoopControl>>(doStmt->t); 2667a66e420SKrzysztof Parzyszek const parser::LoopControl::Bounds *bounds = 2677a66e420SKrzysztof Parzyszek std::get_if<parser::LoopControl::Bounds>(&loopControl->u); 2684d4af15cSKareem Ergawy assert(bounds && "Expected bounds for worksharing do loop"); 2697a66e420SKrzysztof Parzyszek lower::StatementContext stmtCtx; 27046ecd7bbSSergio Afonso result.loopLowerBounds.push_back(fir::getBase( 2717a66e420SKrzysztof Parzyszek converter.genExprValue(*semantics::GetExpr(bounds->lower), stmtCtx))); 27246ecd7bbSSergio Afonso result.loopUpperBounds.push_back(fir::getBase( 2737a66e420SKrzysztof Parzyszek converter.genExprValue(*semantics::GetExpr(bounds->upper), stmtCtx))); 2744d4af15cSKareem Ergawy if (bounds->step) { 27546ecd7bbSSergio Afonso result.loopSteps.push_back(fir::getBase( 2767a66e420SKrzysztof Parzyszek converter.genExprValue(*semantics::GetExpr(bounds->step), stmtCtx))); 2774d4af15cSKareem Ergawy } else { // If `step` is not present, assume it as `1`. 27846ecd7bbSSergio Afonso result.loopSteps.push_back(firOpBuilder.createIntegerConstant( 2794d4af15cSKareem Ergawy currentLocation, firOpBuilder.getIntegerType(32), 1)); 2804d4af15cSKareem Ergawy } 2814d4af15cSKareem Ergawy iv.push_back(bounds->name.thing.symbol); 2824d4af15cSKareem Ergawy loopVarTypeSize = std::max(loopVarTypeSize, 2834d4af15cSKareem Ergawy bounds->name.thing.symbol->GetUltimate().size()); 2844d4af15cSKareem Ergawy collapseValue--; 2854d4af15cSKareem Ergawy doConstructEval = 2864d4af15cSKareem Ergawy &*std::next(doConstructEval->getNestedEvaluations().begin()); 2874d4af15cSKareem Ergawy } while (collapseValue > 0); 2884d4af15cSKareem Ergawy 28978eac466SSergio Afonso convertLoopBounds(converter, currentLocation, result, loopVarTypeSize); 29073402634SSergio Afonso 2914d4af15cSKareem Ergawy return found; 2924d4af15cSKareem Ergawy } 2934d4af15cSKareem Ergawy 2947a66e420SKrzysztof Parzyszek bool ClauseProcessor::processDevice(lower::StatementContext &stmtCtx, 29578eac466SSergio Afonso mlir::omp::DeviceClauseOps &result) const { 2967a66e420SKrzysztof Parzyszek const parser::CharBlock *source = nullptr; 297f9e55796SKrzysztof Parzyszek if (auto *clause = findUniqueClause<omp::clause::Device>(&source)) { 2984d4af15cSKareem Ergawy mlir::Location clauseLocation = converter.genLocation(*source); 299f9e55796SKrzysztof Parzyszek if (auto deviceModifier = 300f9e55796SKrzysztof Parzyszek std::get<std::optional<omp::clause::Device::DeviceModifier>>( 301f9e55796SKrzysztof Parzyszek clause->t)) { 302f9e55796SKrzysztof Parzyszek if (deviceModifier == omp::clause::Device::DeviceModifier::Ancestor) { 3034d4af15cSKareem Ergawy TODO(clauseLocation, "OMPD_target Device Modifier Ancestor"); 3044d4af15cSKareem Ergawy } 3054d4af15cSKareem Ergawy } 306f9e55796SKrzysztof Parzyszek const auto &deviceExpr = std::get<omp::SomeExpr>(clause->t); 307fdfeea5bSSergio Afonso result.device = fir::getBase(converter.genExprValue(deviceExpr, stmtCtx)); 3084d4af15cSKareem Ergawy return true; 3094d4af15cSKareem Ergawy } 3104d4af15cSKareem Ergawy return false; 3114d4af15cSKareem Ergawy } 3124d4af15cSKareem Ergawy 3134d4af15cSKareem Ergawy bool ClauseProcessor::processDeviceType( 31478eac466SSergio Afonso mlir::omp::DeviceTypeClauseOps &result) const { 315f9e55796SKrzysztof Parzyszek if (auto *clause = findUniqueClause<omp::clause::DeviceType>()) { 3164d4af15cSKareem Ergawy // Case: declare target ... device_type(any | host | nohost) 317f9e55796SKrzysztof Parzyszek switch (clause->v) { 318148a5579SKrzysztof Parzyszek case omp::clause::DeviceType::DeviceTypeDescription::Nohost: 31978eac466SSergio Afonso result.deviceType = mlir::omp::DeclareTargetDeviceType::nohost; 3204d4af15cSKareem Ergawy break; 321148a5579SKrzysztof Parzyszek case omp::clause::DeviceType::DeviceTypeDescription::Host: 32278eac466SSergio Afonso result.deviceType = mlir::omp::DeclareTargetDeviceType::host; 3234d4af15cSKareem Ergawy break; 324148a5579SKrzysztof Parzyszek case omp::clause::DeviceType::DeviceTypeDescription::Any: 32578eac466SSergio Afonso result.deviceType = mlir::omp::DeclareTargetDeviceType::any; 3264d4af15cSKareem Ergawy break; 3274d4af15cSKareem Ergawy } 3284d4af15cSKareem Ergawy return true; 3294d4af15cSKareem Ergawy } 3304d4af15cSKareem Ergawy return false; 3314d4af15cSKareem Ergawy } 3324d4af15cSKareem Ergawy 333fc1c34bbSSergio Afonso bool ClauseProcessor::processDistSchedule( 334fc1c34bbSSergio Afonso lower::StatementContext &stmtCtx, 335fc1c34bbSSergio Afonso mlir::omp::DistScheduleClauseOps &result) const { 336fc1c34bbSSergio Afonso if (auto *clause = findUniqueClause<omp::clause::DistSchedule>()) { 337fdfeea5bSSergio Afonso result.distScheduleStatic = converter.getFirOpBuilder().getUnitAttr(); 338fc1c34bbSSergio Afonso const auto &chunkSize = std::get<std::optional<ExprTy>>(clause->t); 339fc1c34bbSSergio Afonso if (chunkSize) 340fdfeea5bSSergio Afonso result.distScheduleChunkSize = 341fc1c34bbSSergio Afonso fir::getBase(converter.genExprValue(*chunkSize, stmtCtx)); 342fc1c34bbSSergio Afonso return true; 343fc1c34bbSSergio Afonso } 344fc1c34bbSSergio Afonso return false; 345fc1c34bbSSergio Afonso } 346fc1c34bbSSergio Afonso 347e34e739bSAnchu Rajendran S bool ClauseProcessor::processFilter(lower::StatementContext &stmtCtx, 348e34e739bSAnchu Rajendran S mlir::omp::FilterClauseOps &result) const { 349e34e739bSAnchu Rajendran S if (auto *clause = findUniqueClause<omp::clause::Filter>()) { 350fdfeea5bSSergio Afonso result.filteredThreadId = 351e34e739bSAnchu Rajendran S fir::getBase(converter.genExprValue(clause->v, stmtCtx)); 352e34e739bSAnchu Rajendran S return true; 353e34e739bSAnchu Rajendran S } 354e34e739bSAnchu Rajendran S return false; 355e34e739bSAnchu Rajendran S } 356e34e739bSAnchu Rajendran S 3577a66e420SKrzysztof Parzyszek bool ClauseProcessor::processFinal(lower::StatementContext &stmtCtx, 35878eac466SSergio Afonso mlir::omp::FinalClauseOps &result) const { 3597a66e420SKrzysztof Parzyszek const parser::CharBlock *source = nullptr; 360f9e55796SKrzysztof Parzyszek if (auto *clause = findUniqueClause<omp::clause::Final>(&source)) { 3614d4af15cSKareem Ergawy fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); 3624d4af15cSKareem Ergawy mlir::Location clauseLocation = converter.genLocation(*source); 3634d4af15cSKareem Ergawy 364f9e55796SKrzysztof Parzyszek mlir::Value finalVal = 365f9e55796SKrzysztof Parzyszek fir::getBase(converter.genExprValue(clause->v, stmtCtx)); 366fdfeea5bSSergio Afonso result.final = firOpBuilder.createConvert( 36778eac466SSergio Afonso clauseLocation, firOpBuilder.getI1Type(), finalVal); 3684d4af15cSKareem Ergawy return true; 3694d4af15cSKareem Ergawy } 3704d4af15cSKareem Ergawy return false; 3714d4af15cSKareem Ergawy } 3724d4af15cSKareem Ergawy 37378eac466SSergio Afonso bool ClauseProcessor::processHint(mlir::omp::HintClauseOps &result) const { 374f9e55796SKrzysztof Parzyszek if (auto *clause = findUniqueClause<omp::clause::Hint>()) { 3754d4af15cSKareem Ergawy fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); 3767a66e420SKrzysztof Parzyszek int64_t hintValue = *evaluate::ToInt64(clause->v); 377fdfeea5bSSergio Afonso result.hint = firOpBuilder.getI64IntegerAttr(hintValue); 3784d4af15cSKareem Ergawy return true; 3794d4af15cSKareem Ergawy } 3804d4af15cSKareem Ergawy return false; 3814d4af15cSKareem Ergawy } 3824d4af15cSKareem Ergawy 38378eac466SSergio Afonso bool ClauseProcessor::processMergeable( 38478eac466SSergio Afonso mlir::omp::MergeableClauseOps &result) const { 385fdfeea5bSSergio Afonso return markClauseOccurrence<omp::clause::Mergeable>(result.mergeable); 3864d4af15cSKareem Ergawy } 3874d4af15cSKareem Ergawy 38878eac466SSergio Afonso bool ClauseProcessor::processNowait(mlir::omp::NowaitClauseOps &result) const { 389fdfeea5bSSergio Afonso return markClauseOccurrence<omp::clause::Nowait>(result.nowait); 3904d4af15cSKareem Ergawy } 3914d4af15cSKareem Ergawy 39278eac466SSergio Afonso bool ClauseProcessor::processNumTeams( 3937a66e420SKrzysztof Parzyszek lower::StatementContext &stmtCtx, 39478eac466SSergio Afonso mlir::omp::NumTeamsClauseOps &result) const { 3954d4af15cSKareem Ergawy // TODO Get lower and upper bounds for num_teams when parser is updated to 3964d4af15cSKareem Ergawy // accept both. 397f9e55796SKrzysztof Parzyszek if (auto *clause = findUniqueClause<omp::clause::NumTeams>()) { 39830646461SKrzysztof Parzyszek // The num_teams directive accepts a list of team lower/upper bounds. 39930646461SKrzysztof Parzyszek // This is an extension to support grid specification for ompx_bare. 40030646461SKrzysztof Parzyszek // Here, only expect a single element in the list. 40130646461SKrzysztof Parzyszek assert(clause->v.size() == 1); 40230646461SKrzysztof Parzyszek // auto lowerBound = std::get<std::optional<ExprTy>>(clause->v[0]->t); 40330646461SKrzysztof Parzyszek auto &upperBound = std::get<ExprTy>(clause->v[0].t); 404fdfeea5bSSergio Afonso result.numTeamsUpper = 40578eac466SSergio Afonso fir::getBase(converter.genExprValue(upperBound, stmtCtx)); 4064d4af15cSKareem Ergawy return true; 4074d4af15cSKareem Ergawy } 4084d4af15cSKareem Ergawy return false; 4094d4af15cSKareem Ergawy } 4104d4af15cSKareem Ergawy 4114d4af15cSKareem Ergawy bool ClauseProcessor::processNumThreads( 4127a66e420SKrzysztof Parzyszek lower::StatementContext &stmtCtx, 41378eac466SSergio Afonso mlir::omp::NumThreadsClauseOps &result) const { 414f9e55796SKrzysztof Parzyszek if (auto *clause = findUniqueClause<omp::clause::NumThreads>()) { 4154d4af15cSKareem Ergawy // OMPIRBuilder expects `NUM_THREADS` clause as a `Value`. 416fdfeea5bSSergio Afonso result.numThreads = 41778eac466SSergio Afonso fir::getBase(converter.genExprValue(clause->v, stmtCtx)); 4184d4af15cSKareem Ergawy return true; 4194d4af15cSKareem Ergawy } 4204d4af15cSKareem Ergawy return false; 4214d4af15cSKareem Ergawy } 4224d4af15cSKareem Ergawy 423b4ab52c8Sharishch4 bool ClauseProcessor::processOrder(mlir::omp::OrderClauseOps &result) const { 424b4ab52c8Sharishch4 using Order = omp::clause::Order; 425b4ab52c8Sharishch4 if (auto *clause = findUniqueClause<Order>()) { 426b4ab52c8Sharishch4 fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); 427fdfeea5bSSergio Afonso result.order = mlir::omp::ClauseOrderKindAttr::get( 428b4ab52c8Sharishch4 firOpBuilder.getContext(), mlir::omp::ClauseOrderKind::Concurrent); 429b4ab52c8Sharishch4 const auto &modifier = 430b4ab52c8Sharishch4 std::get<std::optional<Order::OrderModifier>>(clause->t); 431b4ab52c8Sharishch4 if (modifier && *modifier == Order::OrderModifier::Unconstrained) { 432fdfeea5bSSergio Afonso result.orderMod = mlir::omp::OrderModifierAttr::get( 433b4ab52c8Sharishch4 firOpBuilder.getContext(), mlir::omp::OrderModifier::unconstrained); 434b4ab52c8Sharishch4 } else { 435b4ab52c8Sharishch4 // "If order-modifier is not unconstrained, the behavior is as if the 436b4ab52c8Sharishch4 // reproducible modifier is present." 437fdfeea5bSSergio Afonso result.orderMod = mlir::omp::OrderModifierAttr::get( 438b4ab52c8Sharishch4 firOpBuilder.getContext(), mlir::omp::OrderModifier::reproducible); 439b4ab52c8Sharishch4 } 440b4ab52c8Sharishch4 return true; 441b4ab52c8Sharishch4 } 442b4ab52c8Sharishch4 return false; 443b4ab52c8Sharishch4 } 444b4ab52c8Sharishch4 44578eac466SSergio Afonso bool ClauseProcessor::processOrdered( 44678eac466SSergio Afonso mlir::omp::OrderedClauseOps &result) const { 447f9e55796SKrzysztof Parzyszek if (auto *clause = findUniqueClause<omp::clause::Ordered>()) { 4484d4af15cSKareem Ergawy fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); 4494d4af15cSKareem Ergawy int64_t orderedClauseValue = 0l; 450f9e55796SKrzysztof Parzyszek if (clause->v.has_value()) 4517a66e420SKrzysztof Parzyszek orderedClauseValue = *evaluate::ToInt64(*clause->v); 452fdfeea5bSSergio Afonso result.ordered = firOpBuilder.getI64IntegerAttr(orderedClauseValue); 4534d4af15cSKareem Ergawy return true; 4544d4af15cSKareem Ergawy } 4554d4af15cSKareem Ergawy return false; 4564d4af15cSKareem Ergawy } 4574d4af15cSKareem Ergawy 45878eac466SSergio Afonso bool ClauseProcessor::processPriority( 4597a66e420SKrzysztof Parzyszek lower::StatementContext &stmtCtx, 46078eac466SSergio Afonso mlir::omp::PriorityClauseOps &result) const { 461f9e55796SKrzysztof Parzyszek if (auto *clause = findUniqueClause<omp::clause::Priority>()) { 462fdfeea5bSSergio Afonso result.priority = fir::getBase(converter.genExprValue(clause->v, stmtCtx)); 4634d4af15cSKareem Ergawy return true; 4644d4af15cSKareem Ergawy } 4654d4af15cSKareem Ergawy return false; 4664d4af15cSKareem Ergawy } 4674d4af15cSKareem Ergawy 468edc50f39SNimishMishra bool ClauseProcessor::processDetach(mlir::omp::DetachClauseOps &result) const { 469edc50f39SNimishMishra if (auto *clause = findUniqueClause<omp::clause::Detach>()) { 470edc50f39SNimishMishra semantics::Symbol *sym = clause->v.sym(); 471edc50f39SNimishMishra mlir::Value symVal = converter.getSymbolAddress(*sym); 472edc50f39SNimishMishra result.eventHandle = symVal; 473edc50f39SNimishMishra return true; 474edc50f39SNimishMishra } 475edc50f39SNimishMishra return false; 476edc50f39SNimishMishra } 477edc50f39SNimishMishra 4784d4af15cSKareem Ergawy bool ClauseProcessor::processProcBind( 47978eac466SSergio Afonso mlir::omp::ProcBindClauseOps &result) const { 480f9e55796SKrzysztof Parzyszek if (auto *clause = findUniqueClause<omp::clause::ProcBind>()) { 4814d4af15cSKareem Ergawy fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); 482fdfeea5bSSergio Afonso result.procBindKind = genProcBindKindAttr(firOpBuilder, *clause); 4834d4af15cSKareem Ergawy return true; 4844d4af15cSKareem Ergawy } 4854d4af15cSKareem Ergawy return false; 4864d4af15cSKareem Ergawy } 4874d4af15cSKareem Ergawy 48878eac466SSergio Afonso bool ClauseProcessor::processSafelen( 48978eac466SSergio Afonso mlir::omp::SafelenClauseOps &result) const { 490f9e55796SKrzysztof Parzyszek if (auto *clause = findUniqueClause<omp::clause::Safelen>()) { 4914d4af15cSKareem Ergawy fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); 4927a66e420SKrzysztof Parzyszek const std::optional<std::int64_t> safelenVal = evaluate::ToInt64(clause->v); 493fdfeea5bSSergio Afonso result.safelen = firOpBuilder.getI64IntegerAttr(*safelenVal); 4944d4af15cSKareem Ergawy return true; 4954d4af15cSKareem Ergawy } 4964d4af15cSKareem Ergawy return false; 4974d4af15cSKareem Ergawy } 4984d4af15cSKareem Ergawy 4994d4af15cSKareem Ergawy bool ClauseProcessor::processSchedule( 5007a66e420SKrzysztof Parzyszek lower::StatementContext &stmtCtx, 50178eac466SSergio Afonso mlir::omp::ScheduleClauseOps &result) const { 502f9e55796SKrzysztof Parzyszek if (auto *clause = findUniqueClause<omp::clause::Schedule>()) { 5034d4af15cSKareem Ergawy fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); 5044d4af15cSKareem Ergawy mlir::MLIRContext *context = firOpBuilder.getContext(); 505148a5579SKrzysztof Parzyszek const auto &scheduleType = std::get<omp::clause::Schedule::Kind>(clause->t); 5064d4af15cSKareem Ergawy 5074d4af15cSKareem Ergawy mlir::omp::ClauseScheduleKind scheduleKind; 508f9e55796SKrzysztof Parzyszek switch (scheduleType) { 509148a5579SKrzysztof Parzyszek case omp::clause::Schedule::Kind::Static: 5104d4af15cSKareem Ergawy scheduleKind = mlir::omp::ClauseScheduleKind::Static; 5114d4af15cSKareem Ergawy break; 512148a5579SKrzysztof Parzyszek case omp::clause::Schedule::Kind::Dynamic: 5134d4af15cSKareem Ergawy scheduleKind = mlir::omp::ClauseScheduleKind::Dynamic; 5144d4af15cSKareem Ergawy break; 515148a5579SKrzysztof Parzyszek case omp::clause::Schedule::Kind::Guided: 5164d4af15cSKareem Ergawy scheduleKind = mlir::omp::ClauseScheduleKind::Guided; 5174d4af15cSKareem Ergawy break; 518148a5579SKrzysztof Parzyszek case omp::clause::Schedule::Kind::Auto: 5194d4af15cSKareem Ergawy scheduleKind = mlir::omp::ClauseScheduleKind::Auto; 5204d4af15cSKareem Ergawy break; 521148a5579SKrzysztof Parzyszek case omp::clause::Schedule::Kind::Runtime: 5224d4af15cSKareem Ergawy scheduleKind = mlir::omp::ClauseScheduleKind::Runtime; 5234d4af15cSKareem Ergawy break; 5244d4af15cSKareem Ergawy } 5254d4af15cSKareem Ergawy 526fdfeea5bSSergio Afonso result.scheduleKind = 52778eac466SSergio Afonso mlir::omp::ClauseScheduleKindAttr::get(context, scheduleKind); 5284d4af15cSKareem Ergawy 529fdfeea5bSSergio Afonso mlir::omp::ScheduleModifier scheduleMod = getScheduleModifier(*clause); 530fdfeea5bSSergio Afonso if (scheduleMod != mlir::omp::ScheduleModifier::none) 531fdfeea5bSSergio Afonso result.scheduleMod = 532fdfeea5bSSergio Afonso mlir::omp::ScheduleModifierAttr::get(context, scheduleMod); 5334d4af15cSKareem Ergawy 534f9e55796SKrzysztof Parzyszek if (getSimdModifier(*clause) != mlir::omp::ScheduleModifier::none) 535fdfeea5bSSergio Afonso result.scheduleSimd = firOpBuilder.getUnitAttr(); 5364d4af15cSKareem Ergawy 537f9e55796SKrzysztof Parzyszek if (const auto &chunkExpr = std::get<omp::MaybeExpr>(clause->t)) 538fdfeea5bSSergio Afonso result.scheduleChunk = 53978eac466SSergio Afonso fir::getBase(converter.genExprValue(*chunkExpr, stmtCtx)); 54078eac466SSergio Afonso 5414d4af15cSKareem Ergawy return true; 5424d4af15cSKareem Ergawy } 5434d4af15cSKareem Ergawy return false; 5444d4af15cSKareem Ergawy } 5454d4af15cSKareem Ergawy 54678eac466SSergio Afonso bool ClauseProcessor::processSimdlen( 54778eac466SSergio Afonso mlir::omp::SimdlenClauseOps &result) const { 548f9e55796SKrzysztof Parzyszek if (auto *clause = findUniqueClause<omp::clause::Simdlen>()) { 5494d4af15cSKareem Ergawy fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); 5507a66e420SKrzysztof Parzyszek const std::optional<std::int64_t> simdlenVal = evaluate::ToInt64(clause->v); 551fdfeea5bSSergio Afonso result.simdlen = firOpBuilder.getI64IntegerAttr(*simdlenVal); 5524d4af15cSKareem Ergawy return true; 5534d4af15cSKareem Ergawy } 5544d4af15cSKareem Ergawy return false; 5554d4af15cSKareem Ergawy } 5564d4af15cSKareem Ergawy 5574d4af15cSKareem Ergawy bool ClauseProcessor::processThreadLimit( 5587a66e420SKrzysztof Parzyszek lower::StatementContext &stmtCtx, 55978eac466SSergio Afonso mlir::omp::ThreadLimitClauseOps &result) const { 560f9e55796SKrzysztof Parzyszek if (auto *clause = findUniqueClause<omp::clause::ThreadLimit>()) { 561fdfeea5bSSergio Afonso result.threadLimit = 56278eac466SSergio Afonso fir::getBase(converter.genExprValue(clause->v, stmtCtx)); 5634d4af15cSKareem Ergawy return true; 5644d4af15cSKareem Ergawy } 5654d4af15cSKareem Ergawy return false; 5664d4af15cSKareem Ergawy } 5674d4af15cSKareem Ergawy 56878eac466SSergio Afonso bool ClauseProcessor::processUntied(mlir::omp::UntiedClauseOps &result) const { 569fdfeea5bSSergio Afonso return markClauseOccurrence<omp::clause::Untied>(result.untied); 5704d4af15cSKareem Ergawy } 5714d4af15cSKareem Ergawy 5724d4af15cSKareem Ergawy //===----------------------------------------------------------------------===// 5734d4af15cSKareem Ergawy // ClauseProcessor repeatable clauses 5744d4af15cSKareem Ergawy //===----------------------------------------------------------------------===// 5757ffeaf0eSharishch4 static llvm::StringMap<bool> getTargetFeatures(mlir::ModuleOp module) { 5767ffeaf0eSharishch4 llvm::StringMap<bool> featuresMap; 5777ffeaf0eSharishch4 llvm::SmallVector<llvm::StringRef> targetFeaturesVec; 5787ffeaf0eSharishch4 if (mlir::LLVM::TargetFeaturesAttr features = 5797ffeaf0eSharishch4 fir::getTargetFeatures(module)) { 5807ffeaf0eSharishch4 llvm::ArrayRef<mlir::StringAttr> featureAttrs = features.getFeatures(); 5817ffeaf0eSharishch4 for (auto &featureAttr : featureAttrs) { 5827ffeaf0eSharishch4 llvm::StringRef featureKeyString = featureAttr.strref(); 5837ffeaf0eSharishch4 featuresMap[featureKeyString.substr(1)] = (featureKeyString[0] == '+'); 5847ffeaf0eSharishch4 } 5857ffeaf0eSharishch4 } 5867ffeaf0eSharishch4 return featuresMap; 5877ffeaf0eSharishch4 } 5887ffeaf0eSharishch4 5897ffeaf0eSharishch4 static void 5907ffeaf0eSharishch4 addAlignedClause(lower::AbstractConverter &converter, 5917ffeaf0eSharishch4 const omp::clause::Aligned &clause, 5927ffeaf0eSharishch4 llvm::SmallVectorImpl<mlir::Value> &alignedVars, 593fdfeea5bSSergio Afonso llvm::SmallVectorImpl<mlir::Attribute> &alignments) { 5947ffeaf0eSharishch4 using Aligned = omp::clause::Aligned; 5957ffeaf0eSharishch4 lower::StatementContext stmtCtx; 5967ffeaf0eSharishch4 mlir::IntegerAttr alignmentValueAttr; 5977ffeaf0eSharishch4 int64_t alignment = 0; 5987ffeaf0eSharishch4 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 5997ffeaf0eSharishch4 6007ffeaf0eSharishch4 if (auto &alignmentValueParserExpr = 6017ffeaf0eSharishch4 std::get<std::optional<Aligned::Alignment>>(clause.t)) { 6027ffeaf0eSharishch4 mlir::Value operand = fir::getBase( 6037ffeaf0eSharishch4 converter.genExprValue(*alignmentValueParserExpr, stmtCtx)); 6047ffeaf0eSharishch4 alignment = *fir::getIntIfConstant(operand); 6057ffeaf0eSharishch4 } else { 6067ffeaf0eSharishch4 llvm::StringMap<bool> featuresMap = getTargetFeatures(builder.getModule()); 6077ffeaf0eSharishch4 llvm::Triple triple = fir::getTargetTriple(builder.getModule()); 6087ffeaf0eSharishch4 alignment = 6097ffeaf0eSharishch4 llvm::OpenMPIRBuilder::getOpenMPDefaultSimdAlign(triple, featuresMap); 6107ffeaf0eSharishch4 } 6117ffeaf0eSharishch4 6127ffeaf0eSharishch4 // The default alignment for some targets is equal to 0. 6137ffeaf0eSharishch4 // Do not generate alignment assumption if alignment is less than or equal to 6147ffeaf0eSharishch4 // 0. 6157ffeaf0eSharishch4 if (alignment > 0) { 616d3eb65f1SKaviya Rajendiran // alignment value must be power of 2 617d3eb65f1SKaviya Rajendiran assert((alignment & (alignment - 1)) == 0 && "alignment is not power of 2"); 6187ffeaf0eSharishch4 auto &objects = std::get<omp::ObjectList>(clause.t); 6197ffeaf0eSharishch4 if (!objects.empty()) 6207ffeaf0eSharishch4 genObjectList(objects, converter, alignedVars); 6217ffeaf0eSharishch4 alignmentValueAttr = builder.getI64IntegerAttr(alignment); 6227ffeaf0eSharishch4 // All the list items in a aligned clause will have same alignment 6237ffeaf0eSharishch4 for (std::size_t i = 0; i < objects.size(); i++) 624fdfeea5bSSergio Afonso alignments.push_back(alignmentValueAttr); 6257ffeaf0eSharishch4 } 6267ffeaf0eSharishch4 } 6277ffeaf0eSharishch4 6287ffeaf0eSharishch4 bool ClauseProcessor::processAligned( 6297ffeaf0eSharishch4 mlir::omp::AlignedClauseOps &result) const { 6307ffeaf0eSharishch4 return findRepeatableClause<omp::clause::Aligned>( 6317ffeaf0eSharishch4 [&](const omp::clause::Aligned &clause, const parser::CharBlock &) { 6327ffeaf0eSharishch4 addAlignedClause(converter, clause, result.alignedVars, 633fdfeea5bSSergio Afonso result.alignments); 6347ffeaf0eSharishch4 }); 6357ffeaf0eSharishch4 } 6364d4af15cSKareem Ergawy 6374d4af15cSKareem Ergawy bool ClauseProcessor::processAllocate( 63878eac466SSergio Afonso mlir::omp::AllocateClauseOps &result) const { 63963e70c05SKrzysztof Parzyszek return findRepeatableClause<omp::clause::Allocate>( 6407a66e420SKrzysztof Parzyszek [&](const omp::clause::Allocate &clause, const parser::CharBlock &) { 64178eac466SSergio Afonso genAllocateClause(converter, clause, result.allocatorVars, 64278eac466SSergio Afonso result.allocateVars); 6434d4af15cSKareem Ergawy }); 6444d4af15cSKareem Ergawy } 6454d4af15cSKareem Ergawy 6464d4af15cSKareem Ergawy bool ClauseProcessor::processCopyin() const { 6474d4af15cSKareem Ergawy fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); 6484d4af15cSKareem Ergawy mlir::OpBuilder::InsertPoint insPt = firOpBuilder.saveInsertionPoint(); 6494d4af15cSKareem Ergawy firOpBuilder.setInsertionPointToStart(firOpBuilder.getAllocaBlock()); 6504d4af15cSKareem Ergawy auto checkAndCopyHostAssociateVar = 6517a66e420SKrzysztof Parzyszek [&](semantics::Symbol *sym, 6524d4af15cSKareem Ergawy mlir::OpBuilder::InsertPoint *copyAssignIP = nullptr) { 6537a66e420SKrzysztof Parzyszek assert(sym->has<semantics::HostAssocDetails>() && 6544d4af15cSKareem Ergawy "No host-association found"); 6554d4af15cSKareem Ergawy if (converter.isPresentShallowLookup(*sym)) 6564d4af15cSKareem Ergawy converter.copyHostAssociateVar(*sym, copyAssignIP); 6574d4af15cSKareem Ergawy }; 65863e70c05SKrzysztof Parzyszek bool hasCopyin = findRepeatableClause<omp::clause::Copyin>( 6597a66e420SKrzysztof Parzyszek [&](const omp::clause::Copyin &clause, const parser::CharBlock &) { 66063e70c05SKrzysztof Parzyszek for (const omp::Object &object : clause.v) { 6618b18f2feSKrzysztof Parzyszek semantics::Symbol *sym = object.sym(); 66263e70c05SKrzysztof Parzyszek assert(sym && "Expecting symbol"); 6634d4af15cSKareem Ergawy if (const auto *commonDetails = 6647a66e420SKrzysztof Parzyszek sym->detailsIf<semantics::CommonBlockDetails>()) { 6654d4af15cSKareem Ergawy for (const auto &mem : commonDetails->objects()) 6664d4af15cSKareem Ergawy checkAndCopyHostAssociateVar(&*mem, &insPt); 6674d4af15cSKareem Ergawy break; 6684d4af15cSKareem Ergawy } 66953b59022SDavid Truby 6707a66e420SKrzysztof Parzyszek assert(sym->has<semantics::HostAssocDetails>() && 6714d4af15cSKareem Ergawy "No host-association found"); 6724d4af15cSKareem Ergawy checkAndCopyHostAssociateVar(sym); 6734d4af15cSKareem Ergawy } 6744d4af15cSKareem Ergawy }); 6754d4af15cSKareem Ergawy 6764d4af15cSKareem Ergawy // [OMP 5.0, 2.19.6.1] The copy is done after the team is formed and prior to 6774d4af15cSKareem Ergawy // the execution of the associated structured block. Emit implicit barrier to 6784d4af15cSKareem Ergawy // synchronize threads and avoid data races on propagation master's thread 6794d4af15cSKareem Ergawy // values of threadprivate variables to local instances of that variables of 6804d4af15cSKareem Ergawy // all other implicit threads. 68194204f59SKrzysztof Parzyszek 68294204f59SKrzysztof Parzyszek // All copies are inserted at either "insPt" (i.e. immediately before it), 68394204f59SKrzysztof Parzyszek // or at some earlier point (as determined by "copyHostAssociateVar"). 68494204f59SKrzysztof Parzyszek // Unless the insertion point is given to "copyHostAssociateVar" explicitly, 68594204f59SKrzysztof Parzyszek // it will not restore the builder's insertion point. Since the copies may be 68694204f59SKrzysztof Parzyszek // inserted in any order (not following the execution order), make sure the 68794204f59SKrzysztof Parzyszek // barrier is inserted following all of them. 68894204f59SKrzysztof Parzyszek firOpBuilder.restoreInsertionPoint(insPt); 6894d4af15cSKareem Ergawy if (hasCopyin) 6904d4af15cSKareem Ergawy firOpBuilder.create<mlir::omp::BarrierOp>(converter.getCurrentLocation()); 6914d4af15cSKareem Ergawy return hasCopyin; 6924d4af15cSKareem Ergawy } 6934d4af15cSKareem Ergawy 694e50a231dSLeandro Lupori /// Class that extracts information from the specified type. 695e50a231dSLeandro Lupori class TypeInfo { 696e50a231dSLeandro Lupori public: 697e50a231dSLeandro Lupori TypeInfo(mlir::Type ty) { typeScan(ty); } 698e50a231dSLeandro Lupori 699e50a231dSLeandro Lupori // Returns the length of character types. 700e50a231dSLeandro Lupori std::optional<fir::CharacterType::LenType> getCharLength() const { 701e50a231dSLeandro Lupori return charLen; 702e50a231dSLeandro Lupori } 703e50a231dSLeandro Lupori 704e50a231dSLeandro Lupori // Returns the shape of array types. 705d671ebe4SSergio Afonso llvm::ArrayRef<int64_t> getShape() const { return shape; } 706e50a231dSLeandro Lupori 707e50a231dSLeandro Lupori // Is the type inside a box? 708e50a231dSLeandro Lupori bool isBox() const { return inBox; } 709e50a231dSLeandro Lupori 710e50a231dSLeandro Lupori private: 711e50a231dSLeandro Lupori void typeScan(mlir::Type type); 712e50a231dSLeandro Lupori 713e50a231dSLeandro Lupori std::optional<fir::CharacterType::LenType> charLen; 714e50a231dSLeandro Lupori llvm::SmallVector<int64_t> shape; 715e50a231dSLeandro Lupori bool inBox = false; 716e50a231dSLeandro Lupori }; 717e50a231dSLeandro Lupori 718e50a231dSLeandro Lupori void TypeInfo::typeScan(mlir::Type ty) { 719e50a231dSLeandro Lupori if (auto sty = mlir::dyn_cast<fir::SequenceType>(ty)) { 720e50a231dSLeandro Lupori assert(shape.empty() && !sty.getShape().empty()); 721e50a231dSLeandro Lupori shape = llvm::SmallVector<int64_t>(sty.getShape()); 722e50a231dSLeandro Lupori typeScan(sty.getEleTy()); 723e50a231dSLeandro Lupori } else if (auto bty = mlir::dyn_cast<fir::BoxType>(ty)) { 724e50a231dSLeandro Lupori inBox = true; 725e50a231dSLeandro Lupori typeScan(bty.getEleTy()); 726e50a231dSLeandro Lupori } else if (auto cty = mlir::dyn_cast<fir::CharacterType>(ty)) { 727e50a231dSLeandro Lupori charLen = cty.getLen(); 728e50a231dSLeandro Lupori } else if (auto hty = mlir::dyn_cast<fir::HeapType>(ty)) { 729e50a231dSLeandro Lupori typeScan(hty.getEleTy()); 730e50a231dSLeandro Lupori } else if (auto pty = mlir::dyn_cast<fir::PointerType>(ty)) { 731e50a231dSLeandro Lupori typeScan(pty.getEleTy()); 732e50a231dSLeandro Lupori } else { 733e50a231dSLeandro Lupori // The scan ends when reaching any built-in or record type. 734c4204c0bSjeanPerier assert(ty.isIntOrIndexOrFloat() || mlir::isa<mlir::ComplexType>(ty) || 735e50a231dSLeandro Lupori mlir::isa<fir::LogicalType>(ty) || mlir::isa<fir::RecordType>(ty)); 736e50a231dSLeandro Lupori } 737e50a231dSLeandro Lupori } 738e50a231dSLeandro Lupori 739e50a231dSLeandro Lupori // Create a function that performs a copy between two variables, compatible 740e50a231dSLeandro Lupori // with their types and attributes. 741e50a231dSLeandro Lupori static mlir::func::FuncOp 7427a66e420SKrzysztof Parzyszek createCopyFunc(mlir::Location loc, lower::AbstractConverter &converter, 743e50a231dSLeandro Lupori mlir::Type varType, fir::FortranVariableFlagsEnum varAttrs) { 744e50a231dSLeandro Lupori fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 745e50a231dSLeandro Lupori mlir::ModuleOp module = builder.getModule(); 746e50a231dSLeandro Lupori mlir::Type eleTy = mlir::cast<fir::ReferenceType>(varType).getEleTy(); 747e50a231dSLeandro Lupori TypeInfo typeInfo(eleTy); 748e50a231dSLeandro Lupori std::string copyFuncName = 749e50a231dSLeandro Lupori fir::getTypeAsString(eleTy, builder.getKindMap(), "_copy"); 750e50a231dSLeandro Lupori 751e50a231dSLeandro Lupori if (auto decl = module.lookupSymbol<mlir::func::FuncOp>(copyFuncName)) 752e50a231dSLeandro Lupori return decl; 753e50a231dSLeandro Lupori 754e50a231dSLeandro Lupori // create function 755e50a231dSLeandro Lupori mlir::OpBuilder::InsertionGuard guard(builder); 756e50a231dSLeandro Lupori mlir::OpBuilder modBuilder(module.getBodyRegion()); 757e50a231dSLeandro Lupori llvm::SmallVector<mlir::Type> argsTy = {varType, varType}; 758e50a231dSLeandro Lupori auto funcType = mlir::FunctionType::get(builder.getContext(), argsTy, {}); 759e50a231dSLeandro Lupori mlir::func::FuncOp funcOp = 760e50a231dSLeandro Lupori modBuilder.create<mlir::func::FuncOp>(loc, copyFuncName, funcType); 761e50a231dSLeandro Lupori funcOp.setVisibility(mlir::SymbolTable::Visibility::Private); 762261a4026SMichael Klemm fir::factory::setInternalLinkage(funcOp); 763e50a231dSLeandro Lupori builder.createBlock(&funcOp.getRegion(), funcOp.getRegion().end(), argsTy, 764e50a231dSLeandro Lupori {loc, loc}); 765e50a231dSLeandro Lupori builder.setInsertionPointToStart(&funcOp.getRegion().back()); 766e50a231dSLeandro Lupori // generate body 767e50a231dSLeandro Lupori fir::FortranVariableFlagsAttr attrs; 768e50a231dSLeandro Lupori if (varAttrs != fir::FortranVariableFlagsEnum::None) 769e50a231dSLeandro Lupori attrs = fir::FortranVariableFlagsAttr::get(builder.getContext(), varAttrs); 770e50a231dSLeandro Lupori llvm::SmallVector<mlir::Value> typeparams; 771e50a231dSLeandro Lupori if (typeInfo.getCharLength().has_value()) { 772e50a231dSLeandro Lupori mlir::Value charLen = builder.createIntegerConstant( 773e50a231dSLeandro Lupori loc, builder.getCharacterLengthType(), *typeInfo.getCharLength()); 774e50a231dSLeandro Lupori typeparams.push_back(charLen); 775e50a231dSLeandro Lupori } 776e50a231dSLeandro Lupori mlir::Value shape; 777e50a231dSLeandro Lupori if (!typeInfo.isBox() && !typeInfo.getShape().empty()) { 778e50a231dSLeandro Lupori llvm::SmallVector<mlir::Value> extents; 779e50a231dSLeandro Lupori for (auto extent : typeInfo.getShape()) 780e50a231dSLeandro Lupori extents.push_back( 781e50a231dSLeandro Lupori builder.createIntegerConstant(loc, builder.getIndexType(), extent)); 782e50a231dSLeandro Lupori shape = builder.create<fir::ShapeOp>(loc, extents); 783e50a231dSLeandro Lupori } 7841710c8cfSSlava Zakharin auto declDst = builder.create<hlfir::DeclareOp>( 7851710c8cfSSlava Zakharin loc, funcOp.getArgument(0), copyFuncName + "_dst", shape, typeparams, 7861710c8cfSSlava Zakharin /*dummy_scope=*/nullptr, attrs); 7871710c8cfSSlava Zakharin auto declSrc = builder.create<hlfir::DeclareOp>( 7881710c8cfSSlava Zakharin loc, funcOp.getArgument(1), copyFuncName + "_src", shape, typeparams, 7891710c8cfSSlava Zakharin /*dummy_scope=*/nullptr, attrs); 790952bdaafSLeandro Lupori converter.copyVar(loc, declDst.getBase(), declSrc.getBase(), varAttrs); 791e50a231dSLeandro Lupori builder.create<mlir::func::ReturnOp>(loc); 792e50a231dSLeandro Lupori return funcOp; 793e50a231dSLeandro Lupori } 794e50a231dSLeandro Lupori 79578eac466SSergio Afonso bool ClauseProcessor::processCopyprivate( 796e50a231dSLeandro Lupori mlir::Location currentLocation, 79778eac466SSergio Afonso mlir::omp::CopyprivateClauseOps &result) const { 7987a66e420SKrzysztof Parzyszek auto addCopyPrivateVar = [&](semantics::Symbol *sym) { 799e50a231dSLeandro Lupori mlir::Value symVal = converter.getSymbolAddress(*sym); 800e50a231dSLeandro Lupori auto declOp = symVal.getDefiningOp<hlfir::DeclareOp>(); 801e50a231dSLeandro Lupori if (!declOp) 802e50a231dSLeandro Lupori fir::emitFatalError(currentLocation, 803e50a231dSLeandro Lupori "COPYPRIVATE is supported only in HLFIR mode"); 804e50a231dSLeandro Lupori symVal = declOp.getBase(); 805e50a231dSLeandro Lupori mlir::Type symType = symVal.getType(); 806e50a231dSLeandro Lupori fir::FortranVariableFlagsEnum attrs = 807e50a231dSLeandro Lupori declOp.getFortranAttrs().has_value() 808e50a231dSLeandro Lupori ? *declOp.getFortranAttrs() 809e50a231dSLeandro Lupori : fir::FortranVariableFlagsEnum::None; 810e50a231dSLeandro Lupori mlir::Value cpVar = symVal; 811e50a231dSLeandro Lupori 812e50a231dSLeandro Lupori // CopyPrivate variables must be passed by reference. However, in the case 813e50a231dSLeandro Lupori // of assumed shapes/vla the type is not a !fir.ref, but a !fir.box. 814e50a231dSLeandro Lupori // In these cases to retrieve the appropriate !fir.ref<!fir.box<...>> to 815e50a231dSLeandro Lupori // access the data we need we must perform an alloca and then store to it 816e50a231dSLeandro Lupori // and retrieve the data from the new alloca. 817e50a231dSLeandro Lupori if (mlir::isa<fir::BaseBoxType>(symType)) { 818e50a231dSLeandro Lupori fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 819e50a231dSLeandro Lupori auto alloca = builder.create<fir::AllocaOp>(currentLocation, symType); 820e50a231dSLeandro Lupori builder.create<fir::StoreOp>(currentLocation, symVal, alloca); 821e50a231dSLeandro Lupori cpVar = alloca; 822e50a231dSLeandro Lupori } 823e50a231dSLeandro Lupori 82478eac466SSergio Afonso result.copyprivateVars.push_back(cpVar); 825e50a231dSLeandro Lupori mlir::func::FuncOp funcOp = 826e50a231dSLeandro Lupori createCopyFunc(currentLocation, converter, cpVar.getType(), attrs); 827fdfeea5bSSergio Afonso result.copyprivateSyms.push_back(mlir::SymbolRefAttr::get(funcOp)); 828e50a231dSLeandro Lupori }; 829e50a231dSLeandro Lupori 83063e70c05SKrzysztof Parzyszek bool hasCopyPrivate = findRepeatableClause<clause::Copyprivate>( 8317a66e420SKrzysztof Parzyszek [&](const clause::Copyprivate &clause, const parser::CharBlock &) { 83263e70c05SKrzysztof Parzyszek for (const Object &object : clause.v) { 8338b18f2feSKrzysztof Parzyszek semantics::Symbol *sym = object.sym(); 834e50a231dSLeandro Lupori if (const auto *commonDetails = 8357a66e420SKrzysztof Parzyszek sym->detailsIf<semantics::CommonBlockDetails>()) { 836e50a231dSLeandro Lupori for (const auto &mem : commonDetails->objects()) 837e50a231dSLeandro Lupori addCopyPrivateVar(&*mem); 838e50a231dSLeandro Lupori break; 839e50a231dSLeandro Lupori } 840e50a231dSLeandro Lupori addCopyPrivateVar(sym); 841e50a231dSLeandro Lupori } 842e50a231dSLeandro Lupori }); 843e50a231dSLeandro Lupori 844e50a231dSLeandro Lupori return hasCopyPrivate; 845e50a231dSLeandro Lupori } 846e50a231dSLeandro Lupori 84778eac466SSergio Afonso bool ClauseProcessor::processDepend(mlir::omp::DependClauseOps &result) const { 848d48c849eSKrzysztof Parzyszek auto process = [&](const omp::clause::Depend &clause, 849d48c849eSKrzysztof Parzyszek const parser::CharBlock &) { 850148a5579SKrzysztof Parzyszek using Depend = omp::clause::Depend; 851f87737f3SKrzysztof Parzyszek if (!std::holds_alternative<Depend::TaskDep>(clause.u)) { 852d48c849eSKrzysztof Parzyszek TODO(converter.getCurrentLocation(), 853d48c849eSKrzysztof Parzyszek "DEPEND clause with SINK or SOURCE is not supported yet"); 854d48c849eSKrzysztof Parzyszek } 855f87737f3SKrzysztof Parzyszek auto &taskDep = std::get<Depend::TaskDep>(clause.u); 856f87737f3SKrzysztof Parzyszek auto depType = std::get<clause::DependenceType>(taskDep.t); 857f87737f3SKrzysztof Parzyszek auto &objects = std::get<omp::ObjectList>(taskDep.t); 85863e70c05SKrzysztof Parzyszek 859f87737f3SKrzysztof Parzyszek if (std::get<std::optional<omp::clause::Iterator>>(taskDep.t)) { 860d48c849eSKrzysztof Parzyszek TODO(converter.getCurrentLocation(), 861d48c849eSKrzysztof Parzyszek "Support for iterator modifiers is not implemented yet"); 862d48c849eSKrzysztof Parzyszek } 8634d4af15cSKareem Ergawy mlir::omp::ClauseTaskDependAttr dependTypeOperand = 864f87737f3SKrzysztof Parzyszek genDependKindAttr(converter, depType); 865fdfeea5bSSergio Afonso result.dependKinds.append(objects.size(), dependTypeOperand); 86663e70c05SKrzysztof Parzyszek 86763e70c05SKrzysztof Parzyszek for (const omp::Object &object : objects) { 86863e70c05SKrzysztof Parzyszek assert(object.ref() && "Expecting designator"); 86963e70c05SKrzysztof Parzyszek 8707a66e420SKrzysztof Parzyszek if (evaluate::ExtractSubstring(*object.ref())) { 87163e70c05SKrzysztof Parzyszek TODO(converter.getCurrentLocation(), 87263e70c05SKrzysztof Parzyszek "substring not supported for task depend"); 8737a66e420SKrzysztof Parzyszek } else if (evaluate::IsArrayElement(*object.ref())) { 8744d4af15cSKareem Ergawy TODO(converter.getCurrentLocation(), 8754d4af15cSKareem Ergawy "array sections not supported for task depend"); 8764d4af15cSKareem Ergawy } 87763e70c05SKrzysztof Parzyszek 8788b18f2feSKrzysztof Parzyszek semantics::Symbol *sym = object.sym(); 8794d4af15cSKareem Ergawy const mlir::Value variable = converter.getSymbolAddress(*sym); 88078eac466SSergio Afonso result.dependVars.push_back(variable); 8814d4af15cSKareem Ergawy } 882d48c849eSKrzysztof Parzyszek }; 883d48c849eSKrzysztof Parzyszek 884d48c849eSKrzysztof Parzyszek return findRepeatableClause<omp::clause::Depend>(process); 8854d4af15cSKareem Ergawy } 8864d4af15cSKareem Ergawy 887298ea9bfSRaghu Maddhipatla bool ClauseProcessor::processHasDeviceAddr( 88878eac466SSergio Afonso mlir::omp::HasDeviceAddrClauseOps &result, 88988478a89SSergio Afonso llvm::SmallVectorImpl<const semantics::Symbol *> &isDeviceSyms) const { 890298ea9bfSRaghu Maddhipatla return findRepeatableClause<omp::clause::HasDeviceAddr>( 891298ea9bfSRaghu Maddhipatla [&](const omp::clause::HasDeviceAddr &devAddrClause, 8927a66e420SKrzysztof Parzyszek const parser::CharBlock &) { 89378eac466SSergio Afonso addUseDeviceClause(converter, devAddrClause.v, result.hasDeviceAddrVars, 89488478a89SSergio Afonso isDeviceSyms); 895298ea9bfSRaghu Maddhipatla }); 896298ea9bfSRaghu Maddhipatla } 897298ea9bfSRaghu Maddhipatla 8984d4af15cSKareem Ergawy bool ClauseProcessor::processIf( 89963e70c05SKrzysztof Parzyszek omp::clause::If::DirectiveNameModifier directiveName, 90078eac466SSergio Afonso mlir::omp::IfClauseOps &result) const { 9014d4af15cSKareem Ergawy bool found = false; 9027a66e420SKrzysztof Parzyszek findRepeatableClause<omp::clause::If>([&](const omp::clause::If &clause, 9037a66e420SKrzysztof Parzyszek const parser::CharBlock &source) { 9044d4af15cSKareem Ergawy mlir::Location clauseLocation = converter.genLocation(source); 9057a66e420SKrzysztof Parzyszek mlir::Value operand = 9067a66e420SKrzysztof Parzyszek getIfClauseOperand(converter, clause, directiveName, clauseLocation); 9074d4af15cSKareem Ergawy // Assume that, at most, a single 'if' clause will be applicable to the 9084d4af15cSKareem Ergawy // given directive. 9094d4af15cSKareem Ergawy if (operand) { 9102f3d0619SSergio Afonso result.ifExpr = operand; 9114d4af15cSKareem Ergawy found = true; 9124d4af15cSKareem Ergawy } 9134d4af15cSKareem Ergawy }); 9144d4af15cSKareem Ergawy return found; 9154d4af15cSKareem Ergawy } 9164d4af15cSKareem Ergawy 917298ea9bfSRaghu Maddhipatla bool ClauseProcessor::processIsDevicePtr( 91878eac466SSergio Afonso mlir::omp::IsDevicePtrClauseOps &result, 91988478a89SSergio Afonso llvm::SmallVectorImpl<const semantics::Symbol *> &isDeviceSyms) const { 920298ea9bfSRaghu Maddhipatla return findRepeatableClause<omp::clause::IsDevicePtr>( 921298ea9bfSRaghu Maddhipatla [&](const omp::clause::IsDevicePtr &devPtrClause, 9227a66e420SKrzysztof Parzyszek const parser::CharBlock &) { 92378eac466SSergio Afonso addUseDeviceClause(converter, devPtrClause.v, result.isDevicePtrVars, 92488478a89SSergio Afonso isDeviceSyms); 925298ea9bfSRaghu Maddhipatla }); 926298ea9bfSRaghu Maddhipatla } 927298ea9bfSRaghu Maddhipatla 9284d4af15cSKareem Ergawy bool ClauseProcessor::processLink( 9294d4af15cSKareem Ergawy llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const { 93063e70c05SKrzysztof Parzyszek return findRepeatableClause<omp::clause::Link>( 9317a66e420SKrzysztof Parzyszek [&](const omp::clause::Link &clause, const parser::CharBlock &) { 9324d4af15cSKareem Ergawy // Case: declare target link(var1, var2)... 9334d4af15cSKareem Ergawy gatherFuncAndVarSyms( 93463e70c05SKrzysztof Parzyszek clause.v, mlir::omp::DeclareTargetCaptureClause::link, result); 9354d4af15cSKareem Ergawy }); 9364d4af15cSKareem Ergawy } 9374d4af15cSKareem Ergawy 9389ba41031SAkash Banerjee void ClauseProcessor::processMapObjects( 9399ba41031SAkash Banerjee lower::StatementContext &stmtCtx, mlir::Location clauseLocation, 9409ba41031SAkash Banerjee const omp::ObjectList &objects, 9419ba41031SAkash Banerjee llvm::omp::OpenMPOffloadMappingFlags mapTypeBits, 942e508baccSagozillon std::map<Object, OmpMapParentAndMemberData> &parentMemberIndices, 9439ba41031SAkash Banerjee llvm::SmallVectorImpl<mlir::Value> &mapVars, 94488478a89SSergio Afonso llvm::SmallVectorImpl<const semantics::Symbol *> &mapSyms) const { 9459ba41031SAkash Banerjee fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); 946e508baccSagozillon 9479ba41031SAkash Banerjee for (const omp::Object &object : objects) { 9489ba41031SAkash Banerjee llvm::SmallVector<mlir::Value> bounds; 9499ba41031SAkash Banerjee std::stringstream asFortran; 950e508baccSagozillon std::optional<omp::Object> parentObj; 9519ba41031SAkash Banerjee 952*662133a2SjeanPerier fir::factory::AddrAndBoundsInfo info = 9539ba41031SAkash Banerjee lower::gatherDataOperandAddrAndBounds<mlir::omp::MapBoundsOp, 9549ba41031SAkash Banerjee mlir::omp::MapBoundsType>( 9559ba41031SAkash Banerjee converter, firOpBuilder, semaCtx, stmtCtx, *object.sym(), 9569ba41031SAkash Banerjee object.ref(), clauseLocation, asFortran, bounds, 9579ba41031SAkash Banerjee treatIndexAsSection); 9589ba41031SAkash Banerjee 959e508baccSagozillon mlir::Value baseOp = info.rawInput; 960e508baccSagozillon if (object.sym()->owner().IsDerivedType()) { 961e508baccSagozillon omp::ObjectList objectList = gatherObjectsOf(object, semaCtx); 962e508baccSagozillon assert(!objectList.empty() && 963e508baccSagozillon "could not find parent objects of derived type member"); 964e508baccSagozillon parentObj = objectList[0]; 965e508baccSagozillon parentMemberIndices.emplace(parentObj.value(), 966e508baccSagozillon OmpMapParentAndMemberData{}); 967e508baccSagozillon 968e508baccSagozillon if (isMemberOrParentAllocatableOrPointer(object, semaCtx)) { 969e508baccSagozillon llvm::SmallVector<int64_t> indices; 970e508baccSagozillon generateMemberPlacementIndices(object, indices, semaCtx); 971e508baccSagozillon baseOp = createParentSymAndGenIntermediateMaps( 972e508baccSagozillon clauseLocation, converter, semaCtx, stmtCtx, objectList, indices, 973e508baccSagozillon parentMemberIndices[parentObj.value()], asFortran.str(), 974e508baccSagozillon mapTypeBits); 975e508baccSagozillon } 976e508baccSagozillon } 977e508baccSagozillon 9789ba41031SAkash Banerjee // Explicit map captures are captured ByRef by default, 9799ba41031SAkash Banerjee // optimisation passes may alter this to ByCopy or other capture 9809ba41031SAkash Banerjee // types to optimise 9819ba41031SAkash Banerjee auto location = mlir::NameLoc::get( 9829ba41031SAkash Banerjee mlir::StringAttr::get(firOpBuilder.getContext(), asFortran.str()), 9839ba41031SAkash Banerjee baseOp.getLoc()); 9849ba41031SAkash Banerjee mlir::omp::MapInfoOp mapOp = createMapInfoOp( 9859ba41031SAkash Banerjee firOpBuilder, location, baseOp, 9869ba41031SAkash Banerjee /*varPtrPtr=*/mlir::Value{}, asFortran.str(), bounds, 987e508baccSagozillon /*members=*/{}, /*membersIndex=*/mlir::ArrayAttr{}, 9889ba41031SAkash Banerjee static_cast< 9899ba41031SAkash Banerjee std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>( 9909ba41031SAkash Banerjee mapTypeBits), 9919ba41031SAkash Banerjee mlir::omp::VariableCaptureKind::ByRef, baseOp.getType()); 9929ba41031SAkash Banerjee 993e508baccSagozillon if (parentObj.has_value()) { 994e508baccSagozillon parentMemberIndices[parentObj.value()].addChildIndexAndMapToParent( 995e508baccSagozillon object, mapOp, semaCtx); 9969ba41031SAkash Banerjee } else { 9979ba41031SAkash Banerjee mapVars.push_back(mapOp); 99888478a89SSergio Afonso mapSyms.push_back(object.sym()); 9999ba41031SAkash Banerjee } 10009ba41031SAkash Banerjee } 10019ba41031SAkash Banerjee } 10029ba41031SAkash Banerjee 10034d4af15cSKareem Ergawy bool ClauseProcessor::processMap( 10047a66e420SKrzysztof Parzyszek mlir::Location currentLocation, lower::StatementContext &stmtCtx, 10054dd5180aSSergio Afonso mlir::omp::MapClauseOps &result, 100688478a89SSergio Afonso llvm::SmallVectorImpl<const semantics::Symbol *> *mapSyms) const { 1007435e850bSAndrew Gozillon // We always require tracking of symbols, even if the caller does not, 1008435e850bSAndrew Gozillon // so we create an optionally used local set of symbols when the mapSyms 1009435e850bSAndrew Gozillon // argument is not present. 10107a66e420SKrzysztof Parzyszek llvm::SmallVector<const semantics::Symbol *> localMapSyms; 10117a66e420SKrzysztof Parzyszek llvm::SmallVectorImpl<const semantics::Symbol *> *ptrMapSyms = 1012435e850bSAndrew Gozillon mapSyms ? mapSyms : &localMapSyms; 1013e508baccSagozillon std::map<Object, OmpMapParentAndMemberData> parentMemberIndices; 1014435e850bSAndrew Gozillon 1015973fa983SKrzysztof Parzyszek auto process = [&](const omp::clause::Map &clause, 1016973fa983SKrzysztof Parzyszek const parser::CharBlock &source) { 101784115494SKrzysztof Parzyszek using Map = omp::clause::Map; 10184d4af15cSKareem Ergawy mlir::Location clauseLocation = converter.genLocation(source); 101952755ac2SKrzysztof Parzyszek const auto &[mapType, typeMods, mappers, iterator, objects] = clause.t; 10204d4af15cSKareem Ergawy llvm::omp::OpenMPOffloadMappingFlags mapTypeBits = 10214d4af15cSKareem Ergawy llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_NONE; 10224d4af15cSKareem Ergawy // If the map type is specified, then process it else Tofrom is the 10234d4af15cSKareem Ergawy // default. 1024697d65deSKrzysztof Parzyszek Map::MapType type = mapType.value_or(Map::MapType::Tofrom); 1025697d65deSKrzysztof Parzyszek switch (type) { 1026148a5579SKrzysztof Parzyszek case Map::MapType::To: 10274d4af15cSKareem Ergawy mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO; 10284d4af15cSKareem Ergawy break; 1029148a5579SKrzysztof Parzyszek case Map::MapType::From: 10304d4af15cSKareem Ergawy mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM; 10314d4af15cSKareem Ergawy break; 1032148a5579SKrzysztof Parzyszek case Map::MapType::Tofrom: 10334d4af15cSKareem Ergawy mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO | 10344d4af15cSKareem Ergawy llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM; 10354d4af15cSKareem Ergawy break; 1036148a5579SKrzysztof Parzyszek case Map::MapType::Alloc: 1037148a5579SKrzysztof Parzyszek case Map::MapType::Release: 10384d4af15cSKareem Ergawy // alloc and release is the default map_type for the Target Data 10394d4af15cSKareem Ergawy // Ops, i.e. if no bits for map_type is supplied then alloc/release 10404d4af15cSKareem Ergawy // is implicitly assumed based on the target directive. Default 10414d4af15cSKareem Ergawy // value for Target Data and Enter Data is alloc and for Exit Data 10424d4af15cSKareem Ergawy // it is release. 10434d4af15cSKareem Ergawy break; 1044148a5579SKrzysztof Parzyszek case Map::MapType::Delete: 10454d4af15cSKareem Ergawy mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_DELETE; 10464d4af15cSKareem Ergawy } 10474d4af15cSKareem Ergawy 104852755ac2SKrzysztof Parzyszek if (typeMods) { 104952755ac2SKrzysztof Parzyszek if (llvm::is_contained(*typeMods, Map::MapTypeModifier::Always)) 1050697d65deSKrzysztof Parzyszek mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_ALWAYS; 1051697d65deSKrzysztof Parzyszek // Diagnose unimplemented map-type-modifiers. 105252755ac2SKrzysztof Parzyszek if (llvm::any_of(*typeMods, [](Map::MapTypeModifier m) { 1053697d65deSKrzysztof Parzyszek return m != Map::MapTypeModifier::Always; 1054697d65deSKrzysztof Parzyszek })) { 1055697d65deSKrzysztof Parzyszek TODO(currentLocation, "Map type modifiers (other than 'ALWAYS')" 1056697d65deSKrzysztof Parzyszek " are not implemented yet"); 1057148a5579SKrzysztof Parzyszek } 10584d4af15cSKareem Ergawy } 1059973fa983SKrzysztof Parzyszek 106052755ac2SKrzysztof Parzyszek if (iterator) { 1061973fa983SKrzysztof Parzyszek TODO(currentLocation, 1062973fa983SKrzysztof Parzyszek "Support for iterator modifiers is not implemented yet"); 1063973fa983SKrzysztof Parzyszek } 106452755ac2SKrzysztof Parzyszek if (mappers) { 106552755ac2SKrzysztof Parzyszek TODO(currentLocation, 106652755ac2SKrzysztof Parzyszek "Support for mapper modifiers is not implemented yet"); 106752755ac2SKrzysztof Parzyszek } 1068973fa983SKrzysztof Parzyszek 10699ba41031SAkash Banerjee processMapObjects(stmtCtx, clauseLocation, 10709ba41031SAkash Banerjee std::get<omp::ObjectList>(clause.t), mapTypeBits, 107188478a89SSergio Afonso parentMemberIndices, result.mapVars, *ptrMapSyms); 1072973fa983SKrzysztof Parzyszek }; 1073435e850bSAndrew Gozillon 1074973fa983SKrzysztof Parzyszek bool clauseFound = findRepeatableClause<omp::clause::Map>(process); 1075e508baccSagozillon insertChildMapInfoIntoParent(converter, semaCtx, stmtCtx, parentMemberIndices, 1076e508baccSagozillon result.mapVars, *ptrMapSyms); 1077435e850bSAndrew Gozillon 1078435e850bSAndrew Gozillon return clauseFound; 10794d4af15cSKareem Ergawy } 10804d4af15cSKareem Ergawy 1081b54be00aSSergio Afonso bool ClauseProcessor::processMotionClauses(lower::StatementContext &stmtCtx, 1082b54be00aSSergio Afonso mlir::omp::MapClauseOps &result) { 1083e508baccSagozillon std::map<Object, OmpMapParentAndMemberData> parentMemberIndices; 1084b54be00aSSergio Afonso llvm::SmallVector<const semantics::Symbol *> mapSymbols; 1085b54be00aSSergio Afonso 1086b54be00aSSergio Afonso auto callbackFn = [&](const auto &clause, const parser::CharBlock &source) { 1087b54be00aSSergio Afonso mlir::Location clauseLocation = converter.genLocation(source); 10881c6ec29bSKrzysztof Parzyszek const auto &[expectation, mapper, iterator, objects] = clause.t; 1089b54be00aSSergio Afonso // TODO Support motion modifiers: present, mapper, iterator. 10901c6ec29bSKrzysztof Parzyszek if (expectation) { 10911c6ec29bSKrzysztof Parzyszek TODO(clauseLocation, "PRESENT modifier is not supported yet"); 10921c6ec29bSKrzysztof Parzyszek } else if (mapper) { 10931c6ec29bSKrzysztof Parzyszek TODO(clauseLocation, "Mapper modifier is not supported yet"); 10941c6ec29bSKrzysztof Parzyszek } else if (iterator) { 10951c6ec29bSKrzysztof Parzyszek TODO(clauseLocation, "Iterator modifier is not supported yet"); 10961c6ec29bSKrzysztof Parzyszek } 1097b54be00aSSergio Afonso constexpr llvm::omp::OpenMPOffloadMappingFlags mapTypeBits = 1098b54be00aSSergio Afonso std::is_same_v<llvm::remove_cvref_t<decltype(clause)>, omp::clause::To> 1099b54be00aSSergio Afonso ? llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO 1100b54be00aSSergio Afonso : llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM; 1101b54be00aSSergio Afonso 11021c6ec29bSKrzysztof Parzyszek processMapObjects(stmtCtx, clauseLocation, objects, mapTypeBits, 11031c6ec29bSKrzysztof Parzyszek parentMemberIndices, result.mapVars, mapSymbols); 1104b54be00aSSergio Afonso }; 1105b54be00aSSergio Afonso 1106b54be00aSSergio Afonso bool clauseFound = findRepeatableClause<omp::clause::To>(callbackFn); 1107b54be00aSSergio Afonso clauseFound = 1108b54be00aSSergio Afonso findRepeatableClause<omp::clause::From>(callbackFn) || clauseFound; 1109b54be00aSSergio Afonso 1110e508baccSagozillon insertChildMapInfoIntoParent(converter, semaCtx, stmtCtx, parentMemberIndices, 1111e508baccSagozillon result.mapVars, mapSymbols); 1112e508baccSagozillon 1113b54be00aSSergio Afonso return clauseFound; 1114b54be00aSSergio Afonso } 1115b54be00aSSergio Afonso 111670ef5eb6Sharishch4 bool ClauseProcessor::processNontemporal( 111770ef5eb6Sharishch4 mlir::omp::NontemporalClauseOps &result) const { 111870ef5eb6Sharishch4 return findRepeatableClause<omp::clause::Nontemporal>( 111970ef5eb6Sharishch4 [&](const omp::clause::Nontemporal &clause, const parser::CharBlock &) { 112070ef5eb6Sharishch4 for (const Object &object : clause.v) { 112170ef5eb6Sharishch4 semantics::Symbol *sym = object.sym(); 112270ef5eb6Sharishch4 mlir::Value symVal = converter.getSymbolAddress(*sym); 112370ef5eb6Sharishch4 result.nontemporalVars.push_back(symVal); 112470ef5eb6Sharishch4 } 112570ef5eb6Sharishch4 }); 112670ef5eb6Sharishch4 } 112770ef5eb6Sharishch4 11284d4af15cSKareem Ergawy bool ClauseProcessor::processReduction( 112978eac466SSergio Afonso mlir::Location currentLocation, mlir::omp::ReductionClauseOps &result, 113088478a89SSergio Afonso llvm::SmallVectorImpl<const semantics::Symbol *> &outReductionSyms) const { 113163e70c05SKrzysztof Parzyszek return findRepeatableClause<omp::clause::Reduction>( 11327a66e420SKrzysztof Parzyszek [&](const omp::clause::Reduction &clause, const parser::CharBlock &) { 113373402634SSergio Afonso llvm::SmallVector<mlir::Value> reductionVars; 113474a87548STom Eccles llvm::SmallVector<bool> reduceVarByRef; 113573402634SSergio Afonso llvm::SmallVector<mlir::Attribute> reductionDeclSymbols; 11367a66e420SKrzysztof Parzyszek llvm::SmallVector<const semantics::Symbol *> reductionSyms; 11374d4af15cSKareem Ergawy ReductionProcessor rp; 113888478a89SSergio Afonso rp.addDeclareReduction(currentLocation, converter, clause, 113988478a89SSergio Afonso reductionVars, reduceVarByRef, 114088478a89SSergio Afonso reductionDeclSymbols, reductionSyms); 114173402634SSergio Afonso 114273402634SSergio Afonso // Copy local lists into the output. 114378eac466SSergio Afonso llvm::copy(reductionVars, std::back_inserter(result.reductionVars)); 1144fdfeea5bSSergio Afonso llvm::copy(reduceVarByRef, std::back_inserter(result.reductionByref)); 114573402634SSergio Afonso llvm::copy(reductionDeclSymbols, 1146fdfeea5bSSergio Afonso std::back_inserter(result.reductionSyms)); 114788478a89SSergio Afonso llvm::copy(reductionSyms, std::back_inserter(outReductionSyms)); 11484d4af15cSKareem Ergawy }); 11494d4af15cSKareem Ergawy } 11504d4af15cSKareem Ergawy 11514d4af15cSKareem Ergawy bool ClauseProcessor::processTo( 11524d4af15cSKareem Ergawy llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const { 115363e70c05SKrzysztof Parzyszek return findRepeatableClause<omp::clause::To>( 11547a66e420SKrzysztof Parzyszek [&](const omp::clause::To &clause, const parser::CharBlock &) { 11554d4af15cSKareem Ergawy // Case: declare target to(func, var1, var2)... 1156148a5579SKrzysztof Parzyszek gatherFuncAndVarSyms(std::get<ObjectList>(clause.t), 11574d4af15cSKareem Ergawy mlir::omp::DeclareTargetCaptureClause::to, result); 11584d4af15cSKareem Ergawy }); 11594d4af15cSKareem Ergawy } 11604d4af15cSKareem Ergawy 11614d4af15cSKareem Ergawy bool ClauseProcessor::processEnter( 11624d4af15cSKareem Ergawy llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const { 116363e70c05SKrzysztof Parzyszek return findRepeatableClause<omp::clause::Enter>( 11647a66e420SKrzysztof Parzyszek [&](const omp::clause::Enter &clause, const parser::CharBlock &) { 11654d4af15cSKareem Ergawy // Case: declare target enter(func, var1, var2)... 116663e70c05SKrzysztof Parzyszek gatherFuncAndVarSyms( 116763e70c05SKrzysztof Parzyszek clause.v, mlir::omp::DeclareTargetCaptureClause::enter, result); 11684d4af15cSKareem Ergawy }); 11694d4af15cSKareem Ergawy } 11704d4af15cSKareem Ergawy 11714d4af15cSKareem Ergawy bool ClauseProcessor::processUseDeviceAddr( 11729ba41031SAkash Banerjee lower::StatementContext &stmtCtx, mlir::omp::UseDeviceAddrClauseOps &result, 11737a66e420SKrzysztof Parzyszek llvm::SmallVectorImpl<const semantics::Symbol *> &useDeviceSyms) const { 1174e508baccSagozillon std::map<Object, OmpMapParentAndMemberData> parentMemberIndices; 11759ba41031SAkash Banerjee bool clauseFound = findRepeatableClause<omp::clause::UseDeviceAddr>( 11769ba41031SAkash Banerjee [&](const omp::clause::UseDeviceAddr &clause, 11779ba41031SAkash Banerjee const parser::CharBlock &source) { 11789ba41031SAkash Banerjee mlir::Location location = converter.genLocation(source); 11799ba41031SAkash Banerjee llvm::omp::OpenMPOffloadMappingFlags mapTypeBits = 11809ba41031SAkash Banerjee llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO | 11819ba41031SAkash Banerjee llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM; 11829ba41031SAkash Banerjee processMapObjects(stmtCtx, location, clause.v, mapTypeBits, 11839ba41031SAkash Banerjee parentMemberIndices, result.useDeviceAddrVars, 118488478a89SSergio Afonso useDeviceSyms); 11854d4af15cSKareem Ergawy }); 11869ba41031SAkash Banerjee 1187e508baccSagozillon insertChildMapInfoIntoParent(converter, semaCtx, stmtCtx, parentMemberIndices, 118888478a89SSergio Afonso result.useDeviceAddrVars, useDeviceSyms); 11899ba41031SAkash Banerjee return clauseFound; 11904d4af15cSKareem Ergawy } 11914d4af15cSKareem Ergawy 11924d4af15cSKareem Ergawy bool ClauseProcessor::processUseDevicePtr( 11939ba41031SAkash Banerjee lower::StatementContext &stmtCtx, mlir::omp::UseDevicePtrClauseOps &result, 11947a66e420SKrzysztof Parzyszek llvm::SmallVectorImpl<const semantics::Symbol *> &useDeviceSyms) const { 1195e508baccSagozillon std::map<Object, OmpMapParentAndMemberData> parentMemberIndices; 1196e508baccSagozillon 11979ba41031SAkash Banerjee bool clauseFound = findRepeatableClause<omp::clause::UseDevicePtr>( 11989ba41031SAkash Banerjee [&](const omp::clause::UseDevicePtr &clause, 11999ba41031SAkash Banerjee const parser::CharBlock &source) { 12009ba41031SAkash Banerjee mlir::Location location = converter.genLocation(source); 12019ba41031SAkash Banerjee llvm::omp::OpenMPOffloadMappingFlags mapTypeBits = 12029ba41031SAkash Banerjee llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO | 12039ba41031SAkash Banerjee llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM; 12049ba41031SAkash Banerjee processMapObjects(stmtCtx, location, clause.v, mapTypeBits, 12059ba41031SAkash Banerjee parentMemberIndices, result.useDevicePtrVars, 120688478a89SSergio Afonso useDeviceSyms); 12074d4af15cSKareem Ergawy }); 12089ba41031SAkash Banerjee 1209e508baccSagozillon insertChildMapInfoIntoParent(converter, semaCtx, stmtCtx, parentMemberIndices, 121088478a89SSergio Afonso result.useDevicePtrVars, useDeviceSyms); 12119ba41031SAkash Banerjee return clauseFound; 12124d4af15cSKareem Ergawy } 1213298ea9bfSRaghu Maddhipatla 12144d4af15cSKareem Ergawy } // namespace omp 12154d4af15cSKareem Ergawy } // namespace lower 12164d4af15cSKareem Ergawy } // namespace Fortran 1217