FLANG
StackArrays.h
1//===- StackArrays.h ------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10//
11//===----------------------------------------------------------------------===//
12//
13// This header exposes the reusable pieces of the StackArrays pass: the
14// analysis that determines which fir.allocmem operations can safely be moved
15// to the stack (and where the replacement fir.alloca should be inserted), and
16// the pattern that performs the heap-to-stack rewrite. They are shared so that
17// other passes can reuse the same "is this heap allocation safely stackifiable,
18// and where" logic.
19//
20//===----------------------------------------------------------------------===//
21
22#ifndef FORTRAN_OPTIMIZER_TRANSFORMS_STACKARRAYS_H
23#define FORTRAN_OPTIMIZER_TRANSFORMS_STACKARRAYS_H
24
25#include "flang/Optimizer/Dialect/FIROps.h"
26#include "flang/Optimizer/Dialect/Support/KindMapping.h"
27#include "mlir/IR/PatternMatch.h"
28#include "mlir/Interfaces/DataLayoutInterfaces.h"
29#include "mlir/Support/TypeID.h"
30#include "llvm/ADT/DenseMap.h"
31#include "llvm/ADT/PointerUnion.h"
32#include "llvm/ADT/SmallVector.h"
33#include "llvm/Support/Casting.h"
34#include <optional>
35
36namespace fir {
37
41class InsertionPoint {
42 llvm::PointerUnion<mlir::Operation *, mlir::Block *> location;
43 bool saveRestoreStack;
44
46 template <class T>
47 T *tryGetPtr() const {
48 // Use llvm::dyn_cast_if_present because location may be null here.
49 if (T *ptr = llvm::dyn_cast_if_present<T *>(location))
50 return ptr;
51 return nullptr;
52 }
53
54public:
55 template <class T>
56 InsertionPoint(T *ptr, bool saveRestoreStack = false)
57 : location(ptr), saveRestoreStack{saveRestoreStack} {}
58 InsertionPoint(std::nullptr_t null)
59 : location(null), saveRestoreStack{false} {}
60
62 mlir::Operation *tryGetOperation() const {
63 return tryGetPtr<mlir::Operation>();
64 }
65
67 mlir::Block *tryGetBlock() const { return tryGetPtr<mlir::Block>(); }
68
72 bool shouldSaveRestoreStack() const { return saveRestoreStack; }
73
74 operator bool() const { return tryGetOperation() || tryGetBlock(); }
75
76 bool operator==(const InsertionPoint &rhs) const {
77 return (location == rhs.location) &&
78 (saveRestoreStack == rhs.saveRestoreStack);
79 }
80
81 bool operator!=(const InsertionPoint &rhs) const { return !(*this == rhs); }
82};
83
86class StackArraysAnalysisWrapper {
87public:
88 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(StackArraysAnalysisWrapper)
89
90 // Maps fir.allocmem -> place to insert alloca
91 using AllocMemMap = llvm::DenseMap<mlir::Operation *, InsertionPoint>;
92
93 StackArraysAnalysisWrapper(mlir::Operation *op) {}
94
95 // Returns nullptr if analysis failed.
96 // Note: the returned pointer points into funcMaps and is invalidated if
97 // funcMaps grows (i.e. when a not-yet-analysed function is queried). This
98 // does not happen currently because each StackArraysAnalysisWrapper instance
99 // is only used to analyse a single function.
100 const AllocMemMap *getCandidateOps(mlir::Operation *func);
101
102private:
103 llvm::DenseMap<mlir::Operation *, AllocMemMap> funcMaps;
104
105 llvm::LogicalResult analyseFunction(mlir::Operation *func);
106};
107
109class AllocMemConversion : public mlir::OpRewritePattern<fir::AllocMemOp> {
110public:
111 explicit AllocMemConversion(
112 mlir::MLIRContext *ctx,
113 const StackArraysAnalysisWrapper::AllocMemMap &candidateOps,
114 std::optional<mlir::DataLayout> &dl,
115 std::optional<fir::KindMapping> &kindMap)
116 : OpRewritePattern(ctx), candidateOps{candidateOps}, dl{dl},
117 kindMap{kindMap} {}
118
119 llvm::LogicalResult
120 matchAndRewrite(fir::AllocMemOp allocmem,
121 mlir::PatternRewriter &rewriter) const override;
122
125 static InsertionPoint
126 findAllocaInsertionPoint(fir::AllocMemOp &oldAlloc,
128
129private:
131 const StackArraysAnalysisWrapper::AllocMemMap &candidateOps;
132
133 const std::optional<mlir::DataLayout> &dl;
134 const std::optional<fir::KindMapping> &kindMap;
135
138 static InsertionPoint findAllocaLoopInsertionPoint(
139 fir::AllocMemOp &oldAlloc,
141
143 std::optional<fir::AllocaOp>
144 insertAlloca(fir::AllocMemOp &oldAlloc,
145 mlir::PatternRewriter &rewriter) const;
146
148 void insertStackSaveRestore(fir::AllocMemOp oldAlloc,
149 mlir::PatternRewriter &rewriter) const;
152 void insertLifetimeMarkers(fir::AllocMemOp oldAlloc, fir::AllocaOp newAlloc,
153 mlir::PatternRewriter &rewriter) const;
154};
155
156} // namespace fir
157
158#endif // FORTRAN_OPTIMIZER_TRANSFORMS_STACKARRAYS_H
static InsertionPoint findAllocaInsertionPoint(fir::AllocMemOp &oldAlloc, const llvm::SmallVector< mlir::Operation * > &freeOps)
Definition StackArrays.cpp:504
Definition StackArrays.h:41
mlir::Block * tryGetBlock() const
Get contained block, or nullptr.
Definition StackArrays.h:67
mlir::Operation * tryGetOperation() const
Get contained operation, or nullptr.
Definition StackArrays.h:62
bool shouldSaveRestoreStack() const
Definition StackArrays.h:72
Definition OpenACC.h:20
Definition AbstractConverter.h:37