13
13
#include " flang/Optimizer/Dialect/FIROps.h"
14
14
#include " flang/Optimizer/Dialect/FIRType.h"
15
15
#include " flang/Optimizer/Dialect/Support/FIRContext.h"
16
+ #include " flang/Optimizer/Support/DataLayout.h"
16
17
#include " flang/Optimizer/Transforms/Passes.h"
17
18
#include " mlir/Analysis/DataFlow/ConstantPropagationAnalysis.h"
18
19
#include " mlir/Analysis/DataFlow/DeadCodeAnalysis.h"
19
20
#include " mlir/Analysis/DataFlow/DenseAnalysis.h"
20
21
#include " mlir/Analysis/DataFlowFramework.h"
22
+ #include " mlir/Dialect/DLTI/DLTI.h"
21
23
#include " mlir/Dialect/Func/IR/FuncOps.h"
24
+ #include " mlir/Dialect/LLVMIR/LLVMDialect.h"
22
25
#include " mlir/Dialect/OpenMP/OpenMPDialect.h"
23
26
#include " mlir/IR/Builders.h"
24
27
#include " mlir/IR/Diagnostics.h"
@@ -48,6 +51,11 @@ static llvm::cl::opt<std::size_t> maxAllocsPerFunc(
48
51
" to 0 for no limit." ),
49
52
llvm::cl::init(1000 ), llvm::cl::Hidden);
50
53
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
+
51
59
namespace {
52
60
53
61
// / The state of an SSA value at each program point
@@ -189,8 +197,11 @@ class AllocMemConversion : public mlir::OpRewritePattern<fir::AllocMemOp> {
189
197
public:
190
198
explicit AllocMemConversion (
191
199
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} {}
194
205
195
206
llvm::LogicalResult
196
207
matchAndRewrite (fir::AllocMemOp allocmem,
@@ -206,6 +217,9 @@ class AllocMemConversion : public mlir::OpRewritePattern<fir::AllocMemOp> {
206
217
// / Handle to the DFA (already run)
207
218
const StackArraysAnalysisWrapper::AllocMemMap &candidateOps;
208
219
220
+ const std::optional<mlir::DataLayout> &dl;
221
+ const std::optional<fir::KindMapping> &kindMap;
222
+
209
223
// / If we failed to find an insertion point not inside a loop, see if it would
210
224
// / be safe to use an llvm.stacksave/llvm.stackrestore inside the loop
211
225
static InsertionPoint findAllocaLoopInsertionPoint (
@@ -218,8 +232,12 @@ class AllocMemConversion : public mlir::OpRewritePattern<fir::AllocMemOp> {
218
232
mlir::PatternRewriter &rewriter) const ;
219
233
220
234
// / Inserts a stacksave before oldAlloc and a stackrestore after each freemem
221
- void insertStackSaveRestore (fir::AllocMemOp & oldAlloc,
235
+ void insertStackSaveRestore (fir::AllocMemOp oldAlloc,
222
236
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 ;
223
241
};
224
242
225
243
class StackArraysPass : public fir ::impl::StackArraysBase<StackArraysPass> {
@@ -740,14 +758,34 @@ AllocMemConversion::insertAlloca(fir::AllocMemOp &oldAlloc,
740
758
741
759
llvm::StringRef uniqName = unpackName (oldAlloc.getUniqName ());
742
760
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
+ }
746
784
}
747
785
748
786
void 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 );
751
789
auto mod = oldAlloc->getParentOfType <mlir::ModuleOp>();
752
790
fir::FirOpBuilder builder{rewriter, mod};
753
791
@@ -758,21 +796,30 @@ void AllocMemConversion::insertStackSaveRestore(
758
796
builder.setInsertionPoint (user);
759
797
builder.genStackRestore (user->getLoc (), sp);
760
798
};
799
+ visitFreeMemOp (oldAlloc, createStackRestoreCall);
800
+ }
761
801
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 ());
773
822
}
774
-
775
- rewriter.restoreInsertionPoint (oldPoint);
776
823
}
777
824
778
825
StackArraysPass::StackArraysPass (const StackArraysPass &pass)
@@ -809,7 +856,16 @@ void StackArraysPass::runOnOperation() {
809
856
config.setRegionSimplificationLevel (
810
857
mlir::GreedySimplifyRegionLevel::Disabled);
811
858
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);
813
869
if (mlir::failed (mlir::applyOpPatternsGreedily (
814
870
opsToConvert, std::move (patterns), config))) {
815
871
mlir::emitError (func->getLoc (), " error in stack arrays optimization\n " );
0 commit comments