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