@@ -149,6 +149,17 @@ mlir::LogicalResult BoxTotalElementsConversion::matchAndRewrite(
149149
150150class DoConcurrentConversion
151151 : public mlir::OpRewritePattern<fir::DoConcurrentOp> {
152+ // / Looks up from the operation from and returns the LocalitySpecifierOp with
153+ // / name symbolName
154+ static fir::LocalitySpecifierOp
155+ findLocalizer (mlir::Operation *from, mlir::SymbolRefAttr symbolName) {
156+ fir::LocalitySpecifierOp localizer =
157+ mlir::SymbolTable::lookupNearestSymbolFrom<fir::LocalitySpecifierOp>(
158+ from, symbolName);
159+ assert (localizer && " localizer not found in the symbol table" );
160+ return localizer;
161+ }
162+
152163public:
153164 using mlir::OpRewritePattern<fir::DoConcurrentOp>::OpRewritePattern;
154165
@@ -162,7 +173,59 @@ class DoConcurrentConversion
162173 assert (loop.getRegion ().hasOneBlock ());
163174 mlir::Block &loopBlock = loop.getRegion ().getBlocks ().front ();
164175
165- // Collect iteration variable(s) allocations do that we can move them
176+ // Handle localization
177+ if (!loop.getLocalVars ().empty ()) {
178+ mlir::OpBuilder::InsertionGuard guard (rewriter);
179+ rewriter.setInsertionPointToStart (&loop.getRegion ().front ());
180+
181+ std::optional<mlir::ArrayAttr> localSyms = loop.getLocalSyms ();
182+
183+ for (auto [localVar, localArg, localizerSym] : llvm::zip_equal (
184+ loop.getLocalVars (), loop.getRegionLocalArgs (), *localSyms)) {
185+ mlir::SymbolRefAttr localizerName =
186+ llvm::cast<mlir::SymbolRefAttr>(localizerSym);
187+ fir::LocalitySpecifierOp localizer = findLocalizer (loop, localizerName);
188+
189+ if (!localizer.getInitRegion ().empty () ||
190+ !localizer.getDeallocRegion ().empty ())
191+ TODO (localizer.getLoc (), " localizers with `init` and `dealloc` "
192+ " regions are not handled yet." );
193+
194+ // TODO Should this be a heap allocation instead? For now, we allocate
195+ // on the stack for each loop iteration.
196+ mlir::Value localAlloc =
197+ rewriter.create <fir::AllocaOp>(loop.getLoc (), localizer.getType ());
198+
199+ if (localizer.getLocalitySpecifierType () ==
200+ fir::LocalitySpecifierType::LocalInit) {
201+ // It is reasonable to make this assumption since, at this stage,
202+ // control-flow ops are not converted yet. Therefore, things like `if`
203+ // conditions will still be represented by their encapsulating `fir`
204+ // dialect ops.
205+ assert (localizer.getCopyRegion ().hasOneBlock () &&
206+ " Expected localizer to have a single block." );
207+ mlir::Block *beforeLocalInit = rewriter.getInsertionBlock ();
208+ mlir::Block *afterLocalInit = rewriter.splitBlock (
209+ rewriter.getInsertionBlock (), rewriter.getInsertionPoint ());
210+ rewriter.cloneRegionBefore (localizer.getCopyRegion (), afterLocalInit);
211+ mlir::Block *copyRegionBody = beforeLocalInit->getNextNode ();
212+
213+ rewriter.eraseOp (copyRegionBody->getTerminator ());
214+ rewriter.mergeBlocks (afterLocalInit, copyRegionBody);
215+ rewriter.mergeBlocks (copyRegionBody, beforeLocalInit,
216+ {localVar, localArg});
217+ }
218+
219+ rewriter.replaceAllUsesWith (localArg, localAlloc);
220+ }
221+
222+ loop.getRegion ().front ().eraseArguments (loop.getNumInductionVars (),
223+ loop.getNumLocalOperands ());
224+ loop.getLocalVarsMutable ().clear ();
225+ loop.setLocalSymsAttr (nullptr );
226+ }
227+
228+ // Collect iteration variable(s) allocations so that we can move them
166229 // outside the `fir.do_concurrent` wrapper.
167230 llvm::SmallVector<mlir::Operation *> opsToMove;
168231 for (mlir::Operation &op : llvm::drop_end (wrapperBlock))
0 commit comments