1313#include " flang/Optimizer/Dialect/FIROps.h"
1414#include " flang/Optimizer/Dialect/FIRType.h"
1515#include " flang/Optimizer/Dialect/Support/FIRContext.h"
16+ #include " flang/Optimizer/Support/DataLayout.h"
1617#include " flang/Optimizer/Transforms/Passes.h"
1718#include " mlir/Analysis/DataFlow/ConstantPropagationAnalysis.h"
1819#include " mlir/Analysis/DataFlow/DeadCodeAnalysis.h"
1920#include " mlir/Analysis/DataFlow/DenseAnalysis.h"
2021#include " mlir/Analysis/DataFlowFramework.h"
22+ #include " mlir/Dialect/DLTI/DLTI.h"
2123#include " mlir/Dialect/Func/IR/FuncOps.h"
24+ #include " mlir/Dialect/LLVMIR/LLVMDialect.h"
2225#include " mlir/Dialect/OpenMP/OpenMPDialect.h"
2326#include " mlir/IR/Builders.h"
2427#include " mlir/IR/Diagnostics.h"
@@ -48,6 +51,11 @@ static llvm::cl::opt<std::size_t> maxAllocsPerFunc(
4851 " to 0 for no limit." ),
4952 llvm::cl::init(1000 ), llvm::cl::Hidden);
5053
54+ static llvm::cl::opt<bool > emitLifetimeMarkers (
55+ " stack-arrays-lifetime" ,
56+ llvm::cl::desc (" Add lifetime markers to generated constant size allocas" ),
57+ llvm::cl::init(false ), llvm::cl::Hidden);
58+
5159namespace {
5260
5361// / The state of an SSA value at each program point
@@ -189,8 +197,11 @@ class AllocMemConversion : public mlir::OpRewritePattern<fir::AllocMemOp> {
189197public:
190198 explicit AllocMemConversion (
191199 mlir::MLIRContext *ctx,
192- const StackArraysAnalysisWrapper::AllocMemMap &candidateOps)
193- : OpRewritePattern(ctx), candidateOps{candidateOps} {}
200+ const StackArraysAnalysisWrapper::AllocMemMap &candidateOps,
201+ std::optional<mlir::DataLayout> &dl,
202+ std::optional<fir::KindMapping> &kindMap)
203+ : OpRewritePattern(ctx), candidateOps{candidateOps}, dl{dl},
204+ kindMap{kindMap} {}
194205
195206 llvm::LogicalResult
196207 matchAndRewrite (fir::AllocMemOp allocmem,
@@ -206,6 +217,9 @@ class AllocMemConversion : public mlir::OpRewritePattern<fir::AllocMemOp> {
206217 // / Handle to the DFA (already run)
207218 const StackArraysAnalysisWrapper::AllocMemMap &candidateOps;
208219
220+ const std::optional<mlir::DataLayout> &dl;
221+ const std::optional<fir::KindMapping> &kindMap;
222+
209223 // / If we failed to find an insertion point not inside a loop, see if it would
210224 // / be safe to use an llvm.stacksave/llvm.stackrestore inside the loop
211225 static InsertionPoint findAllocaLoopInsertionPoint (
@@ -218,8 +232,12 @@ class AllocMemConversion : public mlir::OpRewritePattern<fir::AllocMemOp> {
218232 mlir::PatternRewriter &rewriter) const ;
219233
220234 // / Inserts a stacksave before oldAlloc and a stackrestore after each freemem
221- void insertStackSaveRestore (fir::AllocMemOp & oldAlloc,
235+ void insertStackSaveRestore (fir::AllocMemOp oldAlloc,
222236 mlir::PatternRewriter &rewriter) const ;
237+ // / Emit lifetime markers for newAlloc between oldAlloc and each freemem.
238+ // / If the allocation is dynamic, no life markers are emitted.
239+ void insertLifetimeMarkers (fir::AllocMemOp oldAlloc, fir::AllocaOp newAlloc,
240+ mlir::PatternRewriter &rewriter) const ;
223241};
224242
225243class StackArraysPass : public fir ::impl::StackArraysBase<StackArraysPass> {
@@ -740,14 +758,34 @@ AllocMemConversion::insertAlloca(fir::AllocMemOp &oldAlloc,
740758
741759 llvm::StringRef uniqName = unpackName (oldAlloc.getUniqName ());
742760 llvm::StringRef bindcName = unpackName (oldAlloc.getBindcName ());
743- return rewriter.create <fir::AllocaOp>(loc, varTy, uniqName, bindcName,
744- oldAlloc.getTypeparams (),
745- oldAlloc.getShape ());
761+ auto alloca = rewriter.create <fir::AllocaOp>(loc, varTy, uniqName, bindcName,
762+ oldAlloc.getTypeparams (),
763+ oldAlloc.getShape ());
764+ if (emitLifetimeMarkers)
765+ insertLifetimeMarkers (oldAlloc, alloca, rewriter);
766+
767+ return alloca;
768+ }
769+
770+ static void
771+ visitFreeMemOp (fir::AllocMemOp oldAlloc,
772+ const std::function<void (mlir::Operation *)> &callBack) {
773+ for (mlir::Operation *user : oldAlloc->getUsers ()) {
774+ if (auto declareOp = mlir::dyn_cast_if_present<fir::DeclareOp>(user)) {
775+ for (mlir::Operation *user : declareOp->getUsers ()) {
776+ if (mlir::isa<fir::FreeMemOp>(user))
777+ callBack (user);
778+ }
779+ }
780+
781+ if (mlir::isa<fir::FreeMemOp>(user))
782+ callBack (user);
783+ }
746784}
747785
748786void AllocMemConversion::insertStackSaveRestore (
749- fir::AllocMemOp & oldAlloc, mlir::PatternRewriter &rewriter) const {
750- auto oldPoint = rewriter. saveInsertionPoint ( );
787+ fir::AllocMemOp oldAlloc, mlir::PatternRewriter &rewriter) const {
788+ mlir::OpBuilder::InsertionGuard insertGuard (rewriter );
751789 auto mod = oldAlloc->getParentOfType <mlir::ModuleOp>();
752790 fir::FirOpBuilder builder{rewriter, mod};
753791
@@ -758,21 +796,30 @@ void AllocMemConversion::insertStackSaveRestore(
758796 builder.setInsertionPoint (user);
759797 builder.genStackRestore (user->getLoc (), sp);
760798 };
799+ visitFreeMemOp (oldAlloc, createStackRestoreCall);
800+ }
761801
762- for (mlir::Operation *user : oldAlloc->getUsers ()) {
763- if (auto declareOp = mlir::dyn_cast_if_present<fir::DeclareOp>(user)) {
764- for (mlir::Operation *user : declareOp->getUsers ()) {
765- if (mlir::isa<fir::FreeMemOp>(user))
766- createStackRestoreCall (user);
767- }
768- }
769-
770- if (mlir::isa<fir::FreeMemOp>(user)) {
771- createStackRestoreCall (user);
772- }
802+ void AllocMemConversion::insertLifetimeMarkers (
803+ fir::AllocMemOp oldAlloc, fir::AllocaOp newAlloc,
804+ mlir::PatternRewriter &rewriter) const {
805+ if (!dl || !kindMap)
806+ return ;
807+ llvm::StringRef attrName = fir::getHasLifetimeMarkerAttrName ();
808+ // Do not add lifetime markers if the alloca already has any.
809+ if (newAlloc->hasAttr (attrName))
810+ return ;
811+ if (std::optional<int64_t > size =
812+ fir::getAllocaByteSize (newAlloc, *dl, *kindMap)) {
813+ mlir::OpBuilder::InsertionGuard insertGuard (rewriter);
814+ rewriter.setInsertionPoint (oldAlloc);
815+ mlir::Value ptr = fir::factory::genLifetimeStart (
816+ rewriter, newAlloc.getLoc (), newAlloc, *size, &*dl);
817+ visitFreeMemOp (oldAlloc, [&](mlir::Operation *op) {
818+ rewriter.setInsertionPoint (op);
819+ fir::factory::genLifetimeEnd (rewriter, op->getLoc (), ptr, *size);
820+ });
821+ newAlloc->setAttr (attrName, rewriter.getUnitAttr ());
773822 }
774-
775- rewriter.restoreInsertionPoint (oldPoint);
776823}
777824
778825StackArraysPass::StackArraysPass (const StackArraysPass &pass)
@@ -809,7 +856,16 @@ void StackArraysPass::runOnOperation() {
809856 config.setRegionSimplificationLevel (
810857 mlir::GreedySimplifyRegionLevel::Disabled);
811858
812- patterns.insert <AllocMemConversion>(&context, *candidateOps);
859+ auto module = func->getParentOfType <mlir::ModuleOp>();
860+ std::optional<mlir::DataLayout> dl =
861+ module ? fir::support::getOrSetMLIRDataLayout (
862+ module , /* allowDefaultLayout=*/ false )
863+ : std::nullopt ;
864+ std::optional<fir::KindMapping> kindMap;
865+ if (module )
866+ kindMap = fir::getKindMapping (module );
867+
868+ patterns.insert <AllocMemConversion>(&context, *candidateOps, dl, kindMap);
813869 if (mlir::failed (mlir::applyOpPatternsGreedily (
814870 opsToConvert, std::move (patterns), config))) {
815871 mlir::emitError (func->getLoc (), " error in stack arrays optimization\n " );
0 commit comments