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/FIRType.h" 21 #include "flang/Optimizer/Support/KindMapping.h" 22 #include "mlir/IR/Builders.h" 23 #include "mlir/IR/BuiltinOps.h" 24 #include "llvm/ADT/DenseMap.h" 25 #include "llvm/ADT/Optional.h" 26 27 namespace fir { 28 class AbstractArrayBox; 29 class ExtendedValue; 30 class BoxValue; 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} {} FirOpBuilder(mlir::OpBuilder & builder,const fir::KindMapping & kindMap)42 explicit FirOpBuilder(mlir::OpBuilder &builder, 43 const fir::KindMapping &kindMap) 44 : OpBuilder{builder}, kindMap{kindMap} {} 45 46 /// Get the current Region of the insertion point. getRegion()47 mlir::Region &getRegion() { return *getBlock()->getParent(); } 48 49 /// Get the current Module getModule()50 mlir::ModuleOp getModule() { 51 return getRegion().getParentOfType<mlir::ModuleOp>(); 52 } 53 54 /// Get the current Function getFunction()55 mlir::func::FuncOp getFunction() { 56 return getRegion().getParentOfType<mlir::func::FuncOp>(); 57 } 58 59 /// Get a reference to the kind map. getKindMap()60 const fir::KindMapping &getKindMap() { return kindMap; } 61 62 /// Get the default integer type getDefaultIntegerType()63 [[maybe_unused]] mlir::IntegerType getDefaultIntegerType() { 64 return getIntegerType( 65 getKindMap().getIntegerBitsize(getKindMap().defaultIntegerKind())); 66 } 67 68 /// The LHS and RHS are not always in agreement in terms of type. In some 69 /// cases, the disagreement is between COMPLEX and other scalar types. In that 70 /// case, the conversion must insert (extract) out of a COMPLEX value to have 71 /// the proper semantics and be strongly typed. E.g., converting an integer 72 /// (real) to a complex, the real part is filled using the integer (real) 73 /// after type conversion and the imaginary part is zero. 74 mlir::Value convertWithSemantics(mlir::Location loc, mlir::Type toTy, 75 mlir::Value val, 76 bool allowCharacterConversion = false); 77 78 /// Get the entry block of the current Function getEntryBlock()79 mlir::Block *getEntryBlock() { return &getFunction().front(); } 80 81 /// Get the block for adding Allocas. If OpenMP is enabled then get the 82 /// the alloca block from an Operation which can be Outlined. Otherwise 83 /// use the entry block of the current Function 84 mlir::Block *getAllocaBlock(); 85 86 /// Safely create a reference type to the type `eleTy`. 87 mlir::Type getRefType(mlir::Type eleTy); 88 89 /// Create a sequence of `eleTy` with `rank` dimensions of unknown size. 90 mlir::Type getVarLenSeqTy(mlir::Type eleTy, unsigned rank = 1); 91 92 /// Get character length type. getCharacterLengthType()93 mlir::Type getCharacterLengthType() { return getIndexType(); } 94 95 /// Get the integer type whose bit width corresponds to the width of pointer 96 /// types, or is bigger. getIntPtrType()97 mlir::Type getIntPtrType() { 98 // TODO: Delay the need of such type until codegen or find a way to use 99 // llvm::DataLayout::getPointerSizeInBits here. 100 return getI64Type(); 101 } 102 103 /// Wrap `str` to a SymbolRefAttr. getSymbolRefAttr(llvm::StringRef str)104 mlir::SymbolRefAttr getSymbolRefAttr(llvm::StringRef str) { 105 return mlir::SymbolRefAttr::get(getContext(), str); 106 } 107 108 /// Get the mlir float type that implements Fortran REAL(kind). 109 mlir::Type getRealType(int kind); 110 getBoxProcType(mlir::FunctionType funcTy)111 fir::BoxProcType getBoxProcType(mlir::FunctionType funcTy) { 112 return fir::BoxProcType::get(getContext(), funcTy); 113 } 114 115 /// Create a null constant memory reference of type \p ptrType. 116 /// If \p ptrType is not provided, !fir.ref<none> type will be used. 117 mlir::Value createNullConstant(mlir::Location loc, mlir::Type ptrType = {}); 118 119 /// Create an integer constant of type \p type and value \p i. 120 mlir::Value createIntegerConstant(mlir::Location loc, mlir::Type integerType, 121 std::int64_t i); 122 123 /// Create a real constant from an integer value. 124 mlir::Value createRealConstant(mlir::Location loc, mlir::Type realType, 125 llvm::APFloat::integerPart val); 126 127 /// Create a real constant from an APFloat value. 128 mlir::Value createRealConstant(mlir::Location loc, mlir::Type realType, 129 const llvm::APFloat &val); 130 131 /// Create a real constant of type \p realType with a value zero. createRealZeroConstant(mlir::Location loc,mlir::Type realType)132 mlir::Value createRealZeroConstant(mlir::Location loc, mlir::Type realType) { 133 return createRealConstant(loc, realType, 0u); 134 } 135 136 /// Create a slot for a local on the stack. Besides the variable's type and 137 /// shape, it may be given name, pinned, or target attributes. 138 mlir::Value allocateLocal(mlir::Location loc, mlir::Type ty, 139 llvm::StringRef uniqName, llvm::StringRef name, 140 bool pinned, llvm::ArrayRef<mlir::Value> shape, 141 llvm::ArrayRef<mlir::Value> lenParams, 142 bool asTarget = false); 143 mlir::Value allocateLocal(mlir::Location loc, mlir::Type ty, 144 llvm::StringRef uniqName, llvm::StringRef name, 145 llvm::ArrayRef<mlir::Value> shape, 146 llvm::ArrayRef<mlir::Value> lenParams, 147 bool asTarget = false); 148 149 /// Create a temporary. A temp is allocated using `fir.alloca` and can be read 150 /// and written using `fir.load` and `fir.store`, resp. The temporary can be 151 /// given a name via a front-end `Symbol` or a `StringRef`. 152 mlir::Value createTemporary(mlir::Location loc, mlir::Type type, 153 llvm::StringRef name = {}, 154 mlir::ValueRange shape = {}, 155 mlir::ValueRange lenParams = {}, 156 llvm::ArrayRef<mlir::NamedAttribute> attrs = {}); 157 158 /// Create an unnamed and untracked temporary on the stack. createTemporary(mlir::Location loc,mlir::Type type,mlir::ValueRange shape)159 mlir::Value createTemporary(mlir::Location loc, mlir::Type type, 160 mlir::ValueRange shape) { 161 return createTemporary(loc, type, llvm::StringRef{}, shape); 162 } 163 createTemporary(mlir::Location loc,mlir::Type type,llvm::ArrayRef<mlir::NamedAttribute> attrs)164 mlir::Value createTemporary(mlir::Location loc, mlir::Type type, 165 llvm::ArrayRef<mlir::NamedAttribute> attrs) { 166 return createTemporary(loc, type, llvm::StringRef{}, {}, {}, attrs); 167 } 168 createTemporary(mlir::Location loc,mlir::Type type,llvm::StringRef name,llvm::ArrayRef<mlir::NamedAttribute> attrs)169 mlir::Value createTemporary(mlir::Location loc, mlir::Type type, 170 llvm::StringRef name, 171 llvm::ArrayRef<mlir::NamedAttribute> attrs) { 172 return createTemporary(loc, type, name, {}, {}, attrs); 173 } 174 175 /// Create a global value. 176 fir::GlobalOp createGlobal(mlir::Location loc, mlir::Type type, 177 llvm::StringRef name, 178 mlir::StringAttr linkage = {}, 179 mlir::Attribute value = {}, bool isConst = false); 180 181 fir::GlobalOp createGlobal(mlir::Location loc, mlir::Type type, 182 llvm::StringRef name, bool isConst, 183 std::function<void(FirOpBuilder &)> bodyBuilder, 184 mlir::StringAttr linkage = {}); 185 186 /// Create a global constant (read-only) value. 187 fir::GlobalOp createGlobalConstant(mlir::Location loc, mlir::Type type, 188 llvm::StringRef name, 189 mlir::StringAttr linkage = {}, 190 mlir::Attribute value = {}) { 191 return createGlobal(loc, type, name, linkage, value, /*isConst=*/true); 192 } 193 194 fir::GlobalOp 195 createGlobalConstant(mlir::Location loc, mlir::Type type, 196 llvm::StringRef name, 197 std::function<void(FirOpBuilder &)> bodyBuilder, 198 mlir::StringAttr linkage = {}) { 199 return createGlobal(loc, type, name, /*isConst=*/true, bodyBuilder, 200 linkage); 201 } 202 203 /// Convert a StringRef string into a fir::StringLitOp. 204 fir::StringLitOp createStringLitOp(mlir::Location loc, 205 llvm::StringRef string); 206 207 //===--------------------------------------------------------------------===// 208 // Linkage helpers (inline). The default linkage is external. 209 //===--------------------------------------------------------------------===// 210 createCommonLinkage()211 mlir::StringAttr createCommonLinkage() { return getStringAttr("common"); } 212 createInternalLinkage()213 mlir::StringAttr createInternalLinkage() { return getStringAttr("internal"); } 214 createLinkOnceLinkage()215 mlir::StringAttr createLinkOnceLinkage() { return getStringAttr("linkonce"); } 216 createLinkOnceODRLinkage()217 mlir::StringAttr createLinkOnceODRLinkage() { 218 return getStringAttr("linkonce_odr"); 219 } 220 createWeakLinkage()221 mlir::StringAttr createWeakLinkage() { return getStringAttr("weak"); } 222 223 /// Get a function by name. If the function exists in the current module, it 224 /// is returned. Otherwise, a null FuncOp is returned. getNamedFunction(llvm::StringRef name)225 mlir::func::FuncOp getNamedFunction(llvm::StringRef name) { 226 return getNamedFunction(getModule(), name); 227 } 228 static mlir::func::FuncOp getNamedFunction(mlir::ModuleOp module, 229 llvm::StringRef name); 230 231 /// Get a function by symbol name. The result will be null if there is no 232 /// function with the given symbol in the module. getNamedFunction(mlir::SymbolRefAttr symbol)233 mlir::func::FuncOp getNamedFunction(mlir::SymbolRefAttr symbol) { 234 return getNamedFunction(getModule(), symbol); 235 } 236 static mlir::func::FuncOp getNamedFunction(mlir::ModuleOp module, 237 mlir::SymbolRefAttr symbol); 238 getNamedGlobal(llvm::StringRef name)239 fir::GlobalOp getNamedGlobal(llvm::StringRef name) { 240 return getNamedGlobal(getModule(), name); 241 } 242 243 static fir::GlobalOp getNamedGlobal(mlir::ModuleOp module, 244 llvm::StringRef name); 245 246 /// Lazy creation of fir.convert op. 247 mlir::Value createConvert(mlir::Location loc, mlir::Type toTy, 248 mlir::Value val); 249 250 /// Create a fir.store of \p val into \p addr. A lazy conversion 251 /// of \p val to the element type of \p addr is created if needed. 252 void createStoreWithConvert(mlir::Location loc, mlir::Value val, 253 mlir::Value addr); 254 255 /// Create a new FuncOp. If the function may have already been created, use 256 /// `addNamedFunction` instead. createFunction(mlir::Location loc,llvm::StringRef name,mlir::FunctionType ty)257 mlir::func::FuncOp createFunction(mlir::Location loc, llvm::StringRef name, 258 mlir::FunctionType ty) { 259 return createFunction(loc, getModule(), name, ty); 260 } 261 262 static mlir::func::FuncOp createFunction(mlir::Location loc, 263 mlir::ModuleOp module, 264 llvm::StringRef name, 265 mlir::FunctionType ty); 266 267 /// Determine if the named function is already in the module. Return the 268 /// instance if found, otherwise add a new named function to the module. addNamedFunction(mlir::Location loc,llvm::StringRef name,mlir::FunctionType ty)269 mlir::func::FuncOp addNamedFunction(mlir::Location loc, llvm::StringRef name, 270 mlir::FunctionType ty) { 271 if (auto func = getNamedFunction(name)) 272 return func; 273 return createFunction(loc, name, ty); 274 } 275 addNamedFunction(mlir::Location loc,mlir::ModuleOp module,llvm::StringRef name,mlir::FunctionType ty)276 static mlir::func::FuncOp addNamedFunction(mlir::Location loc, 277 mlir::ModuleOp module, 278 llvm::StringRef name, 279 mlir::FunctionType ty) { 280 if (auto func = getNamedFunction(module, name)) 281 return func; 282 return createFunction(loc, module, name, ty); 283 } 284 285 /// Cast the input value to IndexType. convertToIndexType(mlir::Location loc,mlir::Value val)286 mlir::Value convertToIndexType(mlir::Location loc, mlir::Value val) { 287 return createConvert(loc, getIndexType(), val); 288 } 289 290 /// Construct one of the two forms of shape op from an array box. 291 mlir::Value genShape(mlir::Location loc, const fir::AbstractArrayBox &arr); 292 mlir::Value genShape(mlir::Location loc, llvm::ArrayRef<mlir::Value> shift, 293 llvm::ArrayRef<mlir::Value> exts); 294 mlir::Value genShape(mlir::Location loc, llvm::ArrayRef<mlir::Value> exts); 295 296 /// Create one of the shape ops given an extended value. For a boxed value, 297 /// this may create a `fir.shift` op. 298 mlir::Value createShape(mlir::Location loc, const fir::ExtendedValue &exv); 299 300 /// Create a slice op extended value. The value to be sliced, `exv`, must be 301 /// an array. 302 mlir::Value createSlice(mlir::Location loc, const fir::ExtendedValue &exv, 303 mlir::ValueRange triples, mlir::ValueRange path); 304 305 /// Create a boxed value (Fortran descriptor) to be passed to the runtime. 306 /// \p exv is an extended value holding a memory reference to the object that 307 /// must be boxed. This function will crash if provided something that is not 308 /// a memory reference type. 309 /// Array entities are boxed with a shape and possibly a shift. Character 310 /// entities are boxed with a LEN parameter. 311 mlir::Value createBox(mlir::Location loc, const fir::ExtendedValue &exv); 312 313 /// Create constant i1 with value 1. if \p b is true or 0. otherwise createBool(mlir::Location loc,bool b)314 mlir::Value createBool(mlir::Location loc, bool b) { 315 return createIntegerConstant(loc, getIntegerType(1), b ? 1 : 0); 316 } 317 318 //===--------------------------------------------------------------------===// 319 // If-Then-Else generation helper 320 //===--------------------------------------------------------------------===// 321 322 /// Helper class to create if-then-else in a structured way: 323 /// Usage: genIfOp().genThen([&](){...}).genElse([&](){...}).end(); 324 /// Alternatively, getResults() can be used instead of end() to end the ifOp 325 /// and get the ifOp results. 326 class IfBuilder { 327 public: IfBuilder(fir::IfOp ifOp,FirOpBuilder & builder)328 IfBuilder(fir::IfOp ifOp, FirOpBuilder &builder) 329 : ifOp{ifOp}, builder{builder} {} 330 template <typename CC> genThen(CC func)331 IfBuilder &genThen(CC func) { 332 builder.setInsertionPointToStart(&ifOp.getThenRegion().front()); 333 func(); 334 return *this; 335 } 336 template <typename CC> genElse(CC func)337 IfBuilder &genElse(CC func) { 338 assert(!ifOp.getElseRegion().empty() && "must have else region"); 339 builder.setInsertionPointToStart(&ifOp.getElseRegion().front()); 340 func(); 341 return *this; 342 } end()343 void end() { builder.setInsertionPointAfter(ifOp); } 344 345 /// End the IfOp and return the results if any. getResults()346 mlir::Operation::result_range getResults() { 347 end(); 348 return ifOp.getResults(); 349 } 350 getIfOp()351 fir::IfOp &getIfOp() { return ifOp; }; 352 353 private: 354 fir::IfOp ifOp; 355 FirOpBuilder &builder; 356 }; 357 358 /// Create an IfOp and returns an IfBuilder that can generate the else/then 359 /// bodies. genIfOp(mlir::Location loc,mlir::TypeRange results,mlir::Value cdt,bool withElseRegion)360 IfBuilder genIfOp(mlir::Location loc, mlir::TypeRange results, 361 mlir::Value cdt, bool withElseRegion) { 362 auto op = create<fir::IfOp>(loc, results, cdt, withElseRegion); 363 return IfBuilder(op, *this); 364 } 365 366 /// Create an IfOp with no "else" region, and no result values. 367 /// Usage: genIfThen(loc, cdt).genThen(lambda).end(); genIfThen(mlir::Location loc,mlir::Value cdt)368 IfBuilder genIfThen(mlir::Location loc, mlir::Value cdt) { 369 auto op = create<fir::IfOp>(loc, llvm::None, cdt, false); 370 return IfBuilder(op, *this); 371 } 372 373 /// Create an IfOp with an "else" region, and no result values. 374 /// Usage: genIfThenElse(loc, cdt).genThen(lambda).genElse(lambda).end(); genIfThenElse(mlir::Location loc,mlir::Value cdt)375 IfBuilder genIfThenElse(mlir::Location loc, mlir::Value cdt) { 376 auto op = create<fir::IfOp>(loc, llvm::None, cdt, true); 377 return IfBuilder(op, *this); 378 } 379 380 /// Generate code testing \p addr is not a null address. 381 mlir::Value genIsNotNullAddr(mlir::Location loc, mlir::Value addr); 382 383 /// Generate code testing \p addr is a null address. 384 mlir::Value genIsNullAddr(mlir::Location loc, mlir::Value addr); 385 386 /// Compute the extent of (lb:ub:step) as max((ub-lb+step)/step, 0). See 387 /// Fortran 2018 9.5.3.3.2 section for more details. 388 mlir::Value genExtentFromTriplet(mlir::Location loc, mlir::Value lb, 389 mlir::Value ub, mlir::Value step, 390 mlir::Type type); 391 392 /// Dump the current function. (debug) 393 LLVM_DUMP_METHOD void dumpFunc(); 394 395 private: 396 const KindMapping &kindMap; 397 }; 398 399 } // namespace fir 400 401 namespace fir::factory { 402 403 //===----------------------------------------------------------------------===// 404 // ExtendedValue inquiry helpers 405 //===----------------------------------------------------------------------===// 406 407 /// Read or get character length from \p box that must contain a character 408 /// entity. If the length value is contained in the ExtendedValue, this will 409 /// not generate any code, otherwise this will generate a read of the fir.box 410 /// describing the entity. 411 mlir::Value readCharLen(fir::FirOpBuilder &builder, mlir::Location loc, 412 const fir::ExtendedValue &box); 413 414 /// Read or get the extent in dimension \p dim of the array described by \p box. 415 mlir::Value readExtent(fir::FirOpBuilder &builder, mlir::Location loc, 416 const fir::ExtendedValue &box, unsigned dim); 417 418 /// Read or get the lower bound in dimension \p dim of the array described by 419 /// \p box. If the lower bound is left default in the ExtendedValue, 420 /// \p defaultValue will be returned. 421 mlir::Value readLowerBound(fir::FirOpBuilder &builder, mlir::Location loc, 422 const fir::ExtendedValue &box, unsigned dim, 423 mlir::Value defaultValue); 424 425 /// Read extents from \p box. 426 llvm::SmallVector<mlir::Value> readExtents(fir::FirOpBuilder &builder, 427 mlir::Location loc, 428 const fir::BoxValue &box); 429 430 /// Read a fir::BoxValue into an fir::UnboxValue, a fir::ArrayBoxValue or a 431 /// fir::CharArrayBoxValue. This should only be called if the fir::BoxValue is 432 /// known to be contiguous given the context (or if the resulting address will 433 /// not be used). If the value is polymorphic, its dynamic type will be lost. 434 /// This must not be used on unlimited polymorphic and assumed rank entities. 435 fir::ExtendedValue readBoxValue(fir::FirOpBuilder &builder, mlir::Location loc, 436 const fir::BoxValue &box); 437 438 /// Get the lower bounds of \p exv. NB: returns an empty vector if the lower 439 /// bounds are all ones, which is the default in Fortran. 440 llvm::SmallVector<mlir::Value> 441 getNonDefaultLowerBounds(fir::FirOpBuilder &builder, mlir::Location loc, 442 const fir::ExtendedValue &exv); 443 444 /// Return LEN parameters associated to \p exv that are not deferred (that are 445 /// available without having to read any fir.box values). Empty if \p exv has no 446 /// LEN parameters or if they are all deferred. 447 llvm::SmallVector<mlir::Value> 448 getNonDeferredLenParams(const fir::ExtendedValue &exv); 449 450 //===----------------------------------------------------------------------===// 451 // String literal helper helpers 452 //===----------------------------------------------------------------------===// 453 454 /// Create a !fir.char<1> string literal global and returns a fir::CharBoxValue 455 /// with its address and length. 456 fir::ExtendedValue createStringLiteral(fir::FirOpBuilder &, mlir::Location, 457 llvm::StringRef string); 458 459 /// Unique a compiler generated identifier. A short prefix should be provided 460 /// to hint at the origin of the identifier. 461 std::string uniqueCGIdent(llvm::StringRef prefix, llvm::StringRef name); 462 463 /// Lowers the extents from the sequence type to Values. 464 /// Any unknown extents are lowered to undefined values. 465 llvm::SmallVector<mlir::Value> createExtents(fir::FirOpBuilder &builder, 466 mlir::Location loc, 467 fir::SequenceType seqTy); 468 469 //===--------------------------------------------------------------------===// 470 // Location helpers 471 //===--------------------------------------------------------------------===// 472 473 /// Generate a string literal containing the file name and return its address 474 mlir::Value locationToFilename(fir::FirOpBuilder &, mlir::Location); 475 /// Generate a constant of the given type with the location line number 476 mlir::Value locationToLineNo(fir::FirOpBuilder &, mlir::Location, mlir::Type); 477 478 //===--------------------------------------------------------------------===// 479 // ExtendedValue helpers 480 //===--------------------------------------------------------------------===// 481 482 /// Return the extended value for a component of a derived type instance given 483 /// the address of the component. 484 fir::ExtendedValue componentToExtendedValue(fir::FirOpBuilder &builder, 485 mlir::Location loc, 486 mlir::Value component); 487 488 /// Given the address of an array element and the ExtendedValue describing the 489 /// array, returns the ExtendedValue describing the array element. The purpose 490 /// is to propagate the LEN parameters of the array to the element. This can be 491 /// used for elements of `array` or `array(i:j:k)`. If \p element belongs to an 492 /// array section `array%x` whose base is \p array, 493 /// arraySectionElementToExtendedValue must be used instead. 494 fir::ExtendedValue arrayElementToExtendedValue(fir::FirOpBuilder &builder, 495 mlir::Location loc, 496 const fir::ExtendedValue &array, 497 mlir::Value element); 498 499 /// Build the ExtendedValue for \p element that is an element of an array or 500 /// array section with \p array base (`array` or `array(i:j:k)%x%y`). 501 /// If it is an array section, \p slice must be provided and be a fir::SliceOp 502 /// that describes the section. 503 fir::ExtendedValue arraySectionElementToExtendedValue( 504 fir::FirOpBuilder &builder, mlir::Location loc, 505 const fir::ExtendedValue &array, mlir::Value element, mlir::Value slice); 506 507 /// Assign \p rhs to \p lhs. Both \p rhs and \p lhs must be scalars. The 508 /// assignment follows Fortran intrinsic assignment semantic (10.2.1.3). 509 void genScalarAssignment(fir::FirOpBuilder &builder, mlir::Location loc, 510 const fir::ExtendedValue &lhs, 511 const fir::ExtendedValue &rhs); 512 /// Assign \p rhs to \p lhs. Both \p rhs and \p lhs must be scalar derived 513 /// types. The assignment follows Fortran intrinsic assignment semantic for 514 /// derived types (10.2.1.3 point 13). 515 void genRecordAssignment(fir::FirOpBuilder &builder, mlir::Location loc, 516 const fir::ExtendedValue &lhs, 517 const fir::ExtendedValue &rhs); 518 519 /// Builds and returns the type of a ragged array header used to cache mask 520 /// evaluations. RaggedArrayHeader is defined in 521 /// flang/include/flang/Runtime/ragged.h. 522 mlir::TupleType getRaggedArrayHeaderType(fir::FirOpBuilder &builder); 523 524 /// Generate the, possibly dynamic, LEN of a CHARACTER. \p arrLoad determines 525 /// the base array. After applying \p path, the result must be a reference to a 526 /// `!fir.char` type object. \p substring must have 0, 1, or 2 members. The 527 /// first member is the starting offset. The second is the ending offset. 528 mlir::Value genLenOfCharacter(fir::FirOpBuilder &builder, mlir::Location loc, 529 fir::ArrayLoadOp arrLoad, 530 llvm::ArrayRef<mlir::Value> path, 531 llvm::ArrayRef<mlir::Value> substring); 532 mlir::Value genLenOfCharacter(fir::FirOpBuilder &builder, mlir::Location loc, 533 fir::SequenceType seqTy, mlir::Value memref, 534 llvm::ArrayRef<mlir::Value> typeParams, 535 llvm::ArrayRef<mlir::Value> path, 536 llvm::ArrayRef<mlir::Value> substring); 537 538 /// Create the zero value of a given the numerical or logical \p type (`false` 539 /// for logical types). 540 mlir::Value createZeroValue(fir::FirOpBuilder &builder, mlir::Location loc, 541 mlir::Type type); 542 543 /// Unwrap integer constant from an mlir::Value. 544 llvm::Optional<std::int64_t> getIntIfConstant(mlir::Value value); 545 546 /// Get the integer constants of triplet and compute the extent. 547 llvm::Optional<std::int64_t> 548 getExtentFromTriplet(mlir::Value lb, mlir::Value ub, mlir::Value stride); 549 550 /// Generate max(\p value, 0) where \p value is a scalar integer. 551 mlir::Value genMaxWithZero(fir::FirOpBuilder &builder, mlir::Location loc, 552 mlir::Value value); 553 554 } // namespace fir::factory 555 556 #endif // FORTRAN_OPTIMIZER_BUILDER_FIRBUILDER_H 557