@@ -149,6 +149,20 @@ mlir::LogicalResult BoxTotalElementsConversion::matchAndRewrite(
149149
150150class DoConcurrentConversion
151151 : public mlir::OpRewritePattern<fir::DoConcurrentOp> {
152+ // / Looks up from the operation from and returns the PrivateClauseOp with
153+ // / name symbolName
154+ // /
155+ // / TODO Copied from OpenMPToLLVMIRTranslation.cpp, move to a shared location.
156+ // / Maybe a static function on the `PrivateClauseOp`.
157+ static mlir::omp::PrivateClauseOp
158+ findPrivatizer (mlir::Operation *from, mlir::SymbolRefAttr symbolName) {
159+ mlir::omp::PrivateClauseOp privatizer =
160+ mlir::SymbolTable::lookupNearestSymbolFrom<mlir::omp::PrivateClauseOp>(
161+ from, symbolName);
162+ assert (privatizer && " privatizer not found in the symbol table" );
163+ return privatizer;
164+ }
165+
152166public:
153167 using mlir::OpRewritePattern<fir::DoConcurrentOp>::OpRewritePattern;
154168
@@ -162,7 +176,55 @@ class DoConcurrentConversion
162176 assert (loop.getRegion ().hasOneBlock ());
163177 mlir::Block &loopBlock = loop.getRegion ().getBlocks ().front ();
164178
165- // Collect iteration variable(s) allocations do that we can move them
179+ // Handle privatization
180+ if (!loop.getPrivateVars ().empty ()) {
181+ mlir::OpBuilder::InsertionGuard guard (rewriter);
182+ rewriter.setInsertionPointToStart (&loop.getRegion ().front ());
183+
184+ std::optional<mlir::ArrayAttr> privateSyms = loop.getPrivateSyms ();
185+
186+ for (auto [privateVar, privateArg, privatizerSym] :
187+ llvm::zip_equal (loop.getPrivateVars (), loop.getRegionPrivateArgs (),
188+ *privateSyms)) {
189+ mlir::SymbolRefAttr privatizerName =
190+ llvm::cast<mlir::SymbolRefAttr>(privatizerSym);
191+ mlir::omp::PrivateClauseOp privatizer =
192+ findPrivatizer (loop, privatizerName);
193+
194+ mlir::Value localAlloc =
195+ rewriter.create <fir::AllocaOp>(loop.getLoc (), privatizer.getType ());
196+
197+ if (privatizer.getDataSharingType () ==
198+ mlir::omp::DataSharingClauseType::FirstPrivate) {
199+ // It is reasonable to make this assumption since, at this stage,
200+ // control-flow ops are not converted yet. Therefore, things like `if`
201+ // conditions will still be represented by their encapsulating `fir`
202+ // dialect ops.
203+ assert (privatizer.getCopyRegion ().hasOneBlock () &&
204+ " Expected privatizer to have a single block." );
205+ mlir::Block *beforeLocalInit = rewriter.getInsertionBlock ();
206+ mlir::Block *afterLocalInit = rewriter.splitBlock (
207+ rewriter.getInsertionBlock (), rewriter.getInsertionPoint ());
208+ rewriter.cloneRegionBefore (privatizer.getCopyRegion (),
209+ afterLocalInit);
210+ mlir::Block *copyRegionBody = beforeLocalInit->getNextNode ();
211+
212+ rewriter.eraseOp (copyRegionBody->getTerminator ());
213+ rewriter.mergeBlocks (afterLocalInit, copyRegionBody);
214+ rewriter.mergeBlocks (copyRegionBody, beforeLocalInit,
215+ {privateVar, privateArg});
216+ }
217+
218+ rewriter.replaceAllUsesWith (privateArg, localAlloc);
219+ }
220+
221+ loop.getRegion ().front ().eraseArguments (loop.getNumInductionVars (),
222+ loop.getNumPrivateOperands ());
223+ loop.getPrivateVarsMutable ().clear ();
224+ loop.setPrivateSymsAttr (nullptr );
225+ }
226+
227+ // Collect iteration variable(s) allocations so that we can move them
166228 // outside the `fir.do_concurrent` wrapper.
167229 llvm::SmallVector<mlir::Operation *> opsToMove;
168230 for (mlir::Operation &op : llvm::drop_end (wrapperBlock))
0 commit comments