@@ -335,6 +335,64 @@ void sinkLoopIVArgs(mlir::ConversionPatternRewriter &rewriter,
335
335
++idx;
336
336
}
337
337
}
338
+
339
+ // / Collects values that are local to a loop: "loop-local values". A loop-local
340
+ // / value is one that is used exclusively inside the loop but allocated outside
341
+ // / of it. This usually corresponds to temporary values that are used inside the
342
+ // / loop body for initialzing other variables for example.
343
+ // /
344
+ // / See `flang/test/Transforms/DoConcurrent/locally_destroyed_temp.f90` for an
345
+ // / example of why we need this.
346
+ // /
347
+ // / \param [in] doLoop - the loop within which the function searches for values
348
+ // / used exclusively inside.
349
+ // /
350
+ // / \param [out] locals - the list of loop-local values detected for \p doLoop.
351
+ void collectLoopLocalValues (fir::DoLoopOp doLoop,
352
+ llvm::SetVector<mlir::Value> &locals) {
353
+ doLoop.walk ([&](mlir::Operation *op) {
354
+ for (mlir::Value operand : op->getOperands ()) {
355
+ if (locals.contains (operand))
356
+ continue ;
357
+
358
+ bool isLocal = true ;
359
+
360
+ if (!mlir::isa_and_present<fir::AllocaOp>(operand.getDefiningOp ()))
361
+ continue ;
362
+
363
+ // Values defined inside the loop are not interesting since they do not
364
+ // need to be localized.
365
+ if (doLoop->isAncestor (operand.getDefiningOp ()))
366
+ continue ;
367
+
368
+ for (auto *user : operand.getUsers ()) {
369
+ if (!doLoop->isAncestor (user)) {
370
+ isLocal = false ;
371
+ break ;
372
+ }
373
+ }
374
+
375
+ if (isLocal)
376
+ locals.insert (operand);
377
+ }
378
+ });
379
+ }
380
+
381
+ // / For a "loop-local" value \p local within a loop's scope, localizes that
382
+ // / value within the scope of the parallel region the loop maps to. Towards that
383
+ // / end, this function moves the allocation of \p local within \p allocRegion.
384
+ // /
385
+ // / \param local - the value used exclusively within a loop's scope (see
386
+ // / collectLoopLocalValues).
387
+ // /
388
+ // / \param allocRegion - the parallel region where \p local's allocation will be
389
+ // / privatized.
390
+ // /
391
+ // / \param rewriter - builder used for updating \p allocRegion.
392
+ static void localizeLoopLocalValue (mlir::Value local, mlir::Region &allocRegion,
393
+ mlir::ConversionPatternRewriter &rewriter) {
394
+ rewriter.moveOpBefore (local.getDefiningOp (), &allocRegion.front ().front ());
395
+ }
338
396
} // namespace looputils
339
397
340
398
class DoConcurrentConversion : public mlir ::OpConversionPattern<fir::DoLoopOp> {
@@ -357,13 +415,21 @@ class DoConcurrentConversion : public mlir::OpConversionPattern<fir::DoLoopOp> {
357
415
" Some `do concurent` loops are not perfectly-nested. "
358
416
" These will be serialzied." );
359
417
418
+ llvm::SetVector<mlir::Value> locals;
419
+ looputils::collectLoopLocalValues (loopNest.back ().first , locals);
360
420
looputils::sinkLoopIVArgs (rewriter, loopNest);
421
+
361
422
mlir::IRMapping mapper;
362
- genParallelOp (doLoop.getLoc (), rewriter, loopNest, mapper);
423
+ mlir::omp::ParallelOp parallelOp =
424
+ genParallelOp (doLoop.getLoc (), rewriter, loopNest, mapper);
363
425
mlir::omp::LoopNestOperands loopNestClauseOps;
364
426
genLoopNestClauseOps (doLoop.getLoc (), rewriter, loopNest, mapper,
365
427
loopNestClauseOps);
366
428
429
+ for (mlir::Value local : locals)
430
+ looputils::localizeLoopLocalValue (local, parallelOp.getRegion (),
431
+ rewriter);
432
+
367
433
mlir::omp::LoopNestOp ompLoopNest =
368
434
genWsLoopOp (rewriter, loopNest.back ().first , mapper, loopNestClauseOps,
369
435
/* isComposite=*/ mapToDevice);
0 commit comments