Warning: This file is not a C or C++ file. It does not have highlighting.
| 1 | //===-- 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_OPTIMIZER_BUILDER_FIRBUILDER_H |
| 17 | #define FORTRAN_OPTIMIZER_BUILDER_FIRBUILDER_H |
| 18 | |
| 19 | #include "flang/Optimizer/Dialect/FIROps.h" |
| 20 | #include "flang/Optimizer/Dialect/FIROpsSupport.h" |
| 21 | #include "flang/Optimizer/Dialect/FIRType.h" |
| 22 | #include "flang/Optimizer/Dialect/Support/FIRContext.h" |
| 23 | #include "flang/Optimizer/Dialect/Support/KindMapping.h" |
| 24 | #include "flang/Support/MathOptionsBase.h" |
| 25 | #include "mlir/IR/Builders.h" |
| 26 | #include "mlir/IR/BuiltinOps.h" |
| 27 | #include "llvm/ADT/DenseMap.h" |
| 28 | #include <optional> |
| 29 | #include <utility> |
| 30 | |
| 31 | namespace mlir { |
| 32 | class DataLayout; |
| 33 | class SymbolTable; |
| 34 | } |
| 35 | |
| 36 | namespace fir { |
| 37 | class AbstractArrayBox; |
| 38 | class ExtendedValue; |
| 39 | class MutableBoxValue; |
| 40 | class BoxValue; |
| 41 | |
| 42 | /// Get the integer type with a pointer size. |
| 43 | inline mlir::Type getIntPtrType(mlir::OpBuilder &builder) { |
| 44 | // TODO: Delay the need of such type until codegen or find a way to use |
| 45 | // llvm::DataLayout::getPointerSizeInBits here. |
| 46 | return builder.getI64Type(); |
| 47 | } |
| 48 | |
| 49 | //===----------------------------------------------------------------------===// |
| 50 | // FirOpBuilder |
| 51 | //===----------------------------------------------------------------------===// |
| 52 | |
| 53 | /// Extends the MLIR OpBuilder to provide methods for building common FIR |
| 54 | /// patterns. |
| 55 | class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener { |
| 56 | public: |
| 57 | explicit FirOpBuilder(mlir::Operation *op, fir::KindMapping kindMap, |
| 58 | mlir::SymbolTable *symbolTable = nullptr) |
| 59 | : OpBuilder{op, /*listener=*/this}, kindMap{std::move(kindMap)}, |
| 60 | symbolTable{symbolTable} { |
| 61 | auto fmi = mlir::dyn_cast<mlir::arith::ArithFastMathInterface>(*op); |
| 62 | if (fmi) { |
| 63 | // Set the builder with FastMathFlags attached to the operation. |
| 64 | setFastMathFlags(fmi.getFastMathFlagsAttr().getValue()); |
| 65 | } |
| 66 | } |
| 67 | explicit FirOpBuilder(mlir::OpBuilder &builder, fir::KindMapping kindMap, |
| 68 | mlir::SymbolTable *symbolTable = nullptr) |
| 69 | : OpBuilder(builder), OpBuilder::Listener(), kindMap{std::move(kindMap)}, |
| 70 | symbolTable{symbolTable} { |
| 71 | setListener(this); |
| 72 | } |
| 73 | explicit FirOpBuilder(mlir::OpBuilder &builder, mlir::ModuleOp mod) |
| 74 | : OpBuilder(builder), OpBuilder::Listener(), |
| 75 | kindMap{getKindMapping(mod)} { |
| 76 | setListener(this); |
| 77 | } |
| 78 | explicit FirOpBuilder(mlir::OpBuilder &builder, fir::KindMapping kindMap, |
| 79 | mlir::Operation *op) |
| 80 | : OpBuilder(builder), OpBuilder::Listener(), kindMap{std::move(kindMap)} { |
| 81 | setListener(this); |
| 82 | auto fmi = mlir::dyn_cast<mlir::arith::ArithFastMathInterface>(*op); |
| 83 | if (fmi) { |
| 84 | // Set the builder with FastMathFlags attached to the operation. |
| 85 | setFastMathFlags(fmi.getFastMathFlagsAttr().getValue()); |
| 86 | } |
| 87 | } |
| 88 | FirOpBuilder(mlir::OpBuilder &builder, mlir::Operation *op) |
| 89 | : FirOpBuilder(builder, fir::getKindMapping(op), op) {} |
| 90 | |
| 91 | // The listener self-reference has to be updated in case of copy-construction. |
| 92 | FirOpBuilder(const FirOpBuilder &other) |
| 93 | : OpBuilder(other), OpBuilder::Listener(), kindMap{other.kindMap}, |
| 94 | fastMathFlags{other.fastMathFlags}, |
| 95 | integerOverflowFlags{other.integerOverflowFlags}, |
| 96 | symbolTable{other.symbolTable} { |
| 97 | setListener(this); |
| 98 | } |
| 99 | |
| 100 | FirOpBuilder(FirOpBuilder &&other) |
| 101 | : OpBuilder(other), OpBuilder::Listener(), |
| 102 | kindMap{std::move(other.kindMap)}, fastMathFlags{other.fastMathFlags}, |
| 103 | integerOverflowFlags{other.integerOverflowFlags}, |
| 104 | symbolTable{other.symbolTable} { |
| 105 | setListener(this); |
| 106 | } |
| 107 | |
| 108 | /// Get the current Region of the insertion point. |
| 109 | mlir::Region &getRegion() { return *getBlock()->getParent(); } |
| 110 | |
| 111 | /// Get the current Module |
| 112 | mlir::ModuleOp getModule() { |
| 113 | return getRegion().getParentOfType<mlir::ModuleOp>(); |
| 114 | } |
| 115 | |
| 116 | /// Get the current Function |
| 117 | mlir::func::FuncOp getFunction() { |
| 118 | return getRegion().getParentOfType<mlir::func::FuncOp>(); |
| 119 | } |
| 120 | |
| 121 | /// Get a reference to the kind map. |
| 122 | const fir::KindMapping &getKindMap() { return kindMap; } |
| 123 | |
| 124 | /// Get func.func/fir.global symbol table attached to this builder if any. |
| 125 | mlir::SymbolTable *getMLIRSymbolTable() { return symbolTable; } |
| 126 | |
| 127 | /// Get the default integer type |
| 128 | [[maybe_unused]] mlir::IntegerType getDefaultIntegerType() { |
| 129 | return getIntegerType( |
| 130 | getKindMap().getIntegerBitsize(getKindMap().defaultIntegerKind())); |
| 131 | } |
| 132 | |
| 133 | /// The LHS and RHS are not always in agreement in terms of type. In some |
| 134 | /// cases, the disagreement is between COMPLEX and other scalar types. In that |
| 135 | /// case, the conversion must insert (extract) out of a COMPLEX value to have |
| 136 | /// the proper semantics and be strongly typed. E.g., converting an integer |
| 137 | /// (real) to a complex, the real part is filled using the integer (real) |
| 138 | /// after type conversion and the imaginary part is zero. |
| 139 | mlir::Value convertWithSemantics(mlir::Location loc, mlir::Type toTy, |
| 140 | mlir::Value val, |
| 141 | bool allowCharacterConversion = false, |
| 142 | bool allowRebox = false); |
| 143 | |
| 144 | /// Get the entry block of the current Function |
| 145 | mlir::Block *getEntryBlock() { return &getFunction().front(); } |
| 146 | |
| 147 | /// Get the block for adding Allocas. If OpenMP is enabled then get the |
| 148 | /// the alloca block from an Operation which can be Outlined. Otherwise |
| 149 | /// use the entry block of the current Function |
| 150 | mlir::Block *getAllocaBlock(); |
| 151 | |
| 152 | /// Safely create a reference type to the type `eleTy`. |
| 153 | mlir::Type getRefType(mlir::Type eleTy, bool isVolatile = false); |
| 154 | |
| 155 | /// Create a sequence of `eleTy` with `rank` dimensions of unknown size. |
| 156 | mlir::Type getVarLenSeqTy(mlir::Type eleTy, unsigned rank = 1); |
| 157 | |
| 158 | /// Get character length type. |
| 159 | mlir::Type getCharacterLengthType() { return getIndexType(); } |
| 160 | |
| 161 | /// Get the integer type whose bit width corresponds to the width of pointer |
| 162 | /// types, or is bigger. |
| 163 | mlir::Type getIntPtrType() { return fir::getIntPtrType(*this); } |
| 164 | |
| 165 | /// Wrap `str` to a SymbolRefAttr. |
| 166 | mlir::SymbolRefAttr getSymbolRefAttr(llvm::StringRef str) { |
| 167 | return mlir::SymbolRefAttr::get(getContext(), str); |
| 168 | } |
| 169 | |
| 170 | /// Get the mlir float type that implements Fortran REAL(kind). |
| 171 | mlir::Type getRealType(int kind); |
| 172 | |
| 173 | fir::BoxProcType getBoxProcType(mlir::FunctionType funcTy) { |
| 174 | return fir::BoxProcType::get(getContext(), funcTy); |
| 175 | } |
| 176 | |
| 177 | /// Create a null constant memory reference of type \p ptrType. |
| 178 | /// If \p ptrType is not provided, !fir.ref<none> type will be used. |
| 179 | mlir::Value createNullConstant(mlir::Location loc, mlir::Type ptrType = {}); |
| 180 | |
| 181 | /// Create an integer constant of type \p type and value \p i. |
| 182 | /// Should not be used with negative values with integer types of more |
| 183 | /// than 64 bits. |
| 184 | mlir::Value createIntegerConstant(mlir::Location loc, mlir::Type integerType, |
| 185 | std::int64_t i); |
| 186 | |
| 187 | /// Create an integer of \p integerType where all the bits have been set to |
| 188 | /// ones. Safe to use regardless of integerType bitwidth. |
| 189 | mlir::Value createAllOnesInteger(mlir::Location loc, mlir::Type integerType); |
| 190 | |
| 191 | /// Create -1 constant of \p integerType. Safe to use regardless of |
| 192 | /// integerType bitwidth. |
| 193 | mlir::Value createMinusOneInteger(mlir::Location loc, |
| 194 | mlir::Type integerType) { |
| 195 | return createAllOnesInteger(loc, integerType); |
| 196 | } |
| 197 | |
| 198 | /// Create a real constant from an integer value. |
| 199 | mlir::Value createRealConstant(mlir::Location loc, mlir::Type realType, |
| 200 | llvm::APFloat::integerPart val); |
| 201 | |
| 202 | /// Create a real constant from an APFloat value. |
| 203 | mlir::Value createRealConstant(mlir::Location loc, mlir::Type realType, |
| 204 | const llvm::APFloat &val); |
| 205 | |
| 206 | /// Create a real constant of type \p realType with a value zero. |
| 207 | mlir::Value createRealZeroConstant(mlir::Location loc, mlir::Type realType) { |
| 208 | return createRealConstant(loc, realType, 0u); |
| 209 | } |
| 210 | |
| 211 | /// Create a slot for a local on the stack. Besides the variable's type and |
| 212 | /// shape, it may be given name, pinned, or target attributes. |
| 213 | mlir::Value allocateLocal(mlir::Location loc, mlir::Type ty, |
| 214 | llvm::StringRef uniqName, llvm::StringRef name, |
| 215 | bool pinned, llvm::ArrayRef<mlir::Value> shape, |
| 216 | llvm::ArrayRef<mlir::Value> lenParams, |
| 217 | bool asTarget = false); |
| 218 | mlir::Value allocateLocal(mlir::Location loc, mlir::Type ty, |
| 219 | llvm::StringRef uniqName, llvm::StringRef name, |
| 220 | llvm::ArrayRef<mlir::Value> shape, |
| 221 | llvm::ArrayRef<mlir::Value> lenParams, |
| 222 | bool asTarget = false); |
| 223 | |
| 224 | /// Create a two dimensional ArrayAttr containing integer data as |
| 225 | /// IntegerAttrs, effectively: ArrayAttr<ArrayAttr<IntegerAttr>>>. |
| 226 | mlir::ArrayAttr create2DI64ArrayAttr( |
| 227 | llvm::SmallVectorImpl<llvm::SmallVector<int64_t>> &intData); |
| 228 | |
| 229 | /// Create a temporary using `fir.alloca`. This function does not hoist. |
| 230 | /// It is the callers responsibility to set the insertion point if |
| 231 | /// hoisting is required. |
| 232 | mlir::Value createTemporaryAlloc( |
| 233 | mlir::Location loc, mlir::Type type, llvm::StringRef name, |
| 234 | mlir::ValueRange lenParams = {}, mlir::ValueRange shape = {}, |
| 235 | llvm::ArrayRef<mlir::NamedAttribute> attrs = {}, |
| 236 | std::optional<Fortran::common::CUDADataAttr> cudaAttr = std::nullopt); |
| 237 | |
| 238 | /// Create a temporary. A temp is allocated using `fir.alloca` and can be read |
| 239 | /// and written using `fir.load` and `fir.store`, resp. The temporary can be |
| 240 | /// given a name via a front-end `Symbol` or a `StringRef`. |
| 241 | mlir::Value createTemporary( |
| 242 | mlir::Location loc, mlir::Type type, llvm::StringRef name = {}, |
| 243 | mlir::ValueRange shape = {}, mlir::ValueRange lenParams = {}, |
| 244 | llvm::ArrayRef<mlir::NamedAttribute> attrs = {}, |
| 245 | std::optional<Fortran::common::CUDADataAttr> cudaAttr = std::nullopt); |
| 246 | |
| 247 | /// Create an unnamed and untracked temporary on the stack. |
| 248 | mlir::Value createTemporary(mlir::Location loc, mlir::Type type, |
| 249 | mlir::ValueRange shape) { |
| 250 | return createTemporary(loc, type, llvm::StringRef{}, shape); |
| 251 | } |
| 252 | |
| 253 | mlir::Value createTemporary(mlir::Location loc, mlir::Type type, |
| 254 | llvm::ArrayRef<mlir::NamedAttribute> attrs) { |
| 255 | return createTemporary(loc, type, llvm::StringRef{}, {}, {}, attrs); |
| 256 | } |
| 257 | |
| 258 | mlir::Value createTemporary(mlir::Location loc, mlir::Type type, |
| 259 | llvm::StringRef name, |
| 260 | llvm::ArrayRef<mlir::NamedAttribute> attrs) { |
| 261 | return createTemporary(loc, type, name, {}, {}, attrs); |
| 262 | } |
| 263 | |
| 264 | /// Create a temporary on the heap. |
| 265 | mlir::Value |
| 266 | createHeapTemporary(mlir::Location loc, mlir::Type type, |
| 267 | llvm::StringRef name = {}, mlir::ValueRange shape = {}, |
| 268 | mlir::ValueRange lenParams = {}, |
| 269 | llvm::ArrayRef<mlir::NamedAttribute> attrs = {}); |
| 270 | |
| 271 | /// Sample genDeclare callback for createArrayTemp() below. |
| 272 | /// It creates fir.declare operation using the given operands. |
| 273 | /// \p memref is the base of the allocated temporary, |
| 274 | /// which may be !fir.ref<!fir.array<>> or !fir.box/class<>. |
| 275 | static mlir::Value genTempDeclareOp(fir::FirOpBuilder &builder, |
| 276 | mlir::Location loc, mlir::Value memref, |
| 277 | llvm::StringRef name, mlir::Value shape, |
| 278 | llvm::ArrayRef<mlir::Value> typeParams, |
| 279 | fir::FortranVariableFlagsAttr attrs); |
| 280 | |
| 281 | /// Create a temporary with the given \p baseType, |
| 282 | /// \p shape, \p extents and \p typeParams. An optional |
| 283 | /// \p polymorphicMold specifies the entity which dynamic type |
| 284 | /// has to be used for the allocation. |
| 285 | /// \p genDeclare callback generates a declare operation |
| 286 | /// for the created temporary. FIR passes may use genTempDeclareOp() |
| 287 | /// function above that creates fir.declare. |
| 288 | /// HLFIR passes may provide their own callback that generates |
| 289 | /// hlfir.declare. Some passes may provide a callback that |
| 290 | /// just passes through the base of the temporary. |
| 291 | /// If \p useStack is true, the function will try to do the allocation |
| 292 | /// in stack memory (which is not always possible currently). |
| 293 | /// The first return value is the base of the temporary object, |
| 294 | /// which may be !fir.ref<!fir.array<>> or !fir.box/class<>. |
| 295 | /// The second return value is true, if the actual allocation |
| 296 | /// was done in heap memory. |
| 297 | std::pair<mlir::Value, bool> createAndDeclareTemp( |
| 298 | mlir::Location loc, mlir::Type baseType, mlir::Value shape, |
| 299 | llvm::ArrayRef<mlir::Value> extents, |
| 300 | llvm::ArrayRef<mlir::Value> typeParams, |
| 301 | const std::function<decltype(genTempDeclareOp)> &genDeclare, |
| 302 | mlir::Value polymorphicMold, bool useStack, llvm::StringRef tmpName); |
| 303 | /// Create and declare an array temporary. |
| 304 | std::pair<mlir::Value, bool> |
| 305 | createArrayTemp(mlir::Location loc, fir::SequenceType arrayType, |
| 306 | mlir::Value shape, llvm::ArrayRef<mlir::Value> extents, |
| 307 | llvm::ArrayRef<mlir::Value> typeParams, |
| 308 | const std::function<decltype(genTempDeclareOp)> &genDeclare, |
| 309 | mlir::Value polymorphicMold, bool useStack = false, |
| 310 | llvm::StringRef tmpName = ".tmp.array") { |
| 311 | return createAndDeclareTemp(loc, arrayType, shape, extents, typeParams, |
| 312 | genDeclare, polymorphicMold, useStack, tmpName); |
| 313 | } |
| 314 | |
| 315 | /// Create an LLVM stack save intrinsic op. Returns the saved stack pointer. |
| 316 | /// The stack address space is fetched from the data layout of the current |
| 317 | /// module. |
| 318 | mlir::Value genStackSave(mlir::Location loc); |
| 319 | |
| 320 | /// Create an LLVM stack restore intrinsic op. stackPointer should be a value |
| 321 | /// previously returned from genStackSave. |
| 322 | void genStackRestore(mlir::Location loc, mlir::Value stackPointer); |
| 323 | |
| 324 | /// Create a global value. |
| 325 | fir::GlobalOp createGlobal(mlir::Location loc, mlir::Type type, |
| 326 | llvm::StringRef name, |
| 327 | mlir::StringAttr linkage = {}, |
| 328 | mlir::Attribute value = {}, bool isConst = false, |
| 329 | bool isTarget = false, |
| 330 | cuf::DataAttributeAttr dataAttr = {}); |
| 331 | |
| 332 | fir::GlobalOp createGlobal(mlir::Location loc, mlir::Type type, |
| 333 | llvm::StringRef name, bool isConst, bool isTarget, |
| 334 | std::function<void(FirOpBuilder &)> bodyBuilder, |
| 335 | mlir::StringAttr linkage = {}, |
| 336 | cuf::DataAttributeAttr dataAttr = {}); |
| 337 | |
| 338 | /// Create a global constant (read-only) value. |
| 339 | fir::GlobalOp createGlobalConstant(mlir::Location loc, mlir::Type type, |
| 340 | llvm::StringRef name, |
| 341 | mlir::StringAttr linkage = {}, |
| 342 | mlir::Attribute value = {}) { |
| 343 | return createGlobal(loc, type, name, linkage, value, /*isConst=*/true, |
| 344 | /*isTarget=*/false); |
| 345 | } |
| 346 | |
| 347 | fir::GlobalOp |
| 348 | createGlobalConstant(mlir::Location loc, mlir::Type type, |
| 349 | llvm::StringRef name, |
| 350 | std::function<void(FirOpBuilder &)> bodyBuilder, |
| 351 | mlir::StringAttr linkage = {}) { |
| 352 | return createGlobal(loc, type, name, /*isConst=*/true, /*isTarget=*/false, |
| 353 | bodyBuilder, linkage); |
| 354 | } |
| 355 | |
| 356 | /// Convert a StringRef string into a fir::StringLitOp. |
| 357 | fir::StringLitOp createStringLitOp(mlir::Location loc, |
| 358 | llvm::StringRef string); |
| 359 | |
| 360 | std::pair<fir::TypeInfoOp, mlir::OpBuilder::InsertPoint> |
| 361 | createTypeInfoOp(mlir::Location loc, fir::RecordType recordType, |
| 362 | fir::RecordType parentType); |
| 363 | |
| 364 | //===--------------------------------------------------------------------===// |
| 365 | // Linkage helpers (inline). The default linkage is external. |
| 366 | //===--------------------------------------------------------------------===// |
| 367 | |
| 368 | mlir::StringAttr createCommonLinkage() { return getStringAttr("common"); } |
| 369 | |
| 370 | mlir::StringAttr createInternalLinkage() { return getStringAttr("internal"); } |
| 371 | |
| 372 | mlir::StringAttr createLinkOnceLinkage() { return getStringAttr("linkonce"); } |
| 373 | |
| 374 | mlir::StringAttr createLinkOnceODRLinkage() { |
| 375 | return getStringAttr("linkonce_odr"); |
| 376 | } |
| 377 | |
| 378 | mlir::StringAttr createWeakLinkage() { return getStringAttr("weak"); } |
| 379 | |
| 380 | /// Get a function by name. If the function exists in the current module, it |
| 381 | /// is returned. Otherwise, a null FuncOp is returned. |
| 382 | mlir::func::FuncOp getNamedFunction(llvm::StringRef name) { |
| 383 | return getNamedFunction(getModule(), getMLIRSymbolTable(), name); |
| 384 | } |
| 385 | static mlir::func::FuncOp |
| 386 | getNamedFunction(mlir::ModuleOp module, const mlir::SymbolTable *symbolTable, |
| 387 | llvm::StringRef name); |
| 388 | |
| 389 | /// Get a function by symbol name. The result will be null if there is no |
| 390 | /// function with the given symbol in the module. |
| 391 | mlir::func::FuncOp getNamedFunction(mlir::SymbolRefAttr symbol) { |
| 392 | return getNamedFunction(getModule(), getMLIRSymbolTable(), symbol); |
| 393 | } |
| 394 | static mlir::func::FuncOp |
| 395 | getNamedFunction(mlir::ModuleOp module, const mlir::SymbolTable *symbolTable, |
| 396 | mlir::SymbolRefAttr symbol); |
| 397 | |
| 398 | fir::GlobalOp getNamedGlobal(llvm::StringRef name) { |
| 399 | return getNamedGlobal(getModule(), getMLIRSymbolTable(), name); |
| 400 | } |
| 401 | |
| 402 | static fir::GlobalOp getNamedGlobal(mlir::ModuleOp module, |
| 403 | const mlir::SymbolTable *symbolTable, |
| 404 | llvm::StringRef name); |
| 405 | |
| 406 | /// Lazy creation of fir.convert op. |
| 407 | mlir::Value createConvert(mlir::Location loc, mlir::Type toTy, |
| 408 | mlir::Value val); |
| 409 | |
| 410 | /// Create a fir.convert op with a volatile cast if the source value's type |
| 411 | /// does not match the target type's volatility. |
| 412 | mlir::Value createConvertWithVolatileCast(mlir::Location loc, mlir::Type toTy, |
| 413 | mlir::Value val); |
| 414 | |
| 415 | /// Cast \p value to have \p isVolatile volatility. |
| 416 | mlir::Value createVolatileCast(mlir::Location loc, bool isVolatile, |
| 417 | mlir::Value value); |
| 418 | |
| 419 | /// Create a fir.store of \p val into \p addr. A lazy conversion |
| 420 | /// of \p val to the element type of \p addr is created if needed. |
| 421 | void createStoreWithConvert(mlir::Location loc, mlir::Value val, |
| 422 | mlir::Value addr); |
| 423 | |
| 424 | /// Create a fir.load if \p val is a reference or pointer type. Return the |
| 425 | /// result of the load if it was created, otherwise return \p val |
| 426 | mlir::Value loadIfRef(mlir::Location loc, mlir::Value val); |
| 427 | |
| 428 | /// Determine if the named function is already in the module. Return the |
| 429 | /// instance if found, otherwise add a new named function to the module. |
| 430 | mlir::func::FuncOp createFunction(mlir::Location loc, llvm::StringRef name, |
| 431 | mlir::FunctionType ty) { |
| 432 | return createFunction(loc, getModule(), name, ty, getMLIRSymbolTable()); |
| 433 | } |
| 434 | |
| 435 | static mlir::func::FuncOp createFunction(mlir::Location loc, |
| 436 | mlir::ModuleOp module, |
| 437 | llvm::StringRef name, |
| 438 | mlir::FunctionType ty, |
| 439 | mlir::SymbolTable *); |
| 440 | |
| 441 | /// Returns a named function for a Fortran runtime API, creating |
| 442 | /// it, if it does not exist in the module yet. |
| 443 | /// If \p isIO is set to true, then the function corresponds |
| 444 | /// to one of Fortran runtime IO APIs. |
| 445 | mlir::func::FuncOp createRuntimeFunction(mlir::Location loc, |
| 446 | llvm::StringRef name, |
| 447 | mlir::FunctionType ty, |
| 448 | bool isIO = false); |
| 449 | |
| 450 | /// Cast the input value to IndexType. |
| 451 | mlir::Value convertToIndexType(mlir::Location loc, mlir::Value val) { |
| 452 | return createConvert(loc, getIndexType(), val); |
| 453 | } |
| 454 | |
| 455 | /// Construct one of the two forms of shape op from an array box. |
| 456 | mlir::Value genShape(mlir::Location loc, const fir::AbstractArrayBox &arr); |
| 457 | mlir::Value genShape(mlir::Location loc, llvm::ArrayRef<mlir::Value> shift, |
| 458 | llvm::ArrayRef<mlir::Value> exts); |
| 459 | mlir::Value genShape(mlir::Location loc, llvm::ArrayRef<mlir::Value> exts); |
| 460 | mlir::Value genShift(mlir::Location loc, llvm::ArrayRef<mlir::Value> shift); |
| 461 | |
| 462 | /// Create one of the shape ops given an extended value. For a boxed value, |
| 463 | /// this may create a `fir.shift` op. |
| 464 | mlir::Value createShape(mlir::Location loc, const fir::ExtendedValue &exv); |
| 465 | |
| 466 | /// Create a slice op extended value. The value to be sliced, `exv`, must be |
| 467 | /// an array. |
| 468 | mlir::Value createSlice(mlir::Location loc, const fir::ExtendedValue &exv, |
| 469 | mlir::ValueRange triples, mlir::ValueRange path); |
| 470 | |
| 471 | /// Create a boxed value (Fortran descriptor) to be passed to the runtime. |
| 472 | /// \p exv is an extended value holding a memory reference to the object that |
| 473 | /// must be boxed. This function will crash if provided something that is not |
| 474 | /// a memory reference type. |
| 475 | /// Array entities are boxed with a shape and possibly a shift. Character |
| 476 | /// entities are boxed with a LEN parameter. |
| 477 | mlir::Value createBox(mlir::Location loc, const fir::ExtendedValue &exv, |
| 478 | bool isPolymorphic = false, bool isAssumedType = false); |
| 479 | |
| 480 | mlir::Value createBox(mlir::Location loc, mlir::Type boxType, |
| 481 | mlir::Value addr, mlir::Value shape, mlir::Value slice, |
| 482 | llvm::ArrayRef<mlir::Value> lengths, mlir::Value tdesc); |
| 483 | |
| 484 | /// Create constant i1 with value 1. if \p b is true or 0. otherwise |
| 485 | mlir::Value createBool(mlir::Location loc, bool b) { |
| 486 | return createIntegerConstant(loc, getIntegerType(1), b ? 1 : 0); |
| 487 | } |
| 488 | |
| 489 | //===--------------------------------------------------------------------===// |
| 490 | // If-Then-Else generation helper |
| 491 | //===--------------------------------------------------------------------===// |
| 492 | |
| 493 | /// Helper class to create if-then-else in a structured way: |
| 494 | /// Usage: genIfOp().genThen([&](){...}).genElse([&](){...}).end(); |
| 495 | /// Alternatively, getResults() can be used instead of end() to end the ifOp |
| 496 | /// and get the ifOp results. |
| 497 | class IfBuilder { |
| 498 | public: |
| 499 | IfBuilder(fir::IfOp ifOp, FirOpBuilder &builder) |
| 500 | : ifOp{ifOp}, builder{builder} {} |
| 501 | template <typename CC> |
| 502 | IfBuilder &genThen(CC func) { |
| 503 | builder.setInsertionPointToStart(&ifOp.getThenRegion().front()); |
| 504 | func(); |
| 505 | return *this; |
| 506 | } |
| 507 | template <typename CC> |
| 508 | IfBuilder &genElse(CC func) { |
| 509 | assert(!ifOp.getElseRegion().empty() && "must have else region"); |
| 510 | builder.setInsertionPointToStart(&ifOp.getElseRegion().front()); |
| 511 | func(); |
| 512 | return *this; |
| 513 | } |
| 514 | void end() { builder.setInsertionPointAfter(ifOp); } |
| 515 | |
| 516 | /// End the IfOp and return the results if any. |
| 517 | mlir::Operation::result_range getResults() { |
| 518 | end(); |
| 519 | return ifOp.getResults(); |
| 520 | } |
| 521 | |
| 522 | fir::IfOp &getIfOp() { return ifOp; }; |
| 523 | |
| 524 | private: |
| 525 | fir::IfOp ifOp; |
| 526 | FirOpBuilder &builder; |
| 527 | }; |
| 528 | |
| 529 | /// Create an IfOp and returns an IfBuilder that can generate the else/then |
| 530 | /// bodies. |
| 531 | IfBuilder genIfOp(mlir::Location loc, mlir::TypeRange results, |
| 532 | mlir::Value cdt, bool withElseRegion) { |
| 533 | auto op = create<fir::IfOp>(loc, results, cdt, withElseRegion); |
| 534 | return IfBuilder(op, *this); |
| 535 | } |
| 536 | |
| 537 | /// Create an IfOp with no "else" region, and no result values. |
| 538 | /// Usage: genIfThen(loc, cdt).genThen(lambda).end(); |
| 539 | IfBuilder genIfThen(mlir::Location loc, mlir::Value cdt) { |
| 540 | auto op = create<fir::IfOp>(loc, std::nullopt, cdt, false); |
| 541 | return IfBuilder(op, *this); |
| 542 | } |
| 543 | |
| 544 | /// Create an IfOp with an "else" region, and no result values. |
| 545 | /// Usage: genIfThenElse(loc, cdt).genThen(lambda).genElse(lambda).end(); |
| 546 | IfBuilder genIfThenElse(mlir::Location loc, mlir::Value cdt) { |
| 547 | auto op = create<fir::IfOp>(loc, std::nullopt, cdt, true); |
| 548 | return IfBuilder(op, *this); |
| 549 | } |
| 550 | |
| 551 | mlir::Value genNot(mlir::Location loc, mlir::Value boolean) { |
| 552 | return create<mlir::arith::CmpIOp>(loc, mlir::arith::CmpIPredicate::eq, |
| 553 | boolean, createBool(loc, false)); |
| 554 | } |
| 555 | |
| 556 | /// Generate code testing \p addr is not a null address. |
| 557 | mlir::Value genIsNotNullAddr(mlir::Location loc, mlir::Value addr); |
| 558 | |
| 559 | /// Generate code testing \p addr is a null address. |
| 560 | mlir::Value genIsNullAddr(mlir::Location loc, mlir::Value addr); |
| 561 | |
| 562 | /// Compute the extent of (lb:ub:step) as max((ub-lb+step)/step, 0). See |
| 563 | /// Fortran 2018 9.5.3.3.2 section for more details. |
| 564 | mlir::Value genExtentFromTriplet(mlir::Location loc, mlir::Value lb, |
| 565 | mlir::Value ub, mlir::Value step, |
| 566 | mlir::Type type); |
| 567 | |
| 568 | /// Create an AbsentOp of \p argTy type and handle special cases, such as |
| 569 | /// Character Procedure Tuple arguments. |
| 570 | mlir::Value genAbsentOp(mlir::Location loc, mlir::Type argTy); |
| 571 | |
| 572 | /// Set default FastMathFlags value for all operations |
| 573 | /// supporting mlir::arith::FastMathAttr that will be created |
| 574 | /// by this builder. |
| 575 | void setFastMathFlags(mlir::arith::FastMathFlags flags) { |
| 576 | fastMathFlags = flags; |
| 577 | } |
| 578 | |
| 579 | /// Set default FastMathFlags value from the passed MathOptionsBase |
| 580 | /// config. |
| 581 | void setFastMathFlags(Fortran::common::MathOptionsBase options); |
| 582 | |
| 583 | /// Get current FastMathFlags value. |
| 584 | mlir::arith::FastMathFlags getFastMathFlags() const { return fastMathFlags; } |
| 585 | |
| 586 | /// Stringify FastMathFlags set in a way |
| 587 | /// that the string may be used for mangling a function name. |
| 588 | /// If FastMathFlags are set to 'none', then the result is an empty |
| 589 | /// string. |
| 590 | std::string getFastMathFlagsString() { |
| 591 | mlir::arith::FastMathFlags flags = getFastMathFlags(); |
| 592 | if (flags == mlir::arith::FastMathFlags::none) |
| 593 | return {}; |
| 594 | |
| 595 | std::string fmfString{mlir::arith::stringifyFastMathFlags(flags)}; |
| 596 | std::replace(fmfString.begin(), fmfString.end(), ',', '_'); |
| 597 | return fmfString; |
| 598 | } |
| 599 | |
| 600 | /// Set default IntegerOverflowFlags value for all operations |
| 601 | /// supporting mlir::arith::IntegerOverflowFlagsAttr that will be created |
| 602 | /// by this builder. |
| 603 | void setIntegerOverflowFlags(mlir::arith::IntegerOverflowFlags flags) { |
| 604 | integerOverflowFlags = flags; |
| 605 | } |
| 606 | |
| 607 | /// Get current IntegerOverflowFlags value. |
| 608 | mlir::arith::IntegerOverflowFlags getIntegerOverflowFlags() const { |
| 609 | return integerOverflowFlags; |
| 610 | } |
| 611 | |
| 612 | /// Dump the current function. (debug) |
| 613 | LLVM_DUMP_METHOD void dumpFunc(); |
| 614 | |
| 615 | /// FirOpBuilder hook for creating new operation. |
| 616 | void notifyOperationInserted(mlir::Operation *op, |
| 617 | mlir::OpBuilder::InsertPoint previous) override { |
| 618 | // We only care about newly created operations. |
| 619 | if (previous.isSet()) |
| 620 | return; |
| 621 | setCommonAttributes(op); |
| 622 | } |
| 623 | |
| 624 | /// Construct a data layout on demand and return it |
| 625 | mlir::DataLayout &getDataLayout(); |
| 626 | |
| 627 | /// Convert operands &/or result from/to unsigned so that the operation |
| 628 | /// only receives/produces signless operands. |
| 629 | template <typename OpTy> |
| 630 | mlir::Value createUnsigned(mlir::Location loc, mlir::Type resultType, |
| 631 | mlir::Value left, mlir::Value right) { |
| 632 | if (!resultType.isIntOrFloat()) |
| 633 | return create<OpTy>(loc, resultType, left, right); |
| 634 | mlir::Type signlessType = mlir::IntegerType::get( |
| 635 | getContext(), resultType.getIntOrFloatBitWidth(), |
| 636 | mlir::IntegerType::SignednessSemantics::Signless); |
| 637 | mlir::Type opResType = resultType; |
| 638 | if (left.getType().isUnsignedInteger()) { |
| 639 | left = createConvert(loc, signlessType, left); |
| 640 | opResType = signlessType; |
| 641 | } |
| 642 | if (right.getType().isUnsignedInteger()) { |
| 643 | right = createConvert(loc, signlessType, right); |
| 644 | opResType = signlessType; |
| 645 | } |
| 646 | mlir::Value result = create<OpTy>(loc, opResType, left, right); |
| 647 | if (resultType.isUnsignedInteger()) |
| 648 | result = createConvert(loc, resultType, result); |
| 649 | return result; |
| 650 | } |
| 651 | |
| 652 | /// Compare two pointer-like values using the given predicate. |
| 653 | mlir::Value genPtrCompare(mlir::Location loc, |
| 654 | mlir::arith::CmpIPredicate predicate, |
| 655 | mlir::Value ptr1, mlir::Value ptr2) { |
| 656 | ptr1 = createConvert(loc, getIndexType(), ptr1); |
| 657 | ptr2 = createConvert(loc, getIndexType(), ptr2); |
| 658 | return create<mlir::arith::CmpIOp>(loc, predicate, ptr1, ptr2); |
| 659 | } |
| 660 | |
| 661 | private: |
| 662 | /// Set attributes (e.g. FastMathAttr) to \p op operation |
| 663 | /// based on the current attributes setting. |
| 664 | void setCommonAttributes(mlir::Operation *op) const; |
| 665 | |
| 666 | KindMapping kindMap; |
| 667 | |
| 668 | /// FastMathFlags that need to be set for operations that support |
| 669 | /// mlir::arith::FastMathAttr. |
| 670 | mlir::arith::FastMathFlags fastMathFlags{}; |
| 671 | |
| 672 | /// IntegerOverflowFlags that need to be set for operations that support |
| 673 | /// mlir::arith::IntegerOverflowFlagsAttr. |
| 674 | mlir::arith::IntegerOverflowFlags integerOverflowFlags{}; |
| 675 | |
| 676 | /// fir::GlobalOp and func::FuncOp symbol table to speed-up |
| 677 | /// lookups. |
| 678 | mlir::SymbolTable *symbolTable = nullptr; |
| 679 | |
| 680 | /// DataLayout constructed on demand. Access via getDataLayout(). |
| 681 | /// Stored via a unique_ptr rather than an optional so as not to bloat this |
| 682 | /// class when most instances won't ever need a data layout. |
| 683 | std::unique_ptr<mlir::DataLayout> dataLayout = nullptr; |
| 684 | }; |
| 685 | |
| 686 | } // namespace fir |
| 687 | |
| 688 | namespace fir::factory { |
| 689 | |
| 690 | //===----------------------------------------------------------------------===// |
| 691 | // ExtendedValue inquiry helpers |
| 692 | //===----------------------------------------------------------------------===// |
| 693 | |
| 694 | /// Read or get character length from \p box that must contain a character |
| 695 | /// entity. If the length value is contained in the ExtendedValue, this will |
| 696 | /// not generate any code, otherwise this will generate a read of the fir.box |
| 697 | /// describing the entity. |
| 698 | mlir::Value readCharLen(fir::FirOpBuilder &builder, mlir::Location loc, |
| 699 | const fir::ExtendedValue &box); |
| 700 | |
| 701 | /// Read or get the extent in dimension \p dim of the array described by \p box. |
| 702 | mlir::Value readExtent(fir::FirOpBuilder &builder, mlir::Location loc, |
| 703 | const fir::ExtendedValue &box, unsigned dim); |
| 704 | |
| 705 | /// Read or get the lower bound in dimension \p dim of the array described by |
| 706 | /// \p box. If the lower bound is left default in the ExtendedValue, |
| 707 | /// \p defaultValue will be returned. |
| 708 | mlir::Value readLowerBound(fir::FirOpBuilder &builder, mlir::Location loc, |
| 709 | const fir::ExtendedValue &box, unsigned dim, |
| 710 | mlir::Value defaultValue); |
| 711 | |
| 712 | /// Read extents from \p box. |
| 713 | llvm::SmallVector<mlir::Value> readExtents(fir::FirOpBuilder &builder, |
| 714 | mlir::Location loc, |
| 715 | const fir::BoxValue &box); |
| 716 | |
| 717 | /// Read a fir::BoxValue into an fir::UnboxValue, a fir::ArrayBoxValue or a |
| 718 | /// fir::CharArrayBoxValue. This should only be called if the fir::BoxValue is |
| 719 | /// known to be contiguous given the context (or if the resulting address will |
| 720 | /// not be used). If the value is polymorphic, its dynamic type will be lost. |
| 721 | /// This must not be used on unlimited polymorphic and assumed rank entities. |
| 722 | fir::ExtendedValue readBoxValue(fir::FirOpBuilder &builder, mlir::Location loc, |
| 723 | const fir::BoxValue &box); |
| 724 | |
| 725 | /// Get the lower bounds of \p exv. NB: returns an empty vector if the lower |
| 726 | /// bounds are all ones, which is the default in Fortran. |
| 727 | llvm::SmallVector<mlir::Value> |
| 728 | getNonDefaultLowerBounds(fir::FirOpBuilder &builder, mlir::Location loc, |
| 729 | const fir::ExtendedValue &exv); |
| 730 | |
| 731 | /// Return LEN parameters associated to \p exv that are not deferred (that are |
| 732 | /// available without having to read any fir.box values). Empty if \p exv has no |
| 733 | /// LEN parameters or if they are all deferred. |
| 734 | llvm::SmallVector<mlir::Value> |
| 735 | getNonDeferredLenParams(const fir::ExtendedValue &exv); |
| 736 | |
| 737 | //===----------------------------------------------------------------------===// |
| 738 | // String literal helper helpers |
| 739 | //===----------------------------------------------------------------------===// |
| 740 | |
| 741 | /// Create a !fir.char<1> string literal global and returns a fir::CharBoxValue |
| 742 | /// with its address and length. |
| 743 | fir::ExtendedValue createStringLiteral(fir::FirOpBuilder &, mlir::Location, |
| 744 | llvm::StringRef string); |
| 745 | |
| 746 | /// Unique a compiler generated identifier. A short prefix should be provided |
| 747 | /// to hint at the origin of the identifier. |
| 748 | std::string uniqueCGIdent(llvm::StringRef prefix, llvm::StringRef name); |
| 749 | |
| 750 | /// Lowers the extents from the sequence type to Values. |
| 751 | /// Any unknown extents are lowered to undefined values. |
| 752 | llvm::SmallVector<mlir::Value> createExtents(fir::FirOpBuilder &builder, |
| 753 | mlir::Location loc, |
| 754 | fir::SequenceType seqTy); |
| 755 | |
| 756 | //===--------------------------------------------------------------------===// |
| 757 | // Location helpers |
| 758 | //===--------------------------------------------------------------------===// |
| 759 | |
| 760 | /// Generate a string literal containing the file name and return its address |
| 761 | mlir::Value locationToFilename(fir::FirOpBuilder &, mlir::Location); |
| 762 | /// Generate a constant of the given type with the location line number |
| 763 | mlir::Value locationToLineNo(fir::FirOpBuilder &, mlir::Location, mlir::Type); |
| 764 | |
| 765 | //===--------------------------------------------------------------------===// |
| 766 | // ExtendedValue helpers |
| 767 | //===--------------------------------------------------------------------===// |
| 768 | |
| 769 | /// Return the extended value for a component of a derived type instance given |
| 770 | /// the address of the component. |
| 771 | fir::ExtendedValue componentToExtendedValue(fir::FirOpBuilder &builder, |
| 772 | mlir::Location loc, |
| 773 | mlir::Value component); |
| 774 | |
| 775 | /// Given the address of an array element and the ExtendedValue describing the |
| 776 | /// array, returns the ExtendedValue describing the array element. The purpose |
| 777 | /// is to propagate the LEN parameters of the array to the element. This can be |
| 778 | /// used for elements of `array` or `array(i:j:k)`. If \p element belongs to an |
| 779 | /// array section `array%x` whose base is \p array, |
| 780 | /// arraySectionElementToExtendedValue must be used instead. |
| 781 | fir::ExtendedValue arrayElementToExtendedValue(fir::FirOpBuilder &builder, |
| 782 | mlir::Location loc, |
| 783 | const fir::ExtendedValue &array, |
| 784 | mlir::Value element); |
| 785 | |
| 786 | /// Build the ExtendedValue for \p element that is an element of an array or |
| 787 | /// array section with \p array base (`array` or `array(i:j:k)%x%y`). |
| 788 | /// If it is an array section, \p slice must be provided and be a fir::SliceOp |
| 789 | /// that describes the section. |
| 790 | fir::ExtendedValue arraySectionElementToExtendedValue( |
| 791 | fir::FirOpBuilder &builder, mlir::Location loc, |
| 792 | const fir::ExtendedValue &array, mlir::Value element, mlir::Value slice); |
| 793 | |
| 794 | /// Assign \p rhs to \p lhs. Both \p rhs and \p lhs must be scalars. The |
| 795 | /// assignment follows Fortran intrinsic assignment semantic (10.2.1.3). |
| 796 | void genScalarAssignment(fir::FirOpBuilder &builder, mlir::Location loc, |
| 797 | const fir::ExtendedValue &lhs, |
| 798 | const fir::ExtendedValue &rhs, |
| 799 | bool needFinalization = false, |
| 800 | bool isTemporaryLHS = false); |
| 801 | |
| 802 | /// Assign \p rhs to \p lhs. Both \p rhs and \p lhs must be scalar derived |
| 803 | /// types. The assignment follows Fortran intrinsic assignment semantic for |
| 804 | /// derived types (10.2.1.3 point 13). |
| 805 | void genRecordAssignment(fir::FirOpBuilder &builder, mlir::Location loc, |
| 806 | const fir::ExtendedValue &lhs, |
| 807 | const fir::ExtendedValue &rhs, |
| 808 | bool needFinalization = false, |
| 809 | bool isTemporaryLHS = false); |
| 810 | |
| 811 | /// Builds and returns the type of a ragged array header used to cache mask |
| 812 | /// evaluations. RaggedArrayHeader is defined in |
| 813 | /// flang/include/flang/Runtime/ragged.h. |
| 814 | mlir::TupleType getRaggedArrayHeaderType(fir::FirOpBuilder &builder); |
| 815 | |
| 816 | /// Generate the, possibly dynamic, LEN of a CHARACTER. \p arrLoad determines |
| 817 | /// the base array. After applying \p path, the result must be a reference to a |
| 818 | /// `!fir.char` type object. \p substring must have 0, 1, or 2 members. The |
| 819 | /// first member is the starting offset. The second is the ending offset. |
| 820 | mlir::Value genLenOfCharacter(fir::FirOpBuilder &builder, mlir::Location loc, |
| 821 | fir::ArrayLoadOp arrLoad, |
| 822 | llvm::ArrayRef<mlir::Value> path, |
| 823 | llvm::ArrayRef<mlir::Value> substring); |
| 824 | mlir::Value genLenOfCharacter(fir::FirOpBuilder &builder, mlir::Location loc, |
| 825 | fir::SequenceType seqTy, mlir::Value memref, |
| 826 | llvm::ArrayRef<mlir::Value> typeParams, |
| 827 | llvm::ArrayRef<mlir::Value> path, |
| 828 | llvm::ArrayRef<mlir::Value> substring); |
| 829 | |
| 830 | /// Create the zero value of a given the numerical or logical \p type (`false` |
| 831 | /// for logical types). |
| 832 | mlir::Value createZeroValue(fir::FirOpBuilder &builder, mlir::Location loc, |
| 833 | mlir::Type type); |
| 834 | |
| 835 | /// Get the integer constants of triplet and compute the extent. |
| 836 | std::optional<std::int64_t> getExtentFromTriplet(mlir::Value lb, mlir::Value ub, |
| 837 | mlir::Value stride); |
| 838 | |
| 839 | /// Compute the extent value given the lower bound \lb and upper bound \ub. |
| 840 | /// All inputs must have the same SSA integer type. |
| 841 | mlir::Value computeExtent(fir::FirOpBuilder &builder, mlir::Location loc, |
| 842 | mlir::Value lb, mlir::Value ub); |
| 843 | mlir::Value computeExtent(fir::FirOpBuilder &builder, mlir::Location loc, |
| 844 | mlir::Value lb, mlir::Value ub, mlir::Value zero, |
| 845 | mlir::Value one); |
| 846 | |
| 847 | /// Generate max(\p value, 0) where \p value is a scalar integer. |
| 848 | mlir::Value genMaxWithZero(fir::FirOpBuilder &builder, mlir::Location loc, |
| 849 | mlir::Value value); |
| 850 | mlir::Value genMaxWithZero(fir::FirOpBuilder &builder, mlir::Location loc, |
| 851 | mlir::Value value, mlir::Value zero); |
| 852 | |
| 853 | /// The type(C_PTR/C_FUNPTR) is defined as the derived type with only one |
| 854 | /// component of integer 64, and the component is the C address. Get the C |
| 855 | /// address. |
| 856 | mlir::Value genCPtrOrCFunptrAddr(fir::FirOpBuilder &builder, mlir::Location loc, |
| 857 | mlir::Value cPtr, mlir::Type ty); |
| 858 | |
| 859 | /// The type(C_DEVPTR) is defined as the derived type with only one |
| 860 | /// component of C_PTR type. Get the C address from the C_PTR component. |
| 861 | mlir::Value genCDevPtrAddr(fir::FirOpBuilder &builder, mlir::Location loc, |
| 862 | mlir::Value cDevPtr, mlir::Type ty); |
| 863 | |
| 864 | /// Get the C address value. |
| 865 | mlir::Value genCPtrOrCFunptrValue(fir::FirOpBuilder &builder, |
| 866 | mlir::Location loc, mlir::Value cPtr); |
| 867 | |
| 868 | /// Create a fir.box from a fir::ExtendedValue and wrap it in a fir::BoxValue |
| 869 | /// to keep all the lower bound and explicit parameter information. |
| 870 | fir::BoxValue createBoxValue(fir::FirOpBuilder &builder, mlir::Location loc, |
| 871 | const fir::ExtendedValue &exv); |
| 872 | |
| 873 | /// Generate Null BoxProc for procedure pointer null initialization. |
| 874 | mlir::Value createNullBoxProc(fir::FirOpBuilder &builder, mlir::Location loc, |
| 875 | mlir::Type boxType); |
| 876 | |
| 877 | /// Convert a value to a new type. Return the value directly if it has the right |
| 878 | /// type. |
| 879 | mlir::Value createConvert(mlir::OpBuilder &, mlir::Location, mlir::Type, |
| 880 | mlir::Value); |
| 881 | |
| 882 | /// Set internal linkage attribute on a function. |
| 883 | void setInternalLinkage(mlir::func::FuncOp); |
| 884 | |
| 885 | llvm::SmallVector<mlir::Value> |
| 886 | elideExtentsAlreadyInType(mlir::Type type, mlir::ValueRange shape); |
| 887 | |
| 888 | llvm::SmallVector<mlir::Value> |
| 889 | elideLengthsAlreadyInType(mlir::Type type, mlir::ValueRange lenParams); |
| 890 | |
| 891 | /// Get the address space which should be used for allocas |
| 892 | uint64_t getAllocaAddressSpace(const mlir::DataLayout *dataLayout); |
| 893 | |
| 894 | /// The two vectors of MLIR values have the following property: |
| 895 | /// \p extents1[i] must have the same value as \p extents2[i] |
| 896 | /// The function returns a new vector of MLIR values that preserves |
| 897 | /// the same property vs \p extents1 and \p extents2, but allows |
| 898 | /// more optimizations. For example, if extents1[j] is a known constant, |
| 899 | /// and extents2[j] is not, then result[j] is the MLIR value extents1[j]. |
| 900 | llvm::SmallVector<mlir::Value> deduceOptimalExtents(mlir::ValueRange extents1, |
| 901 | mlir::ValueRange extents2); |
| 902 | |
| 903 | /// Given array extents generate code that sets them all to zeroes, |
| 904 | /// if the array is empty, e.g.: |
| 905 | /// %false = arith.constant false |
| 906 | /// %c0 = arith.constant 0 : index |
| 907 | /// %p1 = arith.cmpi eq, %e0, %c0 : index |
| 908 | /// %p2 = arith.ori %false, %p1 : i1 |
| 909 | /// %p3 = arith.cmpi eq, %e1, %c0 : index |
| 910 | /// %p4 = arith.ori %p1, %p2 : i1 |
| 911 | /// %result0 = arith.select %p4, %c0, %e0 : index |
| 912 | /// %result1 = arith.select %p4, %c0, %e1 : index |
| 913 | llvm::SmallVector<mlir::Value> updateRuntimeExtentsForEmptyArrays( |
| 914 | fir::FirOpBuilder &builder, mlir::Location loc, mlir::ValueRange extents); |
| 915 | |
| 916 | /// Given \p box of type fir::BaseBoxType representing an array, |
| 917 | /// the function generates code to fetch the lower bounds, |
| 918 | /// the extents and the strides from the box. The values are returned via |
| 919 | /// \p lbounds, \p extents and \p strides. |
| 920 | void genDimInfoFromBox(fir::FirOpBuilder &builder, mlir::Location loc, |
| 921 | mlir::Value box, |
| 922 | llvm::SmallVectorImpl<mlir::Value> *lbounds, |
| 923 | llvm::SmallVectorImpl<mlir::Value> *extents, |
| 924 | llvm::SmallVectorImpl<mlir::Value> *strides); |
| 925 | |
| 926 | /// Generate an LLVM dialect lifetime start marker at the current insertion |
| 927 | /// point given an fir.alloca and its constant size in bytes. Returns the value |
| 928 | /// to be passed to the lifetime end marker. |
| 929 | mlir::Value genLifetimeStart(mlir::OpBuilder &builder, mlir::Location loc, |
| 930 | fir::AllocaOp alloc, int64_t size, |
| 931 | const mlir::DataLayout *dl); |
| 932 | |
| 933 | /// Generate an LLVM dialect lifetime end marker at the current insertion point |
| 934 | /// given an llvm.ptr value and the constant size in bytes of its storage. |
| 935 | void genLifetimeEnd(mlir::OpBuilder &builder, mlir::Location loc, |
| 936 | mlir::Value mem, int64_t size); |
| 937 | |
| 938 | } // namespace fir::factory |
| 939 | |
| 940 | #endif // FORTRAN_OPTIMIZER_BUILDER_FIRBUILDER_H |
| 941 |
Warning: This file is not a C or C++ file. It does not have highlighting.
