1 //===-- Lower/FirBuilder.h -- FIR operation builder -------------*- C++ -*-===//
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 // Builder routines for constructing the FIR dialect of MLIR. As FIR is a
10 // dialect of MLIR, it makes extensive use of MLIR interfaces and MLIR's coding
11 // style (https://mlir.llvm.org/getting_started/DeveloperGuide/) is used in this
12 // module.
13 //
14 //===----------------------------------------------------------------------===//
15 
16 #ifndef FORTRAN_LOWER_FIRBUILDER_H
17 #define FORTRAN_LOWER_FIRBUILDER_H
18 
19 #include "flang/Common/reference.h"
20 #include "flang/Optimizer/Dialect/FIROps.h"
21 #include "flang/Optimizer/Dialect/FIRType.h"
22 #include "flang/Optimizer/Support/KindMapping.h"
23 #include "mlir/IR/Builders.h"
24 #include "mlir/IR/BuiltinOps.h"
25 #include "llvm/ADT/DenseMap.h"
26 #include "llvm/ADT/Optional.h"
27 
28 namespace Fortran::lower {
29 
30 class AbstractConverter;
31 
32 //===----------------------------------------------------------------------===//
33 // FirOpBuilder
34 //===----------------------------------------------------------------------===//
35 
36 /// Extends the MLIR OpBuilder to provide methods for building common FIR
37 /// patterns.
38 class FirOpBuilder : public mlir::OpBuilder {
39 public:
FirOpBuilder(mlir::Operation * op,const fir::KindMapping & kindMap)40   explicit FirOpBuilder(mlir::Operation *op, const fir::KindMapping &kindMap)
41       : OpBuilder{op}, kindMap{kindMap} {}
42 
43   /// Get the current Region of the insertion point.
getRegion()44   mlir::Region &getRegion() { return *getBlock()->getParent(); }
45 
46   /// Get the current Module
getModule()47   mlir::ModuleOp getModule() {
48     return getRegion().getParentOfType<mlir::ModuleOp>();
49   }
50 
51   /// Get the current Function
getFunction()52   mlir::FuncOp getFunction() {
53     return getRegion().getParentOfType<mlir::FuncOp>();
54   }
55 
56   /// Get a reference to the kind map.
getKindMap()57   const fir::KindMapping &getKindMap() { return kindMap; }
58 
59   /// The LHS and RHS are not always in agreement in terms of
60   /// type. In some cases, the disagreement is between COMPLEX and other scalar
61   /// types. In that case, the conversion must insert/extract out of a COMPLEX
62   /// value to have the proper semantics and be strongly typed.
63   mlir::Value convertWithSemantics(mlir::Location loc, mlir::Type toTy,
64                                    mlir::Value val);
65 
66   /// Get the entry block of the current Function
getEntryBlock()67   mlir::Block *getEntryBlock() { return &getFunction().front(); }
68 
69   /// Safely create a reference type to the type `eleTy`.
70   mlir::Type getRefType(mlir::Type eleTy);
71 
72   /// Create a null constant of type RefType and value 0. Need to pass in the
73   /// Location information.
74   mlir::Value createNullConstant(mlir::Location loc);
75 
76   /// Create an integer constant of type \p type and value \p i.
77   mlir::Value createIntegerConstant(mlir::Location loc, mlir::Type integerType,
78                                     std::int64_t i);
79 
80   mlir::Value createRealConstant(mlir::Location loc, mlir::Type realType,
81                                  const llvm::APFloat &val);
82   /// Create a real constant of type \p realType with a value zero.
83   mlir::Value createRealZeroConstant(mlir::Location loc, mlir::Type realType);
84 
85   /// Create a slot for a local on the stack. Besides the variable's type and
86   /// shape, it may be given name or target attributes.
87   mlir::Value allocateLocal(mlir::Location loc, mlir::Type ty,
88                             llvm::StringRef nm,
89                             llvm::ArrayRef<mlir::Value> shape,
90                             bool asTarget = false);
91 
92   /// Create a temporary. A temp is allocated using `fir.alloca` and can be read
93   /// and written using `fir.load` and `fir.store`, resp.  The temporary can be
94   /// given a name via a front-end `Symbol` or a `StringRef`.
95   mlir::Value createTemporary(mlir::Location loc, mlir::Type type,
96                               llvm::StringRef name = {},
97                               llvm::ArrayRef<mlir::Value> shape = {});
98 
99   /// Create an unnamed and untracked temporary on the stack.
createTemporary(mlir::Location loc,mlir::Type type,llvm::ArrayRef<mlir::Value> shape)100   mlir::Value createTemporary(mlir::Location loc, mlir::Type type,
101                               llvm::ArrayRef<mlir::Value> shape) {
102     return createTemporary(loc, type, llvm::StringRef{}, shape);
103   }
104 
105   /// Create a global value.
106   fir::GlobalOp createGlobal(mlir::Location loc, mlir::Type type,
107                              llvm::StringRef name,
108                              mlir::StringAttr linkage = {},
109                              mlir::Attribute value = {}, bool isConst = false);
110 
111   fir::GlobalOp createGlobal(mlir::Location loc, mlir::Type type,
112                              llvm::StringRef name, bool isConst,
113                              std::function<void(FirOpBuilder &)> bodyBuilder,
114                              mlir::StringAttr linkage = {});
115 
116   /// Create a global constant (read-only) value.
117   fir::GlobalOp createGlobalConstant(mlir::Location loc, mlir::Type type,
118                                      llvm::StringRef name,
119                                      mlir::StringAttr linkage = {},
120                                      mlir::Attribute value = {}) {
121     return createGlobal(loc, type, name, linkage, value, /*isConst=*/true);
122   }
123 
124   fir::GlobalOp
125   createGlobalConstant(mlir::Location loc, mlir::Type type,
126                        llvm::StringRef name,
127                        std::function<void(FirOpBuilder &)> bodyBuilder,
128                        mlir::StringAttr linkage = {}) {
129     return createGlobal(loc, type, name, /*isConst=*/true, bodyBuilder,
130                         linkage);
131   }
132 
133   /// Convert a StringRef string into a fir::StringLitOp.
134   fir::StringLitOp createStringLit(mlir::Location loc, mlir::Type eleTy,
135                                    llvm::StringRef string);
136 
137   /// Get a function by name. If the function exists in the current module, it
138   /// is returned. Otherwise, a null FuncOp is returned.
getNamedFunction(llvm::StringRef name)139   mlir::FuncOp getNamedFunction(llvm::StringRef name) {
140     return getNamedFunction(getModule(), name);
141   }
142 
143   static mlir::FuncOp getNamedFunction(mlir::ModuleOp module,
144                                        llvm::StringRef name);
145 
getNamedGlobal(llvm::StringRef name)146   fir::GlobalOp getNamedGlobal(llvm::StringRef name) {
147     return getNamedGlobal(getModule(), name);
148   }
149 
150   static fir::GlobalOp getNamedGlobal(mlir::ModuleOp module,
151                                       llvm::StringRef name);
152 
153   /// Lazy creation of fir.convert op.
154   mlir::Value createConvert(mlir::Location loc, mlir::Type toTy,
155                             mlir::Value val);
156 
157   /// Create a new FuncOp. If the function may have already been created, use
158   /// `addNamedFunction` instead.
createFunction(mlir::Location loc,llvm::StringRef name,mlir::FunctionType ty)159   mlir::FuncOp createFunction(mlir::Location loc, llvm::StringRef name,
160                               mlir::FunctionType ty) {
161     return createFunction(loc, getModule(), name, ty);
162   }
163 
164   static mlir::FuncOp createFunction(mlir::Location loc, mlir::ModuleOp module,
165                                      llvm::StringRef name,
166                                      mlir::FunctionType ty);
167 
168   /// Determine if the named function is already in the module. Return the
169   /// instance if found, otherwise add a new named function to the module.
addNamedFunction(mlir::Location loc,llvm::StringRef name,mlir::FunctionType ty)170   mlir::FuncOp addNamedFunction(mlir::Location loc, llvm::StringRef name,
171                                 mlir::FunctionType ty) {
172     if (auto func = getNamedFunction(name))
173       return func;
174     return createFunction(loc, name, ty);
175   }
176 
addNamedFunction(mlir::Location loc,mlir::ModuleOp module,llvm::StringRef name,mlir::FunctionType ty)177   static mlir::FuncOp addNamedFunction(mlir::Location loc,
178                                        mlir::ModuleOp module,
179                                        llvm::StringRef name,
180                                        mlir::FunctionType ty) {
181     if (auto func = getNamedFunction(module, name))
182       return func;
183     return createFunction(loc, module, name, ty);
184   }
185 
186   /// Cast the input value to IndexType.
convertToIndexType(mlir::Location loc,mlir::Value val)187   mlir::Value convertToIndexType(mlir::Location loc, mlir::Value val) {
188     return createConvert(loc, getIndexType(), val);
189   }
190 
191 private:
192   const fir::KindMapping &kindMap;
193 };
194 
195 } // namespace Fortran::lower
196 
197 #endif // FORTRAN_LOWER_FIRBUILDER_H
198