1717#include " flang/Lower/OpenMP/Utils.h"
1818#include " flang/Lower/PFTBuilder.h"
1919#include " flang/Lower/SymbolMap.h"
20+ #include " flang/Optimizer/Builder/BoxValue.h"
2021#include " flang/Optimizer/Builder/HLFIRTools.h"
2122#include " flang/Optimizer/Builder/Todo.h"
23+ #include " flang/Optimizer/HLFIR/HLFIRDialect.h"
2224#include " flang/Optimizer/HLFIR/HLFIROps.h"
25+ #include " flang/Semantics/attr.h"
2326#include " flang/Semantics/tools.h"
2427
2528namespace Fortran {
@@ -91,35 +94,65 @@ void DataSharingProcessor::insertDeallocs() {
9194 converter.createHostAssociateVarCloneDealloc (*sym);
9295 continue ;
9396 }
94-
95- lower::SymbolBox hsb = converter.lookupOneLevelUpSymbol (*sym);
96- assert (hsb && " Host symbol box not found" );
97- mlir::Type symType = hsb.getAddr ().getType ();
98- mlir::Location symLoc = hsb.getAddr ().getLoc ();
99- fir::ExtendedValue symExV = converter.getSymbolExtendedValue (*sym);
100- mlir::omp::PrivateClauseOp privatizer = symToPrivatizer.at (sym);
101-
102- lower::SymMapScope scope (symTable);
103- mlir::OpBuilder::InsertionGuard guard (firOpBuilder);
104-
105- mlir::Region &deallocRegion = privatizer.getDeallocRegion ();
106- fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder ();
107- mlir::Block *deallocEntryBlock = firOpBuilder.createBlock (
108- &deallocRegion, /* insertPt=*/ {}, symType, symLoc);
109-
110- firOpBuilder.setInsertionPointToEnd (deallocEntryBlock);
111- symTable.addSymbol (*sym,
112- fir::substBase (symExV, deallocRegion.getArgument (0 )));
113-
114- converter.createHostAssociateVarCloneDealloc (*sym);
115- firOpBuilder.create <mlir::omp::YieldOp>(hsb.getAddr ().getLoc ());
97+ // For delayed privatization deallocs are created by
98+ // populateByRefInitAndCleanupRegions
11699 }
117100}
118101
119102void DataSharingProcessor::cloneSymbol (const semantics::Symbol *sym) {
120103 bool isFirstPrivate = sym->test (semantics::Symbol::Flag::OmpFirstPrivate);
121- bool success = converter.createHostAssociateVarClone (
122- *sym, /* skipDefaultInit=*/ isFirstPrivate);
104+
105+ // If we are doing eager-privatization on a symbol created using delayed
106+ // privatization there could be incompatible types here e.g.
107+ // fir.ref<fir.box<fir.array<>>>
108+ bool success = [&]() -> bool {
109+ const auto *details =
110+ sym->detailsIf <Fortran::semantics::HostAssocDetails>();
111+ assert (details && " No host-association found" );
112+ const Fortran::semantics::Symbol &hsym = details->symbol ();
113+ mlir::Value addr = converter.getSymbolAddress (hsym);
114+
115+ if (auto refTy = mlir::dyn_cast<fir::ReferenceType>(addr.getType ())) {
116+ if (auto boxTy = mlir::dyn_cast<fir::BoxType>(refTy.getElementType ())) {
117+ if (auto arrayTy =
118+ mlir::dyn_cast<fir::SequenceType>(boxTy.getElementType ())) {
119+ // FirConverter/fir::ExtendedValue considers all references to boxes
120+ // as mutable boxes. Outside of OpenMP it doesn't make sense to have a
121+ // mutable box of an array. Work around this here by loading the
122+ // reference so it is a normal boxed array.
123+ fir::FirOpBuilder &builder = converter.getFirOpBuilder ();
124+ mlir::Location loc = converter.genLocation (hsym.name ());
125+ fir::ExtendedValue hexv = converter.getSymbolExtendedValue (hsym);
126+
127+ llvm::SmallVector<mlir::Value> extents =
128+ fir::factory::getExtents (loc, builder, hexv);
129+
130+ // TODO: uniqName, name
131+ mlir::Value allocVal =
132+ builder.allocateLocal (loc, arrayTy, /* uniqName=*/ " " ,
133+ /* name=*/ " " , extents, /* typeParams=*/ {},
134+ sym->GetUltimate ().attrs ().test (
135+ Fortran::semantics::Attr::TARGET));
136+ mlir::Value shape = builder.genShape (loc, extents);
137+ mlir::Value box = builder.createBox (loc, boxTy, allocVal, shape,
138+ nullptr , {}, nullptr );
139+
140+ // This can't be a CharArrayBoxValue because otherwise
141+ // boxTy.getElementType() would be a character type.
142+ // Assume the array element type isn't polymorphic because we are
143+ // privatizing.
144+ fir::ExtendedValue newExv = fir::ArrayBoxValue{box, extents};
145+
146+ converter.bindSymbol (*sym, newExv);
147+ return true ;
148+ }
149+ }
150+ }
151+
152+ // Normal case:
153+ return converter.createHostAssociateVarClone (
154+ *sym, /* skipDefaultInit=*/ isFirstPrivate);
155+ }();
123156 (void )success;
124157 assert (success && " Privatization failed due to existing binding" );
125158
@@ -138,7 +171,7 @@ void DataSharingProcessor::cloneSymbol(const semantics::Symbol *sym) {
138171
139172 if (needInitClone ()) {
140173 Fortran::lower::initializeCloneAtRuntime (converter, *sym, symTable);
141- callsInitClone = true ;
174+ mightHaveReadHostSym = true ;
142175 }
143176}
144177
@@ -190,7 +223,8 @@ bool DataSharingProcessor::needBarrier() {
190223 // Emit implicit barrier for linear clause. Maybe on somewhere else.
191224 for (const semantics::Symbol *sym : allPrivatizedSymbols) {
192225 if (sym->test (semantics::Symbol::Flag::OmpLastPrivate) &&
193- (sym->test (semantics::Symbol::Flag::OmpFirstPrivate) || callsInitClone))
226+ (sym->test (semantics::Symbol::Flag::OmpFirstPrivate) ||
227+ mightHaveReadHostSym))
194228 return true ;
195229 }
196230 return false ;
@@ -475,15 +509,47 @@ void DataSharingProcessor::doPrivatize(const semantics::Symbol *sym,
475509 lower::SymbolBox hsb = converter.lookupOneLevelUpSymbol (*sym);
476510 assert (hsb && " Host symbol box not found" );
477511
478- mlir::Type symType = hsb.getAddr ().getType ();
479512 mlir::Location symLoc = hsb.getAddr ().getLoc ();
480513 std::string privatizerName = sym->name ().ToString () + " .privatizer" ;
481514 bool isFirstPrivate = sym->test (semantics::Symbol::Flag::OmpFirstPrivate);
482515
516+ mlir::Value privVal = hsb.getAddr ();
517+ mlir::Type allocType = privVal.getType ();
518+ if (!mlir::isa<fir::PointerType>(privVal.getType ()))
519+ allocType = fir::unwrapRefType (privVal.getType ());
520+
521+ if (auto poly = mlir::dyn_cast<fir::ClassType>(allocType)) {
522+ if (!mlir::isa<fir::PointerType>(poly.getEleTy ()) && isFirstPrivate)
523+ TODO (symLoc, " create polymorphic host associated copy" );
524+ }
525+
526+ // fir.array<> cannot be converted to any single llvm type and fir helpers
527+ // are not available in openmp to llvmir translation so we cannot generate
528+ // an alloca for a fir.array type there. Get around this by boxing all
529+ // arrays.
530+ if (mlir::isa<fir::SequenceType>(allocType)) {
531+ hlfir::Entity entity{hsb.getAddr ()};
532+ entity = genVariableBox (symLoc, firOpBuilder, entity);
533+ privVal = entity.getBase ();
534+ allocType = privVal.getType ();
535+ }
536+
537+ if (mlir::isa<fir::BaseBoxType>(privVal.getType ())) {
538+ // Boxes should be passed by reference into nested regions:
539+ auto oldIP = firOpBuilder.saveInsertionPoint ();
540+ firOpBuilder.setInsertionPointToStart (firOpBuilder.getAllocaBlock ());
541+ auto alloca = firOpBuilder.create <fir::AllocaOp>(symLoc, privVal.getType ());
542+ firOpBuilder.restoreInsertionPoint (oldIP);
543+ firOpBuilder.create <fir::StoreOp>(symLoc, privVal, alloca);
544+ privVal = alloca;
545+ }
546+
547+ mlir::Type argType = privVal.getType ();
548+
483549 mlir::omp::PrivateClauseOp privatizerOp = [&]() {
484550 auto moduleOp = firOpBuilder.getModule ();
485551 auto uniquePrivatizerName = fir::getTypeAsString (
486- symType , converter.getKindMap (),
552+ allocType , converter.getKindMap (),
487553 converter.mangleName (*sym) +
488554 (isFirstPrivate ? " _firstprivate" : " _private" ));
489555
@@ -495,44 +561,40 @@ void DataSharingProcessor::doPrivatize(const semantics::Symbol *sym,
495561 mlir::OpBuilder::InsertionGuard guard (firOpBuilder);
496562 firOpBuilder.setInsertionPointToStart (moduleOp.getBody ());
497563 auto result = firOpBuilder.create <mlir::omp::PrivateClauseOp>(
498- symLoc, uniquePrivatizerName, symType ,
564+ symLoc, uniquePrivatizerName, allocType ,
499565 isFirstPrivate ? mlir::omp::DataSharingClauseType::FirstPrivate
500566 : mlir::omp::DataSharingClauseType::Private);
501567 fir::ExtendedValue symExV = converter.getSymbolExtendedValue (*sym);
502568 lower::SymMapScope outerScope (symTable);
503569
504- // Populate the `alloc` region.
505- {
506- mlir::Region &allocRegion = result.getAllocRegion ();
507- mlir::Block *allocEntryBlock = firOpBuilder.createBlock (
508- &allocRegion, /* insertPt=*/ {}, symType, symLoc);
509-
510- firOpBuilder.setInsertionPointToEnd (allocEntryBlock);
511-
512- fir::ExtendedValue localExV =
513- hlfir::translateToExtendedValue (
514- symLoc, firOpBuilder, hlfir::Entity{allocRegion.getArgument (0 )},
515- /* contiguousHint=*/
516- evaluate::IsSimplyContiguous (*sym, converter.getFoldingContext ()))
517- .first ;
518-
519- symTable.addSymbol (*sym, localExV);
520- lower::SymMapScope innerScope (symTable);
521- cloneSymbol (sym);
522- mlir::Value cloneAddr = symTable.shallowLookupSymbol (*sym).getAddr ();
523- mlir::Type cloneType = cloneAddr.getType ();
524-
525- // A `convert` op is required for variables that are storage associated
526- // via `equivalence`. The problem is that these variables are declared as
527- // `fir.ptr`s while their privatized storage is declared as `fir.ref`,
528- // therefore we convert to proper symbol type.
529- mlir::Value yieldedValue =
530- (symType == cloneType) ? cloneAddr
531- : firOpBuilder.createConvert (
532- cloneAddr.getLoc (), symType, cloneAddr);
533-
534- firOpBuilder.create <mlir::omp::YieldOp>(hsb.getAddr ().getLoc (),
535- yieldedValue);
570+ // Populate the `init` region.
571+ // We need to initialize in the following cases:
572+ // 1. The allocation was for a derived type which requires initialization
573+ // (this can be skipped if it will be initialized anyway by the copy
574+ // region, unless the derived type has allocatable components)
575+ // 2. The allocation was for any kind of box
576+ // 3. The allocation was for a boxed character
577+ const bool needsInitialization =
578+ (Fortran::lower::hasDefaultInitialization (sym->GetUltimate ()) &&
579+ (!isFirstPrivate || hlfir::mayHaveAllocatableComponent (allocType))) ||
580+ mlir::isa<fir::BaseBoxType>(allocType) ||
581+ mlir::isa<fir::BoxCharType>(allocType);
582+ if (needsInitialization) {
583+ mlir::Region &initRegion = result.getInitRegion ();
584+ mlir::Block *initBlock = firOpBuilder.createBlock (
585+ &initRegion, /* insertPt=*/ {}, {argType, argType}, {symLoc, symLoc});
586+
587+ populateByRefInitAndCleanupRegions (
588+ converter, symLoc, argType, /* scalarInitValue=*/ nullptr , initBlock,
589+ result.getInitPrivateArg (), result.getInitMoldArg (),
590+ result.getDeallocRegion (),
591+ isFirstPrivate ? DeclOperationKind::FirstPrivate
592+ : DeclOperationKind::Private,
593+ sym);
594+ // TODO: currently there are false positives from dead uses of the mold
595+ // arg
596+ if (!result.getInitMoldArg ().getUses ().empty ())
597+ mightHaveReadHostSym = true ;
536598 }
537599
538600 // Populate the `copy` region if this is a `firstprivate`.
@@ -541,7 +603,7 @@ void DataSharingProcessor::doPrivatize(const semantics::Symbol *sym,
541603 // First block argument corresponding to the original/host value while
542604 // second block argument corresponding to the privatized value.
543605 mlir::Block *copyEntryBlock = firOpBuilder.createBlock (
544- ©Region, /* insertPt=*/ {}, {symType, symType }, {symLoc, symLoc});
606+ ©Region, /* insertPt=*/ {}, {argType, argType }, {symLoc, symLoc});
545607 firOpBuilder.setInsertionPointToEnd (copyEntryBlock);
546608
547609 auto addSymbol = [&](unsigned argIdx, bool force = false ) {
@@ -572,7 +634,7 @@ void DataSharingProcessor::doPrivatize(const semantics::Symbol *sym,
572634
573635 if (clauseOps) {
574636 clauseOps->privateSyms .push_back (mlir::SymbolRefAttr::get (privatizerOp));
575- clauseOps->privateVars .push_back (hsb. getAddr () );
637+ clauseOps->privateVars .push_back (privVal );
576638 }
577639
578640 symToPrivatizer[sym] = privatizerOp;
0 commit comments