629 lines · cpp
1//===-- DataSharingProcessor.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 "DataSharingProcessor.h"14 15#include "Utils.h"16#include "flang/Lower/ConvertVariable.h"17#include "flang/Lower/PFTBuilder.h"18#include "flang/Lower/Support/PrivateReductionUtils.h"19#include "flang/Lower/Support/Utils.h"20#include "flang/Lower/SymbolMap.h"21#include "flang/Optimizer/Builder/BoxValue.h"22#include "flang/Optimizer/Builder/HLFIRTools.h"23#include "flang/Optimizer/Builder/Todo.h"24#include "flang/Optimizer/Dialect/FIROps.h"25#include "flang/Optimizer/HLFIR/HLFIRDialect.h"26#include "flang/Optimizer/HLFIR/HLFIROps.h"27#include "flang/Parser/openmp-utils.h"28#include "flang/Semantics/attr.h"29#include "flang/Semantics/openmp-directive-sets.h"30#include "flang/Semantics/tools.h"31#include "llvm/ADT/Sequence.h"32#include "llvm/ADT/SmallSet.h"33#include "llvm/Frontend/OpenMP/OMP.h"34#include <variant>35 36namespace Fortran {37namespace lower {38namespace omp {39bool DataSharingProcessor::OMPConstructSymbolVisitor::isSymbolDefineBy(40 const semantics::Symbol *symbol, lower::pft::Evaluation &eval) const {41 return eval.visit(common::visitors{42 [&](const parser::OpenMPConstruct &functionParserNode) {43 return symDefMap.count(symbol) &&44 symDefMap.at(symbol) == ConstructPtr(&functionParserNode);45 },46 [](const auto &functionParserNode) { return false; }});47}48 49bool DataSharingProcessor::OMPConstructSymbolVisitor::50 isSymbolDefineByNestedDeclaration(const semantics::Symbol *symbol) const {51 return symDefMap.count(symbol) &&52 std::holds_alternative<const parser::DeclarationConstruct *>(53 symDefMap.at(symbol));54}55 56static bool isConstructWithTopLevelTarget(lower::pft::Evaluation &eval) {57 const auto *ompEval = eval.getIf<parser::OpenMPConstruct>();58 if (ompEval) {59 auto dir = parser::omp::GetOmpDirectiveName(*ompEval).v;60 if (llvm::omp::topTargetSet.test(dir))61 return true;62 }63 return false;64}65 66DataSharingProcessor::DataSharingProcessor(67 lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx,68 const List<Clause> &clauses, lower::pft::Evaluation &eval,69 bool shouldCollectPreDeterminedSymbols, bool useDelayedPrivatization,70 lower::SymMap &symTable, bool isTargetPrivatization)71 : converter(converter), semaCtx(semaCtx),72 firOpBuilder(converter.getFirOpBuilder()), clauses(clauses), eval(eval),73 shouldCollectPreDeterminedSymbols(shouldCollectPreDeterminedSymbols),74 useDelayedPrivatization(useDelayedPrivatization), symTable(symTable),75 isTargetPrivatization(isTargetPrivatization), visitor(semaCtx) {76 eval.visit([&](const auto &functionParserNode) {77 parser::Walk(functionParserNode, visitor);78 });79}80 81DataSharingProcessor::DataSharingProcessor(lower::AbstractConverter &converter,82 semantics::SemanticsContext &semaCtx,83 lower::pft::Evaluation &eval,84 bool useDelayedPrivatization,85 lower::SymMap &symTable,86 bool isTargetPrivatization)87 : DataSharingProcessor(converter, semaCtx, {}, eval,88 /*shouldCollectPreDeterminedSymols=*/false,89 useDelayedPrivatization, symTable,90 isTargetPrivatization) {}91 92void DataSharingProcessor::processStep1(93 mlir::omp::PrivateClauseOps *clauseOps,94 std::optional<llvm::omp::Directive> dir) {95 collectSymbolsForPrivatization();96 collectDefaultSymbols();97 collectImplicitSymbols();98 collectPreDeterminedSymbols();99 100 privatize(clauseOps, dir);101 102 insertBarrier(clauseOps);103}104 105void DataSharingProcessor::processStep2(mlir::Operation *op, bool isLoop) {106 // 'sections' lastprivate is handled by genOMP()107 if (mlir::isa<mlir::omp::SectionOp>(op))108 return;109 if (!mlir::isa<mlir::omp::SectionsOp>(op)) {110 mlir::OpBuilder::InsertionGuard guard(firOpBuilder);111 copyLastPrivatize(op);112 }113 114 if (isLoop) {115 // push deallocs out of the loop116 firOpBuilder.setInsertionPointAfter(op);117 insertDeallocs();118 } else {119 mlir::OpBuilder::InsertionGuard guard(firOpBuilder);120 insertDeallocs();121 }122}123 124void DataSharingProcessor::insertDeallocs() {125 for (const semantics::Symbol *sym : allPrivatizedSymbols)126 if (semantics::IsAllocatable(sym->GetUltimate())) {127 if (!useDelayedPrivatization) {128 converter.createHostAssociateVarCloneDealloc(*sym);129 continue;130 }131 // For delayed privatization deallocs are created by132 // populateByRefInitAndCleanupRegions133 }134}135 136void DataSharingProcessor::cloneSymbol(const semantics::Symbol *sym) {137 bool isFirstPrivate = sym->test(semantics::Symbol::Flag::OmpFirstPrivate);138 139 // If we are doing eager-privatization on a symbol created using delayed140 // privatization there could be incompatible types here e.g.141 // fir.ref<fir.box<fir.array<>>>142 bool success = [&]() -> bool {143 const auto *details =144 sym->detailsIf<Fortran::semantics::HostAssocDetails>();145 assert(details && "No host-association found");146 const Fortran::semantics::Symbol &hsym = details->symbol();147 mlir::Value addr = converter.getSymbolAddress(hsym);148 149 if (auto refTy = mlir::dyn_cast<fir::ReferenceType>(addr.getType())) {150 if (auto boxTy = mlir::dyn_cast<fir::BoxType>(refTy.getElementType())) {151 if (auto arrayTy =152 mlir::dyn_cast<fir::SequenceType>(boxTy.getElementType())) {153 // FirConverter/fir::ExtendedValue considers all references to boxes154 // as mutable boxes. Outside of OpenMP it doesn't make sense to have a155 // mutable box of an array. Work around this here by loading the156 // reference so it is a normal boxed array.157 fir::FirOpBuilder &builder = converter.getFirOpBuilder();158 mlir::Location loc = converter.genLocation(hsym.name());159 fir::ExtendedValue hexv = converter.getSymbolExtendedValue(hsym);160 161 llvm::SmallVector<mlir::Value> extents =162 fir::factory::getExtents(loc, builder, hexv);163 164 // TODO: uniqName, name165 mlir::Value allocVal =166 builder.allocateLocal(loc, arrayTy, /*uniqName=*/"",167 /*name=*/"", extents, /*typeParams=*/{},168 sym->GetUltimate().attrs().test(169 Fortran::semantics::Attr::TARGET));170 mlir::Value shape = builder.genShape(loc, extents);171 mlir::Value box = builder.createBox(loc, boxTy, allocVal, shape,172 nullptr, {}, nullptr);173 174 // This can't be a CharArrayBoxValue because otherwise175 // boxTy.getElementType() would be a character type.176 // Assume the array element type isn't polymorphic because we are177 // privatizing.178 fir::ExtendedValue newExv = fir::ArrayBoxValue{box, extents};179 180 converter.bindSymbol(*sym, newExv);181 return true;182 }183 }184 }185 186 // Normal case:187 return converter.createHostAssociateVarClone(188 *sym, /*skipDefaultInit=*/isFirstPrivate);189 }();190 (void)success;191 assert(success && "Privatization failed due to existing binding");192 193 // Initialize clone from original object if it has any allocatable member.194 auto needInitClone = [&] {195 if (isFirstPrivate)196 return false;197 198 SymbolBox sb = symTable.lookupSymbol(sym);199 assert(sb);200 mlir::Value addr = sb.getAddr();201 assert(addr);202 return !fir::isPointerType(addr.getType()) &&203 hlfir::mayHaveAllocatableComponent(addr.getType());204 };205 206 if (needInitClone()) {207 Fortran::lower::initializeCloneAtRuntime(converter, *sym, symTable);208 mightHaveReadHostSym.insert(sym);209 }210}211 212void DataSharingProcessor::copyFirstPrivateSymbol(213 const semantics::Symbol *sym, mlir::OpBuilder::InsertPoint *copyAssignIP) {214 if (sym->test(semantics::Symbol::Flag::OmpFirstPrivate) ||215 sym->test(semantics::Symbol::Flag::LocalityLocalInit))216 converter.copyHostAssociateVar(*sym, copyAssignIP);217}218 219void DataSharingProcessor::copyLastPrivateSymbol(220 const semantics::Symbol *sym, mlir::OpBuilder::InsertPoint *lastPrivIP) {221 if (sym->test(semantics::Symbol::Flag::OmpLastPrivate))222 converter.copyHostAssociateVar(*sym, lastPrivIP, /*hostIsSource=*/false);223}224 225void DataSharingProcessor::collectOmpObjectListSymbol(226 const omp::ObjectList &objects,227 llvm::SetVector<const semantics::Symbol *> &symbolSet) {228 for (const omp::Object &object : objects)229 symbolSet.insert(object.sym());230}231 232void DataSharingProcessor::collectSymbolsForPrivatization() {233 // Add checks here for exceptional cases where privatization is not234 // needed and be deferred to a later phase (like OpenMP IRBuilder).235 // Such cases are suggested to be clearly documented and explained236 // instead of being silently skipped237 auto isException = [&](const Fortran::semantics::Symbol *sym) -> bool {238 // `OmpPreDetermined` symbols cannot be exceptions since239 // their privatized symbols are heavily used in FIR.240 if (sym->test(Fortran::semantics::Symbol::Flag::OmpPreDetermined))241 return false;242 243 // The handling of linear clause is deferred to the OpenMP244 // IRBuilder which is responsible for all its aspects,245 // including privatization. Privatizing linear variables at this point would246 // cause the following structure:247 //248 // omp.op linear(%linear = %step : !fir.ref<type>) {249 // Use %linear in this BB250 // }251 //252 // to be changed to the following:253 //254 // omp. op linear(%linear = %step : !fir.ref<type>)255 // private(%linear -> %arg0 : !fir.ref<i32>) {256 // Declare and use %arg0 in this BB257 // }258 //259 // The OpenMP IRBuilder needs to map the linear MLIR value260 // (i.e. %linear) to its `uses` in the BB to correctly261 // implement the functionalities of linear clause. However,262 // privatizing here disallows the IRBuilder to263 // draw a relation between %linear and %arg0. Hence skip.264 if (sym->test(Fortran::semantics::Symbol::Flag::OmpLinear))265 return true;266 return false;267 };268 269 for (const omp::Clause &clause : clauses) {270 if (const auto &privateClause =271 std::get_if<omp::clause::Private>(&clause.u)) {272 collectOmpObjectListSymbol(privateClause->v, explicitlyPrivatizedSymbols);273 } else if (const auto &firstPrivateClause =274 std::get_if<omp::clause::Firstprivate>(&clause.u)) {275 collectOmpObjectListSymbol(firstPrivateClause->v,276 explicitlyPrivatizedSymbols);277 } else if (const auto &lastPrivateClause =278 std::get_if<omp::clause::Lastprivate>(&clause.u)) {279 lastprivateModifierNotSupported(*lastPrivateClause,280 converter.getCurrentLocation());281 const ObjectList &objects = std::get<ObjectList>(lastPrivateClause->t);282 collectOmpObjectListSymbol(objects, explicitlyPrivatizedSymbols);283 }284 }285 286 // TODO For common blocks, add the underlying objects within the block. Doing287 // so, we won't need to explicitly handle block objects (or forget to do288 // so).289 for (auto *sym : explicitlyPrivatizedSymbols)290 if (!isException(sym))291 allPrivatizedSymbols.insert(sym);292}293 294bool DataSharingProcessor::needBarrier() {295 // Emit implicit barrier to synchronize threads and avoid data races on296 // initialization of firstprivate variables and post-update of lastprivate297 // variables.298 // Emit implicit barrier for linear clause in the OpenMPIRBuilder.299 for (const semantics::Symbol *sym : allPrivatizedSymbols) {300 if (sym->test(semantics::Symbol::Flag::OmpLastPrivate) &&301 (sym->test(semantics::Symbol::Flag::OmpFirstPrivate) ||302 mightHaveReadHostSym.contains(sym)))303 return true;304 }305 return false;306}307 308void DataSharingProcessor::insertBarrier(309 mlir::omp::PrivateClauseOps *clauseOps) {310 if (!needBarrier())311 return;312 313 if (useDelayedPrivatization) {314 if (clauseOps)315 clauseOps->privateNeedsBarrier =316 mlir::UnitAttr::get(&converter.getMLIRContext());317 } else {318 mlir::omp::BarrierOp::create(firOpBuilder, converter.getCurrentLocation());319 }320}321 322void DataSharingProcessor::insertLastPrivateCompare(mlir::Operation *op) {323 mlir::omp::LoopNestOp loopOp;324 if (auto wrapper = mlir::dyn_cast<mlir::omp::LoopWrapperInterface>(op))325 loopOp = mlir::cast<mlir::omp::LoopNestOp>(wrapper.getWrappedLoop());326 327 mlir::OpBuilder::InsertionGuard guard(firOpBuilder);328 bool hasLastPrivate = [&]() {329 for (const semantics::Symbol *sym : allPrivatizedSymbols) {330 if (const auto *commonDet =331 sym->detailsIf<semantics::CommonBlockDetails>()) {332 for (const auto &mem : commonDet->objects())333 if (mem->test(semantics::Symbol::Flag::OmpLastPrivate))334 return true;335 } else if (sym->test(semantics::Symbol::Flag::OmpLastPrivate))336 return true;337 }338 339 return false;340 }();341 342 if (!hasLastPrivate)343 return;344 345 if (mlir::isa<mlir::omp::WsloopOp>(op) || mlir::isa<mlir::omp::SimdOp>(op) ||346 mlir::isa<mlir::omp::TaskloopOp>(op)) {347 mlir::omp::LoopRelatedClauseOps result;348 llvm::SmallVector<const semantics::Symbol *> iv;349 collectLoopRelatedInfo(converter, converter.getCurrentLocation(), eval,350 clauses, result, iv);351 352 // Update the original variable just before exiting the worksharing353 // loop. Conversion as follows:354 //355 // omp.wsloop / omp.simd { omp.wsloop / omp.simd {356 // omp.loop_nest { omp.loop_nest {357 // ... ...358 // store ===> store359 // omp.yield %v = arith.addi %iv, %step360 // } %cmp = %step < 0 ? %v < %ub : %v > %ub361 // } fir.if %cmp {362 // fir.store %v to %loopIV363 // ^%lpv_update_blk:364 // }365 // omp.yield366 // }367 // }368 mlir::Location loc = loopOp.getLoc();369 mlir::Operation *lastOper = loopOp.getRegion().back().getTerminator();370 firOpBuilder.setInsertionPoint(lastOper);371 372 mlir::Value cmpOp;373 llvm::SmallVector<mlir::Value> vs;374 vs.reserve(loopOp.getIVs().size());375 for (auto [iv, ub, step] : llvm::zip_equal(376 loopOp.getIVs(), result.loopUpperBounds, result.loopSteps)) {377 // v = iv + step378 // cmp = step < 0 ? v < ub : v > ub379 mlir::Value v = mlir::arith::AddIOp::create(firOpBuilder, loc, iv, step);380 vs.push_back(v);381 mlir::Value zero =382 firOpBuilder.createIntegerConstant(loc, step.getType(), 0);383 mlir::Value negativeStep = mlir::arith::CmpIOp::create(384 firOpBuilder, loc, mlir::arith::CmpIPredicate::slt, step, zero);385 mlir::Value vLT = mlir::arith::CmpIOp::create(386 firOpBuilder, loc, mlir::arith::CmpIPredicate::slt, v, ub);387 mlir::Value vGT = mlir::arith::CmpIOp::create(388 firOpBuilder, loc, mlir::arith::CmpIPredicate::sgt, v, ub);389 mlir::Value icmpOp = mlir::arith::SelectOp::create(390 firOpBuilder, loc, negativeStep, vLT, vGT);391 392 if (cmpOp)393 cmpOp = mlir::arith::AndIOp::create(firOpBuilder, loc, cmpOp, icmpOp);394 else395 cmpOp = icmpOp;396 }397 398 auto ifOp = fir::IfOp::create(firOpBuilder, loc, cmpOp, /*else*/ false);399 firOpBuilder.setInsertionPointToStart(&ifOp.getThenRegion().front());400 for (auto [v, loopIV] : llvm::zip_equal(vs, loopIVs)) {401 hlfir::Entity loopIVEntity{loopIV};402 loopIVEntity =403 hlfir::derefPointersAndAllocatables(loc, firOpBuilder, loopIVEntity);404 hlfir::AssignOp::create(firOpBuilder, loc, v, loopIVEntity);405 }406 lastPrivIP = firOpBuilder.saveInsertionPoint();407 } else if (mlir::isa<mlir::omp::SectionsOp>(op)) {408 // Already handled by genOMP()409 } else {410 TODO(converter.getCurrentLocation(),411 "lastprivate clause in constructs other than "412 "simd/worksharing-loop/taskloop");413 }414}415 416static parser::CharBlock getSource(const semantics::SemanticsContext &semaCtx,417 const lower::pft::Evaluation &eval) {418 return eval.visit(common::visitors{419 [&](const parser::OpenMPConstruct &x) {420 return parser::omp::GetOmpDirectiveName(x).source;421 },422 [&](const parser::OpenMPDeclarativeConstruct &x) { return x.source; },423 [&](const parser::OmpEndLoopDirective &x) { return x.source; },424 [&](const auto &x) { return parser::CharBlock{}; },425 });426}427 428bool DataSharingProcessor::isOpenMPPrivatizingConstruct(429 const parser::OpenMPConstruct &omp, unsigned version) {430 return llvm::omp::isPrivatizingConstruct(431 parser::omp::GetOmpDirectiveName(omp).v, version);432}433 434bool DataSharingProcessor::isOpenMPPrivatizingEvaluation(435 const pft::Evaluation &eval) const {436 unsigned version = semaCtx.langOptions().OpenMPVersion;437 return eval.visit([=](auto &&s) {438 using BareS = llvm::remove_cvref_t<decltype(s)>;439 if constexpr (std::is_same_v<BareS, parser::OpenMPConstruct>) {440 return isOpenMPPrivatizingConstruct(s, version);441 } else {442 return false;443 }444 });445}446 447void DataSharingProcessor::collectSymbolsInNestedRegions(448 lower::pft::Evaluation &eval, semantics::Symbol::Flag flag,449 llvm::SetVector<const semantics::Symbol *> &symbolsInNestedRegions) {450 if (!eval.hasNestedEvaluations())451 return;452 for (pft::Evaluation &nestedEval : eval.getNestedEvaluations()) {453 if (isOpenMPPrivatizingEvaluation(nestedEval)) {454 converter.collectSymbolSet(nestedEval, symbolsInNestedRegions, flag,455 /*collectSymbols=*/true,456 /*collectHostAssociatedSymbols=*/false);457 } else {458 // Recursively look for OpenMP constructs within `nestedEval`'s region459 collectSymbolsInNestedRegions(nestedEval, flag, symbolsInNestedRegions);460 }461 }462}463 464// Collect symbols to be default privatized in two steps.465// In step 1, collect all symbols in `eval` that match `flag` into466// `defaultSymbols`. In step 2, for nested constructs (if any), if and only if467// the nested construct is an OpenMP construct, collect those nested468// symbols skipping host associated symbols into `symbolsInNestedRegions`.469// Later, in current context, all symbols in the set470// `defaultSymbols` - `symbolsInNestedRegions` will be privatized.471void DataSharingProcessor::collectSymbols(472 semantics::Symbol::Flag flag,473 llvm::SetVector<const semantics::Symbol *> &symbols) {474 // Collect all scopes associated with 'eval'.475 llvm::SetVector<const semantics::Scope *> clauseScopes;476 std::function<void(const semantics::Scope *)> collectScopes =477 [&](const semantics::Scope *scope) {478 clauseScopes.insert(scope);479 for (const semantics::Scope &child : scope->children())480 collectScopes(&child);481 };482 parser::CharBlock source =483 clauses.empty() ? getSource(semaCtx, eval) : clauses.front().source;484 const semantics::Scope *curScope = nullptr;485 if (!source.empty()) {486 curScope = &semaCtx.FindScope(source);487 collectScopes(curScope);488 }489 // Collect all symbols referenced in the evaluation being processed,490 // that matches 'flag'.491 llvm::SetVector<const semantics::Symbol *> allSymbols;492 converter.collectSymbolSet(eval, allSymbols, flag,493 /*collectSymbols=*/true,494 /*collectHostAssociatedSymbols=*/true);495 496 llvm::SetVector<const semantics::Symbol *> symbolsInNestedRegions;497 collectSymbolsInNestedRegions(eval, flag, symbolsInNestedRegions);498 499 for (auto *symbol : allSymbols)500 if (visitor.isSymbolDefineBy(symbol, eval))501 symbolsInNestedRegions.remove(symbol);502 503 // Filter-out symbols that must not be privatized.504 bool collectImplicit = flag == semantics::Symbol::Flag::OmpImplicit;505 bool collectPreDetermined = flag == semantics::Symbol::Flag::OmpPreDetermined;506 507 auto isPrivatizable = [](const semantics::Symbol &sym) -> bool {508 return !semantics::IsProcedure(sym) &&509 !sym.GetUltimate().has<semantics::DerivedTypeDetails>() &&510 !sym.GetUltimate().has<semantics::NamelistDetails>() &&511 !semantics::IsImpliedDoIndex(sym.GetUltimate()) &&512 !semantics::IsStmtFunction(sym);513 };514 515 auto shouldCollectSymbol = [&](const semantics::Symbol *sym) {516 if (collectImplicit) {517 // If we're a combined construct with a target region, implicit518 // firstprivate captures, should only belong to the target region519 // and not be added/captured by later directives. Parallel regions520 // will likely want the same captures to be shared and for SIMD it's521 // illegal to have firstprivate clauses.522 if (isConstructWithTopLevelTarget(eval) && !isTargetPrivatization &&523 sym->test(semantics::Symbol::Flag::OmpFirstPrivate)) {524 return false;525 }526 527 // Collect implicit symbols only if they are not defined by a nested528 // `DeclarationConstruct`. If `sym` is not defined by the current OpenMP529 // evaluation then it is defined by a block nested within the OpenMP530 // construct. This, in turn, means that the private allocation for the531 // symbol will be emitted as part of the nested block and there is no need532 // to privatize it within the OpenMP construct.533 return !visitor.isSymbolDefineByNestedDeclaration(sym) &&534 sym->test(semantics::Symbol::Flag::OmpImplicit);535 }536 537 if (collectPreDetermined) {538 // Similar to implicit symbols, collect pre-determined symbols only if539 // they are not defined by a nested `DeclarationConstruct`540 return visitor.isSymbolDefineBy(sym, eval) &&541 !visitor.isSymbolDefineByNestedDeclaration(sym) &&542 sym->test(semantics::Symbol::Flag::OmpPreDetermined);543 }544 545 return !sym->test(semantics::Symbol::Flag::OmpImplicit) &&546 !sym->test(semantics::Symbol::Flag::OmpPreDetermined);547 };548 549 for (const auto *sym : allSymbols) {550 assert(curScope && "couldn't find current scope");551 if (isPrivatizable(*sym) && !symbolsInNestedRegions.contains(sym) &&552 !explicitlyPrivatizedSymbols.contains(sym) &&553 shouldCollectSymbol(sym) && clauseScopes.contains(&sym->owner())) {554 allPrivatizedSymbols.insert(sym);555 symbols.insert(sym);556 }557 }558}559 560void DataSharingProcessor::collectDefaultSymbols() {561 using DataSharingAttribute = omp::clause::Default::DataSharingAttribute;562 for (const omp::Clause &clause : clauses) {563 if (const auto *defaultClause =564 std::get_if<omp::clause::Default>(&clause.u)) {565 if (defaultClause->v == DataSharingAttribute::Private)566 collectSymbols(semantics::Symbol::Flag::OmpPrivate, defaultSymbols);567 else if (defaultClause->v == DataSharingAttribute::Firstprivate)568 collectSymbols(semantics::Symbol::Flag::OmpFirstPrivate,569 defaultSymbols);570 }571 }572}573 574void DataSharingProcessor::collectImplicitSymbols() {575 // There will be no implicit symbols when a default clause is present.576 if (defaultSymbols.empty())577 collectSymbols(semantics::Symbol::Flag::OmpImplicit, implicitSymbols);578}579 580void DataSharingProcessor::collectPreDeterminedSymbols() {581 if (shouldCollectPreDeterminedSymbols)582 collectSymbols(semantics::Symbol::Flag::OmpPreDetermined,583 preDeterminedSymbols);584}585 586void DataSharingProcessor::privatize(mlir::omp::PrivateClauseOps *clauseOps,587 std::optional<llvm::omp::Directive> dir) {588 for (const semantics::Symbol *sym : allPrivatizedSymbols) {589 if (const auto *commonDet =590 sym->detailsIf<semantics::CommonBlockDetails>()) {591 for (const auto &mem : commonDet->objects())592 privatizeSymbol(&*mem, clauseOps, dir);593 } else594 privatizeSymbol(sym, clauseOps, dir);595 }596}597 598void DataSharingProcessor::copyLastPrivatize(mlir::Operation *op) {599 insertLastPrivateCompare(op);600 for (const semantics::Symbol *sym : allPrivatizedSymbols)601 if (const auto *commonDet =602 sym->detailsIf<semantics::CommonBlockDetails>()) {603 for (const auto &mem : commonDet->objects()) {604 copyLastPrivateSymbol(&*mem, &lastPrivIP);605 }606 } else {607 copyLastPrivateSymbol(sym, &lastPrivIP);608 }609}610 611void DataSharingProcessor::privatizeSymbol(612 const semantics::Symbol *symToPrivatize,613 mlir::omp::PrivateClauseOps *clauseOps,614 std::optional<llvm::omp::Directive> dir) {615 if (!useDelayedPrivatization) {616 cloneSymbol(symToPrivatize);617 copyFirstPrivateSymbol(symToPrivatize);618 return;619 }620 621 Fortran::lower::privatizeSymbol<mlir::omp::PrivateClauseOp,622 mlir::omp::PrivateClauseOps>(623 converter, firOpBuilder, symTable, allPrivatizedSymbols,624 mightHaveReadHostSym, symToPrivatize, clauseOps, dir);625}626} // namespace omp627} // namespace lower628} // namespace Fortran629