@@ -198,15 +198,19 @@ class AllocMemConversion : public mlir::OpRewritePattern<fir::AllocMemOp> {
198
198
199
199
// / Determine where to insert the alloca operation. The returned value should
200
200
// / be checked to see if it is inside a loop
201
- static InsertionPoint findAllocaInsertionPoint (fir::AllocMemOp &oldAlloc);
201
+ static InsertionPoint
202
+ findAllocaInsertionPoint (fir::AllocMemOp &oldAlloc,
203
+ const llvm::SmallVector<mlir::Operation *> &freeOps);
202
204
203
205
private:
204
206
// / Handle to the DFA (already run)
205
207
const StackArraysAnalysisWrapper::AllocMemMap &candidateOps;
206
208
207
209
// / If we failed to find an insertion point not inside a loop, see if it would
208
210
// / be safe to use an llvm.stacksave/llvm.stackrestore inside the loop
209
- static InsertionPoint findAllocaLoopInsertionPoint (fir::AllocMemOp &oldAlloc);
211
+ static InsertionPoint findAllocaLoopInsertionPoint (
212
+ fir::AllocMemOp &oldAlloc,
213
+ const llvm::SmallVector<mlir::Operation *> &freeOps);
210
214
211
215
// / Returns the alloca if it was successfully inserted, otherwise {}
212
216
std::optional<fir::AllocaOp>
@@ -484,14 +488,31 @@ StackArraysAnalysisWrapper::analyseFunction(mlir::Operation *func) {
484
488
llvm::DenseSet<mlir::Value> freedValues;
485
489
point.appendFreedValues (freedValues);
486
490
491
+ // Find all fir.freemem operations corresponding to fir.allocmem
492
+ // in freedValues. It is best to find the association going back
493
+ // from fir.freemem to fir.allocmem through the def-use chains,
494
+ // so that we can use lookThroughDeclaresAndConverts same way
495
+ // the AllocationAnalysis is handling them.
496
+ llvm::DenseMap<mlir::Operation *, llvm::SmallVector<mlir::Operation *>>
497
+ allocToFreeMemMap;
498
+ func->walk ([&](fir::FreeMemOp freeOp) {
499
+ mlir::Value memref = lookThroughDeclaresAndConverts (freeOp.getHeapref ());
500
+ if (!freedValues.count (memref))
501
+ return ;
502
+
503
+ auto allocMem = memref.getDefiningOp <fir::AllocMemOp>();
504
+ allocToFreeMemMap[allocMem].push_back (freeOp);
505
+ });
506
+
487
507
// We only replace allocations which are definately freed on all routes
488
508
// through the function because otherwise the allocation may have an intende
489
509
// lifetime longer than the current stack frame (e.g. a heap allocation which
490
510
// is then freed by another function).
491
511
for (mlir::Value freedValue : freedValues) {
492
512
fir::AllocMemOp allocmem = freedValue.getDefiningOp <fir::AllocMemOp>();
493
513
InsertionPoint insertionPoint =
494
- AllocMemConversion::findAllocaInsertionPoint (allocmem);
514
+ AllocMemConversion::findAllocaInsertionPoint (
515
+ allocmem, allocToFreeMemMap[allocmem]);
495
516
if (insertionPoint)
496
517
candidateOps.insert ({allocmem, insertionPoint});
497
518
}
@@ -578,8 +599,9 @@ static bool isInLoop(mlir::Operation *op) {
578
599
op->getParentOfType <mlir::LoopLikeOpInterface>();
579
600
}
580
601
581
- InsertionPoint
582
- AllocMemConversion::findAllocaInsertionPoint (fir::AllocMemOp &oldAlloc) {
602
+ InsertionPoint AllocMemConversion::findAllocaInsertionPoint (
603
+ fir::AllocMemOp &oldAlloc,
604
+ const llvm::SmallVector<mlir::Operation *> &freeOps) {
583
605
// Ideally the alloca should be inserted at the end of the function entry
584
606
// block so that we do not allocate stack space in a loop. However,
585
607
// the operands to the alloca may not be available that early, so insert it
@@ -596,7 +618,7 @@ AllocMemConversion::findAllocaInsertionPoint(fir::AllocMemOp &oldAlloc) {
596
618
if (isInLoop (oldAllocOp)) {
597
619
// where we want to put it is in a loop, and even the old location is in
598
620
// a loop. Give up.
599
- return findAllocaLoopInsertionPoint (oldAlloc);
621
+ return findAllocaLoopInsertionPoint (oldAlloc, freeOps );
600
622
}
601
623
return {oldAllocOp};
602
624
}
@@ -657,28 +679,14 @@ AllocMemConversion::findAllocaInsertionPoint(fir::AllocMemOp &oldAlloc) {
657
679
return checkReturn (&entryBlock);
658
680
}
659
681
660
- InsertionPoint
661
- AllocMemConversion::findAllocaLoopInsertionPoint (fir::AllocMemOp &oldAlloc) {
682
+ InsertionPoint AllocMemConversion::findAllocaLoopInsertionPoint (
683
+ fir::AllocMemOp &oldAlloc,
684
+ const llvm::SmallVector<mlir::Operation *> &freeOps) {
662
685
mlir::Operation *oldAllocOp = oldAlloc;
663
686
// This is only called as a last resort. We should try to insert at the
664
687
// location of the old allocation, which is inside of a loop, using
665
688
// llvm.stacksave/llvm.stackrestore
666
689
667
- // find freemem ops
668
- llvm::SmallVector<mlir::Operation *, 1 > freeOps;
669
-
670
- for (mlir::Operation *user : oldAllocOp->getUsers ()) {
671
- if (auto declareOp = mlir::dyn_cast_if_present<fir::DeclareOp>(user)) {
672
- for (mlir::Operation *user : declareOp->getUsers ()) {
673
- if (mlir::isa<fir::FreeMemOp>(user))
674
- freeOps.push_back (user);
675
- }
676
- }
677
-
678
- if (mlir::isa<fir::FreeMemOp>(user))
679
- freeOps.push_back (user);
680
- }
681
-
682
690
assert (freeOps.size () && " DFA should only return freed memory" );
683
691
684
692
// Don't attempt to reason about a stacksave/stackrestore between different
0 commit comments