1 //===-- ConvertExpr.cpp ---------------------------------------------------===// 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 #include "flang/Lower/ConvertExpr.h" 14 #include "flang/Common/default-kinds.h" 15 #include "flang/Common/unwrap.h" 16 #include "flang/Evaluate/fold.h" 17 #include "flang/Evaluate/real.h" 18 #include "flang/Evaluate/traverse.h" 19 #include "flang/Lower/Allocatable.h" 20 #include "flang/Lower/Bridge.h" 21 #include "flang/Lower/BuiltinModules.h" 22 #include "flang/Lower/CallInterface.h" 23 #include "flang/Lower/Coarray.h" 24 #include "flang/Lower/ComponentPath.h" 25 #include "flang/Lower/ConvertType.h" 26 #include "flang/Lower/ConvertVariable.h" 27 #include "flang/Lower/CustomIntrinsicCall.h" 28 #include "flang/Lower/DumpEvaluateExpr.h" 29 #include "flang/Lower/IntrinsicCall.h" 30 #include "flang/Lower/Mangler.h" 31 #include "flang/Lower/Runtime.h" 32 #include "flang/Lower/Support/Utils.h" 33 #include "flang/Lower/Todo.h" 34 #include "flang/Optimizer/Builder/Character.h" 35 #include "flang/Optimizer/Builder/Complex.h" 36 #include "flang/Optimizer/Builder/Factory.h" 37 #include "flang/Optimizer/Builder/Runtime/Character.h" 38 #include "flang/Optimizer/Builder/Runtime/RTBuilder.h" 39 #include "flang/Optimizer/Builder/Runtime/Ragged.h" 40 #include "flang/Optimizer/Dialect/FIRAttr.h" 41 #include "flang/Optimizer/Dialect/FIRDialect.h" 42 #include "flang/Optimizer/Dialect/FIROpsSupport.h" 43 #include "flang/Optimizer/Support/FatalError.h" 44 #include "flang/Semantics/expression.h" 45 #include "flang/Semantics/symbol.h" 46 #include "flang/Semantics/tools.h" 47 #include "flang/Semantics/type.h" 48 #include "mlir/Dialect/Func/IR/FuncOps.h" 49 #include "llvm/Support/CommandLine.h" 50 #include "llvm/Support/Debug.h" 51 #include "llvm/Support/ErrorHandling.h" 52 #include "llvm/Support/raw_ostream.h" 53 #include <algorithm> 54 55 #define DEBUG_TYPE "flang-lower-expr" 56 57 //===----------------------------------------------------------------------===// 58 // The composition and structure of Fortran::evaluate::Expr is defined in 59 // the various header files in include/flang/Evaluate. You are referred 60 // there for more information on these data structures. Generally speaking, 61 // these data structures are a strongly typed family of abstract data types 62 // that, composed as trees, describe the syntax of Fortran expressions. 63 // 64 // This part of the bridge can traverse these tree structures and lower them 65 // to the correct FIR representation in SSA form. 66 //===----------------------------------------------------------------------===// 67 68 static llvm::cl::opt<bool> generateArrayCoordinate( 69 "gen-array-coor", 70 llvm::cl::desc("in lowering create ArrayCoorOp instead of CoordinateOp"), 71 llvm::cl::init(false)); 72 73 // The default attempts to balance a modest allocation size with expected user 74 // input to minimize bounds checks and reallocations during dynamic array 75 // construction. Some user codes may have very large array constructors for 76 // which the default can be increased. 77 static llvm::cl::opt<unsigned> clInitialBufferSize( 78 "array-constructor-initial-buffer-size", 79 llvm::cl::desc( 80 "set the incremental array construction buffer size (default=32)"), 81 llvm::cl::init(32u)); 82 83 /// The various semantics of a program constituent (or a part thereof) as it may 84 /// appear in an expression. 85 /// 86 /// Given the following Fortran declarations. 87 /// ```fortran 88 /// REAL :: v1, v2, v3 89 /// REAL, POINTER :: vp1 90 /// REAL :: a1(c), a2(c) 91 /// REAL ELEMENTAL FUNCTION f1(arg) ! array -> array 92 /// FUNCTION f2(arg) ! array -> array 93 /// vp1 => v3 ! 1 94 /// v1 = v2 * vp1 ! 2 95 /// a1 = a1 + a2 ! 3 96 /// a1 = f1(a2) ! 4 97 /// a1 = f2(a2) ! 5 98 /// ``` 99 /// 100 /// In line 1, `vp1` is a BoxAddr to copy a box value into. The box value is 101 /// constructed from the DataAddr of `v3`. 102 /// In line 2, `v1` is a DataAddr to copy a value into. The value is constructed 103 /// from the DataValue of `v2` and `vp1`. DataValue is implicitly a double 104 /// dereference in the `vp1` case. 105 /// In line 3, `a1` and `a2` on the rhs are RefTransparent. The `a1` on the lhs 106 /// is CopyInCopyOut as `a1` is replaced elementally by the additions. 107 /// In line 4, `a2` can be RefTransparent, ByValueArg, RefOpaque, or BoxAddr if 108 /// `arg` is declared as C-like pass-by-value, VALUE, INTENT(?), or ALLOCATABLE/ 109 /// POINTER, respectively. `a1` on the lhs is CopyInCopyOut. 110 /// In line 5, `a2` may be DataAddr or BoxAddr assuming f2 is transformational. 111 /// `a1` on the lhs is again CopyInCopyOut. 112 enum class ConstituentSemantics { 113 // Scalar data reference semantics. 114 // 115 // For these let `v` be the location in memory of a variable with value `x` 116 DataValue, // refers to the value `x` 117 DataAddr, // refers to the address `v` 118 BoxValue, // refers to a box value containing `v` 119 BoxAddr, // refers to the address of a box value containing `v` 120 121 // Array data reference semantics. 122 // 123 // For these let `a` be the location in memory of a sequence of value `[xs]`. 124 // Let `x_i` be the `i`-th value in the sequence `[xs]`. 125 126 // Referentially transparent. Refers to the array's value, `[xs]`. 127 RefTransparent, 128 // Refers to an ephemeral address `tmp` containing value `x_i` (15.5.2.3.p7 129 // note 2). (Passing a copy by reference to simulate pass-by-value.) 130 ByValueArg, 131 // Refers to the merge of array value `[xs]` with another array value `[ys]`. 132 // This merged array value will be written into memory location `a`. 133 CopyInCopyOut, 134 // Similar to CopyInCopyOut but `a` may be a transient projection (rather than 135 // a whole array). 136 ProjectedCopyInCopyOut, 137 // Similar to ProjectedCopyInCopyOut, except the merge value is not assigned 138 // automatically by the framework. Instead, and address for `[xs]` is made 139 // accessible so that custom assignments to `[xs]` can be implemented. 140 CustomCopyInCopyOut, 141 // Referentially opaque. Refers to the address of `x_i`. 142 RefOpaque 143 }; 144 145 /// Convert parser's INTEGER relational operators to MLIR. TODO: using 146 /// unordered, but we may want to cons ordered in certain situation. 147 static mlir::arith::CmpIPredicate 148 translateRelational(Fortran::common::RelationalOperator rop) { 149 switch (rop) { 150 case Fortran::common::RelationalOperator::LT: 151 return mlir::arith::CmpIPredicate::slt; 152 case Fortran::common::RelationalOperator::LE: 153 return mlir::arith::CmpIPredicate::sle; 154 case Fortran::common::RelationalOperator::EQ: 155 return mlir::arith::CmpIPredicate::eq; 156 case Fortran::common::RelationalOperator::NE: 157 return mlir::arith::CmpIPredicate::ne; 158 case Fortran::common::RelationalOperator::GT: 159 return mlir::arith::CmpIPredicate::sgt; 160 case Fortran::common::RelationalOperator::GE: 161 return mlir::arith::CmpIPredicate::sge; 162 } 163 llvm_unreachable("unhandled INTEGER relational operator"); 164 } 165 166 /// Convert parser's REAL relational operators to MLIR. 167 /// The choice of order (O prefix) vs unorder (U prefix) follows Fortran 2018 168 /// requirements in the IEEE context (table 17.1 of F2018). This choice is 169 /// also applied in other contexts because it is easier and in line with 170 /// other Fortran compilers. 171 /// FIXME: The signaling/quiet aspect of the table 17.1 requirement is not 172 /// fully enforced. FIR and LLVM `fcmp` instructions do not give any guarantee 173 /// whether the comparison will signal or not in case of quiet NaN argument. 174 static mlir::arith::CmpFPredicate 175 translateFloatRelational(Fortran::common::RelationalOperator rop) { 176 switch (rop) { 177 case Fortran::common::RelationalOperator::LT: 178 return mlir::arith::CmpFPredicate::OLT; 179 case Fortran::common::RelationalOperator::LE: 180 return mlir::arith::CmpFPredicate::OLE; 181 case Fortran::common::RelationalOperator::EQ: 182 return mlir::arith::CmpFPredicate::OEQ; 183 case Fortran::common::RelationalOperator::NE: 184 return mlir::arith::CmpFPredicate::UNE; 185 case Fortran::common::RelationalOperator::GT: 186 return mlir::arith::CmpFPredicate::OGT; 187 case Fortran::common::RelationalOperator::GE: 188 return mlir::arith::CmpFPredicate::OGE; 189 } 190 llvm_unreachable("unhandled REAL relational operator"); 191 } 192 193 static mlir::Value genActualIsPresentTest(fir::FirOpBuilder &builder, 194 mlir::Location loc, 195 fir::ExtendedValue actual) { 196 if (const auto *ptrOrAlloc = actual.getBoxOf<fir::MutableBoxValue>()) 197 return fir::factory::genIsAllocatedOrAssociatedTest(builder, loc, 198 *ptrOrAlloc); 199 // Optional case (not that optional allocatable/pointer cannot be absent 200 // when passed to CMPLX as per 15.5.2.12 point 3 (7) and (8)). It is 201 // therefore possible to catch them in the `then` case above. 202 return builder.create<fir::IsPresentOp>(loc, builder.getI1Type(), 203 fir::getBase(actual)); 204 } 205 206 /// Convert the array_load, `load`, to an extended value. If `path` is not 207 /// empty, then traverse through the components designated. The base value is 208 /// `newBase`. This does not accept an array_load with a slice operand. 209 static fir::ExtendedValue 210 arrayLoadExtValue(fir::FirOpBuilder &builder, mlir::Location loc, 211 fir::ArrayLoadOp load, llvm::ArrayRef<mlir::Value> path, 212 mlir::Value newBase, mlir::Value newLen = {}) { 213 // Recover the extended value from the load. 214 assert(!load.getSlice() && "slice is not allowed"); 215 mlir::Type arrTy = load.getType(); 216 if (!path.empty()) { 217 mlir::Type ty = fir::applyPathToType(arrTy, path); 218 if (!ty) 219 fir::emitFatalError(loc, "path does not apply to type"); 220 if (!ty.isa<fir::SequenceType>()) { 221 if (fir::isa_char(ty)) { 222 mlir::Value len = newLen; 223 if (!len) 224 len = fir::factory::CharacterExprHelper{builder, loc}.getLength( 225 load.getMemref()); 226 if (!len) { 227 assert(load.getTypeparams().size() == 1 && 228 "length must be in array_load"); 229 len = load.getTypeparams()[0]; 230 } 231 return fir::CharBoxValue{newBase, len}; 232 } 233 return newBase; 234 } 235 arrTy = ty.cast<fir::SequenceType>(); 236 } 237 238 // Use the shape op, if there is one. 239 mlir::Value shapeVal = load.getShape(); 240 if (shapeVal) { 241 if (!mlir::isa<fir::ShiftOp>(shapeVal.getDefiningOp())) { 242 mlir::Type eleTy = fir::unwrapSequenceType(arrTy); 243 std::vector<mlir::Value> extents = fir::factory::getExtents(shapeVal); 244 std::vector<mlir::Value> origins = fir::factory::getOrigins(shapeVal); 245 if (fir::isa_char(eleTy)) { 246 mlir::Value len = newLen; 247 if (!len) 248 len = fir::factory::CharacterExprHelper{builder, loc}.getLength( 249 load.getMemref()); 250 if (!len) { 251 assert(load.getTypeparams().size() == 1 && 252 "length must be in array_load"); 253 len = load.getTypeparams()[0]; 254 } 255 return fir::CharArrayBoxValue(newBase, len, extents, origins); 256 } 257 return fir::ArrayBoxValue(newBase, extents, origins); 258 } 259 if (!fir::isa_box_type(load.getMemref().getType())) 260 fir::emitFatalError(loc, "shift op is invalid in this context"); 261 } 262 263 // There is no shape or the array is in a box. Extents and lower bounds must 264 // be read at runtime. 265 if (path.empty() && !shapeVal) { 266 fir::ExtendedValue exv = 267 fir::factory::readBoxValue(builder, loc, load.getMemref()); 268 return fir::substBase(exv, newBase); 269 } 270 TODO(loc, "component is boxed, retreive its type parameters"); 271 } 272 273 /// Place \p exv in memory if it is not already a memory reference. If 274 /// \p forceValueType is provided, the value is first casted to the provided 275 /// type before being stored (this is mainly intended for logicals whose value 276 /// may be `i1` but needed to be stored as Fortran logicals). 277 static fir::ExtendedValue 278 placeScalarValueInMemory(fir::FirOpBuilder &builder, mlir::Location loc, 279 const fir::ExtendedValue &exv, 280 mlir::Type storageType) { 281 mlir::Value valBase = fir::getBase(exv); 282 if (fir::conformsWithPassByRef(valBase.getType())) 283 return exv; 284 285 assert(!fir::hasDynamicSize(storageType) && 286 "only expect statically sized scalars to be by value"); 287 288 // Since `a` is not itself a valid referent, determine its value and 289 // create a temporary location at the beginning of the function for 290 // referencing. 291 mlir::Value val = builder.createConvert(loc, storageType, valBase); 292 mlir::Value temp = builder.createTemporary( 293 loc, storageType, 294 llvm::ArrayRef<mlir::NamedAttribute>{ 295 Fortran::lower::getAdaptToByRefAttr(builder)}); 296 builder.create<fir::StoreOp>(loc, val, temp); 297 return fir::substBase(exv, temp); 298 } 299 300 // Copy a copy of scalar \p exv in a new temporary. 301 static fir::ExtendedValue 302 createInMemoryScalarCopy(fir::FirOpBuilder &builder, mlir::Location loc, 303 const fir::ExtendedValue &exv) { 304 assert(exv.rank() == 0 && "input to scalar memory copy must be a scalar"); 305 if (exv.getCharBox() != nullptr) 306 return fir::factory::CharacterExprHelper{builder, loc}.createTempFrom(exv); 307 if (fir::isDerivedWithLengthParameters(exv)) 308 TODO(loc, "copy derived type with length parameters"); 309 mlir::Type type = fir::unwrapPassByRefType(fir::getBase(exv).getType()); 310 fir::ExtendedValue temp = builder.createTemporary(loc, type); 311 fir::factory::genScalarAssignment(builder, loc, temp, exv); 312 return temp; 313 } 314 315 // An expression with non-zero rank is an array expression. 316 template <typename A> 317 static bool isArray(const A &x) { 318 return x.Rank() != 0; 319 } 320 321 /// Is this a variable wrapped in parentheses? 322 template <typename A> 323 static bool isParenthesizedVariable(const A &) { 324 return false; 325 } 326 template <typename T> 327 static bool isParenthesizedVariable(const Fortran::evaluate::Expr<T> &expr) { 328 using ExprVariant = decltype(Fortran::evaluate::Expr<T>::u); 329 using Parentheses = Fortran::evaluate::Parentheses<T>; 330 if constexpr (Fortran::common::HasMember<Parentheses, ExprVariant>) { 331 if (const auto *parentheses = std::get_if<Parentheses>(&expr.u)) 332 return Fortran::evaluate::IsVariable(parentheses->left()); 333 return false; 334 } else { 335 return std::visit([&](const auto &x) { return isParenthesizedVariable(x); }, 336 expr.u); 337 } 338 } 339 340 /// Does \p expr only refer to symbols that are mapped to IR values in \p symMap 341 /// ? 342 static bool allSymbolsInExprPresentInMap(const Fortran::lower::SomeExpr &expr, 343 Fortran::lower::SymMap &symMap) { 344 for (const auto &sym : Fortran::evaluate::CollectSymbols(expr)) 345 if (!symMap.lookupSymbol(sym)) 346 return false; 347 return true; 348 } 349 350 /// Generate a load of a value from an address. Beware that this will lose 351 /// any dynamic type information for polymorphic entities (note that unlimited 352 /// polymorphic cannot be loaded and must not be provided here). 353 static fir::ExtendedValue genLoad(fir::FirOpBuilder &builder, 354 mlir::Location loc, 355 const fir::ExtendedValue &addr) { 356 return addr.match( 357 [](const fir::CharBoxValue &box) -> fir::ExtendedValue { return box; }, 358 [&](const fir::UnboxedValue &v) -> fir::ExtendedValue { 359 if (fir::unwrapRefType(fir::getBase(v).getType()) 360 .isa<fir::RecordType>()) 361 return v; 362 return builder.create<fir::LoadOp>(loc, fir::getBase(v)); 363 }, 364 [&](const fir::MutableBoxValue &box) -> fir::ExtendedValue { 365 return genLoad(builder, loc, 366 fir::factory::genMutableBoxRead(builder, loc, box)); 367 }, 368 [&](const fir::BoxValue &box) -> fir::ExtendedValue { 369 if (box.isUnlimitedPolymorphic()) 370 fir::emitFatalError( 371 loc, 372 "lowering attempting to load an unlimited polymorphic entity"); 373 return genLoad(builder, loc, 374 fir::factory::readBoxValue(builder, loc, box)); 375 }, 376 [&](const auto &) -> fir::ExtendedValue { 377 fir::emitFatalError( 378 loc, "attempting to load whole array or procedure address"); 379 }); 380 } 381 382 /// Create an optional dummy argument value from entity \p exv that may be 383 /// absent. This can only be called with numerical or logical scalar \p exv. 384 /// If \p exv is considered absent according to 15.5.2.12 point 1., the returned 385 /// value is zero (or false), otherwise it is the value of \p exv. 386 static fir::ExtendedValue genOptionalValue(fir::FirOpBuilder &builder, 387 mlir::Location loc, 388 const fir::ExtendedValue &exv, 389 mlir::Value isPresent) { 390 mlir::Type eleType = fir::getBaseTypeOf(exv); 391 assert(exv.rank() == 0 && fir::isa_trivial(eleType) && 392 "must be a numerical or logical scalar"); 393 return builder 394 .genIfOp(loc, {eleType}, isPresent, 395 /*withElseRegion=*/true) 396 .genThen([&]() { 397 mlir::Value val = fir::getBase(genLoad(builder, loc, exv)); 398 builder.create<fir::ResultOp>(loc, val); 399 }) 400 .genElse([&]() { 401 mlir::Value zero = fir::factory::createZeroValue(builder, loc, eleType); 402 builder.create<fir::ResultOp>(loc, zero); 403 }) 404 .getResults()[0]; 405 } 406 407 /// Create an optional dummy argument address from entity \p exv that may be 408 /// absent. If \p exv is considered absent according to 15.5.2.12 point 1., the 409 /// returned value is a null pointer, otherwise it is the address of \p exv. 410 static fir::ExtendedValue genOptionalAddr(fir::FirOpBuilder &builder, 411 mlir::Location loc, 412 const fir::ExtendedValue &exv, 413 mlir::Value isPresent) { 414 // If it is an exv pointer/allocatable, then it cannot be absent 415 // because it is passed to a non-pointer/non-allocatable. 416 if (const auto *box = exv.getBoxOf<fir::MutableBoxValue>()) 417 return fir::factory::genMutableBoxRead(builder, loc, *box); 418 // If this is not a POINTER or ALLOCATABLE, then it is already an OPTIONAL 419 // address and can be passed directly. 420 return exv; 421 } 422 423 /// Create an optional dummy argument address from entity \p exv that may be 424 /// absent. If \p exv is considered absent according to 15.5.2.12 point 1., the 425 /// returned value is an absent fir.box, otherwise it is a fir.box describing \p 426 /// exv. 427 static fir::ExtendedValue genOptionalBox(fir::FirOpBuilder &builder, 428 mlir::Location loc, 429 const fir::ExtendedValue &exv, 430 mlir::Value isPresent) { 431 // Non allocatable/pointer optional box -> simply forward 432 if (exv.getBoxOf<fir::BoxValue>()) 433 return exv; 434 435 fir::ExtendedValue newExv = exv; 436 // Optional allocatable/pointer -> Cannot be absent, but need to translate 437 // unallocated/diassociated into absent fir.box. 438 if (const auto *box = exv.getBoxOf<fir::MutableBoxValue>()) 439 newExv = fir::factory::genMutableBoxRead(builder, loc, *box); 440 441 // createBox will not do create any invalid memory dereferences if exv is 442 // absent. The created fir.box will not be usable, but the SelectOp below 443 // ensures it won't be. 444 mlir::Value box = builder.createBox(loc, newExv); 445 mlir::Type boxType = box.getType(); 446 auto absent = builder.create<fir::AbsentOp>(loc, boxType); 447 auto boxOrAbsent = builder.create<mlir::arith::SelectOp>( 448 loc, boxType, isPresent, box, absent); 449 return fir::BoxValue(boxOrAbsent); 450 } 451 452 /// Is this a call to an elemental procedure with at least one array argument? 453 static bool 454 isElementalProcWithArrayArgs(const Fortran::evaluate::ProcedureRef &procRef) { 455 if (procRef.IsElemental()) 456 for (const std::optional<Fortran::evaluate::ActualArgument> &arg : 457 procRef.arguments()) 458 if (arg && arg->Rank() != 0) 459 return true; 460 return false; 461 } 462 template <typename T> 463 static bool isElementalProcWithArrayArgs(const Fortran::evaluate::Expr<T> &) { 464 return false; 465 } 466 template <> 467 bool isElementalProcWithArrayArgs(const Fortran::lower::SomeExpr &x) { 468 if (const auto *procRef = std::get_if<Fortran::evaluate::ProcedureRef>(&x.u)) 469 return isElementalProcWithArrayArgs(*procRef); 470 return false; 471 } 472 473 /// Some auxiliary data for processing initialization in ScalarExprLowering 474 /// below. This is currently used for generating dense attributed global 475 /// arrays. 476 struct InitializerData { 477 explicit InitializerData(bool getRawVals = false) : genRawVals{getRawVals} {} 478 llvm::SmallVector<mlir::Attribute> rawVals; // initialization raw values 479 mlir::Type rawType; // Type of elements processed for rawVals vector. 480 bool genRawVals; // generate the rawVals vector if set. 481 }; 482 483 /// If \p arg is the address of a function with a denoted host-association tuple 484 /// argument, then return the host-associations tuple value of the current 485 /// procedure. Otherwise, return nullptr. 486 static mlir::Value 487 argumentHostAssocs(Fortran::lower::AbstractConverter &converter, 488 mlir::Value arg) { 489 if (auto addr = mlir::dyn_cast_or_null<fir::AddrOfOp>(arg.getDefiningOp())) { 490 auto &builder = converter.getFirOpBuilder(); 491 if (auto funcOp = builder.getNamedFunction(addr.getSymbol())) 492 if (fir::anyFuncArgsHaveAttr(funcOp, fir::getHostAssocAttrName())) 493 return converter.hostAssocTupleValue(); 494 } 495 return {}; 496 } 497 498 /// \p argTy must be a tuple (pair) of boxproc and integral types. Convert the 499 /// \p funcAddr argument to a boxproc value, with the host-association as 500 /// required. Call the factory function to finish creating the tuple value. 501 static mlir::Value 502 createBoxProcCharTuple(Fortran::lower::AbstractConverter &converter, 503 mlir::Type argTy, mlir::Value funcAddr, 504 mlir::Value charLen) { 505 auto boxTy = 506 argTy.cast<mlir::TupleType>().getType(0).cast<fir::BoxProcType>(); 507 mlir::Location loc = converter.getCurrentLocation(); 508 auto &builder = converter.getFirOpBuilder(); 509 auto boxProc = [&]() -> mlir::Value { 510 if (auto host = argumentHostAssocs(converter, funcAddr)) 511 return builder.create<fir::EmboxProcOp>( 512 loc, boxTy, llvm::ArrayRef<mlir::Value>{funcAddr, host}); 513 return builder.create<fir::EmboxProcOp>(loc, boxTy, funcAddr); 514 }(); 515 return fir::factory::createCharacterProcedureTuple(builder, loc, argTy, 516 boxProc, charLen); 517 } 518 519 // Helper to get the ultimate first symbol. This works around the fact that 520 // symbol resolution in the front end doesn't always resolve a symbol to its 521 // ultimate symbol but may leave placeholder indirections for use and host 522 // associations. 523 template <typename A> 524 const Fortran::semantics::Symbol &getFirstSym(const A &obj) { 525 return obj.GetFirstSymbol().GetUltimate(); 526 } 527 528 // Helper to get the ultimate last symbol. 529 template <typename A> 530 const Fortran::semantics::Symbol &getLastSym(const A &obj) { 531 return obj.GetLastSymbol().GetUltimate(); 532 } 533 534 namespace { 535 536 /// Lowering of Fortran::evaluate::Expr<T> expressions 537 class ScalarExprLowering { 538 public: 539 using ExtValue = fir::ExtendedValue; 540 541 explicit ScalarExprLowering(mlir::Location loc, 542 Fortran::lower::AbstractConverter &converter, 543 Fortran::lower::SymMap &symMap, 544 Fortran::lower::StatementContext &stmtCtx, 545 InitializerData *initializer = nullptr) 546 : location{loc}, converter{converter}, 547 builder{converter.getFirOpBuilder()}, stmtCtx{stmtCtx}, symMap{symMap}, 548 inInitializer{initializer} {} 549 550 ExtValue genExtAddr(const Fortran::lower::SomeExpr &expr) { 551 return gen(expr); 552 } 553 554 /// Lower `expr` to be passed as a fir.box argument. Do not create a temp 555 /// for the expr if it is a variable that can be described as a fir.box. 556 ExtValue genBoxArg(const Fortran::lower::SomeExpr &expr) { 557 bool saveUseBoxArg = useBoxArg; 558 useBoxArg = true; 559 ExtValue result = gen(expr); 560 useBoxArg = saveUseBoxArg; 561 return result; 562 } 563 564 ExtValue genExtValue(const Fortran::lower::SomeExpr &expr) { 565 return genval(expr); 566 } 567 568 /// Lower an expression that is a pointer or an allocatable to a 569 /// MutableBoxValue. 570 fir::MutableBoxValue 571 genMutableBoxValue(const Fortran::lower::SomeExpr &expr) { 572 // Pointers and allocatables can only be: 573 // - a simple designator "x" 574 // - a component designator "a%b(i,j)%x" 575 // - a function reference "foo()" 576 // - result of NULL() or NULL(MOLD) intrinsic. 577 // NULL() requires some context to be lowered, so it is not handled 578 // here and must be lowered according to the context where it appears. 579 ExtValue exv = std::visit( 580 [&](const auto &x) { return genMutableBoxValueImpl(x); }, expr.u); 581 const fir::MutableBoxValue *mutableBox = 582 exv.getBoxOf<fir::MutableBoxValue>(); 583 if (!mutableBox) 584 fir::emitFatalError(getLoc(), "expr was not lowered to MutableBoxValue"); 585 return *mutableBox; 586 } 587 588 template <typename T> 589 ExtValue genMutableBoxValueImpl(const T &) { 590 // NULL() case should not be handled here. 591 fir::emitFatalError(getLoc(), "NULL() must be lowered in its context"); 592 } 593 594 /// A `NULL()` in a position where a mutable box is expected has the same 595 /// semantics as an absent optional box value. 596 ExtValue genMutableBoxValueImpl(const Fortran::evaluate::NullPointer &) { 597 mlir::Location loc = getLoc(); 598 auto nullConst = builder.createNullConstant(loc); 599 auto noneTy = mlir::NoneType::get(builder.getContext()); 600 auto polyRefTy = fir::LLVMPointerType::get(noneTy); 601 // MutableBoxValue will dereference the box, so create a bogus temporary for 602 // the `nullptr`. The LLVM optimizer will garbage collect the temp. 603 auto temp = 604 builder.createTemporary(loc, polyRefTy, /*shape=*/mlir::ValueRange{}); 605 auto nullPtr = builder.createConvert(loc, polyRefTy, nullConst); 606 builder.create<fir::StoreOp>(loc, nullPtr, temp); 607 auto nullBoxTy = builder.getRefType(fir::BoxType::get(noneTy)); 608 return fir::MutableBoxValue(builder.createConvert(loc, nullBoxTy, temp), 609 /*lenParameters=*/mlir::ValueRange{}, 610 /*mutableProperties=*/{}); 611 } 612 613 template <typename T> 614 ExtValue 615 genMutableBoxValueImpl(const Fortran::evaluate::FunctionRef<T> &funRef) { 616 return genRawProcedureRef(funRef, converter.genType(toEvExpr(funRef))); 617 } 618 619 template <typename T> 620 ExtValue 621 genMutableBoxValueImpl(const Fortran::evaluate::Designator<T> &designator) { 622 return std::visit( 623 Fortran::common::visitors{ 624 [&](const Fortran::evaluate::SymbolRef &sym) -> ExtValue { 625 return symMap.lookupSymbol(*sym).toExtendedValue(); 626 }, 627 [&](const Fortran::evaluate::Component &comp) -> ExtValue { 628 return genComponent(comp); 629 }, 630 [&](const auto &) -> ExtValue { 631 fir::emitFatalError(getLoc(), 632 "not an allocatable or pointer designator"); 633 }}, 634 designator.u); 635 } 636 637 template <typename T> 638 ExtValue genMutableBoxValueImpl(const Fortran::evaluate::Expr<T> &expr) { 639 return std::visit([&](const auto &x) { return genMutableBoxValueImpl(x); }, 640 expr.u); 641 } 642 643 mlir::Location getLoc() { return location; } 644 645 template <typename A> 646 mlir::Value genunbox(const A &expr) { 647 ExtValue e = genval(expr); 648 if (const fir::UnboxedValue *r = e.getUnboxed()) 649 return *r; 650 fir::emitFatalError(getLoc(), "unboxed expression expected"); 651 } 652 653 /// Generate an integral constant of `value` 654 template <int KIND> 655 mlir::Value genIntegerConstant(mlir::MLIRContext *context, 656 std::int64_t value) { 657 mlir::Type type = 658 converter.genType(Fortran::common::TypeCategory::Integer, KIND); 659 return builder.createIntegerConstant(getLoc(), type, value); 660 } 661 662 /// Generate a logical/boolean constant of `value` 663 mlir::Value genBoolConstant(bool value) { 664 return builder.createBool(getLoc(), value); 665 } 666 667 /// Generate a real constant with a value `value`. 668 template <int KIND> 669 mlir::Value genRealConstant(mlir::MLIRContext *context, 670 const llvm::APFloat &value) { 671 mlir::Type fltTy = Fortran::lower::convertReal(context, KIND); 672 return builder.createRealConstant(getLoc(), fltTy, value); 673 } 674 675 mlir::Type getSomeKindInteger() { return builder.getIndexType(); } 676 677 mlir::func::FuncOp getFunction(llvm::StringRef name, 678 mlir::FunctionType funTy) { 679 if (mlir::func::FuncOp func = builder.getNamedFunction(name)) 680 return func; 681 return builder.createFunction(getLoc(), name, funTy); 682 } 683 684 template <typename OpTy> 685 mlir::Value createCompareOp(mlir::arith::CmpIPredicate pred, 686 const ExtValue &left, const ExtValue &right) { 687 if (const fir::UnboxedValue *lhs = left.getUnboxed()) 688 if (const fir::UnboxedValue *rhs = right.getUnboxed()) 689 return builder.create<OpTy>(getLoc(), pred, *lhs, *rhs); 690 fir::emitFatalError(getLoc(), "array compare should be handled in genarr"); 691 } 692 template <typename OpTy, typename A> 693 mlir::Value createCompareOp(const A &ex, mlir::arith::CmpIPredicate pred) { 694 ExtValue left = genval(ex.left()); 695 return createCompareOp<OpTy>(pred, left, genval(ex.right())); 696 } 697 698 template <typename OpTy> 699 mlir::Value createFltCmpOp(mlir::arith::CmpFPredicate pred, 700 const ExtValue &left, const ExtValue &right) { 701 if (const fir::UnboxedValue *lhs = left.getUnboxed()) 702 if (const fir::UnboxedValue *rhs = right.getUnboxed()) 703 return builder.create<OpTy>(getLoc(), pred, *lhs, *rhs); 704 fir::emitFatalError(getLoc(), "array compare should be handled in genarr"); 705 } 706 template <typename OpTy, typename A> 707 mlir::Value createFltCmpOp(const A &ex, mlir::arith::CmpFPredicate pred) { 708 ExtValue left = genval(ex.left()); 709 return createFltCmpOp<OpTy>(pred, left, genval(ex.right())); 710 } 711 712 /// Create a call to the runtime to compare two CHARACTER values. 713 /// Precondition: This assumes that the two values have `fir.boxchar` type. 714 mlir::Value createCharCompare(mlir::arith::CmpIPredicate pred, 715 const ExtValue &left, const ExtValue &right) { 716 return fir::runtime::genCharCompare(builder, getLoc(), pred, left, right); 717 } 718 719 template <typename A> 720 mlir::Value createCharCompare(const A &ex, mlir::arith::CmpIPredicate pred) { 721 ExtValue left = genval(ex.left()); 722 return createCharCompare(pred, left, genval(ex.right())); 723 } 724 725 /// Returns a reference to a symbol or its box/boxChar descriptor if it has 726 /// one. 727 ExtValue gen(Fortran::semantics::SymbolRef sym) { 728 if (Fortran::lower::SymbolBox val = symMap.lookupSymbol(sym)) 729 return val.match( 730 [&](const Fortran::lower::SymbolBox::PointerOrAllocatable &boxAddr) { 731 return fir::factory::genMutableBoxRead(builder, getLoc(), boxAddr); 732 }, 733 [&val](auto &) { return val.toExtendedValue(); }); 734 LLVM_DEBUG(llvm::dbgs() 735 << "unknown symbol: " << sym << "\nmap: " << symMap << '\n'); 736 fir::emitFatalError(getLoc(), "symbol is not mapped to any IR value"); 737 } 738 739 ExtValue genLoad(const ExtValue &exv) { 740 return ::genLoad(builder, getLoc(), exv); 741 } 742 743 ExtValue genval(Fortran::semantics::SymbolRef sym) { 744 mlir::Location loc = getLoc(); 745 ExtValue var = gen(sym); 746 if (const fir::UnboxedValue *s = var.getUnboxed()) 747 if (fir::isReferenceLike(s->getType())) { 748 // A function with multiple entry points returning different types 749 // tags all result variables with one of the largest types to allow 750 // them to share the same storage. A reference to a result variable 751 // of one of the other types requires conversion to the actual type. 752 fir::UnboxedValue addr = *s; 753 if (Fortran::semantics::IsFunctionResult(sym)) { 754 mlir::Type resultType = converter.genType(*sym); 755 if (addr.getType() != resultType) 756 addr = builder.createConvert(loc, builder.getRefType(resultType), 757 addr); 758 } 759 return genLoad(addr); 760 } 761 return var; 762 } 763 764 ExtValue genval(const Fortran::evaluate::BOZLiteralConstant &) { 765 TODO(getLoc(), "BOZ"); 766 } 767 768 /// Return indirection to function designated in ProcedureDesignator. 769 /// The type of the function indirection is not guaranteed to match the one 770 /// of the ProcedureDesignator due to Fortran implicit typing rules. 771 ExtValue genval(const Fortran::evaluate::ProcedureDesignator &proc) { 772 mlir::Location loc = getLoc(); 773 if (const Fortran::evaluate::SpecificIntrinsic *intrinsic = 774 proc.GetSpecificIntrinsic()) { 775 mlir::FunctionType signature = 776 Fortran::lower::translateSignature(proc, converter); 777 // Intrinsic lowering is based on the generic name, so retrieve it here in 778 // case it is different from the specific name. The type of the specific 779 // intrinsic is retained in the signature. 780 std::string genericName = 781 converter.getFoldingContext().intrinsics().GetGenericIntrinsicName( 782 intrinsic->name); 783 mlir::SymbolRefAttr symbolRefAttr = 784 Fortran::lower::getUnrestrictedIntrinsicSymbolRefAttr( 785 builder, loc, genericName, signature); 786 mlir::Value funcPtr = 787 builder.create<fir::AddrOfOp>(loc, signature, symbolRefAttr); 788 return funcPtr; 789 } 790 const Fortran::semantics::Symbol *symbol = proc.GetSymbol(); 791 assert(symbol && "expected symbol in ProcedureDesignator"); 792 mlir::Value funcPtr; 793 mlir::Value funcPtrResultLength; 794 if (Fortran::semantics::IsDummy(*symbol)) { 795 Fortran::lower::SymbolBox val = symMap.lookupSymbol(*symbol); 796 assert(val && "Dummy procedure not in symbol map"); 797 funcPtr = val.getAddr(); 798 if (fir::isCharacterProcedureTuple(funcPtr.getType(), 799 /*acceptRawFunc=*/false)) 800 std::tie(funcPtr, funcPtrResultLength) = 801 fir::factory::extractCharacterProcedureTuple(builder, loc, funcPtr); 802 } else { 803 std::string name = converter.mangleName(*symbol); 804 mlir::func::FuncOp func = 805 Fortran::lower::getOrDeclareFunction(name, proc, converter); 806 funcPtr = builder.create<fir::AddrOfOp>(loc, func.getFunctionType(), 807 builder.getSymbolRefAttr(name)); 808 } 809 if (Fortran::lower::mustPassLengthWithDummyProcedure(proc, converter)) { 810 // The result length, if available here, must be propagated along the 811 // procedure address so that call sites where the result length is assumed 812 // can retrieve the length. 813 Fortran::evaluate::DynamicType resultType = proc.GetType().value(); 814 if (const auto &lengthExpr = resultType.GetCharLength()) { 815 // The length expression may refer to dummy argument symbols that are 816 // meaningless without any actual arguments. Leave the length as 817 // unknown in that case, it be resolved on the call site 818 // with the actual arguments. 819 if (allSymbolsInExprPresentInMap(toEvExpr(*lengthExpr), symMap)) { 820 mlir::Value rawLen = fir::getBase(genval(*lengthExpr)); 821 // F2018 7.4.4.2 point 5. 822 funcPtrResultLength = 823 Fortran::lower::genMaxWithZero(builder, getLoc(), rawLen); 824 } 825 } 826 if (!funcPtrResultLength) 827 funcPtrResultLength = builder.createIntegerConstant( 828 loc, builder.getCharacterLengthType(), -1); 829 return fir::CharBoxValue{funcPtr, funcPtrResultLength}; 830 } 831 return funcPtr; 832 } 833 ExtValue genval(const Fortran::evaluate::NullPointer &) { 834 return builder.createNullConstant(getLoc()); 835 } 836 837 static bool 838 isDerivedTypeWithLengthParameters(const Fortran::semantics::Symbol &sym) { 839 if (const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType()) 840 if (const Fortran::semantics::DerivedTypeSpec *derived = 841 declTy->AsDerived()) 842 return Fortran::semantics::CountLenParameters(*derived) > 0; 843 return false; 844 } 845 846 static bool isBuiltinCPtr(const Fortran::semantics::Symbol &sym) { 847 if (const Fortran::semantics::DeclTypeSpec *declType = sym.GetType()) 848 if (const Fortran::semantics::DerivedTypeSpec *derived = 849 declType->AsDerived()) 850 return Fortran::semantics::IsIsoCType(derived); 851 return false; 852 } 853 854 /// Lower structure constructor without a temporary. This can be used in 855 /// fir::GloablOp, and assumes that the structure component is a constant. 856 ExtValue genStructComponentInInitializer( 857 const Fortran::evaluate::StructureConstructor &ctor) { 858 mlir::Location loc = getLoc(); 859 mlir::Type ty = translateSomeExprToFIRType(converter, toEvExpr(ctor)); 860 auto recTy = ty.cast<fir::RecordType>(); 861 auto fieldTy = fir::FieldType::get(ty.getContext()); 862 mlir::Value res = builder.create<fir::UndefOp>(loc, recTy); 863 864 for (const auto &[sym, expr] : ctor.values()) { 865 // Parent components need more work because they do not appear in the 866 // fir.rec type. 867 if (sym->test(Fortran::semantics::Symbol::Flag::ParentComp)) 868 TODO(loc, "parent component in structure constructor"); 869 870 llvm::StringRef name = toStringRef(sym->name()); 871 mlir::Type componentTy = recTy.getType(name); 872 // FIXME: type parameters must come from the derived-type-spec 873 auto field = builder.create<fir::FieldIndexOp>( 874 loc, fieldTy, name, ty, 875 /*typeParams=*/mlir::ValueRange{} /*TODO*/); 876 877 if (Fortran::semantics::IsAllocatable(sym)) 878 TODO(loc, "allocatable component in structure constructor"); 879 880 if (Fortran::semantics::IsPointer(sym)) { 881 mlir::Value initialTarget = Fortran::lower::genInitialDataTarget( 882 converter, loc, componentTy, expr.value()); 883 res = builder.create<fir::InsertValueOp>( 884 loc, recTy, res, initialTarget, 885 builder.getArrayAttr(field.getAttributes())); 886 continue; 887 } 888 889 if (isDerivedTypeWithLengthParameters(sym)) 890 TODO(loc, "component with length parameters in structure constructor"); 891 892 if (isBuiltinCPtr(sym)) { 893 // Builtin c_ptr and c_funptr have special handling because initial 894 // value are handled for them as an extension. 895 mlir::Value addr = fir::getBase(Fortran::lower::genExtAddrInInitializer( 896 converter, loc, expr.value())); 897 if (addr.getType() == componentTy) { 898 // Do nothing. The Ev::Expr was returned as a value that can be 899 // inserted directly to the component without an intermediary. 900 } else { 901 // The Ev::Expr returned is an initializer that is a pointer (e.g., 902 // null) that must be inserted into an intermediate cptr record 903 // value's address field, which ought to be an intptr_t on the target. 904 assert((fir::isa_ref_type(addr.getType()) || 905 addr.getType().isa<mlir::FunctionType>()) && 906 "expect reference type for address field"); 907 assert(fir::isa_derived(componentTy) && 908 "expect C_PTR, C_FUNPTR to be a record"); 909 auto cPtrRecTy = componentTy.cast<fir::RecordType>(); 910 llvm::StringRef addrFieldName = 911 Fortran::lower::builtin::cptrFieldName; 912 mlir::Type addrFieldTy = cPtrRecTy.getType(addrFieldName); 913 auto addrField = builder.create<fir::FieldIndexOp>( 914 loc, fieldTy, addrFieldName, componentTy, 915 /*typeParams=*/mlir::ValueRange{}); 916 mlir::Value castAddr = builder.createConvert(loc, addrFieldTy, addr); 917 auto undef = builder.create<fir::UndefOp>(loc, componentTy); 918 addr = builder.create<fir::InsertValueOp>( 919 loc, componentTy, undef, castAddr, 920 builder.getArrayAttr(addrField.getAttributes())); 921 } 922 res = builder.create<fir::InsertValueOp>( 923 loc, recTy, res, addr, builder.getArrayAttr(field.getAttributes())); 924 continue; 925 } 926 927 mlir::Value val = fir::getBase(genval(expr.value())); 928 assert(!fir::isa_ref_type(val.getType()) && "expecting a constant value"); 929 mlir::Value castVal = builder.createConvert(loc, componentTy, val); 930 res = builder.create<fir::InsertValueOp>( 931 loc, recTy, res, castVal, 932 builder.getArrayAttr(field.getAttributes())); 933 } 934 return res; 935 } 936 937 /// A structure constructor is lowered two ways. In an initializer context, 938 /// the entire structure must be constant, so the aggregate value is 939 /// constructed inline. This allows it to be the body of a GlobalOp. 940 /// Otherwise, the structure constructor is in an expression. In that case, a 941 /// temporary object is constructed in the stack frame of the procedure. 942 ExtValue genval(const Fortran::evaluate::StructureConstructor &ctor) { 943 if (inInitializer) 944 return genStructComponentInInitializer(ctor); 945 mlir::Location loc = getLoc(); 946 mlir::Type ty = translateSomeExprToFIRType(converter, toEvExpr(ctor)); 947 auto recTy = ty.cast<fir::RecordType>(); 948 auto fieldTy = fir::FieldType::get(ty.getContext()); 949 mlir::Value res = builder.createTemporary(loc, recTy); 950 951 for (const auto &value : ctor.values()) { 952 const Fortran::semantics::Symbol &sym = *value.first; 953 const Fortran::lower::SomeExpr &expr = value.second.value(); 954 // Parent components need more work because they do not appear in the 955 // fir.rec type. 956 if (sym.test(Fortran::semantics::Symbol::Flag::ParentComp)) 957 TODO(loc, "parent component in structure constructor"); 958 959 if (isDerivedTypeWithLengthParameters(sym)) 960 TODO(loc, "component with length parameters in structure constructor"); 961 962 llvm::StringRef name = toStringRef(sym.name()); 963 // FIXME: type parameters must come from the derived-type-spec 964 mlir::Value field = builder.create<fir::FieldIndexOp>( 965 loc, fieldTy, name, ty, 966 /*typeParams=*/mlir::ValueRange{} /*TODO*/); 967 mlir::Type coorTy = builder.getRefType(recTy.getType(name)); 968 auto coor = builder.create<fir::CoordinateOp>(loc, coorTy, 969 fir::getBase(res), field); 970 ExtValue to = fir::factory::componentToExtendedValue(builder, loc, coor); 971 to.match( 972 [&](const fir::UnboxedValue &toPtr) { 973 ExtValue value = genval(expr); 974 fir::factory::genScalarAssignment(builder, loc, to, value); 975 }, 976 [&](const fir::CharBoxValue &) { 977 ExtValue value = genval(expr); 978 fir::factory::genScalarAssignment(builder, loc, to, value); 979 }, 980 [&](const fir::ArrayBoxValue &) { 981 Fortran::lower::createSomeArrayAssignment(converter, to, expr, 982 symMap, stmtCtx); 983 }, 984 [&](const fir::CharArrayBoxValue &) { 985 Fortran::lower::createSomeArrayAssignment(converter, to, expr, 986 symMap, stmtCtx); 987 }, 988 [&](const fir::BoxValue &toBox) { 989 fir::emitFatalError(loc, "derived type components must not be " 990 "represented by fir::BoxValue"); 991 }, 992 [&](const fir::MutableBoxValue &toBox) { 993 if (toBox.isPointer()) { 994 Fortran::lower::associateMutableBox( 995 converter, loc, toBox, expr, /*lbounds=*/llvm::None, stmtCtx); 996 return; 997 } 998 // For allocatable components, a deep copy is needed. 999 TODO(loc, "allocatable components in derived type assignment"); 1000 }, 1001 [&](const fir::ProcBoxValue &toBox) { 1002 TODO(loc, "procedure pointer component in derived type assignment"); 1003 }); 1004 } 1005 return res; 1006 } 1007 1008 /// Lowering of an <i>ac-do-variable</i>, which is not a Symbol. 1009 ExtValue genval(const Fortran::evaluate::ImpliedDoIndex &var) { 1010 return converter.impliedDoBinding(toStringRef(var.name)); 1011 } 1012 1013 ExtValue genval(const Fortran::evaluate::DescriptorInquiry &desc) { 1014 ExtValue exv = desc.base().IsSymbol() ? gen(getLastSym(desc.base())) 1015 : gen(desc.base().GetComponent()); 1016 mlir::IndexType idxTy = builder.getIndexType(); 1017 mlir::Location loc = getLoc(); 1018 auto castResult = [&](mlir::Value v) { 1019 using ResTy = Fortran::evaluate::DescriptorInquiry::Result; 1020 return builder.createConvert( 1021 loc, converter.genType(ResTy::category, ResTy::kind), v); 1022 }; 1023 switch (desc.field()) { 1024 case Fortran::evaluate::DescriptorInquiry::Field::Len: 1025 return castResult(fir::factory::readCharLen(builder, loc, exv)); 1026 case Fortran::evaluate::DescriptorInquiry::Field::LowerBound: 1027 return castResult(fir::factory::readLowerBound( 1028 builder, loc, exv, desc.dimension(), 1029 builder.createIntegerConstant(loc, idxTy, 1))); 1030 case Fortran::evaluate::DescriptorInquiry::Field::Extent: 1031 return castResult( 1032 fir::factory::readExtent(builder, loc, exv, desc.dimension())); 1033 case Fortran::evaluate::DescriptorInquiry::Field::Rank: 1034 TODO(loc, "rank inquiry on assumed rank"); 1035 case Fortran::evaluate::DescriptorInquiry::Field::Stride: 1036 // So far the front end does not generate this inquiry. 1037 TODO(loc, "Stride inquiry"); 1038 } 1039 llvm_unreachable("unknown descriptor inquiry"); 1040 } 1041 1042 ExtValue genval(const Fortran::evaluate::TypeParamInquiry &) { 1043 TODO(getLoc(), "type parameter inquiry"); 1044 } 1045 1046 mlir::Value extractComplexPart(mlir::Value cplx, bool isImagPart) { 1047 return fir::factory::Complex{builder, getLoc()}.extractComplexPart( 1048 cplx, isImagPart); 1049 } 1050 1051 template <int KIND> 1052 ExtValue genval(const Fortran::evaluate::ComplexComponent<KIND> &part) { 1053 return extractComplexPart(genunbox(part.left()), part.isImaginaryPart); 1054 } 1055 1056 template <int KIND> 1057 ExtValue genval(const Fortran::evaluate::Negate<Fortran::evaluate::Type< 1058 Fortran::common::TypeCategory::Integer, KIND>> &op) { 1059 mlir::Value input = genunbox(op.left()); 1060 // Like LLVM, integer negation is the binary op "0 - value" 1061 mlir::Value zero = genIntegerConstant<KIND>(builder.getContext(), 0); 1062 return builder.create<mlir::arith::SubIOp>(getLoc(), zero, input); 1063 } 1064 template <int KIND> 1065 ExtValue genval(const Fortran::evaluate::Negate<Fortran::evaluate::Type< 1066 Fortran::common::TypeCategory::Real, KIND>> &op) { 1067 return builder.create<mlir::arith::NegFOp>(getLoc(), genunbox(op.left())); 1068 } 1069 template <int KIND> 1070 ExtValue genval(const Fortran::evaluate::Negate<Fortran::evaluate::Type< 1071 Fortran::common::TypeCategory::Complex, KIND>> &op) { 1072 return builder.create<fir::NegcOp>(getLoc(), genunbox(op.left())); 1073 } 1074 1075 template <typename OpTy> 1076 mlir::Value createBinaryOp(const ExtValue &left, const ExtValue &right) { 1077 assert(fir::isUnboxedValue(left) && fir::isUnboxedValue(right)); 1078 mlir::Value lhs = fir::getBase(left); 1079 mlir::Value rhs = fir::getBase(right); 1080 assert(lhs.getType() == rhs.getType() && "types must be the same"); 1081 return builder.create<OpTy>(getLoc(), lhs, rhs); 1082 } 1083 1084 template <typename OpTy, typename A> 1085 mlir::Value createBinaryOp(const A &ex) { 1086 ExtValue left = genval(ex.left()); 1087 return createBinaryOp<OpTy>(left, genval(ex.right())); 1088 } 1089 1090 #undef GENBIN 1091 #define GENBIN(GenBinEvOp, GenBinTyCat, GenBinFirOp) \ 1092 template <int KIND> \ 1093 ExtValue genval(const Fortran::evaluate::GenBinEvOp<Fortran::evaluate::Type< \ 1094 Fortran::common::TypeCategory::GenBinTyCat, KIND>> &x) { \ 1095 return createBinaryOp<GenBinFirOp>(x); \ 1096 } 1097 1098 GENBIN(Add, Integer, mlir::arith::AddIOp) 1099 GENBIN(Add, Real, mlir::arith::AddFOp) 1100 GENBIN(Add, Complex, fir::AddcOp) 1101 GENBIN(Subtract, Integer, mlir::arith::SubIOp) 1102 GENBIN(Subtract, Real, mlir::arith::SubFOp) 1103 GENBIN(Subtract, Complex, fir::SubcOp) 1104 GENBIN(Multiply, Integer, mlir::arith::MulIOp) 1105 GENBIN(Multiply, Real, mlir::arith::MulFOp) 1106 GENBIN(Multiply, Complex, fir::MulcOp) 1107 GENBIN(Divide, Integer, mlir::arith::DivSIOp) 1108 GENBIN(Divide, Real, mlir::arith::DivFOp) 1109 GENBIN(Divide, Complex, fir::DivcOp) 1110 1111 template <Fortran::common::TypeCategory TC, int KIND> 1112 ExtValue genval( 1113 const Fortran::evaluate::Power<Fortran::evaluate::Type<TC, KIND>> &op) { 1114 mlir::Type ty = converter.genType(TC, KIND); 1115 mlir::Value lhs = genunbox(op.left()); 1116 mlir::Value rhs = genunbox(op.right()); 1117 return Fortran::lower::genPow(builder, getLoc(), ty, lhs, rhs); 1118 } 1119 1120 template <Fortran::common::TypeCategory TC, int KIND> 1121 ExtValue genval( 1122 const Fortran::evaluate::RealToIntPower<Fortran::evaluate::Type<TC, KIND>> 1123 &op) { 1124 mlir::Type ty = converter.genType(TC, KIND); 1125 mlir::Value lhs = genunbox(op.left()); 1126 mlir::Value rhs = genunbox(op.right()); 1127 return Fortran::lower::genPow(builder, getLoc(), ty, lhs, rhs); 1128 } 1129 1130 template <int KIND> 1131 ExtValue genval(const Fortran::evaluate::ComplexConstructor<KIND> &op) { 1132 mlir::Value realPartValue = genunbox(op.left()); 1133 return fir::factory::Complex{builder, getLoc()}.createComplex( 1134 KIND, realPartValue, genunbox(op.right())); 1135 } 1136 1137 template <int KIND> 1138 ExtValue genval(const Fortran::evaluate::Concat<KIND> &op) { 1139 ExtValue lhs = genval(op.left()); 1140 ExtValue rhs = genval(op.right()); 1141 const fir::CharBoxValue *lhsChar = lhs.getCharBox(); 1142 const fir::CharBoxValue *rhsChar = rhs.getCharBox(); 1143 if (lhsChar && rhsChar) 1144 return fir::factory::CharacterExprHelper{builder, getLoc()} 1145 .createConcatenate(*lhsChar, *rhsChar); 1146 TODO(getLoc(), "character array concatenate"); 1147 } 1148 1149 /// MIN and MAX operations 1150 template <Fortran::common::TypeCategory TC, int KIND> 1151 ExtValue 1152 genval(const Fortran::evaluate::Extremum<Fortran::evaluate::Type<TC, KIND>> 1153 &op) { 1154 mlir::Value lhs = genunbox(op.left()); 1155 mlir::Value rhs = genunbox(op.right()); 1156 switch (op.ordering) { 1157 case Fortran::evaluate::Ordering::Greater: 1158 return Fortran::lower::genMax(builder, getLoc(), 1159 llvm::ArrayRef<mlir::Value>{lhs, rhs}); 1160 case Fortran::evaluate::Ordering::Less: 1161 return Fortran::lower::genMin(builder, getLoc(), 1162 llvm::ArrayRef<mlir::Value>{lhs, rhs}); 1163 case Fortran::evaluate::Ordering::Equal: 1164 llvm_unreachable("Equal is not a valid ordering in this context"); 1165 } 1166 llvm_unreachable("unknown ordering"); 1167 } 1168 1169 // Change the dynamic length information without actually changing the 1170 // underlying character storage. 1171 fir::ExtendedValue 1172 replaceScalarCharacterLength(const fir::ExtendedValue &scalarChar, 1173 mlir::Value newLenValue) { 1174 mlir::Location loc = getLoc(); 1175 const fir::CharBoxValue *charBox = scalarChar.getCharBox(); 1176 if (!charBox) 1177 fir::emitFatalError(loc, "expected scalar character"); 1178 mlir::Value charAddr = charBox->getAddr(); 1179 auto charType = 1180 fir::unwrapPassByRefType(charAddr.getType()).cast<fir::CharacterType>(); 1181 if (charType.hasConstantLen()) { 1182 // Erase previous constant length from the base type. 1183 fir::CharacterType::LenType newLen = fir::CharacterType::unknownLen(); 1184 mlir::Type newCharTy = fir::CharacterType::get( 1185 builder.getContext(), charType.getFKind(), newLen); 1186 mlir::Type newType = fir::ReferenceType::get(newCharTy); 1187 charAddr = builder.createConvert(loc, newType, charAddr); 1188 return fir::CharBoxValue{charAddr, newLenValue}; 1189 } 1190 return fir::CharBoxValue{charAddr, newLenValue}; 1191 } 1192 1193 template <int KIND> 1194 ExtValue genval(const Fortran::evaluate::SetLength<KIND> &x) { 1195 mlir::Value newLenValue = genunbox(x.right()); 1196 fir::ExtendedValue lhs = gen(x.left()); 1197 return replaceScalarCharacterLength(lhs, newLenValue); 1198 } 1199 1200 template <int KIND> 1201 ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type< 1202 Fortran::common::TypeCategory::Integer, KIND>> &op) { 1203 return createCompareOp<mlir::arith::CmpIOp>(op, 1204 translateRelational(op.opr)); 1205 } 1206 template <int KIND> 1207 ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type< 1208 Fortran::common::TypeCategory::Real, KIND>> &op) { 1209 return createFltCmpOp<mlir::arith::CmpFOp>( 1210 op, translateFloatRelational(op.opr)); 1211 } 1212 template <int KIND> 1213 ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type< 1214 Fortran::common::TypeCategory::Complex, KIND>> &op) { 1215 return createFltCmpOp<fir::CmpcOp>(op, translateFloatRelational(op.opr)); 1216 } 1217 template <int KIND> 1218 ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type< 1219 Fortran::common::TypeCategory::Character, KIND>> &op) { 1220 return createCharCompare(op, translateRelational(op.opr)); 1221 } 1222 1223 ExtValue 1224 genval(const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &op) { 1225 return std::visit([&](const auto &x) { return genval(x); }, op.u); 1226 } 1227 1228 template <Fortran::common::TypeCategory TC1, int KIND, 1229 Fortran::common::TypeCategory TC2> 1230 ExtValue 1231 genval(const Fortran::evaluate::Convert<Fortran::evaluate::Type<TC1, KIND>, 1232 TC2> &convert) { 1233 mlir::Type ty = converter.genType(TC1, KIND); 1234 auto fromExpr = genval(convert.left()); 1235 auto loc = getLoc(); 1236 return fromExpr.match( 1237 [&](const fir::CharBoxValue &boxchar) -> ExtValue { 1238 if constexpr (TC1 == Fortran::common::TypeCategory::Character && 1239 TC2 == TC1) { 1240 // Use char_convert. Each code point is translated from a 1241 // narrower/wider encoding to the target encoding. For example, 'A' 1242 // may be translated from 0x41 : i8 to 0x0041 : i16. The symbol 1243 // for euro (0x20AC : i16) may be translated from a wide character 1244 // to "0xE2 0x82 0xAC" : UTF-8. 1245 mlir::Value bufferSize = boxchar.getLen(); 1246 auto kindMap = builder.getKindMap(); 1247 auto fromBits = kindMap.getCharacterBitsize( 1248 fir::unwrapRefType(boxchar.getAddr().getType()) 1249 .cast<fir::CharacterType>() 1250 .getFKind()); 1251 auto toBits = kindMap.getCharacterBitsize( 1252 ty.cast<fir::CharacterType>().getFKind()); 1253 if (toBits < fromBits) { 1254 // Scale by relative ratio to give a buffer of the same length. 1255 auto ratio = builder.createIntegerConstant( 1256 loc, bufferSize.getType(), fromBits / toBits); 1257 bufferSize = 1258 builder.create<mlir::arith::MulIOp>(loc, bufferSize, ratio); 1259 } 1260 auto dest = builder.create<fir::AllocaOp>( 1261 loc, ty, mlir::ValueRange{bufferSize}); 1262 builder.create<fir::CharConvertOp>(loc, boxchar.getAddr(), 1263 boxchar.getLen(), dest); 1264 return fir::CharBoxValue{dest, boxchar.getLen()}; 1265 } else { 1266 fir::emitFatalError( 1267 loc, "unsupported evaluate::Convert between CHARACTER type " 1268 "category and non-CHARACTER category"); 1269 } 1270 }, 1271 [&](const fir::UnboxedValue &value) -> ExtValue { 1272 return builder.convertWithSemantics(loc, ty, value); 1273 }, 1274 [&](auto &) -> ExtValue { 1275 fir::emitFatalError(loc, "unsupported evaluate::Convert"); 1276 }); 1277 } 1278 1279 template <typename A> 1280 ExtValue genval(const Fortran::evaluate::Parentheses<A> &op) { 1281 ExtValue input = genval(op.left()); 1282 mlir::Value base = fir::getBase(input); 1283 mlir::Value newBase = 1284 builder.create<fir::NoReassocOp>(getLoc(), base.getType(), base); 1285 return fir::substBase(input, newBase); 1286 } 1287 1288 template <int KIND> 1289 ExtValue genval(const Fortran::evaluate::Not<KIND> &op) { 1290 mlir::Value logical = genunbox(op.left()); 1291 mlir::Value one = genBoolConstant(true); 1292 mlir::Value val = 1293 builder.createConvert(getLoc(), builder.getI1Type(), logical); 1294 return builder.create<mlir::arith::XOrIOp>(getLoc(), val, one); 1295 } 1296 1297 template <int KIND> 1298 ExtValue genval(const Fortran::evaluate::LogicalOperation<KIND> &op) { 1299 mlir::IntegerType i1Type = builder.getI1Type(); 1300 mlir::Value slhs = genunbox(op.left()); 1301 mlir::Value srhs = genunbox(op.right()); 1302 mlir::Value lhs = builder.createConvert(getLoc(), i1Type, slhs); 1303 mlir::Value rhs = builder.createConvert(getLoc(), i1Type, srhs); 1304 switch (op.logicalOperator) { 1305 case Fortran::evaluate::LogicalOperator::And: 1306 return createBinaryOp<mlir::arith::AndIOp>(lhs, rhs); 1307 case Fortran::evaluate::LogicalOperator::Or: 1308 return createBinaryOp<mlir::arith::OrIOp>(lhs, rhs); 1309 case Fortran::evaluate::LogicalOperator::Eqv: 1310 return createCompareOp<mlir::arith::CmpIOp>( 1311 mlir::arith::CmpIPredicate::eq, lhs, rhs); 1312 case Fortran::evaluate::LogicalOperator::Neqv: 1313 return createCompareOp<mlir::arith::CmpIOp>( 1314 mlir::arith::CmpIPredicate::ne, lhs, rhs); 1315 case Fortran::evaluate::LogicalOperator::Not: 1316 // lib/evaluate expression for .NOT. is Fortran::evaluate::Not<KIND>. 1317 llvm_unreachable(".NOT. is not a binary operator"); 1318 } 1319 llvm_unreachable("unhandled logical operation"); 1320 } 1321 1322 /// Convert a scalar literal constant to IR. 1323 template <Fortran::common::TypeCategory TC, int KIND> 1324 ExtValue genScalarLit( 1325 const Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>> 1326 &value) { 1327 if constexpr (TC == Fortran::common::TypeCategory::Integer) { 1328 return genIntegerConstant<KIND>(builder.getContext(), value.ToInt64()); 1329 } else if constexpr (TC == Fortran::common::TypeCategory::Logical) { 1330 return genBoolConstant(value.IsTrue()); 1331 } else if constexpr (TC == Fortran::common::TypeCategory::Real) { 1332 std::string str = value.DumpHexadecimal(); 1333 if constexpr (KIND == 2) { 1334 llvm::APFloat floatVal{llvm::APFloatBase::IEEEhalf(), str}; 1335 return genRealConstant<KIND>(builder.getContext(), floatVal); 1336 } else if constexpr (KIND == 3) { 1337 llvm::APFloat floatVal{llvm::APFloatBase::BFloat(), str}; 1338 return genRealConstant<KIND>(builder.getContext(), floatVal); 1339 } else if constexpr (KIND == 4) { 1340 llvm::APFloat floatVal{llvm::APFloatBase::IEEEsingle(), str}; 1341 return genRealConstant<KIND>(builder.getContext(), floatVal); 1342 } else if constexpr (KIND == 10) { 1343 llvm::APFloat floatVal{llvm::APFloatBase::x87DoubleExtended(), str}; 1344 return genRealConstant<KIND>(builder.getContext(), floatVal); 1345 } else if constexpr (KIND == 16) { 1346 llvm::APFloat floatVal{llvm::APFloatBase::IEEEquad(), str}; 1347 return genRealConstant<KIND>(builder.getContext(), floatVal); 1348 } else { 1349 // convert everything else to double 1350 llvm::APFloat floatVal{llvm::APFloatBase::IEEEdouble(), str}; 1351 return genRealConstant<KIND>(builder.getContext(), floatVal); 1352 } 1353 } else if constexpr (TC == Fortran::common::TypeCategory::Complex) { 1354 using TR = 1355 Fortran::evaluate::Type<Fortran::common::TypeCategory::Real, KIND>; 1356 Fortran::evaluate::ComplexConstructor<KIND> ctor( 1357 Fortran::evaluate::Expr<TR>{ 1358 Fortran::evaluate::Constant<TR>{value.REAL()}}, 1359 Fortran::evaluate::Expr<TR>{ 1360 Fortran::evaluate::Constant<TR>{value.AIMAG()}}); 1361 return genunbox(ctor); 1362 } else /*constexpr*/ { 1363 llvm_unreachable("unhandled constant"); 1364 } 1365 } 1366 1367 /// Generate a raw literal value and store it in the rawVals vector. 1368 template <Fortran::common::TypeCategory TC, int KIND> 1369 void 1370 genRawLit(const Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>> 1371 &value) { 1372 mlir::Attribute val; 1373 assert(inInitializer != nullptr); 1374 if constexpr (TC == Fortran::common::TypeCategory::Integer) { 1375 inInitializer->rawType = converter.genType(TC, KIND); 1376 val = builder.getIntegerAttr(inInitializer->rawType, value.ToInt64()); 1377 } else if constexpr (TC == Fortran::common::TypeCategory::Logical) { 1378 inInitializer->rawType = 1379 converter.genType(Fortran::common::TypeCategory::Integer, KIND); 1380 val = builder.getIntegerAttr(inInitializer->rawType, value.IsTrue()); 1381 } else if constexpr (TC == Fortran::common::TypeCategory::Real) { 1382 std::string str = value.DumpHexadecimal(); 1383 inInitializer->rawType = converter.genType(TC, KIND); 1384 llvm::APFloat floatVal{builder.getKindMap().getFloatSemantics(KIND), str}; 1385 val = builder.getFloatAttr(inInitializer->rawType, floatVal); 1386 } else if constexpr (TC == Fortran::common::TypeCategory::Complex) { 1387 std::string strReal = value.REAL().DumpHexadecimal(); 1388 std::string strImg = value.AIMAG().DumpHexadecimal(); 1389 inInitializer->rawType = converter.genType(TC, KIND); 1390 llvm::APFloat realVal{builder.getKindMap().getFloatSemantics(KIND), 1391 strReal}; 1392 val = builder.getFloatAttr(inInitializer->rawType, realVal); 1393 inInitializer->rawVals.push_back(val); 1394 llvm::APFloat imgVal{builder.getKindMap().getFloatSemantics(KIND), 1395 strImg}; 1396 val = builder.getFloatAttr(inInitializer->rawType, imgVal); 1397 } 1398 inInitializer->rawVals.push_back(val); 1399 } 1400 1401 /// Convert a scalar literal CHARACTER to IR. 1402 template <int KIND> 1403 ExtValue 1404 genScalarLit(const Fortran::evaluate::Scalar<Fortran::evaluate::Type< 1405 Fortran::common::TypeCategory::Character, KIND>> &value, 1406 int64_t len) { 1407 using ET = typename std::decay_t<decltype(value)>::value_type; 1408 if constexpr (KIND == 1) { 1409 assert(value.size() == static_cast<std::uint64_t>(len)); 1410 // Outline character constant in ro data if it is not in an initializer. 1411 if (!inInitializer) 1412 return fir::factory::createStringLiteral(builder, getLoc(), value); 1413 // When in an initializer context, construct the literal op itself and do 1414 // not construct another constant object in rodata. 1415 fir::StringLitOp stringLit = builder.createStringLitOp(getLoc(), value); 1416 mlir::Value lenp = builder.createIntegerConstant( 1417 getLoc(), builder.getCharacterLengthType(), len); 1418 return fir::CharBoxValue{stringLit.getResult(), lenp}; 1419 } 1420 fir::CharacterType type = 1421 fir::CharacterType::get(builder.getContext(), KIND, len); 1422 auto consLit = [&]() -> fir::StringLitOp { 1423 mlir::MLIRContext *context = builder.getContext(); 1424 std::int64_t size = static_cast<std::int64_t>(value.size()); 1425 mlir::ShapedType shape = mlir::RankedTensorType::get( 1426 llvm::ArrayRef<std::int64_t>{size}, 1427 mlir::IntegerType::get(builder.getContext(), sizeof(ET) * 8)); 1428 auto denseAttr = mlir::DenseElementsAttr::get( 1429 shape, llvm::ArrayRef<ET>{value.data(), value.size()}); 1430 auto denseTag = mlir::StringAttr::get(context, fir::StringLitOp::xlist()); 1431 mlir::NamedAttribute dataAttr(denseTag, denseAttr); 1432 auto sizeTag = mlir::StringAttr::get(context, fir::StringLitOp::size()); 1433 mlir::NamedAttribute sizeAttr(sizeTag, builder.getI64IntegerAttr(len)); 1434 llvm::SmallVector<mlir::NamedAttribute> attrs = {dataAttr, sizeAttr}; 1435 return builder.create<fir::StringLitOp>( 1436 getLoc(), llvm::ArrayRef<mlir::Type>{type}, llvm::None, attrs); 1437 }; 1438 1439 mlir::Value lenp = builder.createIntegerConstant( 1440 getLoc(), builder.getCharacterLengthType(), len); 1441 // When in an initializer context, construct the literal op itself and do 1442 // not construct another constant object in rodata. 1443 if (inInitializer) 1444 return fir::CharBoxValue{consLit().getResult(), lenp}; 1445 1446 // Otherwise, the string is in a plain old expression so "outline" the value 1447 // by hashconsing it to a constant literal object. 1448 1449 std::string globalName = 1450 fir::factory::uniqueCGIdent("cl", (const char *)value.c_str()); 1451 fir::GlobalOp global = builder.getNamedGlobal(globalName); 1452 if (!global) 1453 global = builder.createGlobalConstant( 1454 getLoc(), type, globalName, 1455 [&](fir::FirOpBuilder &builder) { 1456 fir::StringLitOp str = consLit(); 1457 builder.create<fir::HasValueOp>(getLoc(), str); 1458 }, 1459 builder.createLinkOnceLinkage()); 1460 auto addr = builder.create<fir::AddrOfOp>(getLoc(), global.resultType(), 1461 global.getSymbol()); 1462 return fir::CharBoxValue{addr, lenp}; 1463 } 1464 1465 template <Fortran::common::TypeCategory TC, int KIND> 1466 ExtValue genArrayLit( 1467 const Fortran::evaluate::Constant<Fortran::evaluate::Type<TC, KIND>> 1468 &con) { 1469 mlir::Location loc = getLoc(); 1470 mlir::IndexType idxTy = builder.getIndexType(); 1471 Fortran::evaluate::ConstantSubscript size = 1472 Fortran::evaluate::GetSize(con.shape()); 1473 fir::SequenceType::Shape shape(con.shape().begin(), con.shape().end()); 1474 mlir::Type eleTy; 1475 if constexpr (TC == Fortran::common::TypeCategory::Character) 1476 eleTy = converter.genType(TC, KIND, {con.LEN()}); 1477 else 1478 eleTy = converter.genType(TC, KIND); 1479 auto arrayTy = fir::SequenceType::get(shape, eleTy); 1480 mlir::Value array; 1481 llvm::SmallVector<mlir::Value> lbounds; 1482 llvm::SmallVector<mlir::Value> extents; 1483 if (!inInitializer || !inInitializer->genRawVals) { 1484 array = builder.create<fir::UndefOp>(loc, arrayTy); 1485 for (auto [lb, extent] : llvm::zip(con.lbounds(), shape)) { 1486 lbounds.push_back(builder.createIntegerConstant(loc, idxTy, lb - 1)); 1487 extents.push_back(builder.createIntegerConstant(loc, idxTy, extent)); 1488 } 1489 } 1490 if (size == 0) { 1491 if constexpr (TC == Fortran::common::TypeCategory::Character) { 1492 mlir::Value len = builder.createIntegerConstant(loc, idxTy, con.LEN()); 1493 return fir::CharArrayBoxValue{array, len, extents, lbounds}; 1494 } else { 1495 return fir::ArrayBoxValue{array, extents, lbounds}; 1496 } 1497 } 1498 Fortran::evaluate::ConstantSubscripts subscripts = con.lbounds(); 1499 auto createIdx = [&]() { 1500 llvm::SmallVector<mlir::Attribute> idx; 1501 for (size_t i = 0; i < subscripts.size(); ++i) 1502 idx.push_back( 1503 builder.getIntegerAttr(idxTy, subscripts[i] - con.lbounds()[i])); 1504 return idx; 1505 }; 1506 if constexpr (TC == Fortran::common::TypeCategory::Character) { 1507 assert(array && "array must not be nullptr"); 1508 do { 1509 mlir::Value elementVal = 1510 fir::getBase(genScalarLit<KIND>(con.At(subscripts), con.LEN())); 1511 array = builder.create<fir::InsertValueOp>( 1512 loc, arrayTy, array, elementVal, builder.getArrayAttr(createIdx())); 1513 } while (con.IncrementSubscripts(subscripts)); 1514 mlir::Value len = builder.createIntegerConstant(loc, idxTy, con.LEN()); 1515 return fir::CharArrayBoxValue{array, len, extents, lbounds}; 1516 } else { 1517 llvm::SmallVector<mlir::Attribute> rangeStartIdx; 1518 uint64_t rangeSize = 0; 1519 do { 1520 if (inInitializer && inInitializer->genRawVals) { 1521 genRawLit<TC, KIND>(con.At(subscripts)); 1522 continue; 1523 } 1524 auto getElementVal = [&]() { 1525 return builder.createConvert( 1526 loc, eleTy, 1527 fir::getBase(genScalarLit<TC, KIND>(con.At(subscripts)))); 1528 }; 1529 Fortran::evaluate::ConstantSubscripts nextSubscripts = subscripts; 1530 bool nextIsSame = con.IncrementSubscripts(nextSubscripts) && 1531 con.At(subscripts) == con.At(nextSubscripts); 1532 if (!rangeSize && !nextIsSame) { // single (non-range) value 1533 array = builder.create<fir::InsertValueOp>( 1534 loc, arrayTy, array, getElementVal(), 1535 builder.getArrayAttr(createIdx())); 1536 } else if (!rangeSize) { // start a range 1537 rangeStartIdx = createIdx(); 1538 rangeSize = 1; 1539 } else if (nextIsSame) { // expand a range 1540 ++rangeSize; 1541 } else { // end a range 1542 llvm::SmallVector<int64_t> rangeBounds; 1543 llvm::SmallVector<mlir::Attribute> idx = createIdx(); 1544 for (size_t i = 0; i < idx.size(); ++i) { 1545 rangeBounds.push_back(rangeStartIdx[i] 1546 .cast<mlir::IntegerAttr>() 1547 .getValue() 1548 .getSExtValue()); 1549 rangeBounds.push_back( 1550 idx[i].cast<mlir::IntegerAttr>().getValue().getSExtValue()); 1551 } 1552 array = builder.create<fir::InsertOnRangeOp>( 1553 loc, arrayTy, array, getElementVal(), 1554 builder.getIndexVectorAttr(rangeBounds)); 1555 rangeSize = 0; 1556 } 1557 } while (con.IncrementSubscripts(subscripts)); 1558 return fir::ArrayBoxValue{array, extents, lbounds}; 1559 } 1560 } 1561 1562 fir::ExtendedValue genArrayLit( 1563 const Fortran::evaluate::Constant<Fortran::evaluate::SomeDerived> &con) { 1564 mlir::Location loc = getLoc(); 1565 mlir::IndexType idxTy = builder.getIndexType(); 1566 Fortran::evaluate::ConstantSubscript size = 1567 Fortran::evaluate::GetSize(con.shape()); 1568 fir::SequenceType::Shape shape(con.shape().begin(), con.shape().end()); 1569 mlir::Type eleTy = converter.genType(con.GetType().GetDerivedTypeSpec()); 1570 auto arrayTy = fir::SequenceType::get(shape, eleTy); 1571 mlir::Value array = builder.create<fir::UndefOp>(loc, arrayTy); 1572 llvm::SmallVector<mlir::Value> lbounds; 1573 llvm::SmallVector<mlir::Value> extents; 1574 for (auto [lb, extent] : llvm::zip(con.lbounds(), con.shape())) { 1575 lbounds.push_back(builder.createIntegerConstant(loc, idxTy, lb - 1)); 1576 extents.push_back(builder.createIntegerConstant(loc, idxTy, extent)); 1577 } 1578 if (size == 0) 1579 return fir::ArrayBoxValue{array, extents, lbounds}; 1580 Fortran::evaluate::ConstantSubscripts subscripts = con.lbounds(); 1581 do { 1582 mlir::Value derivedVal = fir::getBase(genval(con.At(subscripts))); 1583 llvm::SmallVector<mlir::Attribute> idx; 1584 for (auto [dim, lb] : llvm::zip(subscripts, con.lbounds())) 1585 idx.push_back(builder.getIntegerAttr(idxTy, dim - lb)); 1586 array = builder.create<fir::InsertValueOp>( 1587 loc, arrayTy, array, derivedVal, builder.getArrayAttr(idx)); 1588 } while (con.IncrementSubscripts(subscripts)); 1589 return fir::ArrayBoxValue{array, extents, lbounds}; 1590 } 1591 1592 template <Fortran::common::TypeCategory TC, int KIND> 1593 ExtValue 1594 genval(const Fortran::evaluate::Constant<Fortran::evaluate::Type<TC, KIND>> 1595 &con) { 1596 if (con.Rank() > 0) 1597 return genArrayLit(con); 1598 std::optional<Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>>> 1599 opt = con.GetScalarValue(); 1600 assert(opt.has_value() && "constant has no value"); 1601 if constexpr (TC == Fortran::common::TypeCategory::Character) { 1602 return genScalarLit<KIND>(opt.value(), con.LEN()); 1603 } else { 1604 return genScalarLit<TC, KIND>(opt.value()); 1605 } 1606 } 1607 fir::ExtendedValue genval( 1608 const Fortran::evaluate::Constant<Fortran::evaluate::SomeDerived> &con) { 1609 if (con.Rank() > 0) 1610 return genArrayLit(con); 1611 if (auto ctor = con.GetScalarValue()) 1612 return genval(ctor.value()); 1613 fir::emitFatalError(getLoc(), 1614 "constant of derived type has no constructor"); 1615 } 1616 1617 template <typename A> 1618 ExtValue genval(const Fortran::evaluate::ArrayConstructor<A> &) { 1619 fir::emitFatalError(getLoc(), 1620 "array constructor: lowering should not reach here"); 1621 } 1622 1623 ExtValue gen(const Fortran::evaluate::ComplexPart &x) { 1624 mlir::Location loc = getLoc(); 1625 auto idxTy = builder.getI32Type(); 1626 ExtValue exv = gen(x.complex()); 1627 mlir::Value base = fir::getBase(exv); 1628 fir::factory::Complex helper{builder, loc}; 1629 mlir::Type eleTy = 1630 helper.getComplexPartType(fir::dyn_cast_ptrEleTy(base.getType())); 1631 mlir::Value offset = builder.createIntegerConstant( 1632 loc, idxTy, 1633 x.part() == Fortran::evaluate::ComplexPart::Part::RE ? 0 : 1); 1634 mlir::Value result = builder.create<fir::CoordinateOp>( 1635 loc, builder.getRefType(eleTy), base, mlir::ValueRange{offset}); 1636 return {result}; 1637 } 1638 ExtValue genval(const Fortran::evaluate::ComplexPart &x) { 1639 return genLoad(gen(x)); 1640 } 1641 1642 /// Reference to a substring. 1643 ExtValue gen(const Fortran::evaluate::Substring &s) { 1644 // Get base string 1645 auto baseString = std::visit( 1646 Fortran::common::visitors{ 1647 [&](const Fortran::evaluate::DataRef &x) { return gen(x); }, 1648 [&](const Fortran::evaluate::StaticDataObject::Pointer &p) 1649 -> ExtValue { 1650 if (std::optional<std::string> str = p->AsString()) 1651 return fir::factory::createStringLiteral(builder, getLoc(), 1652 *str); 1653 // TODO: convert StaticDataObject to Constant<T> and use normal 1654 // constant path. Beware that StaticDataObject data() takes into 1655 // account build machine endianness. 1656 TODO(getLoc(), 1657 "StaticDataObject::Pointer substring with kind > 1"); 1658 }, 1659 }, 1660 s.parent()); 1661 llvm::SmallVector<mlir::Value> bounds; 1662 mlir::Value lower = genunbox(s.lower()); 1663 bounds.push_back(lower); 1664 if (Fortran::evaluate::MaybeExtentExpr upperBound = s.upper()) { 1665 mlir::Value upper = genunbox(*upperBound); 1666 bounds.push_back(upper); 1667 } 1668 fir::factory::CharacterExprHelper charHelper{builder, getLoc()}; 1669 return baseString.match( 1670 [&](const fir::CharBoxValue &x) -> ExtValue { 1671 return charHelper.createSubstring(x, bounds); 1672 }, 1673 [&](const fir::CharArrayBoxValue &) -> ExtValue { 1674 fir::emitFatalError( 1675 getLoc(), 1676 "array substring should be handled in array expression"); 1677 }, 1678 [&](const auto &) -> ExtValue { 1679 fir::emitFatalError(getLoc(), "substring base is not a CharBox"); 1680 }); 1681 } 1682 1683 /// The value of a substring. 1684 ExtValue genval(const Fortran::evaluate::Substring &ss) { 1685 // FIXME: why is the value of a substring being lowered the same as the 1686 // address of a substring? 1687 return gen(ss); 1688 } 1689 1690 ExtValue genval(const Fortran::evaluate::Subscript &subs) { 1691 if (auto *s = std::get_if<Fortran::evaluate::IndirectSubscriptIntegerExpr>( 1692 &subs.u)) { 1693 if (s->value().Rank() > 0) 1694 fir::emitFatalError(getLoc(), "vector subscript is not scalar"); 1695 return {genval(s->value())}; 1696 } 1697 fir::emitFatalError(getLoc(), "subscript triple notation is not scalar"); 1698 } 1699 ExtValue genSubscript(const Fortran::evaluate::Subscript &subs) { 1700 return genval(subs); 1701 } 1702 1703 ExtValue gen(const Fortran::evaluate::DataRef &dref) { 1704 return std::visit([&](const auto &x) { return gen(x); }, dref.u); 1705 } 1706 ExtValue genval(const Fortran::evaluate::DataRef &dref) { 1707 return std::visit([&](const auto &x) { return genval(x); }, dref.u); 1708 } 1709 1710 // Helper function to turn the Component structure into a list of nested 1711 // components, ordered from largest/leftmost to smallest/rightmost: 1712 // - where only the smallest/rightmost item may be allocatable or a pointer 1713 // (nested allocatable/pointer components require nested coordinate_of ops) 1714 // - that does not contain any parent components 1715 // (the front end places parent components directly in the object) 1716 // Return the object used as the base coordinate for the component chain. 1717 static Fortran::evaluate::DataRef const * 1718 reverseComponents(const Fortran::evaluate::Component &cmpt, 1719 std::list<const Fortran::evaluate::Component *> &list) { 1720 if (!getLastSym(cmpt).test(Fortran::semantics::Symbol::Flag::ParentComp)) 1721 list.push_front(&cmpt); 1722 return std::visit( 1723 Fortran::common::visitors{ 1724 [&](const Fortran::evaluate::Component &x) { 1725 if (Fortran::semantics::IsAllocatableOrPointer(getLastSym(x))) 1726 return &cmpt.base(); 1727 return reverseComponents(x, list); 1728 }, 1729 [&](auto &) { return &cmpt.base(); }, 1730 }, 1731 cmpt.base().u); 1732 } 1733 1734 // Return the coordinate of the component reference 1735 ExtValue genComponent(const Fortran::evaluate::Component &cmpt) { 1736 std::list<const Fortran::evaluate::Component *> list; 1737 const Fortran::evaluate::DataRef *base = reverseComponents(cmpt, list); 1738 llvm::SmallVector<mlir::Value> coorArgs; 1739 ExtValue obj = gen(*base); 1740 mlir::Type ty = fir::dyn_cast_ptrOrBoxEleTy(fir::getBase(obj).getType()); 1741 mlir::Location loc = getLoc(); 1742 auto fldTy = fir::FieldType::get(&converter.getMLIRContext()); 1743 // FIXME: need to thread the LEN type parameters here. 1744 for (const Fortran::evaluate::Component *field : list) { 1745 auto recTy = ty.cast<fir::RecordType>(); 1746 const Fortran::semantics::Symbol &sym = getLastSym(*field); 1747 llvm::StringRef name = toStringRef(sym.name()); 1748 coorArgs.push_back(builder.create<fir::FieldIndexOp>( 1749 loc, fldTy, name, recTy, fir::getTypeParams(obj))); 1750 ty = recTy.getType(name); 1751 } 1752 ty = builder.getRefType(ty); 1753 return fir::factory::componentToExtendedValue( 1754 builder, loc, 1755 builder.create<fir::CoordinateOp>(loc, ty, fir::getBase(obj), 1756 coorArgs)); 1757 } 1758 1759 ExtValue gen(const Fortran::evaluate::Component &cmpt) { 1760 // Components may be pointer or allocatable. In the gen() path, the mutable 1761 // aspect is lost to simplify handling on the client side. To retain the 1762 // mutable aspect, genMutableBoxValue should be used. 1763 return genComponent(cmpt).match( 1764 [&](const fir::MutableBoxValue &mutableBox) { 1765 return fir::factory::genMutableBoxRead(builder, getLoc(), mutableBox); 1766 }, 1767 [](auto &box) -> ExtValue { return box; }); 1768 } 1769 1770 ExtValue genval(const Fortran::evaluate::Component &cmpt) { 1771 return genLoad(gen(cmpt)); 1772 } 1773 1774 // Determine the result type after removing `dims` dimensions from the array 1775 // type `arrTy` 1776 mlir::Type genSubType(mlir::Type arrTy, unsigned dims) { 1777 mlir::Type unwrapTy = fir::dyn_cast_ptrOrBoxEleTy(arrTy); 1778 assert(unwrapTy && "must be a pointer or box type"); 1779 auto seqTy = unwrapTy.cast<fir::SequenceType>(); 1780 llvm::ArrayRef<int64_t> shape = seqTy.getShape(); 1781 assert(shape.size() > 0 && "removing columns for sequence sans shape"); 1782 assert(dims <= shape.size() && "removing more columns than exist"); 1783 fir::SequenceType::Shape newBnds; 1784 // follow Fortran semantics and remove columns (from right) 1785 std::size_t e = shape.size() - dims; 1786 for (decltype(e) i = 0; i < e; ++i) 1787 newBnds.push_back(shape[i]); 1788 if (!newBnds.empty()) 1789 return fir::SequenceType::get(newBnds, seqTy.getEleTy()); 1790 return seqTy.getEleTy(); 1791 } 1792 1793 // Generate the code for a Bound value. 1794 ExtValue genval(const Fortran::semantics::Bound &bound) { 1795 if (bound.isExplicit()) { 1796 Fortran::semantics::MaybeSubscriptIntExpr sub = bound.GetExplicit(); 1797 if (sub.has_value()) 1798 return genval(*sub); 1799 return genIntegerConstant<8>(builder.getContext(), 1); 1800 } 1801 TODO(getLoc(), "non explicit semantics::Bound lowering"); 1802 } 1803 1804 static bool isSlice(const Fortran::evaluate::ArrayRef &aref) { 1805 for (const Fortran::evaluate::Subscript &sub : aref.subscript()) 1806 if (std::holds_alternative<Fortran::evaluate::Triplet>(sub.u)) 1807 return true; 1808 return false; 1809 } 1810 1811 /// Lower an ArrayRef to a fir.coordinate_of given its lowered base. 1812 ExtValue genCoordinateOp(const ExtValue &array, 1813 const Fortran::evaluate::ArrayRef &aref) { 1814 mlir::Location loc = getLoc(); 1815 // References to array of rank > 1 with non constant shape that are not 1816 // fir.box must be collapsed into an offset computation in lowering already. 1817 // The same is needed with dynamic length character arrays of all ranks. 1818 mlir::Type baseType = 1819 fir::dyn_cast_ptrOrBoxEleTy(fir::getBase(array).getType()); 1820 if ((array.rank() > 1 && fir::hasDynamicSize(baseType)) || 1821 fir::characterWithDynamicLen(fir::unwrapSequenceType(baseType))) 1822 if (!array.getBoxOf<fir::BoxValue>()) 1823 return genOffsetAndCoordinateOp(array, aref); 1824 // Generate a fir.coordinate_of with zero based array indexes. 1825 llvm::SmallVector<mlir::Value> args; 1826 for (const auto &subsc : llvm::enumerate(aref.subscript())) { 1827 ExtValue subVal = genSubscript(subsc.value()); 1828 assert(fir::isUnboxedValue(subVal) && "subscript must be simple scalar"); 1829 mlir::Value val = fir::getBase(subVal); 1830 mlir::Type ty = val.getType(); 1831 mlir::Value lb = getLBound(array, subsc.index(), ty); 1832 args.push_back(builder.create<mlir::arith::SubIOp>(loc, ty, val, lb)); 1833 } 1834 1835 mlir::Value base = fir::getBase(array); 1836 auto seqTy = 1837 fir::dyn_cast_ptrOrBoxEleTy(base.getType()).cast<fir::SequenceType>(); 1838 assert(args.size() == seqTy.getDimension()); 1839 mlir::Type ty = builder.getRefType(seqTy.getEleTy()); 1840 auto addr = builder.create<fir::CoordinateOp>(loc, ty, base, args); 1841 return fir::factory::arrayElementToExtendedValue(builder, loc, array, addr); 1842 } 1843 1844 /// Lower an ArrayRef to a fir.coordinate_of using an element offset instead 1845 /// of array indexes. 1846 /// This generates offset computation from the indexes and length parameters, 1847 /// and use the offset to access the element with a fir.coordinate_of. This 1848 /// must only be used if it is not possible to generate a normal 1849 /// fir.coordinate_of using array indexes (i.e. when the shape information is 1850 /// unavailable in the IR). 1851 ExtValue genOffsetAndCoordinateOp(const ExtValue &array, 1852 const Fortran::evaluate::ArrayRef &aref) { 1853 mlir::Location loc = getLoc(); 1854 mlir::Value addr = fir::getBase(array); 1855 mlir::Type arrTy = fir::dyn_cast_ptrEleTy(addr.getType()); 1856 auto eleTy = arrTy.cast<fir::SequenceType>().getEleTy(); 1857 mlir::Type seqTy = builder.getRefType(builder.getVarLenSeqTy(eleTy)); 1858 mlir::Type refTy = builder.getRefType(eleTy); 1859 mlir::Value base = builder.createConvert(loc, seqTy, addr); 1860 mlir::IndexType idxTy = builder.getIndexType(); 1861 mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); 1862 mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0); 1863 auto getLB = [&](const auto &arr, unsigned dim) -> mlir::Value { 1864 return arr.getLBounds().empty() ? one : arr.getLBounds()[dim]; 1865 }; 1866 auto genFullDim = [&](const auto &arr, mlir::Value delta) -> mlir::Value { 1867 mlir::Value total = zero; 1868 assert(arr.getExtents().size() == aref.subscript().size()); 1869 delta = builder.createConvert(loc, idxTy, delta); 1870 unsigned dim = 0; 1871 for (auto [ext, sub] : llvm::zip(arr.getExtents(), aref.subscript())) { 1872 ExtValue subVal = genSubscript(sub); 1873 assert(fir::isUnboxedValue(subVal)); 1874 mlir::Value val = 1875 builder.createConvert(loc, idxTy, fir::getBase(subVal)); 1876 mlir::Value lb = builder.createConvert(loc, idxTy, getLB(arr, dim)); 1877 mlir::Value diff = builder.create<mlir::arith::SubIOp>(loc, val, lb); 1878 mlir::Value prod = 1879 builder.create<mlir::arith::MulIOp>(loc, delta, diff); 1880 total = builder.create<mlir::arith::AddIOp>(loc, prod, total); 1881 if (ext) 1882 delta = builder.create<mlir::arith::MulIOp>(loc, delta, ext); 1883 ++dim; 1884 } 1885 mlir::Type origRefTy = refTy; 1886 if (fir::factory::CharacterExprHelper::isCharacterScalar(refTy)) { 1887 fir::CharacterType chTy = 1888 fir::factory::CharacterExprHelper::getCharacterType(refTy); 1889 if (fir::characterWithDynamicLen(chTy)) { 1890 mlir::MLIRContext *ctx = builder.getContext(); 1891 fir::KindTy kind = 1892 fir::factory::CharacterExprHelper::getCharacterKind(chTy); 1893 fir::CharacterType singleTy = 1894 fir::CharacterType::getSingleton(ctx, kind); 1895 refTy = builder.getRefType(singleTy); 1896 mlir::Type seqRefTy = 1897 builder.getRefType(builder.getVarLenSeqTy(singleTy)); 1898 base = builder.createConvert(loc, seqRefTy, base); 1899 } 1900 } 1901 auto coor = builder.create<fir::CoordinateOp>( 1902 loc, refTy, base, llvm::ArrayRef<mlir::Value>{total}); 1903 // Convert to expected, original type after address arithmetic. 1904 return builder.createConvert(loc, origRefTy, coor); 1905 }; 1906 return array.match( 1907 [&](const fir::ArrayBoxValue &arr) -> ExtValue { 1908 // FIXME: this check can be removed when slicing is implemented 1909 if (isSlice(aref)) 1910 fir::emitFatalError( 1911 getLoc(), 1912 "slice should be handled in array expression context"); 1913 return genFullDim(arr, one); 1914 }, 1915 [&](const fir::CharArrayBoxValue &arr) -> ExtValue { 1916 mlir::Value delta = arr.getLen(); 1917 // If the length is known in the type, fir.coordinate_of will 1918 // already take the length into account. 1919 if (fir::factory::CharacterExprHelper::hasConstantLengthInType(arr)) 1920 delta = one; 1921 return fir::CharBoxValue(genFullDim(arr, delta), arr.getLen()); 1922 }, 1923 [&](const fir::BoxValue &arr) -> ExtValue { 1924 // CoordinateOp for BoxValue is not generated here. The dimensions 1925 // must be kept in the fir.coordinate_op so that potential fir.box 1926 // strides can be applied by codegen. 1927 fir::emitFatalError( 1928 loc, "internal: BoxValue in dim-collapsed fir.coordinate_of"); 1929 }, 1930 [&](const auto &) -> ExtValue { 1931 fir::emitFatalError(loc, "internal: array lowering failed"); 1932 }); 1933 } 1934 1935 /// Lower an ArrayRef to a fir.array_coor. 1936 ExtValue genArrayCoorOp(const ExtValue &exv, 1937 const Fortran::evaluate::ArrayRef &aref) { 1938 mlir::Location loc = getLoc(); 1939 mlir::Value addr = fir::getBase(exv); 1940 mlir::Type arrTy = fir::dyn_cast_ptrOrBoxEleTy(addr.getType()); 1941 mlir::Type eleTy = arrTy.cast<fir::SequenceType>().getEleTy(); 1942 mlir::Type refTy = builder.getRefType(eleTy); 1943 mlir::IndexType idxTy = builder.getIndexType(); 1944 llvm::SmallVector<mlir::Value> arrayCoorArgs; 1945 // The ArrayRef is expected to be scalar here, arrays are handled in array 1946 // expression lowering. So no vector subscript or triplet is expected here. 1947 for (const auto &sub : aref.subscript()) { 1948 ExtValue subVal = genSubscript(sub); 1949 assert(fir::isUnboxedValue(subVal)); 1950 arrayCoorArgs.push_back( 1951 builder.createConvert(loc, idxTy, fir::getBase(subVal))); 1952 } 1953 mlir::Value shape = builder.createShape(loc, exv); 1954 mlir::Value elementAddr = builder.create<fir::ArrayCoorOp>( 1955 loc, refTy, addr, shape, /*slice=*/mlir::Value{}, arrayCoorArgs, 1956 fir::getTypeParams(exv)); 1957 return fir::factory::arrayElementToExtendedValue(builder, loc, exv, 1958 elementAddr); 1959 } 1960 1961 /// Return the coordinate of the array reference. 1962 ExtValue gen(const Fortran::evaluate::ArrayRef &aref) { 1963 ExtValue base = aref.base().IsSymbol() ? gen(getFirstSym(aref.base())) 1964 : gen(aref.base().GetComponent()); 1965 // Check for command-line override to use array_coor op. 1966 if (generateArrayCoordinate) 1967 return genArrayCoorOp(base, aref); 1968 // Otherwise, use coordinate_of op. 1969 return genCoordinateOp(base, aref); 1970 } 1971 1972 /// Return lower bounds of \p box in dimension \p dim. The returned value 1973 /// has type \ty. 1974 mlir::Value getLBound(const ExtValue &box, unsigned dim, mlir::Type ty) { 1975 assert(box.rank() > 0 && "must be an array"); 1976 mlir::Location loc = getLoc(); 1977 mlir::Value one = builder.createIntegerConstant(loc, ty, 1); 1978 mlir::Value lb = fir::factory::readLowerBound(builder, loc, box, dim, one); 1979 return builder.createConvert(loc, ty, lb); 1980 } 1981 1982 ExtValue genval(const Fortran::evaluate::ArrayRef &aref) { 1983 return genLoad(gen(aref)); 1984 } 1985 1986 ExtValue gen(const Fortran::evaluate::CoarrayRef &coref) { 1987 return Fortran::lower::CoarrayExprHelper{converter, getLoc(), symMap} 1988 .genAddr(coref); 1989 } 1990 1991 ExtValue genval(const Fortran::evaluate::CoarrayRef &coref) { 1992 return Fortran::lower::CoarrayExprHelper{converter, getLoc(), symMap} 1993 .genValue(coref); 1994 } 1995 1996 template <typename A> 1997 ExtValue gen(const Fortran::evaluate::Designator<A> &des) { 1998 return std::visit([&](const auto &x) { return gen(x); }, des.u); 1999 } 2000 template <typename A> 2001 ExtValue genval(const Fortran::evaluate::Designator<A> &des) { 2002 return std::visit([&](const auto &x) { return genval(x); }, des.u); 2003 } 2004 2005 mlir::Type genType(const Fortran::evaluate::DynamicType &dt) { 2006 if (dt.category() != Fortran::common::TypeCategory::Derived) 2007 return converter.genType(dt.category(), dt.kind()); 2008 return converter.genType(dt.GetDerivedTypeSpec()); 2009 } 2010 2011 /// Lower a function reference 2012 template <typename A> 2013 ExtValue genFunctionRef(const Fortran::evaluate::FunctionRef<A> &funcRef) { 2014 if (!funcRef.GetType().has_value()) 2015 fir::emitFatalError(getLoc(), "a function must have a type"); 2016 mlir::Type resTy = genType(*funcRef.GetType()); 2017 return genProcedureRef(funcRef, {resTy}); 2018 } 2019 2020 /// Lower function call `funcRef` and return a reference to the resultant 2021 /// value. This is required for lowering expressions such as `f1(f2(v))`. 2022 template <typename A> 2023 ExtValue gen(const Fortran::evaluate::FunctionRef<A> &funcRef) { 2024 ExtValue retVal = genFunctionRef(funcRef); 2025 mlir::Type resultType = converter.genType(toEvExpr(funcRef)); 2026 return placeScalarValueInMemory(builder, getLoc(), retVal, resultType); 2027 } 2028 2029 /// Helper to lower intrinsic arguments for inquiry intrinsic. 2030 ExtValue 2031 lowerIntrinsicArgumentAsInquired(const Fortran::lower::SomeExpr &expr) { 2032 if (Fortran::evaluate::IsAllocatableOrPointerObject( 2033 expr, converter.getFoldingContext())) 2034 return genMutableBoxValue(expr); 2035 /// Do not create temps for array sections whose properties only need to be 2036 /// inquired: create a descriptor that will be inquired. 2037 if (Fortran::evaluate::IsVariable(expr) && isArray(expr) && 2038 !Fortran::evaluate::UnwrapWholeSymbolOrComponentDataRef(expr)) 2039 return lowerIntrinsicArgumentAsBox(expr); 2040 return gen(expr); 2041 } 2042 2043 /// Helper to lower intrinsic arguments to a fir::BoxValue. 2044 /// It preserves all the non default lower bounds/non deferred length 2045 /// parameter information. 2046 ExtValue lowerIntrinsicArgumentAsBox(const Fortran::lower::SomeExpr &expr) { 2047 mlir::Location loc = getLoc(); 2048 ExtValue exv = genBoxArg(expr); 2049 mlir::Value box = builder.createBox(loc, exv); 2050 return fir::BoxValue( 2051 box, fir::factory::getNonDefaultLowerBounds(builder, loc, exv), 2052 fir::factory::getNonDeferredLengthParams(exv)); 2053 } 2054 2055 /// Generate a call to an intrinsic function. 2056 ExtValue 2057 genIntrinsicRef(const Fortran::evaluate::ProcedureRef &procRef, 2058 const Fortran::evaluate::SpecificIntrinsic &intrinsic, 2059 llvm::Optional<mlir::Type> resultType) { 2060 llvm::SmallVector<ExtValue> operands; 2061 2062 llvm::StringRef name = intrinsic.name; 2063 mlir::Location loc = getLoc(); 2064 if (Fortran::lower::intrinsicRequiresCustomOptionalHandling( 2065 procRef, intrinsic, converter)) { 2066 using ExvAndPresence = std::pair<ExtValue, llvm::Optional<mlir::Value>>; 2067 llvm::SmallVector<ExvAndPresence, 4> operands; 2068 auto prepareOptionalArg = [&](const Fortran::lower::SomeExpr &expr) { 2069 ExtValue optionalArg = lowerIntrinsicArgumentAsInquired(expr); 2070 mlir::Value isPresent = 2071 genActualIsPresentTest(builder, loc, optionalArg); 2072 operands.emplace_back(optionalArg, isPresent); 2073 }; 2074 auto prepareOtherArg = [&](const Fortran::lower::SomeExpr &expr) { 2075 operands.emplace_back(genval(expr), llvm::None); 2076 }; 2077 Fortran::lower::prepareCustomIntrinsicArgument( 2078 procRef, intrinsic, resultType, prepareOptionalArg, prepareOtherArg, 2079 converter); 2080 2081 auto getArgument = [&](std::size_t i) -> ExtValue { 2082 if (fir::conformsWithPassByRef( 2083 fir::getBase(operands[i].first).getType())) 2084 return genLoad(operands[i].first); 2085 return operands[i].first; 2086 }; 2087 auto isPresent = [&](std::size_t i) -> llvm::Optional<mlir::Value> { 2088 return operands[i].second; 2089 }; 2090 return Fortran::lower::lowerCustomIntrinsic( 2091 builder, loc, name, resultType, isPresent, getArgument, 2092 operands.size(), stmtCtx); 2093 } 2094 2095 const Fortran::lower::IntrinsicArgumentLoweringRules *argLowering = 2096 Fortran::lower::getIntrinsicArgumentLowering(name); 2097 for (const auto &[arg, dummy] : 2098 llvm::zip(procRef.arguments(), 2099 intrinsic.characteristics.value().dummyArguments)) { 2100 auto *expr = Fortran::evaluate::UnwrapExpr<Fortran::lower::SomeExpr>(arg); 2101 if (!expr) { 2102 // Absent optional. 2103 operands.emplace_back(Fortran::lower::getAbsentIntrinsicArgument()); 2104 continue; 2105 } 2106 if (!argLowering) { 2107 // No argument lowering instruction, lower by value. 2108 operands.emplace_back(genval(*expr)); 2109 continue; 2110 } 2111 // Ad-hoc argument lowering handling. 2112 Fortran::lower::ArgLoweringRule argRules = 2113 Fortran::lower::lowerIntrinsicArgumentAs(loc, *argLowering, 2114 dummy.name); 2115 if (argRules.handleDynamicOptional && 2116 Fortran::evaluate::MayBePassedAsAbsentOptional( 2117 *expr, converter.getFoldingContext())) { 2118 ExtValue optional = lowerIntrinsicArgumentAsInquired(*expr); 2119 mlir::Value isPresent = genActualIsPresentTest(builder, loc, optional); 2120 switch (argRules.lowerAs) { 2121 case Fortran::lower::LowerIntrinsicArgAs::Value: 2122 operands.emplace_back( 2123 genOptionalValue(builder, loc, optional, isPresent)); 2124 continue; 2125 case Fortran::lower::LowerIntrinsicArgAs::Addr: 2126 operands.emplace_back( 2127 genOptionalAddr(builder, loc, optional, isPresent)); 2128 continue; 2129 case Fortran::lower::LowerIntrinsicArgAs::Box: 2130 operands.emplace_back( 2131 genOptionalBox(builder, loc, optional, isPresent)); 2132 continue; 2133 case Fortran::lower::LowerIntrinsicArgAs::Inquired: 2134 operands.emplace_back(optional); 2135 continue; 2136 } 2137 llvm_unreachable("bad switch"); 2138 } 2139 switch (argRules.lowerAs) { 2140 case Fortran::lower::LowerIntrinsicArgAs::Value: 2141 operands.emplace_back(genval(*expr)); 2142 continue; 2143 case Fortran::lower::LowerIntrinsicArgAs::Addr: 2144 operands.emplace_back(gen(*expr)); 2145 continue; 2146 case Fortran::lower::LowerIntrinsicArgAs::Box: 2147 operands.emplace_back(lowerIntrinsicArgumentAsBox(*expr)); 2148 continue; 2149 case Fortran::lower::LowerIntrinsicArgAs::Inquired: 2150 operands.emplace_back(lowerIntrinsicArgumentAsInquired(*expr)); 2151 continue; 2152 } 2153 llvm_unreachable("bad switch"); 2154 } 2155 // Let the intrinsic library lower the intrinsic procedure call 2156 return Fortran::lower::genIntrinsicCall(builder, getLoc(), name, resultType, 2157 operands, stmtCtx); 2158 } 2159 2160 template <typename A> 2161 bool isCharacterType(const A &exp) { 2162 if (auto type = exp.GetType()) 2163 return type->category() == Fortran::common::TypeCategory::Character; 2164 return false; 2165 } 2166 2167 /// helper to detect statement functions 2168 static bool 2169 isStatementFunctionCall(const Fortran::evaluate::ProcedureRef &procRef) { 2170 if (const Fortran::semantics::Symbol *symbol = procRef.proc().GetSymbol()) 2171 if (const auto *details = 2172 symbol->detailsIf<Fortran::semantics::SubprogramDetails>()) 2173 return details->stmtFunction().has_value(); 2174 return false; 2175 } 2176 /// Generate Statement function calls 2177 ExtValue genStmtFunctionRef(const Fortran::evaluate::ProcedureRef &procRef) { 2178 const Fortran::semantics::Symbol *symbol = procRef.proc().GetSymbol(); 2179 assert(symbol && "expected symbol in ProcedureRef of statement functions"); 2180 const auto &details = symbol->get<Fortran::semantics::SubprogramDetails>(); 2181 2182 // Statement functions have their own scope, we just need to associate 2183 // the dummy symbols to argument expressions. They are no 2184 // optional/alternate return arguments. Statement functions cannot be 2185 // recursive (directly or indirectly) so it is safe to add dummy symbols to 2186 // the local map here. 2187 symMap.pushScope(); 2188 for (auto [arg, bind] : 2189 llvm::zip(details.dummyArgs(), procRef.arguments())) { 2190 assert(arg && "alternate return in statement function"); 2191 assert(bind && "optional argument in statement function"); 2192 const auto *expr = bind->UnwrapExpr(); 2193 // TODO: assumed type in statement function, that surprisingly seems 2194 // allowed, probably because nobody thought of restricting this usage. 2195 // gfortran/ifort compiles this. 2196 assert(expr && "assumed type used as statement function argument"); 2197 // As per Fortran 2018 C1580, statement function arguments can only be 2198 // scalars, so just pass the box with the address. The only care is to 2199 // to use the dummy character explicit length if any instead of the 2200 // actual argument length (that can be bigger). 2201 if (const Fortran::semantics::DeclTypeSpec *type = arg->GetType()) 2202 if (type->category() == Fortran::semantics::DeclTypeSpec::Character) 2203 if (const Fortran::semantics::MaybeIntExpr &lenExpr = 2204 type->characterTypeSpec().length().GetExplicit()) { 2205 mlir::Value len = fir::getBase(genval(*lenExpr)); 2206 // F2018 7.4.4.2 point 5. 2207 len = Fortran::lower::genMaxWithZero(builder, getLoc(), len); 2208 symMap.addSymbol(*arg, 2209 replaceScalarCharacterLength(gen(*expr), len)); 2210 continue; 2211 } 2212 symMap.addSymbol(*arg, gen(*expr)); 2213 } 2214 2215 // Explicitly map statement function host associated symbols to their 2216 // parent scope lowered symbol box. 2217 for (const Fortran::semantics::SymbolRef &sym : 2218 Fortran::evaluate::CollectSymbols(*details.stmtFunction())) 2219 if (const auto *details = 2220 sym->detailsIf<Fortran::semantics::HostAssocDetails>()) 2221 if (!symMap.lookupSymbol(*sym)) 2222 symMap.addSymbol(*sym, gen(details->symbol())); 2223 2224 ExtValue result = genval(details.stmtFunction().value()); 2225 LLVM_DEBUG(llvm::dbgs() << "stmt-function: " << result << '\n'); 2226 symMap.popScope(); 2227 return result; 2228 } 2229 2230 /// Helper to package a Value and its properties into an ExtendedValue. 2231 static ExtValue toExtendedValue(mlir::Location loc, mlir::Value base, 2232 llvm::ArrayRef<mlir::Value> extents, 2233 llvm::ArrayRef<mlir::Value> lengths) { 2234 mlir::Type type = base.getType(); 2235 if (type.isa<fir::BoxType>()) 2236 return fir::BoxValue(base, /*lbounds=*/{}, lengths, extents); 2237 type = fir::unwrapRefType(type); 2238 if (type.isa<fir::BoxType>()) 2239 return fir::MutableBoxValue(base, lengths, /*mutableProperties*/ {}); 2240 if (auto seqTy = type.dyn_cast<fir::SequenceType>()) { 2241 if (seqTy.getDimension() != extents.size()) 2242 fir::emitFatalError(loc, "incorrect number of extents for array"); 2243 if (seqTy.getEleTy().isa<fir::CharacterType>()) { 2244 if (lengths.empty()) 2245 fir::emitFatalError(loc, "missing length for character"); 2246 assert(lengths.size() == 1); 2247 return fir::CharArrayBoxValue(base, lengths[0], extents); 2248 } 2249 return fir::ArrayBoxValue(base, extents); 2250 } 2251 if (type.isa<fir::CharacterType>()) { 2252 if (lengths.empty()) 2253 fir::emitFatalError(loc, "missing length for character"); 2254 assert(lengths.size() == 1); 2255 return fir::CharBoxValue(base, lengths[0]); 2256 } 2257 return base; 2258 } 2259 2260 // Find the argument that corresponds to the host associations. 2261 // Verify some assumptions about how the signature was built here. 2262 [[maybe_unused]] static unsigned 2263 findHostAssocTuplePos(mlir::func::FuncOp fn) { 2264 // Scan the argument list from last to first as the host associations are 2265 // appended for now. 2266 for (unsigned i = fn.getNumArguments(); i > 0; --i) 2267 if (fn.getArgAttr(i - 1, fir::getHostAssocAttrName())) { 2268 // Host assoc tuple must be last argument (for now). 2269 assert(i == fn.getNumArguments() && "tuple must be last"); 2270 return i - 1; 2271 } 2272 llvm_unreachable("anyFuncArgsHaveAttr failed"); 2273 } 2274 2275 /// Create a contiguous temporary array with the same shape, 2276 /// length parameters and type as mold. It is up to the caller to deallocate 2277 /// the temporary. 2278 ExtValue genArrayTempFromMold(const ExtValue &mold, 2279 llvm::StringRef tempName) { 2280 mlir::Type type = fir::dyn_cast_ptrOrBoxEleTy(fir::getBase(mold).getType()); 2281 assert(type && "expected descriptor or memory type"); 2282 mlir::Location loc = getLoc(); 2283 llvm::SmallVector<mlir::Value> extents = 2284 fir::factory::getExtents(builder, loc, mold); 2285 llvm::SmallVector<mlir::Value> allocMemTypeParams = 2286 fir::getTypeParams(mold); 2287 mlir::Value charLen; 2288 mlir::Type elementType = fir::unwrapSequenceType(type); 2289 if (auto charType = elementType.dyn_cast<fir::CharacterType>()) { 2290 charLen = allocMemTypeParams.empty() 2291 ? fir::factory::readCharLen(builder, loc, mold) 2292 : allocMemTypeParams[0]; 2293 if (charType.hasDynamicLen() && allocMemTypeParams.empty()) 2294 allocMemTypeParams.push_back(charLen); 2295 } else if (fir::hasDynamicSize(elementType)) { 2296 TODO(loc, "Creating temporary for derived type with length parameters"); 2297 } 2298 2299 mlir::Value temp = builder.create<fir::AllocMemOp>( 2300 loc, type, tempName, allocMemTypeParams, extents); 2301 if (fir::unwrapSequenceType(type).isa<fir::CharacterType>()) 2302 return fir::CharArrayBoxValue{temp, charLen, extents}; 2303 return fir::ArrayBoxValue{temp, extents}; 2304 } 2305 2306 /// Copy \p source array into \p dest array. Both arrays must be 2307 /// conforming, but neither array must be contiguous. 2308 void genArrayCopy(ExtValue dest, ExtValue source) { 2309 return createSomeArrayAssignment(converter, dest, source, symMap, stmtCtx); 2310 } 2311 2312 /// Lower a non-elemental procedure reference and read allocatable and pointer 2313 /// results into normal values. 2314 ExtValue genProcedureRef(const Fortran::evaluate::ProcedureRef &procRef, 2315 llvm::Optional<mlir::Type> resultType) { 2316 ExtValue res = genRawProcedureRef(procRef, resultType); 2317 // In most contexts, pointers and allocatable do not appear as allocatable 2318 // or pointer variable on the caller side (see 8.5.3 note 1 for 2319 // allocatables). The few context where this can happen must call 2320 // genRawProcedureRef directly. 2321 if (const auto *box = res.getBoxOf<fir::MutableBoxValue>()) 2322 return fir::factory::genMutableBoxRead(builder, getLoc(), *box); 2323 return res; 2324 } 2325 2326 /// Given a call site for which the arguments were already lowered, generate 2327 /// the call and return the result. This function deals with explicit result 2328 /// allocation and lowering if needed. It also deals with passing the host 2329 /// link to internal procedures. 2330 ExtValue genCallOpAndResult(Fortran::lower::CallerInterface &caller, 2331 mlir::FunctionType callSiteType, 2332 llvm::Optional<mlir::Type> resultType) { 2333 mlir::Location loc = getLoc(); 2334 using PassBy = Fortran::lower::CallerInterface::PassEntityBy; 2335 // Handle cases where caller must allocate the result or a fir.box for it. 2336 bool mustPopSymMap = false; 2337 if (caller.mustMapInterfaceSymbols()) { 2338 symMap.pushScope(); 2339 mustPopSymMap = true; 2340 Fortran::lower::mapCallInterfaceSymbols(converter, caller, symMap); 2341 } 2342 // If this is an indirect call, retrieve the function address. Also retrieve 2343 // the result length if this is a character function (note that this length 2344 // will be used only if there is no explicit length in the local interface). 2345 mlir::Value funcPointer; 2346 mlir::Value charFuncPointerLength; 2347 if (const Fortran::semantics::Symbol *sym = 2348 caller.getIfIndirectCallSymbol()) { 2349 funcPointer = symMap.lookupSymbol(*sym).getAddr(); 2350 if (!funcPointer) 2351 fir::emitFatalError(loc, "failed to find indirect call symbol address"); 2352 if (fir::isCharacterProcedureTuple(funcPointer.getType(), 2353 /*acceptRawFunc=*/false)) 2354 std::tie(funcPointer, charFuncPointerLength) = 2355 fir::factory::extractCharacterProcedureTuple(builder, loc, 2356 funcPointer); 2357 } 2358 2359 mlir::IndexType idxTy = builder.getIndexType(); 2360 auto lowerSpecExpr = [&](const auto &expr) -> mlir::Value { 2361 return builder.createConvert( 2362 loc, idxTy, fir::getBase(converter.genExprValue(expr, stmtCtx))); 2363 }; 2364 llvm::SmallVector<mlir::Value> resultLengths; 2365 auto allocatedResult = [&]() -> llvm::Optional<ExtValue> { 2366 llvm::SmallVector<mlir::Value> extents; 2367 llvm::SmallVector<mlir::Value> lengths; 2368 if (!caller.callerAllocateResult()) 2369 return {}; 2370 mlir::Type type = caller.getResultStorageType(); 2371 if (type.isa<fir::SequenceType>()) 2372 caller.walkResultExtents([&](const Fortran::lower::SomeExpr &e) { 2373 extents.emplace_back(lowerSpecExpr(e)); 2374 }); 2375 caller.walkResultLengths([&](const Fortran::lower::SomeExpr &e) { 2376 lengths.emplace_back(lowerSpecExpr(e)); 2377 }); 2378 2379 // Result length parameters should not be provided to box storage 2380 // allocation and save_results, but they are still useful information to 2381 // keep in the ExtendedValue if non-deferred. 2382 if (!type.isa<fir::BoxType>()) { 2383 if (fir::isa_char(fir::unwrapSequenceType(type)) && lengths.empty()) { 2384 // Calling an assumed length function. This is only possible if this 2385 // is a call to a character dummy procedure. 2386 if (!charFuncPointerLength) 2387 fir::emitFatalError(loc, "failed to retrieve character function " 2388 "length while calling it"); 2389 lengths.push_back(charFuncPointerLength); 2390 } 2391 resultLengths = lengths; 2392 } 2393 2394 if (!extents.empty() || !lengths.empty()) { 2395 auto *bldr = &converter.getFirOpBuilder(); 2396 auto stackSaveFn = fir::factory::getLlvmStackSave(builder); 2397 auto stackSaveSymbol = bldr->getSymbolRefAttr(stackSaveFn.getName()); 2398 mlir::Value sp = 2399 bldr->create<fir::CallOp>( 2400 loc, stackSaveFn.getFunctionType().getResults(), 2401 stackSaveSymbol, mlir::ValueRange{}) 2402 .getResult(0); 2403 stmtCtx.attachCleanup([bldr, loc, sp]() { 2404 auto stackRestoreFn = fir::factory::getLlvmStackRestore(*bldr); 2405 auto stackRestoreSymbol = 2406 bldr->getSymbolRefAttr(stackRestoreFn.getName()); 2407 bldr->create<fir::CallOp>( 2408 loc, stackRestoreFn.getFunctionType().getResults(), 2409 stackRestoreSymbol, mlir::ValueRange{sp}); 2410 }); 2411 } 2412 mlir::Value temp = 2413 builder.createTemporary(loc, type, ".result", extents, resultLengths); 2414 return toExtendedValue(loc, temp, extents, lengths); 2415 }(); 2416 2417 if (mustPopSymMap) 2418 symMap.popScope(); 2419 2420 // Place allocated result or prepare the fir.save_result arguments. 2421 mlir::Value arrayResultShape; 2422 if (allocatedResult) { 2423 if (std::optional<Fortran::lower::CallInterface< 2424 Fortran::lower::CallerInterface>::PassedEntity> 2425 resultArg = caller.getPassedResult()) { 2426 if (resultArg->passBy == PassBy::AddressAndLength) 2427 caller.placeAddressAndLengthInput(*resultArg, 2428 fir::getBase(*allocatedResult), 2429 fir::getLen(*allocatedResult)); 2430 else if (resultArg->passBy == PassBy::BaseAddress) 2431 caller.placeInput(*resultArg, fir::getBase(*allocatedResult)); 2432 else 2433 fir::emitFatalError( 2434 loc, "only expect character scalar result to be passed by ref"); 2435 } else { 2436 assert(caller.mustSaveResult()); 2437 arrayResultShape = allocatedResult->match( 2438 [&](const fir::CharArrayBoxValue &) { 2439 return builder.createShape(loc, *allocatedResult); 2440 }, 2441 [&](const fir::ArrayBoxValue &) { 2442 return builder.createShape(loc, *allocatedResult); 2443 }, 2444 [&](const auto &) { return mlir::Value{}; }); 2445 } 2446 } 2447 2448 // In older Fortran, procedure argument types are inferred. This may lead 2449 // different view of what the function signature is in different locations. 2450 // Casts are inserted as needed below to accommodate this. 2451 2452 // The mlir::func::FuncOp type prevails, unless it has a different number of 2453 // arguments which can happen in legal program if it was passed as a dummy 2454 // procedure argument earlier with no further type information. 2455 mlir::SymbolRefAttr funcSymbolAttr; 2456 bool addHostAssociations = false; 2457 if (!funcPointer) { 2458 mlir::FunctionType funcOpType = caller.getFuncOp().getFunctionType(); 2459 mlir::SymbolRefAttr symbolAttr = 2460 builder.getSymbolRefAttr(caller.getMangledName()); 2461 if (callSiteType.getNumResults() == funcOpType.getNumResults() && 2462 callSiteType.getNumInputs() + 1 == funcOpType.getNumInputs() && 2463 fir::anyFuncArgsHaveAttr(caller.getFuncOp(), 2464 fir::getHostAssocAttrName())) { 2465 // The number of arguments is off by one, and we're lowering a function 2466 // with host associations. Modify call to include host associations 2467 // argument by appending the value at the end of the operands. 2468 assert(funcOpType.getInput(findHostAssocTuplePos(caller.getFuncOp())) == 2469 converter.hostAssocTupleValue().getType()); 2470 addHostAssociations = true; 2471 } 2472 if (!addHostAssociations && 2473 (callSiteType.getNumResults() != funcOpType.getNumResults() || 2474 callSiteType.getNumInputs() != funcOpType.getNumInputs())) { 2475 // Deal with argument number mismatch by making a function pointer so 2476 // that function type cast can be inserted. Do not emit a warning here 2477 // because this can happen in legal program if the function is not 2478 // defined here and it was first passed as an argument without any more 2479 // information. 2480 funcPointer = 2481 builder.create<fir::AddrOfOp>(loc, funcOpType, symbolAttr); 2482 } else if (callSiteType.getResults() != funcOpType.getResults()) { 2483 // Implicit interface result type mismatch are not standard Fortran, but 2484 // some compilers are not complaining about it. The front end is not 2485 // protecting lowering from this currently. Support this with a 2486 // discouraging warning. 2487 LLVM_DEBUG(mlir::emitWarning( 2488 loc, "a return type mismatch is not standard compliant and may " 2489 "lead to undefined behavior.")); 2490 // Cast the actual function to the current caller implicit type because 2491 // that is the behavior we would get if we could not see the definition. 2492 funcPointer = 2493 builder.create<fir::AddrOfOp>(loc, funcOpType, symbolAttr); 2494 } else { 2495 funcSymbolAttr = symbolAttr; 2496 } 2497 } 2498 2499 mlir::FunctionType funcType = 2500 funcPointer ? callSiteType : caller.getFuncOp().getFunctionType(); 2501 llvm::SmallVector<mlir::Value> operands; 2502 // First operand of indirect call is the function pointer. Cast it to 2503 // required function type for the call to handle procedures that have a 2504 // compatible interface in Fortran, but that have different signatures in 2505 // FIR. 2506 if (funcPointer) { 2507 operands.push_back( 2508 funcPointer.getType().isa<fir::BoxProcType>() 2509 ? builder.create<fir::BoxAddrOp>(loc, funcType, funcPointer) 2510 : builder.createConvert(loc, funcType, funcPointer)); 2511 } 2512 2513 // Deal with potential mismatches in arguments types. Passing an array to a 2514 // scalar argument should for instance be tolerated here. 2515 bool callingImplicitInterface = caller.canBeCalledViaImplicitInterface(); 2516 for (auto [fst, snd] : 2517 llvm::zip(caller.getInputs(), funcType.getInputs())) { 2518 // When passing arguments to a procedure that can be called an implicit 2519 // interface, allow character actual arguments to be passed to dummy 2520 // arguments of any type and vice versa 2521 mlir::Value cast; 2522 auto *context = builder.getContext(); 2523 if (snd.isa<fir::BoxProcType>() && 2524 fst.getType().isa<mlir::FunctionType>()) { 2525 auto funcTy = mlir::FunctionType::get(context, llvm::None, llvm::None); 2526 auto boxProcTy = builder.getBoxProcType(funcTy); 2527 if (mlir::Value host = argumentHostAssocs(converter, fst)) { 2528 cast = builder.create<fir::EmboxProcOp>( 2529 loc, boxProcTy, llvm::ArrayRef<mlir::Value>{fst, host}); 2530 } else { 2531 cast = builder.create<fir::EmboxProcOp>(loc, boxProcTy, fst); 2532 } 2533 } else { 2534 cast = builder.convertWithSemantics(loc, snd, fst, 2535 callingImplicitInterface); 2536 } 2537 operands.push_back(cast); 2538 } 2539 2540 // Add host associations as necessary. 2541 if (addHostAssociations) 2542 operands.push_back(converter.hostAssocTupleValue()); 2543 2544 auto call = builder.create<fir::CallOp>(loc, funcType.getResults(), 2545 funcSymbolAttr, operands); 2546 2547 if (caller.mustSaveResult()) 2548 builder.create<fir::SaveResultOp>( 2549 loc, call.getResult(0), fir::getBase(allocatedResult.getValue()), 2550 arrayResultShape, resultLengths); 2551 2552 if (allocatedResult) { 2553 allocatedResult->match( 2554 [&](const fir::MutableBoxValue &box) { 2555 if (box.isAllocatable()) { 2556 // 9.7.3.2 point 4. Finalize allocatables. 2557 fir::FirOpBuilder *bldr = &converter.getFirOpBuilder(); 2558 stmtCtx.attachCleanup([bldr, loc, box]() { 2559 fir::factory::genFinalization(*bldr, loc, box); 2560 }); 2561 } 2562 }, 2563 [](const auto &) {}); 2564 return *allocatedResult; 2565 } 2566 2567 if (!resultType.hasValue()) 2568 return mlir::Value{}; // subroutine call 2569 // For now, Fortran return values are implemented with a single MLIR 2570 // function return value. 2571 assert(call.getNumResults() == 1 && 2572 "Expected exactly one result in FUNCTION call"); 2573 return call.getResult(0); 2574 } 2575 2576 /// Like genExtAddr, but ensure the address returned is a temporary even if \p 2577 /// expr is variable inside parentheses. 2578 ExtValue genTempExtAddr(const Fortran::lower::SomeExpr &expr) { 2579 // In general, genExtAddr might not create a temp for variable inside 2580 // parentheses to avoid creating array temporary in sub-expressions. It only 2581 // ensures the sub-expression is not re-associated with other parts of the 2582 // expression. In the call semantics, there is a difference between expr and 2583 // variable (see R1524). For expressions, a variable storage must not be 2584 // argument associated since it could be modified inside the call, or the 2585 // variable could also be modified by other means during the call. 2586 if (!isParenthesizedVariable(expr)) 2587 return genExtAddr(expr); 2588 if (expr.Rank() > 0) 2589 return asArray(expr); 2590 mlir::Location loc = getLoc(); 2591 return genExtValue(expr).match( 2592 [&](const fir::CharBoxValue &boxChar) -> ExtValue { 2593 return fir::factory::CharacterExprHelper{builder, loc}.createTempFrom( 2594 boxChar); 2595 }, 2596 [&](const fir::UnboxedValue &v) -> ExtValue { 2597 mlir::Type type = v.getType(); 2598 mlir::Value value = v; 2599 if (fir::isa_ref_type(type)) 2600 value = builder.create<fir::LoadOp>(loc, value); 2601 mlir::Value temp = builder.createTemporary(loc, value.getType()); 2602 builder.create<fir::StoreOp>(loc, value, temp); 2603 return temp; 2604 }, 2605 [&](const fir::BoxValue &x) -> ExtValue { 2606 // Derived type scalar that may be polymorphic. 2607 assert(!x.hasRank() && x.isDerived()); 2608 if (x.isDerivedWithLengthParameters()) 2609 fir::emitFatalError( 2610 loc, "making temps for derived type with length parameters"); 2611 // TODO: polymorphic aspects should be kept but for now the temp 2612 // created always has the declared type. 2613 mlir::Value var = 2614 fir::getBase(fir::factory::readBoxValue(builder, loc, x)); 2615 auto value = builder.create<fir::LoadOp>(loc, var); 2616 mlir::Value temp = builder.createTemporary(loc, value.getType()); 2617 builder.create<fir::StoreOp>(loc, value, temp); 2618 return temp; 2619 }, 2620 [&](const auto &) -> ExtValue { 2621 fir::emitFatalError(loc, "expr is not a scalar value"); 2622 }); 2623 } 2624 2625 /// Helper structure to track potential copy-in of non contiguous variable 2626 /// argument into a contiguous temp. It is used to deallocate the temp that 2627 /// may have been created as well as to the copy-out from the temp to the 2628 /// variable after the call. 2629 struct CopyOutPair { 2630 ExtValue var; 2631 ExtValue temp; 2632 // Flag to indicate if the argument may have been modified by the 2633 // callee, in which case it must be copied-out to the variable. 2634 bool argMayBeModifiedByCall; 2635 // Optional boolean value that, if present and false, prevents 2636 // the copy-out and temp deallocation. 2637 llvm::Optional<mlir::Value> restrictCopyAndFreeAtRuntime; 2638 }; 2639 using CopyOutPairs = llvm::SmallVector<CopyOutPair, 4>; 2640 2641 /// Helper to read any fir::BoxValue into other fir::ExtendedValue categories 2642 /// not based on fir.box. 2643 /// This will lose any non contiguous stride information and dynamic type and 2644 /// should only be called if \p exv is known to be contiguous or if its base 2645 /// address will be replaced by a contiguous one. If \p exv is not a 2646 /// fir::BoxValue, this is a no-op. 2647 ExtValue readIfBoxValue(const ExtValue &exv) { 2648 if (const auto *box = exv.getBoxOf<fir::BoxValue>()) 2649 return fir::factory::readBoxValue(builder, getLoc(), *box); 2650 return exv; 2651 } 2652 2653 /// Generate a contiguous temp to pass \p actualArg as argument \p arg. The 2654 /// creation of the temp and copy-in can be made conditional at runtime by 2655 /// providing a runtime boolean flag \p restrictCopyAtRuntime (in which case 2656 /// the temp and copy will only be made if the value is true at runtime). 2657 ExtValue genCopyIn(const ExtValue &actualArg, 2658 const Fortran::lower::CallerInterface::PassedEntity &arg, 2659 CopyOutPairs ©OutPairs, 2660 llvm::Optional<mlir::Value> restrictCopyAtRuntime) { 2661 if (!restrictCopyAtRuntime) { 2662 ExtValue temp = genArrayTempFromMold(actualArg, ".copyinout"); 2663 if (arg.mayBeReadByCall()) 2664 genArrayCopy(temp, actualArg); 2665 copyOutPairs.emplace_back(CopyOutPair{ 2666 actualArg, temp, arg.mayBeModifiedByCall(), restrictCopyAtRuntime}); 2667 return temp; 2668 } 2669 // Otherwise, need to be careful to only copy-in if allowed at runtime. 2670 mlir::Location loc = getLoc(); 2671 auto addrType = fir::HeapType::get( 2672 fir::unwrapPassByRefType(fir::getBase(actualArg).getType())); 2673 mlir::Value addr = 2674 builder 2675 .genIfOp(loc, {addrType}, *restrictCopyAtRuntime, 2676 /*withElseRegion=*/true) 2677 .genThen([&]() { 2678 auto temp = genArrayTempFromMold(actualArg, ".copyinout"); 2679 if (arg.mayBeReadByCall()) 2680 genArrayCopy(temp, actualArg); 2681 builder.create<fir::ResultOp>(loc, fir::getBase(temp)); 2682 }) 2683 .genElse([&]() { 2684 auto nullPtr = builder.createNullConstant(loc, addrType); 2685 builder.create<fir::ResultOp>(loc, nullPtr); 2686 }) 2687 .getResults()[0]; 2688 // Associate the temp address with actualArg lengths and extents. 2689 fir::ExtendedValue temp = fir::substBase(readIfBoxValue(actualArg), addr); 2690 copyOutPairs.emplace_back(CopyOutPair{ 2691 actualArg, temp, arg.mayBeModifiedByCall(), restrictCopyAtRuntime}); 2692 return temp; 2693 } 2694 2695 /// Generate copy-out if needed and free the temporary for an argument that 2696 /// has been copied-in into a contiguous temp. 2697 void genCopyOut(const CopyOutPair ©OutPair) { 2698 mlir::Location loc = getLoc(); 2699 if (!copyOutPair.restrictCopyAndFreeAtRuntime) { 2700 if (copyOutPair.argMayBeModifiedByCall) 2701 genArrayCopy(copyOutPair.var, copyOutPair.temp); 2702 builder.create<fir::FreeMemOp>(loc, fir::getBase(copyOutPair.temp)); 2703 return; 2704 } 2705 builder.genIfThen(loc, *copyOutPair.restrictCopyAndFreeAtRuntime) 2706 .genThen([&]() { 2707 if (copyOutPair.argMayBeModifiedByCall) 2708 genArrayCopy(copyOutPair.var, copyOutPair.temp); 2709 builder.create<fir::FreeMemOp>(loc, fir::getBase(copyOutPair.temp)); 2710 }) 2711 .end(); 2712 } 2713 2714 /// Lower a non-elemental procedure reference. 2715 ExtValue genRawProcedureRef(const Fortran::evaluate::ProcedureRef &procRef, 2716 llvm::Optional<mlir::Type> resultType) { 2717 mlir::Location loc = getLoc(); 2718 if (isElementalProcWithArrayArgs(procRef)) 2719 fir::emitFatalError(loc, "trying to lower elemental procedure with array " 2720 "arguments as normal procedure"); 2721 if (const Fortran::evaluate::SpecificIntrinsic *intrinsic = 2722 procRef.proc().GetSpecificIntrinsic()) 2723 return genIntrinsicRef(procRef, *intrinsic, resultType); 2724 2725 if (isStatementFunctionCall(procRef)) 2726 return genStmtFunctionRef(procRef); 2727 2728 Fortran::lower::CallerInterface caller(procRef, converter); 2729 using PassBy = Fortran::lower::CallerInterface::PassEntityBy; 2730 2731 llvm::SmallVector<fir::MutableBoxValue> mutableModifiedByCall; 2732 // List of <var, temp> where temp must be copied into var after the call. 2733 CopyOutPairs copyOutPairs; 2734 2735 mlir::FunctionType callSiteType = caller.genFunctionType(); 2736 2737 // Lower the actual arguments and map the lowered values to the dummy 2738 // arguments. 2739 for (const Fortran::lower::CallInterface< 2740 Fortran::lower::CallerInterface>::PassedEntity &arg : 2741 caller.getPassedArguments()) { 2742 const auto *actual = arg.entity; 2743 mlir::Type argTy = callSiteType.getInput(arg.firArgument); 2744 if (!actual) { 2745 // Optional dummy argument for which there is no actual argument. 2746 caller.placeInput(arg, builder.create<fir::AbsentOp>(loc, argTy)); 2747 continue; 2748 } 2749 const auto *expr = actual->UnwrapExpr(); 2750 if (!expr) 2751 TODO(loc, "assumed type actual argument lowering"); 2752 2753 if (arg.passBy == PassBy::Value) { 2754 ExtValue argVal = genval(*expr); 2755 if (!fir::isUnboxedValue(argVal)) 2756 fir::emitFatalError( 2757 loc, "internal error: passing non trivial value by value"); 2758 caller.placeInput(arg, fir::getBase(argVal)); 2759 continue; 2760 } 2761 2762 if (arg.passBy == PassBy::MutableBox) { 2763 if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>( 2764 *expr)) { 2765 // If expr is NULL(), the mutableBox created must be a deallocated 2766 // pointer with the dummy argument characteristics (see table 16.5 2767 // in Fortran 2018 standard). 2768 // No length parameters are set for the created box because any non 2769 // deferred type parameters of the dummy will be evaluated on the 2770 // callee side, and it is illegal to use NULL without a MOLD if any 2771 // dummy length parameters are assumed. 2772 mlir::Type boxTy = fir::dyn_cast_ptrEleTy(argTy); 2773 assert(boxTy && boxTy.isa<fir::BoxType>() && 2774 "must be a fir.box type"); 2775 mlir::Value boxStorage = builder.createTemporary(loc, boxTy); 2776 mlir::Value nullBox = fir::factory::createUnallocatedBox( 2777 builder, loc, boxTy, /*nonDeferredParams=*/{}); 2778 builder.create<fir::StoreOp>(loc, nullBox, boxStorage); 2779 caller.placeInput(arg, boxStorage); 2780 continue; 2781 } 2782 if (fir::isPointerType(argTy) && 2783 !Fortran::evaluate::IsObjectPointer( 2784 *expr, converter.getFoldingContext())) { 2785 // Passing a non POINTER actual argument to a POINTER dummy argument. 2786 // Create a pointer of the dummy argument type and assign the actual 2787 // argument to it. 2788 mlir::Value irBox = 2789 builder.createTemporary(loc, fir::unwrapRefType(argTy)); 2790 // Non deferred parameters will be evaluated on the callee side. 2791 fir::MutableBoxValue pointer(irBox, 2792 /*nonDeferredParams=*/mlir::ValueRange{}, 2793 /*mutableProperties=*/{}); 2794 Fortran::lower::associateMutableBox(converter, loc, pointer, *expr, 2795 /*lbounds*/ mlir::ValueRange{}, 2796 stmtCtx); 2797 caller.placeInput(arg, irBox); 2798 continue; 2799 } 2800 // Passing a POINTER to a POINTER, or an ALLOCATABLE to an ALLOCATABLE. 2801 fir::MutableBoxValue mutableBox = genMutableBoxValue(*expr); 2802 mlir::Value irBox = 2803 fir::factory::getMutableIRBox(builder, loc, mutableBox); 2804 caller.placeInput(arg, irBox); 2805 if (arg.mayBeModifiedByCall()) 2806 mutableModifiedByCall.emplace_back(std::move(mutableBox)); 2807 continue; 2808 } 2809 const bool actualArgIsVariable = Fortran::evaluate::IsVariable(*expr); 2810 if (arg.passBy == PassBy::BaseAddressValueAttribute) { 2811 mlir::Value temp; 2812 if (isArray(*expr)) { 2813 auto val = genBoxArg(*expr); 2814 if (!actualArgIsVariable) 2815 temp = getBase(val); 2816 else { 2817 ExtValue copy = genArrayTempFromMold(val, ".copy"); 2818 genArrayCopy(copy, val); 2819 temp = fir::getBase(copy); 2820 } 2821 } else { 2822 mlir::Value val = fir::getBase(genval(*expr)); 2823 temp = builder.createTemporary( 2824 loc, val.getType(), 2825 llvm::ArrayRef<mlir::NamedAttribute>{ 2826 Fortran::lower::getAdaptToByRefAttr(builder)}); 2827 builder.create<fir::StoreOp>(loc, val, temp); 2828 } 2829 caller.placeInput(arg, temp); 2830 continue; 2831 } 2832 if (arg.passBy == PassBy::BaseAddress || arg.passBy == PassBy::BoxChar) { 2833 const bool actualIsSimplyContiguous = 2834 !actualArgIsVariable || Fortran::evaluate::IsSimplyContiguous( 2835 *expr, converter.getFoldingContext()); 2836 auto argAddr = [&]() -> ExtValue { 2837 ExtValue baseAddr; 2838 if (actualArgIsVariable && arg.isOptional()) { 2839 if (Fortran::evaluate::IsAllocatableOrPointerObject( 2840 *expr, converter.getFoldingContext())) { 2841 // Fortran 2018 15.5.2.12 point 1: If unallocated/disassociated, 2842 // it is as if the argument was absent. The main care here is to 2843 // not do a copy-in/copy-out because the temp address, even though 2844 // pointing to a null size storage, would not be a nullptr and 2845 // therefore the argument would not be considered absent on the 2846 // callee side. Note: if wholeSymbol is optional, it cannot be 2847 // absent as per 15.5.2.12 point 7. and 8. We rely on this to 2848 // un-conditionally read the allocatable/pointer descriptor here. 2849 if (actualIsSimplyContiguous) 2850 return genBoxArg(*expr); 2851 fir::MutableBoxValue mutableBox = genMutableBoxValue(*expr); 2852 mlir::Value isAssociated = 2853 fir::factory::genIsAllocatedOrAssociatedTest(builder, loc, 2854 mutableBox); 2855 fir::ExtendedValue actualExv = 2856 fir::factory::genMutableBoxRead(builder, loc, mutableBox); 2857 return genCopyIn(actualExv, arg, copyOutPairs, isAssociated); 2858 } 2859 if (const Fortran::semantics::Symbol *wholeSymbol = 2860 Fortran::evaluate::UnwrapWholeSymbolOrComponentDataRef( 2861 *expr)) 2862 if (Fortran::semantics::IsOptional(*wholeSymbol)) { 2863 ExtValue actualArg = gen(*expr); 2864 mlir::Value actualArgBase = fir::getBase(actualArg); 2865 if (!actualArgBase.getType().isa<fir::BoxType>()) 2866 return actualArg; 2867 // Do not read wholeSymbol descriptor that may be a nullptr in 2868 // case wholeSymbol is absent. 2869 // Absent descriptor cannot be read. To avoid any issue in 2870 // copy-in/copy-out, and when retrieving the address/length 2871 // create an descriptor pointing to a null address here if the 2872 // fir.box is absent. 2873 mlir::Value isPresent = builder.create<fir::IsPresentOp>( 2874 loc, builder.getI1Type(), actualArgBase); 2875 mlir::Type boxType = actualArgBase.getType(); 2876 mlir::Value emptyBox = fir::factory::createUnallocatedBox( 2877 builder, loc, boxType, llvm::None); 2878 auto safeToReadBox = builder.create<mlir::arith::SelectOp>( 2879 loc, isPresent, actualArgBase, emptyBox); 2880 fir::ExtendedValue safeToReadExv = 2881 fir::substBase(actualArg, safeToReadBox); 2882 if (actualIsSimplyContiguous) 2883 return safeToReadExv; 2884 return genCopyIn(safeToReadExv, arg, copyOutPairs, isPresent); 2885 } 2886 // Fall through: The actual argument can safely be 2887 // copied-in/copied-out without any care if needed. 2888 } 2889 if (actualArgIsVariable && expr->Rank() > 0) { 2890 ExtValue box = genBoxArg(*expr); 2891 if (!actualIsSimplyContiguous) 2892 return genCopyIn(box, arg, copyOutPairs, 2893 /*restrictCopyAtRuntime=*/llvm::None); 2894 // Contiguous: just use the box we created above! 2895 // This gets "unboxed" below, if needed. 2896 return box; 2897 } 2898 // Actual argument is a non optional/non pointer/non allocatable 2899 // scalar. 2900 if (actualArgIsVariable) 2901 return genExtAddr(*expr); 2902 // Actual argument is not a variable. Make sure a variable address is 2903 // not passed. 2904 return genTempExtAddr(*expr); 2905 }(); 2906 // Scalar and contiguous expressions may be lowered to a fir.box, 2907 // either to account for potential polymorphism, or because lowering 2908 // did not account for some contiguity hints. 2909 // Here, polymorphism does not matter (an entity of the declared type 2910 // is passed, not one of the dynamic type), and the expr is known to 2911 // be simply contiguous, so it is safe to unbox it and pass the 2912 // address without making a copy. 2913 argAddr = readIfBoxValue(argAddr); 2914 2915 if (arg.passBy == PassBy::BaseAddress) { 2916 caller.placeInput(arg, fir::getBase(argAddr)); 2917 } else { 2918 assert(arg.passBy == PassBy::BoxChar); 2919 auto helper = fir::factory::CharacterExprHelper{builder, loc}; 2920 auto boxChar = argAddr.match( 2921 [&](const fir::CharBoxValue &x) { return helper.createEmbox(x); }, 2922 [&](const fir::CharArrayBoxValue &x) { 2923 return helper.createEmbox(x); 2924 }, 2925 [&](const auto &x) -> mlir::Value { 2926 // Fortran allows an actual argument of a completely different 2927 // type to be passed to a procedure expecting a CHARACTER in the 2928 // dummy argument position. When this happens, the data pointer 2929 // argument is simply assumed to point to CHARACTER data and the 2930 // LEN argument used is garbage. Simulate this behavior by 2931 // free-casting the base address to be a !fir.char reference and 2932 // setting the LEN argument to undefined. What could go wrong? 2933 auto dataPtr = fir::getBase(x); 2934 assert(!dataPtr.getType().template isa<fir::BoxType>()); 2935 return builder.convertWithSemantics( 2936 loc, argTy, dataPtr, 2937 /*allowCharacterConversion=*/true); 2938 }); 2939 caller.placeInput(arg, boxChar); 2940 } 2941 } else if (arg.passBy == PassBy::Box) { 2942 // Before lowering to an address, handle the allocatable/pointer actual 2943 // argument to optional fir.box dummy. It is legal to pass 2944 // unallocated/disassociated entity to an optional. In this case, an 2945 // absent fir.box must be created instead of a fir.box with a null value 2946 // (Fortran 2018 15.5.2.12 point 1). 2947 if (arg.isOptional() && Fortran::evaluate::IsAllocatableOrPointerObject( 2948 *expr, converter.getFoldingContext())) { 2949 // Note that passing an absent allocatable to a non-allocatable 2950 // optional dummy argument is illegal (15.5.2.12 point 3 (8)). So 2951 // nothing has to be done to generate an absent argument in this case, 2952 // and it is OK to unconditionally read the mutable box here. 2953 fir::MutableBoxValue mutableBox = genMutableBoxValue(*expr); 2954 mlir::Value isAllocated = 2955 fir::factory::genIsAllocatedOrAssociatedTest(builder, loc, 2956 mutableBox); 2957 auto absent = builder.create<fir::AbsentOp>(loc, argTy); 2958 /// For now, assume it is not OK to pass the allocatable/pointer 2959 /// descriptor to a non pointer/allocatable dummy. That is a strict 2960 /// interpretation of 18.3.6 point 4 that stipulates the descriptor 2961 /// has the dummy attributes in BIND(C) contexts. 2962 mlir::Value box = builder.createBox( 2963 loc, fir::factory::genMutableBoxRead(builder, loc, mutableBox)); 2964 // Need the box types to be exactly similar for the selectOp. 2965 mlir::Value convertedBox = builder.createConvert(loc, argTy, box); 2966 caller.placeInput(arg, builder.create<mlir::arith::SelectOp>( 2967 loc, isAllocated, convertedBox, absent)); 2968 } else { 2969 // Make sure a variable address is only passed if the expression is 2970 // actually a variable. 2971 mlir::Value box = 2972 actualArgIsVariable 2973 ? builder.createBox(loc, genBoxArg(*expr)) 2974 : builder.createBox(getLoc(), genTempExtAddr(*expr)); 2975 caller.placeInput(arg, box); 2976 } 2977 } else if (arg.passBy == PassBy::AddressAndLength) { 2978 ExtValue argRef = genExtAddr(*expr); 2979 caller.placeAddressAndLengthInput(arg, fir::getBase(argRef), 2980 fir::getLen(argRef)); 2981 } else if (arg.passBy == PassBy::CharProcTuple) { 2982 ExtValue argRef = genExtAddr(*expr); 2983 mlir::Value tuple = createBoxProcCharTuple( 2984 converter, argTy, fir::getBase(argRef), fir::getLen(argRef)); 2985 caller.placeInput(arg, tuple); 2986 } else { 2987 TODO(loc, "pass by value in non elemental function call"); 2988 } 2989 } 2990 2991 ExtValue result = genCallOpAndResult(caller, callSiteType, resultType); 2992 2993 // Sync pointers and allocatables that may have been modified during the 2994 // call. 2995 for (const auto &mutableBox : mutableModifiedByCall) 2996 fir::factory::syncMutableBoxFromIRBox(builder, loc, mutableBox); 2997 // Handle case where result was passed as argument 2998 2999 // Copy-out temps that were created for non contiguous variable arguments if 3000 // needed. 3001 for (const auto ©OutPair : copyOutPairs) 3002 genCopyOut(copyOutPair); 3003 3004 return result; 3005 } 3006 3007 template <typename A> 3008 ExtValue genval(const Fortran::evaluate::FunctionRef<A> &funcRef) { 3009 ExtValue result = genFunctionRef(funcRef); 3010 if (result.rank() == 0 && fir::isa_ref_type(fir::getBase(result).getType())) 3011 return genLoad(result); 3012 return result; 3013 } 3014 3015 ExtValue genval(const Fortran::evaluate::ProcedureRef &procRef) { 3016 llvm::Optional<mlir::Type> resTy; 3017 if (procRef.hasAlternateReturns()) 3018 resTy = builder.getIndexType(); 3019 return genProcedureRef(procRef, resTy); 3020 } 3021 3022 template <typename A> 3023 bool isScalar(const A &x) { 3024 return x.Rank() == 0; 3025 } 3026 3027 /// Helper to detect Transformational function reference. 3028 template <typename T> 3029 bool isTransformationalRef(const T &) { 3030 return false; 3031 } 3032 template <typename T> 3033 bool isTransformationalRef(const Fortran::evaluate::FunctionRef<T> &funcRef) { 3034 return !funcRef.IsElemental() && funcRef.Rank(); 3035 } 3036 template <typename T> 3037 bool isTransformationalRef(Fortran::evaluate::Expr<T> expr) { 3038 return std::visit([&](const auto &e) { return isTransformationalRef(e); }, 3039 expr.u); 3040 } 3041 3042 template <typename A> 3043 ExtValue asArray(const A &x) { 3044 return Fortran::lower::createSomeArrayTempValue(converter, toEvExpr(x), 3045 symMap, stmtCtx); 3046 } 3047 3048 /// Lower an array value as an argument. This argument can be passed as a box 3049 /// value, so it may be possible to avoid making a temporary. 3050 template <typename A> 3051 ExtValue asArrayArg(const Fortran::evaluate::Expr<A> &x) { 3052 return std::visit([&](const auto &e) { return asArrayArg(e, x); }, x.u); 3053 } 3054 template <typename A, typename B> 3055 ExtValue asArrayArg(const Fortran::evaluate::Expr<A> &x, const B &y) { 3056 return std::visit([&](const auto &e) { return asArrayArg(e, y); }, x.u); 3057 } 3058 template <typename A, typename B> 3059 ExtValue asArrayArg(const Fortran::evaluate::Designator<A> &, const B &x) { 3060 // Designator is being passed as an argument to a procedure. Lower the 3061 // expression to a boxed value. 3062 auto someExpr = toEvExpr(x); 3063 return Fortran::lower::createBoxValue(getLoc(), converter, someExpr, symMap, 3064 stmtCtx); 3065 } 3066 template <typename A, typename B> 3067 ExtValue asArrayArg(const A &, const B &x) { 3068 // If the expression to pass as an argument is not a designator, then create 3069 // an array temp. 3070 return asArray(x); 3071 } 3072 3073 template <typename A> 3074 ExtValue gen(const Fortran::evaluate::Expr<A> &x) { 3075 // Whole array symbols or components, and results of transformational 3076 // functions already have a storage and the scalar expression lowering path 3077 // is used to not create a new temporary storage. 3078 if (isScalar(x) || 3079 Fortran::evaluate::UnwrapWholeSymbolOrComponentDataRef(x) || 3080 isTransformationalRef(x)) 3081 return std::visit([&](const auto &e) { return genref(e); }, x.u); 3082 if (useBoxArg) 3083 return asArrayArg(x); 3084 return asArray(x); 3085 } 3086 template <typename A> 3087 ExtValue genval(const Fortran::evaluate::Expr<A> &x) { 3088 if (isScalar(x) || Fortran::evaluate::UnwrapWholeSymbolDataRef(x) || 3089 inInitializer) 3090 return std::visit([&](const auto &e) { return genval(e); }, x.u); 3091 return asArray(x); 3092 } 3093 3094 template <int KIND> 3095 ExtValue genval(const Fortran::evaluate::Expr<Fortran::evaluate::Type< 3096 Fortran::common::TypeCategory::Logical, KIND>> &exp) { 3097 return std::visit([&](const auto &e) { return genval(e); }, exp.u); 3098 } 3099 3100 using RefSet = 3101 std::tuple<Fortran::evaluate::ComplexPart, Fortran::evaluate::Substring, 3102 Fortran::evaluate::DataRef, Fortran::evaluate::Component, 3103 Fortran::evaluate::ArrayRef, Fortran::evaluate::CoarrayRef, 3104 Fortran::semantics::SymbolRef>; 3105 template <typename A> 3106 static constexpr bool inRefSet = Fortran::common::HasMember<A, RefSet>; 3107 3108 template <typename A, typename = std::enable_if_t<inRefSet<A>>> 3109 ExtValue genref(const A &a) { 3110 return gen(a); 3111 } 3112 template <typename A> 3113 ExtValue genref(const A &a) { 3114 if (inInitializer) { 3115 // Initialization expressions can never allocate memory. 3116 return genval(a); 3117 } 3118 mlir::Type storageType = converter.genType(toEvExpr(a)); 3119 return placeScalarValueInMemory(builder, getLoc(), genval(a), storageType); 3120 } 3121 3122 template <typename A, template <typename> typename T, 3123 typename B = std::decay_t<T<A>>, 3124 std::enable_if_t< 3125 std::is_same_v<B, Fortran::evaluate::Expr<A>> || 3126 std::is_same_v<B, Fortran::evaluate::Designator<A>> || 3127 std::is_same_v<B, Fortran::evaluate::FunctionRef<A>>, 3128 bool> = true> 3129 ExtValue genref(const T<A> &x) { 3130 return gen(x); 3131 } 3132 3133 private: 3134 mlir::Location location; 3135 Fortran::lower::AbstractConverter &converter; 3136 fir::FirOpBuilder &builder; 3137 Fortran::lower::StatementContext &stmtCtx; 3138 Fortran::lower::SymMap &symMap; 3139 InitializerData *inInitializer = nullptr; 3140 bool useBoxArg = false; // expression lowered as argument 3141 }; 3142 } // namespace 3143 3144 // Helper for changing the semantics in a given context. Preserves the current 3145 // semantics which is resumed when the "push" goes out of scope. 3146 #define PushSemantics(PushVal) \ 3147 [[maybe_unused]] auto pushSemanticsLocalVariable##__LINE__ = \ 3148 Fortran::common::ScopedSet(semant, PushVal); 3149 3150 static bool isAdjustedArrayElementType(mlir::Type t) { 3151 return fir::isa_char(t) || fir::isa_derived(t) || t.isa<fir::SequenceType>(); 3152 } 3153 static bool elementTypeWasAdjusted(mlir::Type t) { 3154 if (auto ty = t.dyn_cast<fir::ReferenceType>()) 3155 return isAdjustedArrayElementType(ty.getEleTy()); 3156 return false; 3157 } 3158 static mlir::Type adjustedArrayElementType(mlir::Type t) { 3159 return isAdjustedArrayElementType(t) ? fir::ReferenceType::get(t) : t; 3160 } 3161 3162 /// Helper to generate calls to scalar user defined assignment procedures. 3163 static void genScalarUserDefinedAssignmentCall(fir::FirOpBuilder &builder, 3164 mlir::Location loc, 3165 mlir::func::FuncOp func, 3166 const fir::ExtendedValue &lhs, 3167 const fir::ExtendedValue &rhs) { 3168 auto prepareUserDefinedArg = 3169 [](fir::FirOpBuilder &builder, mlir::Location loc, 3170 const fir::ExtendedValue &value, mlir::Type argType) -> mlir::Value { 3171 if (argType.isa<fir::BoxCharType>()) { 3172 const fir::CharBoxValue *charBox = value.getCharBox(); 3173 assert(charBox && "argument type mismatch in elemental user assignment"); 3174 return fir::factory::CharacterExprHelper{builder, loc}.createEmbox( 3175 *charBox); 3176 } 3177 if (argType.isa<fir::BoxType>()) { 3178 mlir::Value box = builder.createBox(loc, value); 3179 return builder.createConvert(loc, argType, box); 3180 } 3181 // Simple pass by address. 3182 mlir::Type argBaseType = fir::unwrapRefType(argType); 3183 assert(!fir::hasDynamicSize(argBaseType)); 3184 mlir::Value from = fir::getBase(value); 3185 if (argBaseType != fir::unwrapRefType(from.getType())) { 3186 // With logicals, it is possible that from is i1 here. 3187 if (fir::isa_ref_type(from.getType())) 3188 from = builder.create<fir::LoadOp>(loc, from); 3189 from = builder.createConvert(loc, argBaseType, from); 3190 } 3191 if (!fir::isa_ref_type(from.getType())) { 3192 mlir::Value temp = builder.createTemporary(loc, argBaseType); 3193 builder.create<fir::StoreOp>(loc, from, temp); 3194 from = temp; 3195 } 3196 return builder.createConvert(loc, argType, from); 3197 }; 3198 assert(func.getNumArguments() == 2); 3199 mlir::Type lhsType = func.getFunctionType().getInput(0); 3200 mlir::Type rhsType = func.getFunctionType().getInput(1); 3201 mlir::Value lhsArg = prepareUserDefinedArg(builder, loc, lhs, lhsType); 3202 mlir::Value rhsArg = prepareUserDefinedArg(builder, loc, rhs, rhsType); 3203 builder.create<fir::CallOp>(loc, func, mlir::ValueRange{lhsArg, rhsArg}); 3204 } 3205 3206 /// Convert the result of a fir.array_modify to an ExtendedValue given the 3207 /// related fir.array_load. 3208 static fir::ExtendedValue arrayModifyToExv(fir::FirOpBuilder &builder, 3209 mlir::Location loc, 3210 fir::ArrayLoadOp load, 3211 mlir::Value elementAddr) { 3212 mlir::Type eleTy = fir::unwrapPassByRefType(elementAddr.getType()); 3213 if (fir::isa_char(eleTy)) { 3214 auto len = fir::factory::CharacterExprHelper{builder, loc}.getLength( 3215 load.getMemref()); 3216 if (!len) { 3217 assert(load.getTypeparams().size() == 1 && 3218 "length must be in array_load"); 3219 len = load.getTypeparams()[0]; 3220 } 3221 return fir::CharBoxValue{elementAddr, len}; 3222 } 3223 return elementAddr; 3224 } 3225 3226 //===----------------------------------------------------------------------===// 3227 // 3228 // Lowering of scalar expressions in an explicit iteration space context. 3229 // 3230 //===----------------------------------------------------------------------===// 3231 3232 // Shared code for creating a copy of a derived type element. This function is 3233 // called from a continuation. 3234 inline static fir::ArrayAmendOp 3235 createDerivedArrayAmend(mlir::Location loc, fir::ArrayLoadOp destLoad, 3236 fir::FirOpBuilder &builder, fir::ArrayAccessOp destAcc, 3237 const fir::ExtendedValue &elementExv, mlir::Type eleTy, 3238 mlir::Value innerArg) { 3239 if (destLoad.getTypeparams().empty()) { 3240 fir::factory::genRecordAssignment(builder, loc, destAcc, elementExv); 3241 } else { 3242 auto boxTy = fir::BoxType::get(eleTy); 3243 auto toBox = builder.create<fir::EmboxOp>(loc, boxTy, destAcc.getResult(), 3244 mlir::Value{}, mlir::Value{}, 3245 destLoad.getTypeparams()); 3246 auto fromBox = builder.create<fir::EmboxOp>( 3247 loc, boxTy, fir::getBase(elementExv), mlir::Value{}, mlir::Value{}, 3248 destLoad.getTypeparams()); 3249 fir::factory::genRecordAssignment(builder, loc, fir::BoxValue(toBox), 3250 fir::BoxValue(fromBox)); 3251 } 3252 return builder.create<fir::ArrayAmendOp>(loc, innerArg.getType(), innerArg, 3253 destAcc); 3254 } 3255 3256 inline static fir::ArrayAmendOp 3257 createCharArrayAmend(mlir::Location loc, fir::FirOpBuilder &builder, 3258 fir::ArrayAccessOp dstOp, mlir::Value &dstLen, 3259 const fir::ExtendedValue &srcExv, mlir::Value innerArg, 3260 llvm::ArrayRef<mlir::Value> bounds) { 3261 fir::CharBoxValue dstChar(dstOp, dstLen); 3262 fir::factory::CharacterExprHelper helper{builder, loc}; 3263 if (!bounds.empty()) { 3264 dstChar = helper.createSubstring(dstChar, bounds); 3265 fir::factory::genCharacterCopy(fir::getBase(srcExv), fir::getLen(srcExv), 3266 dstChar.getAddr(), dstChar.getLen(), builder, 3267 loc); 3268 // Update the LEN to the substring's LEN. 3269 dstLen = dstChar.getLen(); 3270 } 3271 // For a CHARACTER, we generate the element assignment loops inline. 3272 helper.createAssign(fir::ExtendedValue{dstChar}, srcExv); 3273 // Mark this array element as amended. 3274 mlir::Type ty = innerArg.getType(); 3275 auto amend = builder.create<fir::ArrayAmendOp>(loc, ty, innerArg, dstOp); 3276 return amend; 3277 } 3278 3279 /// Build an ExtendedValue from a fir.array<?x...?xT> without actually setting 3280 /// the actual extents and lengths. This is only to allow their propagation as 3281 /// ExtendedValue without triggering verifier failures when propagating 3282 /// character/arrays as unboxed values. Only the base of the resulting 3283 /// ExtendedValue should be used, it is undefined to use the length or extents 3284 /// of the extended value returned, 3285 inline static fir::ExtendedValue 3286 convertToArrayBoxValue(mlir::Location loc, fir::FirOpBuilder &builder, 3287 mlir::Value val, mlir::Value len) { 3288 mlir::Type ty = fir::unwrapRefType(val.getType()); 3289 mlir::IndexType idxTy = builder.getIndexType(); 3290 auto seqTy = ty.cast<fir::SequenceType>(); 3291 auto undef = builder.create<fir::UndefOp>(loc, idxTy); 3292 llvm::SmallVector<mlir::Value> extents(seqTy.getDimension(), undef); 3293 if (fir::isa_char(seqTy.getEleTy())) 3294 return fir::CharArrayBoxValue(val, len ? len : undef, extents); 3295 return fir::ArrayBoxValue(val, extents); 3296 } 3297 3298 //===----------------------------------------------------------------------===// 3299 // 3300 // Lowering of array expressions. 3301 // 3302 //===----------------------------------------------------------------------===// 3303 3304 namespace { 3305 class ArrayExprLowering { 3306 using ExtValue = fir::ExtendedValue; 3307 3308 /// Structure to keep track of lowered array operands in the 3309 /// array expression. Useful to later deduce the shape of the 3310 /// array expression. 3311 struct ArrayOperand { 3312 /// Array base (can be a fir.box). 3313 mlir::Value memref; 3314 /// ShapeOp, ShapeShiftOp or ShiftOp 3315 mlir::Value shape; 3316 /// SliceOp 3317 mlir::Value slice; 3318 /// Can this operand be absent ? 3319 bool mayBeAbsent = false; 3320 }; 3321 3322 using ImplicitSubscripts = Fortran::lower::details::ImplicitSubscripts; 3323 using PathComponent = Fortran::lower::PathComponent; 3324 3325 /// Active iteration space. 3326 using IterationSpace = Fortran::lower::IterationSpace; 3327 using IterSpace = const Fortran::lower::IterationSpace &; 3328 3329 /// Current continuation. Function that will generate IR for a single 3330 /// iteration of the pending iterative loop structure. 3331 using CC = Fortran::lower::GenerateElementalArrayFunc; 3332 3333 /// Projection continuation. Function that will project one iteration space 3334 /// into another. 3335 using PC = std::function<IterationSpace(IterSpace)>; 3336 using ArrayBaseTy = 3337 std::variant<std::monostate, const Fortran::evaluate::ArrayRef *, 3338 const Fortran::evaluate::DataRef *>; 3339 using ComponentPath = Fortran::lower::ComponentPath; 3340 3341 public: 3342 //===--------------------------------------------------------------------===// 3343 // Regular array assignment 3344 //===--------------------------------------------------------------------===// 3345 3346 /// Entry point for array assignments. Both the left-hand and right-hand sides 3347 /// can either be ExtendedValue or evaluate::Expr. 3348 template <typename TL, typename TR> 3349 static void lowerArrayAssignment(Fortran::lower::AbstractConverter &converter, 3350 Fortran::lower::SymMap &symMap, 3351 Fortran::lower::StatementContext &stmtCtx, 3352 const TL &lhs, const TR &rhs) { 3353 ArrayExprLowering ael{converter, stmtCtx, symMap, 3354 ConstituentSemantics::CopyInCopyOut}; 3355 ael.lowerArrayAssignment(lhs, rhs); 3356 } 3357 3358 template <typename TL, typename TR> 3359 void lowerArrayAssignment(const TL &lhs, const TR &rhs) { 3360 mlir::Location loc = getLoc(); 3361 /// Here the target subspace is not necessarily contiguous. The ArrayUpdate 3362 /// continuation is implicitly returned in `ccStoreToDest` and the ArrayLoad 3363 /// in `destination`. 3364 PushSemantics(ConstituentSemantics::ProjectedCopyInCopyOut); 3365 ccStoreToDest = genarr(lhs); 3366 determineShapeOfDest(lhs); 3367 semant = ConstituentSemantics::RefTransparent; 3368 ExtValue exv = lowerArrayExpression(rhs); 3369 if (explicitSpaceIsActive()) { 3370 explicitSpace->finalizeContext(); 3371 builder.create<fir::ResultOp>(loc, fir::getBase(exv)); 3372 } else { 3373 builder.create<fir::ArrayMergeStoreOp>( 3374 loc, destination, fir::getBase(exv), destination.getMemref(), 3375 destination.getSlice(), destination.getTypeparams()); 3376 } 3377 } 3378 3379 //===--------------------------------------------------------------------===// 3380 // WHERE array assignment, FORALL assignment, and FORALL+WHERE array 3381 // assignment 3382 //===--------------------------------------------------------------------===// 3383 3384 /// Entry point for array assignment when the iteration space is explicitly 3385 /// defined (Fortran's FORALL) with or without masks, and/or the implied 3386 /// iteration space involves masks (Fortran's WHERE). Both contexts (explicit 3387 /// space and implicit space with masks) may be present. 3388 static void lowerAnyMaskedArrayAssignment( 3389 Fortran::lower::AbstractConverter &converter, 3390 Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx, 3391 const Fortran::lower::SomeExpr &lhs, const Fortran::lower::SomeExpr &rhs, 3392 Fortran::lower::ExplicitIterSpace &explicitSpace, 3393 Fortran::lower::ImplicitIterSpace &implicitSpace) { 3394 if (explicitSpace.isActive() && lhs.Rank() == 0) { 3395 // Scalar assignment expression in a FORALL context. 3396 ArrayExprLowering ael(converter, stmtCtx, symMap, 3397 ConstituentSemantics::RefTransparent, 3398 &explicitSpace, &implicitSpace); 3399 ael.lowerScalarAssignment(lhs, rhs); 3400 return; 3401 } 3402 // Array assignment expression in a FORALL and/or WHERE context. 3403 ArrayExprLowering ael(converter, stmtCtx, symMap, 3404 ConstituentSemantics::CopyInCopyOut, &explicitSpace, 3405 &implicitSpace); 3406 ael.lowerArrayAssignment(lhs, rhs); 3407 } 3408 3409 //===--------------------------------------------------------------------===// 3410 // Array assignment to allocatable array 3411 //===--------------------------------------------------------------------===// 3412 3413 /// Entry point for assignment to allocatable array. 3414 static void lowerAllocatableArrayAssignment( 3415 Fortran::lower::AbstractConverter &converter, 3416 Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx, 3417 const Fortran::lower::SomeExpr &lhs, const Fortran::lower::SomeExpr &rhs, 3418 Fortran::lower::ExplicitIterSpace &explicitSpace, 3419 Fortran::lower::ImplicitIterSpace &implicitSpace) { 3420 ArrayExprLowering ael(converter, stmtCtx, symMap, 3421 ConstituentSemantics::CopyInCopyOut, &explicitSpace, 3422 &implicitSpace); 3423 ael.lowerAllocatableArrayAssignment(lhs, rhs); 3424 } 3425 3426 /// Assignment to allocatable array. 3427 /// 3428 /// The semantics are reverse that of a "regular" array assignment. The rhs 3429 /// defines the iteration space of the computation and the lhs is 3430 /// resized/reallocated to fit if necessary. 3431 void lowerAllocatableArrayAssignment(const Fortran::lower::SomeExpr &lhs, 3432 const Fortran::lower::SomeExpr &rhs) { 3433 // With assignment to allocatable, we want to lower the rhs first and use 3434 // its shape to determine if we need to reallocate, etc. 3435 mlir::Location loc = getLoc(); 3436 // FIXME: If the lhs is in an explicit iteration space, the assignment may 3437 // be to an array of allocatable arrays rather than a single allocatable 3438 // array. 3439 fir::MutableBoxValue mutableBox = 3440 createMutableBox(loc, converter, lhs, symMap); 3441 mlir::Type resultTy = converter.genType(rhs); 3442 if (rhs.Rank() > 0) 3443 determineShapeOfDest(rhs); 3444 auto rhsCC = [&]() { 3445 PushSemantics(ConstituentSemantics::RefTransparent); 3446 return genarr(rhs); 3447 }(); 3448 3449 llvm::SmallVector<mlir::Value> lengthParams; 3450 // Currently no safe way to gather length from rhs (at least for 3451 // character, it cannot be taken from array_loads since it may be 3452 // changed by concatenations). 3453 if ((mutableBox.isCharacter() && !mutableBox.hasNonDeferredLenParams()) || 3454 mutableBox.isDerivedWithLengthParameters()) 3455 TODO(loc, "gather rhs length parameters in assignment to allocatable"); 3456 3457 // The allocatable must take lower bounds from the expr if it is 3458 // reallocated and the right hand side is not a scalar. 3459 const bool takeLboundsIfRealloc = rhs.Rank() > 0; 3460 llvm::SmallVector<mlir::Value> lbounds; 3461 // When the reallocated LHS takes its lower bounds from the RHS, 3462 // they will be non default only if the RHS is a whole array 3463 // variable. Otherwise, lbounds is left empty and default lower bounds 3464 // will be used. 3465 if (takeLboundsIfRealloc && 3466 Fortran::evaluate::UnwrapWholeSymbolOrComponentDataRef(rhs)) { 3467 assert(arrayOperands.size() == 1 && 3468 "lbounds can only come from one array"); 3469 std::vector<mlir::Value> lbs = 3470 fir::factory::getOrigins(arrayOperands[0].shape); 3471 lbounds.append(lbs.begin(), lbs.end()); 3472 } 3473 fir::factory::MutableBoxReallocation realloc = 3474 fir::factory::genReallocIfNeeded(builder, loc, mutableBox, destShape, 3475 lengthParams); 3476 // Create ArrayLoad for the mutable box and save it into `destination`. 3477 PushSemantics(ConstituentSemantics::ProjectedCopyInCopyOut); 3478 ccStoreToDest = genarr(realloc.newValue); 3479 // If the rhs is scalar, get shape from the allocatable ArrayLoad. 3480 if (destShape.empty()) 3481 destShape = getShape(destination); 3482 // Finish lowering the loop nest. 3483 assert(destination && "destination must have been set"); 3484 ExtValue exv = lowerArrayExpression(rhsCC, resultTy); 3485 if (explicitSpaceIsActive()) { 3486 explicitSpace->finalizeContext(); 3487 builder.create<fir::ResultOp>(loc, fir::getBase(exv)); 3488 } else { 3489 builder.create<fir::ArrayMergeStoreOp>( 3490 loc, destination, fir::getBase(exv), destination.getMemref(), 3491 destination.getSlice(), destination.getTypeparams()); 3492 } 3493 fir::factory::finalizeRealloc(builder, loc, mutableBox, lbounds, 3494 takeLboundsIfRealloc, realloc); 3495 } 3496 3497 /// Entry point for when an array expression appears in a context where the 3498 /// result must be boxed. (BoxValue semantics.) 3499 static ExtValue 3500 lowerBoxedArrayExpression(Fortran::lower::AbstractConverter &converter, 3501 Fortran::lower::SymMap &symMap, 3502 Fortran::lower::StatementContext &stmtCtx, 3503 const Fortran::lower::SomeExpr &expr) { 3504 ArrayExprLowering ael{converter, stmtCtx, symMap, 3505 ConstituentSemantics::BoxValue}; 3506 return ael.lowerBoxedArrayExpr(expr); 3507 } 3508 3509 ExtValue lowerBoxedArrayExpr(const Fortran::lower::SomeExpr &exp) { 3510 return std::visit( 3511 [&](const auto &e) { 3512 auto f = genarr(e); 3513 ExtValue exv = f(IterationSpace{}); 3514 if (fir::getBase(exv).getType().template isa<fir::BoxType>()) 3515 return exv; 3516 fir::emitFatalError(getLoc(), "array must be emboxed"); 3517 }, 3518 exp.u); 3519 } 3520 3521 /// Entry point into lowering an expression with rank. This entry point is for 3522 /// lowering a rhs expression, for example. (RefTransparent semantics.) 3523 static ExtValue 3524 lowerNewArrayExpression(Fortran::lower::AbstractConverter &converter, 3525 Fortran::lower::SymMap &symMap, 3526 Fortran::lower::StatementContext &stmtCtx, 3527 const Fortran::lower::SomeExpr &expr) { 3528 ArrayExprLowering ael{converter, stmtCtx, symMap}; 3529 ael.determineShapeOfDest(expr); 3530 ExtValue loopRes = ael.lowerArrayExpression(expr); 3531 fir::ArrayLoadOp dest = ael.destination; 3532 mlir::Value tempRes = dest.getMemref(); 3533 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 3534 mlir::Location loc = converter.getCurrentLocation(); 3535 builder.create<fir::ArrayMergeStoreOp>(loc, dest, fir::getBase(loopRes), 3536 tempRes, dest.getSlice(), 3537 dest.getTypeparams()); 3538 3539 auto arrTy = 3540 fir::dyn_cast_ptrEleTy(tempRes.getType()).cast<fir::SequenceType>(); 3541 if (auto charTy = 3542 arrTy.getEleTy().template dyn_cast<fir::CharacterType>()) { 3543 if (fir::characterWithDynamicLen(charTy)) 3544 TODO(loc, "CHARACTER does not have constant LEN"); 3545 mlir::Value len = builder.createIntegerConstant( 3546 loc, builder.getCharacterLengthType(), charTy.getLen()); 3547 return fir::CharArrayBoxValue(tempRes, len, dest.getExtents()); 3548 } 3549 return fir::ArrayBoxValue(tempRes, dest.getExtents()); 3550 } 3551 3552 static void lowerLazyArrayExpression( 3553 Fortran::lower::AbstractConverter &converter, 3554 Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx, 3555 const Fortran::lower::SomeExpr &expr, mlir::Value raggedHeader) { 3556 ArrayExprLowering ael(converter, stmtCtx, symMap); 3557 ael.lowerLazyArrayExpression(expr, raggedHeader); 3558 } 3559 3560 /// Lower the expression \p expr into a buffer that is created on demand. The 3561 /// variable containing the pointer to the buffer is \p var and the variable 3562 /// containing the shape of the buffer is \p shapeBuffer. 3563 void lowerLazyArrayExpression(const Fortran::lower::SomeExpr &expr, 3564 mlir::Value header) { 3565 mlir::Location loc = getLoc(); 3566 mlir::TupleType hdrTy = fir::factory::getRaggedArrayHeaderType(builder); 3567 mlir::IntegerType i32Ty = builder.getIntegerType(32); 3568 3569 // Once the loop extents have been computed, which may require being inside 3570 // some explicit loops, lazily allocate the expression on the heap. The 3571 // following continuation creates the buffer as needed. 3572 ccPrelude = [=](llvm::ArrayRef<mlir::Value> shape) { 3573 mlir::IntegerType i64Ty = builder.getIntegerType(64); 3574 mlir::Value byteSize = builder.createIntegerConstant(loc, i64Ty, 1); 3575 fir::runtime::genRaggedArrayAllocate( 3576 loc, builder, header, /*asHeaders=*/false, byteSize, shape); 3577 }; 3578 3579 // Create a dummy array_load before the loop. We're storing to a lazy 3580 // temporary, so there will be no conflict and no copy-in. TODO: skip this 3581 // as there isn't any necessity for it. 3582 ccLoadDest = [=](llvm::ArrayRef<mlir::Value> shape) -> fir::ArrayLoadOp { 3583 mlir::Value one = builder.createIntegerConstant(loc, i32Ty, 1); 3584 auto var = builder.create<fir::CoordinateOp>( 3585 loc, builder.getRefType(hdrTy.getType(1)), header, one); 3586 auto load = builder.create<fir::LoadOp>(loc, var); 3587 mlir::Type eleTy = 3588 fir::unwrapSequenceType(fir::unwrapRefType(load.getType())); 3589 auto seqTy = fir::SequenceType::get(eleTy, shape.size()); 3590 mlir::Value castTo = 3591 builder.createConvert(loc, fir::HeapType::get(seqTy), load); 3592 mlir::Value shapeOp = builder.genShape(loc, shape); 3593 return builder.create<fir::ArrayLoadOp>( 3594 loc, seqTy, castTo, shapeOp, /*slice=*/mlir::Value{}, llvm::None); 3595 }; 3596 // Custom lowering of the element store to deal with the extra indirection 3597 // to the lazy allocated buffer. 3598 ccStoreToDest = [=](IterSpace iters) { 3599 mlir::Value one = builder.createIntegerConstant(loc, i32Ty, 1); 3600 auto var = builder.create<fir::CoordinateOp>( 3601 loc, builder.getRefType(hdrTy.getType(1)), header, one); 3602 auto load = builder.create<fir::LoadOp>(loc, var); 3603 mlir::Type eleTy = 3604 fir::unwrapSequenceType(fir::unwrapRefType(load.getType())); 3605 auto seqTy = fir::SequenceType::get(eleTy, iters.iterVec().size()); 3606 auto toTy = fir::HeapType::get(seqTy); 3607 mlir::Value castTo = builder.createConvert(loc, toTy, load); 3608 mlir::Value shape = builder.genShape(loc, genIterationShape()); 3609 llvm::SmallVector<mlir::Value> indices = fir::factory::originateIndices( 3610 loc, builder, castTo.getType(), shape, iters.iterVec()); 3611 auto eleAddr = builder.create<fir::ArrayCoorOp>( 3612 loc, builder.getRefType(eleTy), castTo, shape, 3613 /*slice=*/mlir::Value{}, indices, destination.getTypeparams()); 3614 mlir::Value eleVal = 3615 builder.createConvert(loc, eleTy, iters.getElement()); 3616 builder.create<fir::StoreOp>(loc, eleVal, eleAddr); 3617 return iters.innerArgument(); 3618 }; 3619 3620 // Lower the array expression now. Clean-up any temps that may have 3621 // been generated when lowering `expr` right after the lowered value 3622 // was stored to the ragged array temporary. The local temps will not 3623 // be needed afterwards. 3624 stmtCtx.pushScope(); 3625 [[maybe_unused]] ExtValue loopRes = lowerArrayExpression(expr); 3626 stmtCtx.finalize(/*popScope=*/true); 3627 assert(fir::getBase(loopRes)); 3628 } 3629 3630 static void 3631 lowerElementalUserAssignment(Fortran::lower::AbstractConverter &converter, 3632 Fortran::lower::SymMap &symMap, 3633 Fortran::lower::StatementContext &stmtCtx, 3634 Fortran::lower::ExplicitIterSpace &explicitSpace, 3635 Fortran::lower::ImplicitIterSpace &implicitSpace, 3636 const Fortran::evaluate::ProcedureRef &procRef) { 3637 ArrayExprLowering ael(converter, stmtCtx, symMap, 3638 ConstituentSemantics::CustomCopyInCopyOut, 3639 &explicitSpace, &implicitSpace); 3640 assert(procRef.arguments().size() == 2); 3641 const auto *lhs = procRef.arguments()[0].value().UnwrapExpr(); 3642 const auto *rhs = procRef.arguments()[1].value().UnwrapExpr(); 3643 assert(lhs && rhs && 3644 "user defined assignment arguments must be expressions"); 3645 mlir::func::FuncOp func = 3646 Fortran::lower::CallerInterface(procRef, converter).getFuncOp(); 3647 ael.lowerElementalUserAssignment(func, *lhs, *rhs); 3648 } 3649 3650 void lowerElementalUserAssignment(mlir::func::FuncOp userAssignment, 3651 const Fortran::lower::SomeExpr &lhs, 3652 const Fortran::lower::SomeExpr &rhs) { 3653 mlir::Location loc = getLoc(); 3654 PushSemantics(ConstituentSemantics::CustomCopyInCopyOut); 3655 auto genArrayModify = genarr(lhs); 3656 ccStoreToDest = [=](IterSpace iters) -> ExtValue { 3657 auto modifiedArray = genArrayModify(iters); 3658 auto arrayModify = mlir::dyn_cast_or_null<fir::ArrayModifyOp>( 3659 fir::getBase(modifiedArray).getDefiningOp()); 3660 assert(arrayModify && "must be created by ArrayModifyOp"); 3661 fir::ExtendedValue lhs = 3662 arrayModifyToExv(builder, loc, destination, arrayModify.getResult(0)); 3663 genScalarUserDefinedAssignmentCall(builder, loc, userAssignment, lhs, 3664 iters.elementExv()); 3665 return modifiedArray; 3666 }; 3667 determineShapeOfDest(lhs); 3668 semant = ConstituentSemantics::RefTransparent; 3669 auto exv = lowerArrayExpression(rhs); 3670 if (explicitSpaceIsActive()) { 3671 explicitSpace->finalizeContext(); 3672 builder.create<fir::ResultOp>(loc, fir::getBase(exv)); 3673 } else { 3674 builder.create<fir::ArrayMergeStoreOp>( 3675 loc, destination, fir::getBase(exv), destination.getMemref(), 3676 destination.getSlice(), destination.getTypeparams()); 3677 } 3678 } 3679 3680 /// Lower an elemental subroutine call with at least one array argument. 3681 /// An elemental subroutine is an exception and does not have copy-in/copy-out 3682 /// semantics. See 15.8.3. 3683 /// Do NOT use this for user defined assignments. 3684 static void 3685 lowerElementalSubroutine(Fortran::lower::AbstractConverter &converter, 3686 Fortran::lower::SymMap &symMap, 3687 Fortran::lower::StatementContext &stmtCtx, 3688 const Fortran::lower::SomeExpr &call) { 3689 ArrayExprLowering ael(converter, stmtCtx, symMap, 3690 ConstituentSemantics::RefTransparent); 3691 ael.lowerElementalSubroutine(call); 3692 } 3693 3694 // TODO: See the comment in genarr(const Fortran::lower::Parentheses<T>&). 3695 // This is skipping generation of copy-in/copy-out code for analysis that is 3696 // required when arguments are in parentheses. 3697 void lowerElementalSubroutine(const Fortran::lower::SomeExpr &call) { 3698 auto f = genarr(call); 3699 llvm::SmallVector<mlir::Value> shape = genIterationShape(); 3700 auto [iterSpace, insPt] = genImplicitLoops(shape, /*innerArg=*/{}); 3701 f(iterSpace); 3702 finalizeElementCtx(); 3703 builder.restoreInsertionPoint(insPt); 3704 } 3705 3706 template <typename A, typename B> 3707 ExtValue lowerScalarAssignment(const A &lhs, const B &rhs) { 3708 // 1) Lower the rhs expression with array_fetch op(s). 3709 IterationSpace iters; 3710 iters.setElement(genarr(rhs)(iters)); 3711 fir::ExtendedValue elementalExv = iters.elementExv(); 3712 // 2) Lower the lhs expression to an array_update. 3713 semant = ConstituentSemantics::ProjectedCopyInCopyOut; 3714 auto lexv = genarr(lhs)(iters); 3715 // 3) Finalize the inner context. 3716 explicitSpace->finalizeContext(); 3717 // 4) Thread the array value updated forward. Note: the lhs might be 3718 // ill-formed (performing scalar assignment in an array context), 3719 // in which case there is no array to thread. 3720 auto createResult = [&](auto op) { 3721 mlir::Value oldInnerArg = op.getSequence(); 3722 std::size_t offset = explicitSpace->argPosition(oldInnerArg); 3723 explicitSpace->setInnerArg(offset, fir::getBase(lexv)); 3724 builder.create<fir::ResultOp>(getLoc(), fir::getBase(lexv)); 3725 }; 3726 if (auto updateOp = mlir::dyn_cast<fir::ArrayUpdateOp>( 3727 fir::getBase(lexv).getDefiningOp())) 3728 createResult(updateOp); 3729 else if (auto amend = mlir::dyn_cast<fir::ArrayAmendOp>( 3730 fir::getBase(lexv).getDefiningOp())) 3731 createResult(amend); 3732 else if (auto modifyOp = mlir::dyn_cast<fir::ArrayModifyOp>( 3733 fir::getBase(lexv).getDefiningOp())) 3734 createResult(modifyOp); 3735 return lexv; 3736 } 3737 3738 static ExtValue lowerScalarUserAssignment( 3739 Fortran::lower::AbstractConverter &converter, 3740 Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx, 3741 Fortran::lower::ExplicitIterSpace &explicitIterSpace, 3742 mlir::func::FuncOp userAssignmentFunction, 3743 const Fortran::lower::SomeExpr &lhs, 3744 const Fortran::lower::SomeExpr &rhs) { 3745 Fortran::lower::ImplicitIterSpace implicit; 3746 ArrayExprLowering ael(converter, stmtCtx, symMap, 3747 ConstituentSemantics::RefTransparent, 3748 &explicitIterSpace, &implicit); 3749 return ael.lowerScalarUserAssignment(userAssignmentFunction, lhs, rhs); 3750 } 3751 3752 ExtValue lowerScalarUserAssignment(mlir::func::FuncOp userAssignment, 3753 const Fortran::lower::SomeExpr &lhs, 3754 const Fortran::lower::SomeExpr &rhs) { 3755 mlir::Location loc = getLoc(); 3756 if (rhs.Rank() > 0) 3757 TODO(loc, "user-defined elemental assigment from expression with rank"); 3758 // 1) Lower the rhs expression with array_fetch op(s). 3759 IterationSpace iters; 3760 iters.setElement(genarr(rhs)(iters)); 3761 fir::ExtendedValue elementalExv = iters.elementExv(); 3762 // 2) Lower the lhs expression to an array_modify. 3763 semant = ConstituentSemantics::CustomCopyInCopyOut; 3764 auto lexv = genarr(lhs)(iters); 3765 bool isIllFormedLHS = false; 3766 // 3) Insert the call 3767 if (auto modifyOp = mlir::dyn_cast<fir::ArrayModifyOp>( 3768 fir::getBase(lexv).getDefiningOp())) { 3769 mlir::Value oldInnerArg = modifyOp.getSequence(); 3770 std::size_t offset = explicitSpace->argPosition(oldInnerArg); 3771 explicitSpace->setInnerArg(offset, fir::getBase(lexv)); 3772 fir::ExtendedValue exv = arrayModifyToExv( 3773 builder, loc, explicitSpace->getLhsLoad(0).getValue(), 3774 modifyOp.getResult(0)); 3775 genScalarUserDefinedAssignmentCall(builder, loc, userAssignment, exv, 3776 elementalExv); 3777 } else { 3778 // LHS is ill formed, it is a scalar with no references to FORALL 3779 // subscripts, so there is actually no array assignment here. The user 3780 // code is probably bad, but still insert user assignment call since it 3781 // was not rejected by semantics (a warning was emitted). 3782 isIllFormedLHS = true; 3783 genScalarUserDefinedAssignmentCall(builder, getLoc(), userAssignment, 3784 lexv, elementalExv); 3785 } 3786 // 4) Finalize the inner context. 3787 explicitSpace->finalizeContext(); 3788 // 5). Thread the array value updated forward. 3789 if (!isIllFormedLHS) 3790 builder.create<fir::ResultOp>(getLoc(), fir::getBase(lexv)); 3791 return lexv; 3792 } 3793 3794 private: 3795 void determineShapeOfDest(const fir::ExtendedValue &lhs) { 3796 destShape = fir::factory::getExtents(builder, getLoc(), lhs); 3797 } 3798 3799 void determineShapeOfDest(const Fortran::lower::SomeExpr &lhs) { 3800 if (!destShape.empty()) 3801 return; 3802 if (explicitSpaceIsActive() && determineShapeWithSlice(lhs)) 3803 return; 3804 mlir::Type idxTy = builder.getIndexType(); 3805 mlir::Location loc = getLoc(); 3806 if (std::optional<Fortran::evaluate::ConstantSubscripts> constantShape = 3807 Fortran::evaluate::GetConstantExtents(converter.getFoldingContext(), 3808 lhs)) 3809 for (Fortran::common::ConstantSubscript extent : *constantShape) 3810 destShape.push_back(builder.createIntegerConstant(loc, idxTy, extent)); 3811 } 3812 3813 bool genShapeFromDataRef(const Fortran::semantics::Symbol &x) { 3814 return false; 3815 } 3816 bool genShapeFromDataRef(const Fortran::evaluate::CoarrayRef &) { 3817 TODO(getLoc(), "coarray ref"); 3818 return false; 3819 } 3820 bool genShapeFromDataRef(const Fortran::evaluate::Component &x) { 3821 return x.base().Rank() > 0 ? genShapeFromDataRef(x.base()) : false; 3822 } 3823 bool genShapeFromDataRef(const Fortran::evaluate::ArrayRef &x) { 3824 if (x.Rank() == 0) 3825 return false; 3826 if (x.base().Rank() > 0) 3827 if (genShapeFromDataRef(x.base())) 3828 return true; 3829 // x has rank and x.base did not produce a shape. 3830 ExtValue exv = x.base().IsSymbol() ? asScalarRef(getFirstSym(x.base())) 3831 : asScalarRef(x.base().GetComponent()); 3832 mlir::Location loc = getLoc(); 3833 mlir::IndexType idxTy = builder.getIndexType(); 3834 llvm::SmallVector<mlir::Value> definedShape = 3835 fir::factory::getExtents(builder, loc, exv); 3836 mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); 3837 for (auto ss : llvm::enumerate(x.subscript())) { 3838 std::visit(Fortran::common::visitors{ 3839 [&](const Fortran::evaluate::Triplet &trip) { 3840 // For a subscript of triple notation, we compute the 3841 // range of this dimension of the iteration space. 3842 auto lo = [&]() { 3843 if (auto optLo = trip.lower()) 3844 return fir::getBase(asScalar(*optLo)); 3845 return getLBound(exv, ss.index(), one); 3846 }(); 3847 auto hi = [&]() { 3848 if (auto optHi = trip.upper()) 3849 return fir::getBase(asScalar(*optHi)); 3850 return getUBound(exv, ss.index(), one); 3851 }(); 3852 auto step = builder.createConvert( 3853 loc, idxTy, fir::getBase(asScalar(trip.stride()))); 3854 auto extent = builder.genExtentFromTriplet(loc, lo, hi, 3855 step, idxTy); 3856 destShape.push_back(extent); 3857 }, 3858 [&](auto) {}}, 3859 ss.value().u); 3860 } 3861 return true; 3862 } 3863 bool genShapeFromDataRef(const Fortran::evaluate::NamedEntity &x) { 3864 if (x.IsSymbol()) 3865 return genShapeFromDataRef(getFirstSym(x)); 3866 return genShapeFromDataRef(x.GetComponent()); 3867 } 3868 bool genShapeFromDataRef(const Fortran::evaluate::DataRef &x) { 3869 return std::visit([&](const auto &v) { return genShapeFromDataRef(v); }, 3870 x.u); 3871 } 3872 3873 /// When in an explicit space, the ranked component must be evaluated to 3874 /// determine the actual number of iterations when slicing triples are 3875 /// present. Lower these expressions here. 3876 bool determineShapeWithSlice(const Fortran::lower::SomeExpr &lhs) { 3877 LLVM_DEBUG(Fortran::lower::DumpEvaluateExpr::dump( 3878 llvm::dbgs() << "determine shape of:\n", lhs)); 3879 // FIXME: We may not want to use ExtractDataRef here since it doesn't deal 3880 // with substrings, etc. 3881 std::optional<Fortran::evaluate::DataRef> dref = 3882 Fortran::evaluate::ExtractDataRef(lhs); 3883 return dref.has_value() ? genShapeFromDataRef(*dref) : false; 3884 } 3885 3886 /// CHARACTER and derived type elements are treated as memory references. The 3887 /// numeric types are treated as values. 3888 static mlir::Type adjustedArraySubtype(mlir::Type ty, 3889 mlir::ValueRange indices) { 3890 mlir::Type pathTy = fir::applyPathToType(ty, indices); 3891 assert(pathTy && "indices failed to apply to type"); 3892 return adjustedArrayElementType(pathTy); 3893 } 3894 3895 ExtValue lowerArrayExpression(const Fortran::lower::SomeExpr &exp) { 3896 mlir::Type resTy = converter.genType(exp); 3897 return std::visit( 3898 [&](const auto &e) { return lowerArrayExpression(genarr(e), resTy); }, 3899 exp.u); 3900 } 3901 ExtValue lowerArrayExpression(const ExtValue &exv) { 3902 assert(!explicitSpace); 3903 mlir::Type resTy = fir::unwrapPassByRefType(fir::getBase(exv).getType()); 3904 return lowerArrayExpression(genarr(exv), resTy); 3905 } 3906 3907 void populateBounds(llvm::SmallVectorImpl<mlir::Value> &bounds, 3908 const Fortran::evaluate::Substring *substring) { 3909 if (!substring) 3910 return; 3911 bounds.push_back(fir::getBase(asScalar(substring->lower()))); 3912 if (auto upper = substring->upper()) 3913 bounds.push_back(fir::getBase(asScalar(*upper))); 3914 } 3915 3916 /// Default store to destination implementation. 3917 /// This implements the default case, which is to assign the value in 3918 /// `iters.element` into the destination array, `iters.innerArgument`. Handles 3919 /// by value and by reference assignment. 3920 CC defaultStoreToDestination(const Fortran::evaluate::Substring *substring) { 3921 return [=](IterSpace iterSpace) -> ExtValue { 3922 mlir::Location loc = getLoc(); 3923 mlir::Value innerArg = iterSpace.innerArgument(); 3924 fir::ExtendedValue exv = iterSpace.elementExv(); 3925 mlir::Type arrTy = innerArg.getType(); 3926 mlir::Type eleTy = fir::applyPathToType(arrTy, iterSpace.iterVec()); 3927 if (isAdjustedArrayElementType(eleTy)) { 3928 // The elemental update is in the memref domain. Under this semantics, 3929 // we must always copy the computed new element from its location in 3930 // memory into the destination array. 3931 mlir::Type resRefTy = builder.getRefType(eleTy); 3932 // Get a reference to the array element to be amended. 3933 auto arrayOp = builder.create<fir::ArrayAccessOp>( 3934 loc, resRefTy, innerArg, iterSpace.iterVec(), 3935 destination.getTypeparams()); 3936 if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) { 3937 llvm::SmallVector<mlir::Value> substringBounds; 3938 populateBounds(substringBounds, substring); 3939 mlir::Value dstLen = fir::factory::genLenOfCharacter( 3940 builder, loc, destination, iterSpace.iterVec(), substringBounds); 3941 fir::ArrayAmendOp amend = createCharArrayAmend( 3942 loc, builder, arrayOp, dstLen, exv, innerArg, substringBounds); 3943 return abstractArrayExtValue(amend, dstLen); 3944 } 3945 if (fir::isa_derived(eleTy)) { 3946 fir::ArrayAmendOp amend = createDerivedArrayAmend( 3947 loc, destination, builder, arrayOp, exv, eleTy, innerArg); 3948 return abstractArrayExtValue(amend /*FIXME: typeparams?*/); 3949 } 3950 assert(eleTy.isa<fir::SequenceType>() && "must be an array"); 3951 TODO(loc, "array (as element) assignment"); 3952 } 3953 // By value semantics. The element is being assigned by value. 3954 mlir::Value ele = builder.createConvert(loc, eleTy, fir::getBase(exv)); 3955 auto update = builder.create<fir::ArrayUpdateOp>( 3956 loc, arrTy, innerArg, ele, iterSpace.iterVec(), 3957 destination.getTypeparams()); 3958 return abstractArrayExtValue(update); 3959 }; 3960 } 3961 3962 /// For an elemental array expression. 3963 /// 1. Lower the scalars and array loads. 3964 /// 2. Create the iteration space. 3965 /// 3. Create the element-by-element computation in the loop. 3966 /// 4. Return the resulting array value. 3967 /// If no destination was set in the array context, a temporary of 3968 /// \p resultTy will be created to hold the evaluated expression. 3969 /// Otherwise, \p resultTy is ignored and the expression is evaluated 3970 /// in the destination. \p f is a continuation built from an 3971 /// evaluate::Expr or an ExtendedValue. 3972 ExtValue lowerArrayExpression(CC f, mlir::Type resultTy) { 3973 mlir::Location loc = getLoc(); 3974 auto [iterSpace, insPt] = genIterSpace(resultTy); 3975 auto exv = f(iterSpace); 3976 iterSpace.setElement(std::move(exv)); 3977 auto lambda = ccStoreToDest.hasValue() 3978 ? ccStoreToDest.getValue() 3979 : defaultStoreToDestination(/*substring=*/nullptr); 3980 mlir::Value updVal = fir::getBase(lambda(iterSpace)); 3981 finalizeElementCtx(); 3982 builder.create<fir::ResultOp>(loc, updVal); 3983 builder.restoreInsertionPoint(insPt); 3984 return abstractArrayExtValue(iterSpace.outerResult()); 3985 } 3986 3987 /// Compute the shape of a slice. 3988 llvm::SmallVector<mlir::Value> computeSliceShape(mlir::Value slice) { 3989 llvm::SmallVector<mlir::Value> slicedShape; 3990 auto slOp = mlir::cast<fir::SliceOp>(slice.getDefiningOp()); 3991 mlir::Operation::operand_range triples = slOp.getTriples(); 3992 mlir::IndexType idxTy = builder.getIndexType(); 3993 mlir::Location loc = getLoc(); 3994 for (unsigned i = 0, end = triples.size(); i < end; i += 3) { 3995 if (!mlir::isa_and_nonnull<fir::UndefOp>( 3996 triples[i + 1].getDefiningOp())) { 3997 // (..., lb:ub:step, ...) case: extent = max((ub-lb+step)/step, 0) 3998 // See Fortran 2018 9.5.3.3.2 section for more details. 3999 mlir::Value res = builder.genExtentFromTriplet( 4000 loc, triples[i], triples[i + 1], triples[i + 2], idxTy); 4001 slicedShape.emplace_back(res); 4002 } else { 4003 // do nothing. `..., i, ...` case, so dimension is dropped. 4004 } 4005 } 4006 return slicedShape; 4007 } 4008 4009 /// Get the shape from an ArrayOperand. The shape of the array is adjusted if 4010 /// the array was sliced. 4011 llvm::SmallVector<mlir::Value> getShape(ArrayOperand array) { 4012 if (array.slice) 4013 return computeSliceShape(array.slice); 4014 if (array.memref.getType().isa<fir::BoxType>()) 4015 return fir::factory::readExtents(builder, getLoc(), 4016 fir::BoxValue{array.memref}); 4017 std::vector<mlir::Value, std::allocator<mlir::Value>> extents = 4018 fir::factory::getExtents(array.shape); 4019 return {extents.begin(), extents.end()}; 4020 } 4021 4022 /// Get the shape from an ArrayLoad. 4023 llvm::SmallVector<mlir::Value> getShape(fir::ArrayLoadOp arrayLoad) { 4024 return getShape(ArrayOperand{arrayLoad.getMemref(), arrayLoad.getShape(), 4025 arrayLoad.getSlice()}); 4026 } 4027 4028 /// Returns the first array operand that may not be absent. If all 4029 /// array operands may be absent, return the first one. 4030 const ArrayOperand &getInducingShapeArrayOperand() const { 4031 assert(!arrayOperands.empty()); 4032 for (const ArrayOperand &op : arrayOperands) 4033 if (!op.mayBeAbsent) 4034 return op; 4035 // If all arrays operand appears in optional position, then none of them 4036 // is allowed to be absent as per 15.5.2.12 point 3. (6). Just pick the 4037 // first operands. 4038 // TODO: There is an opportunity to add a runtime check here that 4039 // this array is present as required. 4040 return arrayOperands[0]; 4041 } 4042 4043 /// Generate the shape of the iteration space over the array expression. The 4044 /// iteration space may be implicit, explicit, or both. If it is implied it is 4045 /// based on the destination and operand array loads, or an optional 4046 /// Fortran::evaluate::Shape from the front end. If the shape is explicit, 4047 /// this returns any implicit shape component, if it exists. 4048 llvm::SmallVector<mlir::Value> genIterationShape() { 4049 // Use the precomputed destination shape. 4050 if (!destShape.empty()) 4051 return destShape; 4052 // Otherwise, use the destination's shape. 4053 if (destination) 4054 return getShape(destination); 4055 // Otherwise, use the first ArrayLoad operand shape. 4056 if (!arrayOperands.empty()) 4057 return getShape(getInducingShapeArrayOperand()); 4058 fir::emitFatalError(getLoc(), 4059 "failed to compute the array expression shape"); 4060 } 4061 4062 bool explicitSpaceIsActive() const { 4063 return explicitSpace && explicitSpace->isActive(); 4064 } 4065 4066 bool implicitSpaceHasMasks() const { 4067 return implicitSpace && !implicitSpace->empty(); 4068 } 4069 4070 CC genMaskAccess(mlir::Value tmp, mlir::Value shape) { 4071 mlir::Location loc = getLoc(); 4072 return [=, builder = &converter.getFirOpBuilder()](IterSpace iters) { 4073 mlir::Type arrTy = fir::dyn_cast_ptrOrBoxEleTy(tmp.getType()); 4074 auto eleTy = arrTy.cast<fir::SequenceType>().getEleTy(); 4075 mlir::Type eleRefTy = builder->getRefType(eleTy); 4076 mlir::IntegerType i1Ty = builder->getI1Type(); 4077 // Adjust indices for any shift of the origin of the array. 4078 llvm::SmallVector<mlir::Value> indices = fir::factory::originateIndices( 4079 loc, *builder, tmp.getType(), shape, iters.iterVec()); 4080 auto addr = builder->create<fir::ArrayCoorOp>( 4081 loc, eleRefTy, tmp, shape, /*slice=*/mlir::Value{}, indices, 4082 /*typeParams=*/llvm::None); 4083 auto load = builder->create<fir::LoadOp>(loc, addr); 4084 return builder->createConvert(loc, i1Ty, load); 4085 }; 4086 } 4087 4088 /// Construct the incremental instantiations of the ragged array structure. 4089 /// Rebind the lazy buffer variable, etc. as we go. 4090 template <bool withAllocation = false> 4091 mlir::Value prepareRaggedArrays(Fortran::lower::FrontEndExpr expr) { 4092 assert(explicitSpaceIsActive()); 4093 mlir::Location loc = getLoc(); 4094 mlir::TupleType raggedTy = fir::factory::getRaggedArrayHeaderType(builder); 4095 llvm::SmallVector<llvm::SmallVector<fir::DoLoopOp>> loopStack = 4096 explicitSpace->getLoopStack(); 4097 const std::size_t depth = loopStack.size(); 4098 mlir::IntegerType i64Ty = builder.getIntegerType(64); 4099 [[maybe_unused]] mlir::Value byteSize = 4100 builder.createIntegerConstant(loc, i64Ty, 1); 4101 mlir::Value header = implicitSpace->lookupMaskHeader(expr); 4102 for (std::remove_const_t<decltype(depth)> i = 0; i < depth; ++i) { 4103 auto insPt = builder.saveInsertionPoint(); 4104 if (i < depth - 1) 4105 builder.setInsertionPoint(loopStack[i + 1][0]); 4106 4107 // Compute and gather the extents. 4108 llvm::SmallVector<mlir::Value> extents; 4109 for (auto doLoop : loopStack[i]) 4110 extents.push_back(builder.genExtentFromTriplet( 4111 loc, doLoop.getLowerBound(), doLoop.getUpperBound(), 4112 doLoop.getStep(), i64Ty)); 4113 if constexpr (withAllocation) { 4114 fir::runtime::genRaggedArrayAllocate( 4115 loc, builder, header, /*asHeader=*/true, byteSize, extents); 4116 } 4117 4118 // Compute the dynamic position into the header. 4119 llvm::SmallVector<mlir::Value> offsets; 4120 for (auto doLoop : loopStack[i]) { 4121 auto m = builder.create<mlir::arith::SubIOp>( 4122 loc, doLoop.getInductionVar(), doLoop.getLowerBound()); 4123 auto n = builder.create<mlir::arith::DivSIOp>(loc, m, doLoop.getStep()); 4124 mlir::Value one = builder.createIntegerConstant(loc, n.getType(), 1); 4125 offsets.push_back(builder.create<mlir::arith::AddIOp>(loc, n, one)); 4126 } 4127 mlir::IntegerType i32Ty = builder.getIntegerType(32); 4128 mlir::Value uno = builder.createIntegerConstant(loc, i32Ty, 1); 4129 mlir::Type coorTy = builder.getRefType(raggedTy.getType(1)); 4130 auto hdOff = builder.create<fir::CoordinateOp>(loc, coorTy, header, uno); 4131 auto toTy = fir::SequenceType::get(raggedTy, offsets.size()); 4132 mlir::Type toRefTy = builder.getRefType(toTy); 4133 auto ldHdr = builder.create<fir::LoadOp>(loc, hdOff); 4134 mlir::Value hdArr = builder.createConvert(loc, toRefTy, ldHdr); 4135 auto shapeOp = builder.genShape(loc, extents); 4136 header = builder.create<fir::ArrayCoorOp>( 4137 loc, builder.getRefType(raggedTy), hdArr, shapeOp, 4138 /*slice=*/mlir::Value{}, offsets, 4139 /*typeparams=*/mlir::ValueRange{}); 4140 auto hdrVar = builder.create<fir::CoordinateOp>(loc, coorTy, header, uno); 4141 auto inVar = builder.create<fir::LoadOp>(loc, hdrVar); 4142 mlir::Value two = builder.createIntegerConstant(loc, i32Ty, 2); 4143 mlir::Type coorTy2 = builder.getRefType(raggedTy.getType(2)); 4144 auto hdrSh = builder.create<fir::CoordinateOp>(loc, coorTy2, header, two); 4145 auto shapePtr = builder.create<fir::LoadOp>(loc, hdrSh); 4146 // Replace the binding. 4147 implicitSpace->rebind(expr, genMaskAccess(inVar, shapePtr)); 4148 if (i < depth - 1) 4149 builder.restoreInsertionPoint(insPt); 4150 } 4151 return header; 4152 } 4153 4154 /// Lower mask expressions with implied iteration spaces from the variants of 4155 /// WHERE syntax. Since it is legal for mask expressions to have side-effects 4156 /// and modify values that will be used for the lhs, rhs, or both of 4157 /// subsequent assignments, the mask must be evaluated before the assignment 4158 /// is processed. 4159 /// Mask expressions are array expressions too. 4160 void genMasks() { 4161 // Lower the mask expressions, if any. 4162 if (implicitSpaceHasMasks()) { 4163 mlir::Location loc = getLoc(); 4164 // Mask expressions are array expressions too. 4165 for (const auto *e : implicitSpace->getExprs()) 4166 if (e && !implicitSpace->isLowered(e)) { 4167 if (mlir::Value var = implicitSpace->lookupMaskVariable(e)) { 4168 // Allocate the mask buffer lazily. 4169 assert(explicitSpaceIsActive()); 4170 mlir::Value header = 4171 prepareRaggedArrays</*withAllocations=*/true>(e); 4172 Fortran::lower::createLazyArrayTempValue(converter, *e, header, 4173 symMap, stmtCtx); 4174 // Close the explicit loops. 4175 builder.create<fir::ResultOp>(loc, explicitSpace->getInnerArgs()); 4176 builder.setInsertionPointAfter(explicitSpace->getOuterLoop()); 4177 // Open a new copy of the explicit loop nest. 4178 explicitSpace->genLoopNest(); 4179 continue; 4180 } 4181 fir::ExtendedValue tmp = Fortran::lower::createSomeArrayTempValue( 4182 converter, *e, symMap, stmtCtx); 4183 mlir::Value shape = builder.createShape(loc, tmp); 4184 implicitSpace->bind(e, genMaskAccess(fir::getBase(tmp), shape)); 4185 } 4186 4187 // Set buffer from the header. 4188 for (const auto *e : implicitSpace->getExprs()) { 4189 if (!e) 4190 continue; 4191 if (implicitSpace->lookupMaskVariable(e)) { 4192 // Index into the ragged buffer to retrieve cached results. 4193 const int rank = e->Rank(); 4194 assert(destShape.empty() || 4195 static_cast<std::size_t>(rank) == destShape.size()); 4196 mlir::Value header = prepareRaggedArrays(e); 4197 mlir::TupleType raggedTy = 4198 fir::factory::getRaggedArrayHeaderType(builder); 4199 mlir::IntegerType i32Ty = builder.getIntegerType(32); 4200 mlir::Value one = builder.createIntegerConstant(loc, i32Ty, 1); 4201 auto coor1 = builder.create<fir::CoordinateOp>( 4202 loc, builder.getRefType(raggedTy.getType(1)), header, one); 4203 auto db = builder.create<fir::LoadOp>(loc, coor1); 4204 mlir::Type eleTy = 4205 fir::unwrapSequenceType(fir::unwrapRefType(db.getType())); 4206 mlir::Type buffTy = 4207 builder.getRefType(fir::SequenceType::get(eleTy, rank)); 4208 // Address of ragged buffer data. 4209 mlir::Value buff = builder.createConvert(loc, buffTy, db); 4210 4211 mlir::Value two = builder.createIntegerConstant(loc, i32Ty, 2); 4212 auto coor2 = builder.create<fir::CoordinateOp>( 4213 loc, builder.getRefType(raggedTy.getType(2)), header, two); 4214 auto shBuff = builder.create<fir::LoadOp>(loc, coor2); 4215 mlir::IntegerType i64Ty = builder.getIntegerType(64); 4216 mlir::IndexType idxTy = builder.getIndexType(); 4217 llvm::SmallVector<mlir::Value> extents; 4218 for (std::remove_const_t<decltype(rank)> i = 0; i < rank; ++i) { 4219 mlir::Value off = builder.createIntegerConstant(loc, i32Ty, i); 4220 auto coor = builder.create<fir::CoordinateOp>( 4221 loc, builder.getRefType(i64Ty), shBuff, off); 4222 auto ldExt = builder.create<fir::LoadOp>(loc, coor); 4223 extents.push_back(builder.createConvert(loc, idxTy, ldExt)); 4224 } 4225 if (destShape.empty()) 4226 destShape = extents; 4227 // Construct shape of buffer. 4228 mlir::Value shapeOp = builder.genShape(loc, extents); 4229 4230 // Replace binding with the local result. 4231 implicitSpace->rebind(e, genMaskAccess(buff, shapeOp)); 4232 } 4233 } 4234 } 4235 } 4236 4237 // FIXME: should take multiple inner arguments. 4238 std::pair<IterationSpace, mlir::OpBuilder::InsertPoint> 4239 genImplicitLoops(mlir::ValueRange shape, mlir::Value innerArg) { 4240 mlir::Location loc = getLoc(); 4241 mlir::IndexType idxTy = builder.getIndexType(); 4242 mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); 4243 mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0); 4244 llvm::SmallVector<mlir::Value> loopUppers; 4245 4246 // Convert any implied shape to closed interval form. The fir.do_loop will 4247 // run from 0 to `extent - 1` inclusive. 4248 for (auto extent : shape) 4249 loopUppers.push_back( 4250 builder.create<mlir::arith::SubIOp>(loc, extent, one)); 4251 4252 // Iteration space is created with outermost columns, innermost rows 4253 llvm::SmallVector<fir::DoLoopOp> loops; 4254 4255 const std::size_t loopDepth = loopUppers.size(); 4256 llvm::SmallVector<mlir::Value> ivars; 4257 4258 for (auto i : llvm::enumerate(llvm::reverse(loopUppers))) { 4259 if (i.index() > 0) { 4260 assert(!loops.empty()); 4261 builder.setInsertionPointToStart(loops.back().getBody()); 4262 } 4263 fir::DoLoopOp loop; 4264 if (innerArg) { 4265 loop = builder.create<fir::DoLoopOp>( 4266 loc, zero, i.value(), one, isUnordered(), 4267 /*finalCount=*/false, mlir::ValueRange{innerArg}); 4268 innerArg = loop.getRegionIterArgs().front(); 4269 if (explicitSpaceIsActive()) 4270 explicitSpace->setInnerArg(0, innerArg); 4271 } else { 4272 loop = builder.create<fir::DoLoopOp>(loc, zero, i.value(), one, 4273 isUnordered(), 4274 /*finalCount=*/false); 4275 } 4276 ivars.push_back(loop.getInductionVar()); 4277 loops.push_back(loop); 4278 } 4279 4280 if (innerArg) 4281 for (std::remove_const_t<decltype(loopDepth)> i = 0; i + 1 < loopDepth; 4282 ++i) { 4283 builder.setInsertionPointToEnd(loops[i].getBody()); 4284 builder.create<fir::ResultOp>(loc, loops[i + 1].getResult(0)); 4285 } 4286 4287 // Move insertion point to the start of the innermost loop in the nest. 4288 builder.setInsertionPointToStart(loops.back().getBody()); 4289 // Set `afterLoopNest` to just after the entire loop nest. 4290 auto currPt = builder.saveInsertionPoint(); 4291 builder.setInsertionPointAfter(loops[0]); 4292 auto afterLoopNest = builder.saveInsertionPoint(); 4293 builder.restoreInsertionPoint(currPt); 4294 4295 // Put the implicit loop variables in row to column order to match FIR's 4296 // Ops. (The loops were constructed from outermost column to innermost 4297 // row.) 4298 mlir::Value outerRes = loops[0].getResult(0); 4299 return {IterationSpace(innerArg, outerRes, llvm::reverse(ivars)), 4300 afterLoopNest}; 4301 } 4302 4303 /// Build the iteration space into which the array expression will be 4304 /// lowered. The resultType is used to create a temporary, if needed. 4305 std::pair<IterationSpace, mlir::OpBuilder::InsertPoint> 4306 genIterSpace(mlir::Type resultType) { 4307 mlir::Location loc = getLoc(); 4308 llvm::SmallVector<mlir::Value> shape = genIterationShape(); 4309 if (!destination) { 4310 // Allocate storage for the result if it is not already provided. 4311 destination = createAndLoadSomeArrayTemp(resultType, shape); 4312 } 4313 4314 // Generate the lazy mask allocation, if one was given. 4315 if (ccPrelude.hasValue()) 4316 ccPrelude.getValue()(shape); 4317 4318 // Now handle the implicit loops. 4319 mlir::Value inner = explicitSpaceIsActive() 4320 ? explicitSpace->getInnerArgs().front() 4321 : destination.getResult(); 4322 auto [iters, afterLoopNest] = genImplicitLoops(shape, inner); 4323 mlir::Value innerArg = iters.innerArgument(); 4324 4325 // Generate the mask conditional structure, if there are masks. Unlike the 4326 // explicit masks, which are interleaved, these mask expression appear in 4327 // the innermost loop. 4328 if (implicitSpaceHasMasks()) { 4329 // Recover the cached condition from the mask buffer. 4330 auto genCond = [&](Fortran::lower::FrontEndExpr e, IterSpace iters) { 4331 return implicitSpace->getBoundClosure(e)(iters); 4332 }; 4333 4334 // Handle the negated conditions in topological order of the WHERE 4335 // clauses. See 10.2.3.2p4 as to why this control structure is produced. 4336 for (llvm::SmallVector<Fortran::lower::FrontEndExpr> maskExprs : 4337 implicitSpace->getMasks()) { 4338 const std::size_t size = maskExprs.size() - 1; 4339 auto genFalseBlock = [&](const auto *e, auto &&cond) { 4340 auto ifOp = builder.create<fir::IfOp>( 4341 loc, mlir::TypeRange{innerArg.getType()}, fir::getBase(cond), 4342 /*withElseRegion=*/true); 4343 builder.create<fir::ResultOp>(loc, ifOp.getResult(0)); 4344 builder.setInsertionPointToStart(&ifOp.getThenRegion().front()); 4345 builder.create<fir::ResultOp>(loc, innerArg); 4346 builder.setInsertionPointToStart(&ifOp.getElseRegion().front()); 4347 }; 4348 auto genTrueBlock = [&](const auto *e, auto &&cond) { 4349 auto ifOp = builder.create<fir::IfOp>( 4350 loc, mlir::TypeRange{innerArg.getType()}, fir::getBase(cond), 4351 /*withElseRegion=*/true); 4352 builder.create<fir::ResultOp>(loc, ifOp.getResult(0)); 4353 builder.setInsertionPointToStart(&ifOp.getElseRegion().front()); 4354 builder.create<fir::ResultOp>(loc, innerArg); 4355 builder.setInsertionPointToStart(&ifOp.getThenRegion().front()); 4356 }; 4357 for (std::remove_const_t<decltype(size)> i = 0; i < size; ++i) 4358 if (const auto *e = maskExprs[i]) 4359 genFalseBlock(e, genCond(e, iters)); 4360 4361 // The last condition is either non-negated or unconditionally negated. 4362 if (const auto *e = maskExprs[size]) 4363 genTrueBlock(e, genCond(e, iters)); 4364 } 4365 } 4366 4367 // We're ready to lower the body (an assignment statement) for this context 4368 // of loop nests at this point. 4369 return {iters, afterLoopNest}; 4370 } 4371 4372 fir::ArrayLoadOp 4373 createAndLoadSomeArrayTemp(mlir::Type type, 4374 llvm::ArrayRef<mlir::Value> shape) { 4375 if (ccLoadDest.hasValue()) 4376 return ccLoadDest.getValue()(shape); 4377 auto seqTy = type.dyn_cast<fir::SequenceType>(); 4378 assert(seqTy && "must be an array"); 4379 mlir::Location loc = getLoc(); 4380 // TODO: Need to thread the length parameters here. For character, they may 4381 // differ from the operands length (e.g concatenation). So the array loads 4382 // type parameters are not enough. 4383 if (auto charTy = seqTy.getEleTy().dyn_cast<fir::CharacterType>()) 4384 if (charTy.hasDynamicLen()) 4385 TODO(loc, "character array expression temp with dynamic length"); 4386 if (auto recTy = seqTy.getEleTy().dyn_cast<fir::RecordType>()) 4387 if (recTy.getNumLenParams() > 0) 4388 TODO(loc, "derived type array expression temp with length parameters"); 4389 mlir::Value temp = seqTy.hasConstantShape() 4390 ? builder.create<fir::AllocMemOp>(loc, type) 4391 : builder.create<fir::AllocMemOp>( 4392 loc, type, ".array.expr", llvm::None, shape); 4393 fir::FirOpBuilder *bldr = &converter.getFirOpBuilder(); 4394 stmtCtx.attachCleanup( 4395 [bldr, loc, temp]() { bldr->create<fir::FreeMemOp>(loc, temp); }); 4396 mlir::Value shapeOp = genShapeOp(shape); 4397 return builder.create<fir::ArrayLoadOp>(loc, seqTy, temp, shapeOp, 4398 /*slice=*/mlir::Value{}, 4399 llvm::None); 4400 } 4401 4402 static fir::ShapeOp genShapeOp(mlir::Location loc, fir::FirOpBuilder &builder, 4403 llvm::ArrayRef<mlir::Value> shape) { 4404 mlir::IndexType idxTy = builder.getIndexType(); 4405 llvm::SmallVector<mlir::Value> idxShape; 4406 for (auto s : shape) 4407 idxShape.push_back(builder.createConvert(loc, idxTy, s)); 4408 auto shapeTy = fir::ShapeType::get(builder.getContext(), idxShape.size()); 4409 return builder.create<fir::ShapeOp>(loc, shapeTy, idxShape); 4410 } 4411 4412 fir::ShapeOp genShapeOp(llvm::ArrayRef<mlir::Value> shape) { 4413 return genShapeOp(getLoc(), builder, shape); 4414 } 4415 4416 //===--------------------------------------------------------------------===// 4417 // Expression traversal and lowering. 4418 //===--------------------------------------------------------------------===// 4419 4420 /// Lower the expression, \p x, in a scalar context. 4421 template <typename A> 4422 ExtValue asScalar(const A &x) { 4423 return ScalarExprLowering{getLoc(), converter, symMap, stmtCtx}.genval(x); 4424 } 4425 4426 /// Lower the expression, \p x, in a scalar context. If this is an explicit 4427 /// space, the expression may be scalar and refer to an array. We want to 4428 /// raise the array access to array operations in FIR to analyze potential 4429 /// conflicts even when the result is a scalar element. 4430 template <typename A> 4431 ExtValue asScalarArray(const A &x) { 4432 return explicitSpaceIsActive() ? genarr(x)(IterationSpace{}) : asScalar(x); 4433 } 4434 4435 /// Lower the expression in a scalar context to a memory reference. 4436 template <typename A> 4437 ExtValue asScalarRef(const A &x) { 4438 return ScalarExprLowering{getLoc(), converter, symMap, stmtCtx}.gen(x); 4439 } 4440 4441 /// Lower an expression without dereferencing any indirection that may be 4442 /// a nullptr (because this is an absent optional or unallocated/disassociated 4443 /// descriptor). The returned expression cannot be addressed directly, it is 4444 /// meant to inquire about its status before addressing the related entity. 4445 template <typename A> 4446 ExtValue asInquired(const A &x) { 4447 return ScalarExprLowering{getLoc(), converter, symMap, stmtCtx} 4448 .lowerIntrinsicArgumentAsInquired(x); 4449 } 4450 4451 /// Some temporaries are allocated on an element-by-element basis during the 4452 /// array expression evaluation. Collect the cleanups here so the resources 4453 /// can be freed before the next loop iteration, avoiding memory leaks. etc. 4454 Fortran::lower::StatementContext &getElementCtx() { 4455 if (!elementCtx) { 4456 stmtCtx.pushScope(); 4457 elementCtx = true; 4458 } 4459 return stmtCtx; 4460 } 4461 4462 /// If there were temporaries created for this element evaluation, finalize 4463 /// and deallocate the resources now. This should be done just prior the the 4464 /// fir::ResultOp at the end of the innermost loop. 4465 void finalizeElementCtx() { 4466 if (elementCtx) { 4467 stmtCtx.finalize(/*popScope=*/true); 4468 elementCtx = false; 4469 } 4470 } 4471 4472 /// Lower an elemental function array argument. This ensures array 4473 /// sub-expressions that are not variables and must be passed by address 4474 /// are lowered by value and placed in memory. 4475 template <typename A> 4476 CC genElementalArgument(const A &x) { 4477 // Ensure the returned element is in memory if this is what was requested. 4478 if ((semant == ConstituentSemantics::RefOpaque || 4479 semant == ConstituentSemantics::DataAddr || 4480 semant == ConstituentSemantics::ByValueArg)) { 4481 if (!Fortran::evaluate::IsVariable(x)) { 4482 PushSemantics(ConstituentSemantics::DataValue); 4483 CC cc = genarr(x); 4484 mlir::Location loc = getLoc(); 4485 if (isParenthesizedVariable(x)) { 4486 // Parenthesised variables are lowered to a reference to the variable 4487 // storage. When passing it as an argument, a copy must be passed. 4488 return [=](IterSpace iters) -> ExtValue { 4489 return createInMemoryScalarCopy(builder, loc, cc(iters)); 4490 }; 4491 } 4492 mlir::Type storageType = 4493 fir::unwrapSequenceType(converter.genType(toEvExpr(x))); 4494 return [=](IterSpace iters) -> ExtValue { 4495 return placeScalarValueInMemory(builder, loc, cc(iters), storageType); 4496 }; 4497 } 4498 } 4499 return genarr(x); 4500 } 4501 4502 // A procedure reference to a Fortran elemental intrinsic procedure. 4503 CC genElementalIntrinsicProcRef( 4504 const Fortran::evaluate::ProcedureRef &procRef, 4505 llvm::Optional<mlir::Type> retTy, 4506 const Fortran::evaluate::SpecificIntrinsic &intrinsic) { 4507 llvm::SmallVector<CC> operands; 4508 llvm::StringRef name = intrinsic.name; 4509 const Fortran::lower::IntrinsicArgumentLoweringRules *argLowering = 4510 Fortran::lower::getIntrinsicArgumentLowering(name); 4511 mlir::Location loc = getLoc(); 4512 if (Fortran::lower::intrinsicRequiresCustomOptionalHandling( 4513 procRef, intrinsic, converter)) { 4514 using CcPairT = std::pair<CC, llvm::Optional<mlir::Value>>; 4515 llvm::SmallVector<CcPairT> operands; 4516 auto prepareOptionalArg = [&](const Fortran::lower::SomeExpr &expr) { 4517 if (expr.Rank() == 0) { 4518 ExtValue optionalArg = this->asInquired(expr); 4519 mlir::Value isPresent = 4520 genActualIsPresentTest(builder, loc, optionalArg); 4521 operands.emplace_back( 4522 [=](IterSpace iters) -> ExtValue { 4523 return genLoad(builder, loc, optionalArg); 4524 }, 4525 isPresent); 4526 } else { 4527 auto [cc, isPresent, _] = this->genOptionalArrayFetch(expr); 4528 operands.emplace_back(cc, isPresent); 4529 } 4530 }; 4531 auto prepareOtherArg = [&](const Fortran::lower::SomeExpr &expr) { 4532 PushSemantics(ConstituentSemantics::RefTransparent); 4533 operands.emplace_back(genElementalArgument(expr), llvm::None); 4534 }; 4535 Fortran::lower::prepareCustomIntrinsicArgument( 4536 procRef, intrinsic, retTy, prepareOptionalArg, prepareOtherArg, 4537 converter); 4538 4539 fir::FirOpBuilder *bldr = &converter.getFirOpBuilder(); 4540 llvm::StringRef name = intrinsic.name; 4541 return [=](IterSpace iters) -> ExtValue { 4542 auto getArgument = [&](std::size_t i) -> ExtValue { 4543 return operands[i].first(iters); 4544 }; 4545 auto isPresent = [&](std::size_t i) -> llvm::Optional<mlir::Value> { 4546 return operands[i].second; 4547 }; 4548 return Fortran::lower::lowerCustomIntrinsic( 4549 *bldr, loc, name, retTy, isPresent, getArgument, operands.size(), 4550 getElementCtx()); 4551 }; 4552 } 4553 /// Otherwise, pre-lower arguments and use intrinsic lowering utility. 4554 for (const auto &[arg, dummy] : 4555 llvm::zip(procRef.arguments(), 4556 intrinsic.characteristics.value().dummyArguments)) { 4557 const auto *expr = 4558 Fortran::evaluate::UnwrapExpr<Fortran::lower::SomeExpr>(arg); 4559 if (!expr) { 4560 // Absent optional. 4561 operands.emplace_back([=](IterSpace) { return mlir::Value{}; }); 4562 } else if (!argLowering) { 4563 // No argument lowering instruction, lower by value. 4564 PushSemantics(ConstituentSemantics::RefTransparent); 4565 operands.emplace_back(genElementalArgument(*expr)); 4566 } else { 4567 // Ad-hoc argument lowering handling. 4568 Fortran::lower::ArgLoweringRule argRules = 4569 Fortran::lower::lowerIntrinsicArgumentAs(getLoc(), *argLowering, 4570 dummy.name); 4571 if (argRules.handleDynamicOptional && 4572 Fortran::evaluate::MayBePassedAsAbsentOptional( 4573 *expr, converter.getFoldingContext())) { 4574 // Currently, there is not elemental intrinsic that requires lowering 4575 // a potentially absent argument to something else than a value (apart 4576 // from character MAX/MIN that are handled elsewhere.) 4577 if (argRules.lowerAs != Fortran::lower::LowerIntrinsicArgAs::Value) 4578 TODO(loc, "lowering non trivial optional elemental intrinsic array " 4579 "argument"); 4580 PushSemantics(ConstituentSemantics::RefTransparent); 4581 operands.emplace_back(genarrForwardOptionalArgumentToCall(*expr)); 4582 continue; 4583 } 4584 switch (argRules.lowerAs) { 4585 case Fortran::lower::LowerIntrinsicArgAs::Value: { 4586 PushSemantics(ConstituentSemantics::RefTransparent); 4587 operands.emplace_back(genElementalArgument(*expr)); 4588 } break; 4589 case Fortran::lower::LowerIntrinsicArgAs::Addr: { 4590 // Note: assume does not have Fortran VALUE attribute semantics. 4591 PushSemantics(ConstituentSemantics::RefOpaque); 4592 operands.emplace_back(genElementalArgument(*expr)); 4593 } break; 4594 case Fortran::lower::LowerIntrinsicArgAs::Box: { 4595 PushSemantics(ConstituentSemantics::RefOpaque); 4596 auto lambda = genElementalArgument(*expr); 4597 operands.emplace_back([=](IterSpace iters) { 4598 return builder.createBox(loc, lambda(iters)); 4599 }); 4600 } break; 4601 case Fortran::lower::LowerIntrinsicArgAs::Inquired: 4602 TODO(loc, "intrinsic function with inquired argument"); 4603 break; 4604 } 4605 } 4606 } 4607 4608 // Let the intrinsic library lower the intrinsic procedure call 4609 return [=](IterSpace iters) { 4610 llvm::SmallVector<ExtValue> args; 4611 for (const auto &cc : operands) 4612 args.push_back(cc(iters)); 4613 return Fortran::lower::genIntrinsicCall(builder, loc, name, retTy, args, 4614 getElementCtx()); 4615 }; 4616 } 4617 4618 /// Lower a procedure reference to a user-defined elemental procedure. 4619 CC genElementalUserDefinedProcRef( 4620 const Fortran::evaluate::ProcedureRef &procRef, 4621 llvm::Optional<mlir::Type> retTy) { 4622 using PassBy = Fortran::lower::CallerInterface::PassEntityBy; 4623 4624 // 10.1.4 p5. Impure elemental procedures must be called in element order. 4625 if (const Fortran::semantics::Symbol *procSym = procRef.proc().GetSymbol()) 4626 if (!Fortran::semantics::IsPureProcedure(*procSym)) 4627 setUnordered(false); 4628 4629 Fortran::lower::CallerInterface caller(procRef, converter); 4630 llvm::SmallVector<CC> operands; 4631 operands.reserve(caller.getPassedArguments().size()); 4632 mlir::Location loc = getLoc(); 4633 mlir::FunctionType callSiteType = caller.genFunctionType(); 4634 for (const Fortran::lower::CallInterface< 4635 Fortran::lower::CallerInterface>::PassedEntity &arg : 4636 caller.getPassedArguments()) { 4637 // 15.8.3 p1. Elemental procedure with intent(out)/intent(inout) 4638 // arguments must be called in element order. 4639 if (arg.mayBeModifiedByCall()) 4640 setUnordered(false); 4641 const auto *actual = arg.entity; 4642 mlir::Type argTy = callSiteType.getInput(arg.firArgument); 4643 if (!actual) { 4644 // Optional dummy argument for which there is no actual argument. 4645 auto absent = builder.create<fir::AbsentOp>(loc, argTy); 4646 operands.emplace_back([=](IterSpace) { return absent; }); 4647 continue; 4648 } 4649 const auto *expr = actual->UnwrapExpr(); 4650 if (!expr) 4651 TODO(loc, "assumed type actual argument lowering"); 4652 4653 LLVM_DEBUG(expr->AsFortran(llvm::dbgs() 4654 << "argument: " << arg.firArgument << " = [") 4655 << "]\n"); 4656 if (arg.isOptional() && Fortran::evaluate::MayBePassedAsAbsentOptional( 4657 *expr, converter.getFoldingContext())) 4658 TODO(loc, 4659 "passing dynamically optional argument to elemental procedures"); 4660 switch (arg.passBy) { 4661 case PassBy::Value: { 4662 // True pass-by-value semantics. 4663 PushSemantics(ConstituentSemantics::RefTransparent); 4664 operands.emplace_back(genElementalArgument(*expr)); 4665 } break; 4666 case PassBy::BaseAddressValueAttribute: { 4667 // VALUE attribute or pass-by-reference to a copy semantics. (byval*) 4668 if (isArray(*expr)) { 4669 PushSemantics(ConstituentSemantics::ByValueArg); 4670 operands.emplace_back(genElementalArgument(*expr)); 4671 } else { 4672 // Store scalar value in a temp to fulfill VALUE attribute. 4673 mlir::Value val = fir::getBase(asScalar(*expr)); 4674 mlir::Value temp = builder.createTemporary( 4675 loc, val.getType(), 4676 llvm::ArrayRef<mlir::NamedAttribute>{ 4677 Fortran::lower::getAdaptToByRefAttr(builder)}); 4678 builder.create<fir::StoreOp>(loc, val, temp); 4679 operands.emplace_back( 4680 [=](IterSpace iters) -> ExtValue { return temp; }); 4681 } 4682 } break; 4683 case PassBy::BaseAddress: { 4684 if (isArray(*expr)) { 4685 PushSemantics(ConstituentSemantics::RefOpaque); 4686 operands.emplace_back(genElementalArgument(*expr)); 4687 } else { 4688 ExtValue exv = asScalarRef(*expr); 4689 operands.emplace_back([=](IterSpace iters) { return exv; }); 4690 } 4691 } break; 4692 case PassBy::CharBoxValueAttribute: { 4693 if (isArray(*expr)) { 4694 PushSemantics(ConstituentSemantics::DataValue); 4695 auto lambda = genElementalArgument(*expr); 4696 operands.emplace_back([=](IterSpace iters) { 4697 return fir::factory::CharacterExprHelper{builder, loc} 4698 .createTempFrom(lambda(iters)); 4699 }); 4700 } else { 4701 fir::factory::CharacterExprHelper helper(builder, loc); 4702 fir::CharBoxValue argVal = helper.createTempFrom(asScalarRef(*expr)); 4703 operands.emplace_back( 4704 [=](IterSpace iters) -> ExtValue { return argVal; }); 4705 } 4706 } break; 4707 case PassBy::BoxChar: { 4708 PushSemantics(ConstituentSemantics::RefOpaque); 4709 operands.emplace_back(genElementalArgument(*expr)); 4710 } break; 4711 case PassBy::AddressAndLength: 4712 // PassBy::AddressAndLength is only used for character results. Results 4713 // are not handled here. 4714 fir::emitFatalError( 4715 loc, "unexpected PassBy::AddressAndLength in elemental call"); 4716 break; 4717 case PassBy::CharProcTuple: { 4718 ExtValue argRef = asScalarRef(*expr); 4719 mlir::Value tuple = createBoxProcCharTuple( 4720 converter, argTy, fir::getBase(argRef), fir::getLen(argRef)); 4721 operands.emplace_back( 4722 [=](IterSpace iters) -> ExtValue { return tuple; }); 4723 } break; 4724 case PassBy::Box: 4725 case PassBy::MutableBox: 4726 // See C15100 and C15101 4727 fir::emitFatalError(loc, "cannot be POINTER, ALLOCATABLE"); 4728 } 4729 } 4730 4731 if (caller.getIfIndirectCallSymbol()) 4732 fir::emitFatalError(loc, "cannot be indirect call"); 4733 4734 // The lambda is mutable so that `caller` copy can be modified inside it. 4735 return 4736 [=, caller = std::move(caller)](IterSpace iters) mutable -> ExtValue { 4737 for (const auto &[cc, argIface] : 4738 llvm::zip(operands, caller.getPassedArguments())) { 4739 auto exv = cc(iters); 4740 auto arg = exv.match( 4741 [&](const fir::CharBoxValue &cb) -> mlir::Value { 4742 return fir::factory::CharacterExprHelper{builder, loc} 4743 .createEmbox(cb); 4744 }, 4745 [&](const auto &) { return fir::getBase(exv); }); 4746 caller.placeInput(argIface, arg); 4747 } 4748 return ScalarExprLowering{loc, converter, symMap, getElementCtx()} 4749 .genCallOpAndResult(caller, callSiteType, retTy); 4750 }; 4751 } 4752 4753 /// Generate a procedure reference. This code is shared for both functions and 4754 /// subroutines, the difference being reflected by `retTy`. 4755 CC genProcRef(const Fortran::evaluate::ProcedureRef &procRef, 4756 llvm::Optional<mlir::Type> retTy) { 4757 mlir::Location loc = getLoc(); 4758 if (procRef.IsElemental()) { 4759 if (const Fortran::evaluate::SpecificIntrinsic *intrin = 4760 procRef.proc().GetSpecificIntrinsic()) { 4761 // All elemental intrinsic functions are pure and cannot modify their 4762 // arguments. The only elemental subroutine, MVBITS has an Intent(inout) 4763 // argument. So for this last one, loops must be in element order 4764 // according to 15.8.3 p1. 4765 if (!retTy) 4766 setUnordered(false); 4767 4768 // Elemental intrinsic call. 4769 // The intrinsic procedure is called once per element of the array. 4770 return genElementalIntrinsicProcRef(procRef, retTy, *intrin); 4771 } 4772 if (ScalarExprLowering::isStatementFunctionCall(procRef)) 4773 fir::emitFatalError(loc, "statement function cannot be elemental"); 4774 4775 // Elemental call. 4776 // The procedure is called once per element of the array argument(s). 4777 return genElementalUserDefinedProcRef(procRef, retTy); 4778 } 4779 4780 // Transformational call. 4781 // The procedure is called once and produces a value of rank > 0. 4782 if (const Fortran::evaluate::SpecificIntrinsic *intrinsic = 4783 procRef.proc().GetSpecificIntrinsic()) { 4784 if (explicitSpaceIsActive() && procRef.Rank() == 0) { 4785 // Elide any implicit loop iters. 4786 return [=, &procRef](IterSpace) { 4787 return ScalarExprLowering{loc, converter, symMap, stmtCtx} 4788 .genIntrinsicRef(procRef, *intrinsic, retTy); 4789 }; 4790 } 4791 return genarr( 4792 ScalarExprLowering{loc, converter, symMap, stmtCtx}.genIntrinsicRef( 4793 procRef, *intrinsic, retTy)); 4794 } 4795 4796 if (explicitSpaceIsActive() && procRef.Rank() == 0) { 4797 // Elide any implicit loop iters. 4798 return [=, &procRef](IterSpace) { 4799 return ScalarExprLowering{loc, converter, symMap, stmtCtx} 4800 .genProcedureRef(procRef, retTy); 4801 }; 4802 } 4803 // In the default case, the call can be hoisted out of the loop nest. Apply 4804 // the iterations to the result, which may be an array value. 4805 return genarr( 4806 ScalarExprLowering{loc, converter, symMap, stmtCtx}.genProcedureRef( 4807 procRef, retTy)); 4808 } 4809 4810 CC genarr(const Fortran::evaluate::ProcedureDesignator &) { 4811 TODO(getLoc(), "procedure designator"); 4812 } 4813 CC genarr(const Fortran::evaluate::ProcedureRef &x) { 4814 if (x.hasAlternateReturns()) 4815 fir::emitFatalError(getLoc(), 4816 "array procedure reference with alt-return"); 4817 return genProcRef(x, llvm::None); 4818 } 4819 template <typename A> 4820 CC genScalarAndForwardValue(const A &x) { 4821 ExtValue result = asScalar(x); 4822 return [=](IterSpace) { return result; }; 4823 } 4824 template <typename A, typename = std::enable_if_t<Fortran::common::HasMember< 4825 A, Fortran::evaluate::TypelessExpression>>> 4826 CC genarr(const A &x) { 4827 return genScalarAndForwardValue(x); 4828 } 4829 4830 template <typename A> 4831 CC genarr(const Fortran::evaluate::Expr<A> &x) { 4832 LLVM_DEBUG(Fortran::lower::DumpEvaluateExpr::dump(llvm::dbgs(), x)); 4833 if (isArray(x) || explicitSpaceIsActive() || 4834 isElementalProcWithArrayArgs(x)) 4835 return std::visit([&](const auto &e) { return genarr(e); }, x.u); 4836 return genScalarAndForwardValue(x); 4837 } 4838 4839 // Converting a value of memory bound type requires creating a temp and 4840 // copying the value. 4841 static ExtValue convertAdjustedType(fir::FirOpBuilder &builder, 4842 mlir::Location loc, mlir::Type toType, 4843 const ExtValue &exv) { 4844 return exv.match( 4845 [&](const fir::CharBoxValue &cb) -> ExtValue { 4846 mlir::Value len = cb.getLen(); 4847 auto mem = 4848 builder.create<fir::AllocaOp>(loc, toType, mlir::ValueRange{len}); 4849 fir::CharBoxValue result(mem, len); 4850 fir::factory::CharacterExprHelper{builder, loc}.createAssign( 4851 ExtValue{result}, exv); 4852 return result; 4853 }, 4854 [&](const auto &) -> ExtValue { 4855 fir::emitFatalError(loc, "convert on adjusted extended value"); 4856 }); 4857 } 4858 template <Fortran::common::TypeCategory TC1, int KIND, 4859 Fortran::common::TypeCategory TC2> 4860 CC genarr(const Fortran::evaluate::Convert<Fortran::evaluate::Type<TC1, KIND>, 4861 TC2> &x) { 4862 mlir::Location loc = getLoc(); 4863 auto lambda = genarr(x.left()); 4864 mlir::Type ty = converter.genType(TC1, KIND); 4865 return [=](IterSpace iters) -> ExtValue { 4866 auto exv = lambda(iters); 4867 mlir::Value val = fir::getBase(exv); 4868 auto valTy = val.getType(); 4869 if (elementTypeWasAdjusted(valTy) && 4870 !(fir::isa_ref_type(valTy) && fir::isa_integer(ty))) 4871 return convertAdjustedType(builder, loc, ty, exv); 4872 return builder.createConvert(loc, ty, val); 4873 }; 4874 } 4875 4876 template <int KIND> 4877 CC genarr(const Fortran::evaluate::ComplexComponent<KIND> &x) { 4878 mlir::Location loc = getLoc(); 4879 auto lambda = genarr(x.left()); 4880 bool isImagPart = x.isImaginaryPart; 4881 return [=](IterSpace iters) -> ExtValue { 4882 mlir::Value lhs = fir::getBase(lambda(iters)); 4883 return fir::factory::Complex{builder, loc}.extractComplexPart(lhs, 4884 isImagPart); 4885 }; 4886 } 4887 4888 template <typename T> 4889 CC genarr(const Fortran::evaluate::Parentheses<T> &x) { 4890 mlir::Location loc = getLoc(); 4891 if (isReferentiallyOpaque()) { 4892 // Context is a call argument in, for example, an elemental procedure 4893 // call. TODO: all array arguments should use array_load, array_access, 4894 // array_amend, and INTENT(OUT), INTENT(INOUT) arguments should have 4895 // array_merge_store ops. 4896 TODO(loc, "parentheses on argument in elemental call"); 4897 } 4898 auto f = genarr(x.left()); 4899 return [=](IterSpace iters) -> ExtValue { 4900 auto val = f(iters); 4901 mlir::Value base = fir::getBase(val); 4902 auto newBase = 4903 builder.create<fir::NoReassocOp>(loc, base.getType(), base); 4904 return fir::substBase(val, newBase); 4905 }; 4906 } 4907 template <int KIND> 4908 CC genarr(const Fortran::evaluate::Negate<Fortran::evaluate::Type< 4909 Fortran::common::TypeCategory::Integer, KIND>> &x) { 4910 mlir::Location loc = getLoc(); 4911 auto f = genarr(x.left()); 4912 return [=](IterSpace iters) -> ExtValue { 4913 mlir::Value val = fir::getBase(f(iters)); 4914 mlir::Type ty = 4915 converter.genType(Fortran::common::TypeCategory::Integer, KIND); 4916 mlir::Value zero = builder.createIntegerConstant(loc, ty, 0); 4917 return builder.create<mlir::arith::SubIOp>(loc, zero, val); 4918 }; 4919 } 4920 template <int KIND> 4921 CC genarr(const Fortran::evaluate::Negate<Fortran::evaluate::Type< 4922 Fortran::common::TypeCategory::Real, KIND>> &x) { 4923 mlir::Location loc = getLoc(); 4924 auto f = genarr(x.left()); 4925 return [=](IterSpace iters) -> ExtValue { 4926 return builder.create<mlir::arith::NegFOp>(loc, fir::getBase(f(iters))); 4927 }; 4928 } 4929 template <int KIND> 4930 CC genarr(const Fortran::evaluate::Negate<Fortran::evaluate::Type< 4931 Fortran::common::TypeCategory::Complex, KIND>> &x) { 4932 mlir::Location loc = getLoc(); 4933 auto f = genarr(x.left()); 4934 return [=](IterSpace iters) -> ExtValue { 4935 return builder.create<fir::NegcOp>(loc, fir::getBase(f(iters))); 4936 }; 4937 } 4938 4939 //===--------------------------------------------------------------------===// 4940 // Binary elemental ops 4941 //===--------------------------------------------------------------------===// 4942 4943 template <typename OP, typename A> 4944 CC createBinaryOp(const A &evEx) { 4945 mlir::Location loc = getLoc(); 4946 auto lambda = genarr(evEx.left()); 4947 auto rf = genarr(evEx.right()); 4948 return [=](IterSpace iters) -> ExtValue { 4949 mlir::Value left = fir::getBase(lambda(iters)); 4950 mlir::Value right = fir::getBase(rf(iters)); 4951 return builder.create<OP>(loc, left, right); 4952 }; 4953 } 4954 4955 #undef GENBIN 4956 #define GENBIN(GenBinEvOp, GenBinTyCat, GenBinFirOp) \ 4957 template <int KIND> \ 4958 CC genarr(const Fortran::evaluate::GenBinEvOp<Fortran::evaluate::Type< \ 4959 Fortran::common::TypeCategory::GenBinTyCat, KIND>> &x) { \ 4960 return createBinaryOp<GenBinFirOp>(x); \ 4961 } 4962 4963 GENBIN(Add, Integer, mlir::arith::AddIOp) 4964 GENBIN(Add, Real, mlir::arith::AddFOp) 4965 GENBIN(Add, Complex, fir::AddcOp) 4966 GENBIN(Subtract, Integer, mlir::arith::SubIOp) 4967 GENBIN(Subtract, Real, mlir::arith::SubFOp) 4968 GENBIN(Subtract, Complex, fir::SubcOp) 4969 GENBIN(Multiply, Integer, mlir::arith::MulIOp) 4970 GENBIN(Multiply, Real, mlir::arith::MulFOp) 4971 GENBIN(Multiply, Complex, fir::MulcOp) 4972 GENBIN(Divide, Integer, mlir::arith::DivSIOp) 4973 GENBIN(Divide, Real, mlir::arith::DivFOp) 4974 GENBIN(Divide, Complex, fir::DivcOp) 4975 4976 template <Fortran::common::TypeCategory TC, int KIND> 4977 CC genarr( 4978 const Fortran::evaluate::Power<Fortran::evaluate::Type<TC, KIND>> &x) { 4979 mlir::Location loc = getLoc(); 4980 mlir::Type ty = converter.genType(TC, KIND); 4981 auto lf = genarr(x.left()); 4982 auto rf = genarr(x.right()); 4983 return [=](IterSpace iters) -> ExtValue { 4984 mlir::Value lhs = fir::getBase(lf(iters)); 4985 mlir::Value rhs = fir::getBase(rf(iters)); 4986 return Fortran::lower::genPow(builder, loc, ty, lhs, rhs); 4987 }; 4988 } 4989 template <Fortran::common::TypeCategory TC, int KIND> 4990 CC genarr( 4991 const Fortran::evaluate::Extremum<Fortran::evaluate::Type<TC, KIND>> &x) { 4992 mlir::Location loc = getLoc(); 4993 auto lf = genarr(x.left()); 4994 auto rf = genarr(x.right()); 4995 switch (x.ordering) { 4996 case Fortran::evaluate::Ordering::Greater: 4997 return [=](IterSpace iters) -> ExtValue { 4998 mlir::Value lhs = fir::getBase(lf(iters)); 4999 mlir::Value rhs = fir::getBase(rf(iters)); 5000 return Fortran::lower::genMax(builder, loc, 5001 llvm::ArrayRef<mlir::Value>{lhs, rhs}); 5002 }; 5003 case Fortran::evaluate::Ordering::Less: 5004 return [=](IterSpace iters) -> ExtValue { 5005 mlir::Value lhs = fir::getBase(lf(iters)); 5006 mlir::Value rhs = fir::getBase(rf(iters)); 5007 return Fortran::lower::genMin(builder, loc, 5008 llvm::ArrayRef<mlir::Value>{lhs, rhs}); 5009 }; 5010 case Fortran::evaluate::Ordering::Equal: 5011 llvm_unreachable("Equal is not a valid ordering in this context"); 5012 } 5013 llvm_unreachable("unknown ordering"); 5014 } 5015 template <Fortran::common::TypeCategory TC, int KIND> 5016 CC genarr( 5017 const Fortran::evaluate::RealToIntPower<Fortran::evaluate::Type<TC, KIND>> 5018 &x) { 5019 mlir::Location loc = getLoc(); 5020 auto ty = converter.genType(TC, KIND); 5021 auto lf = genarr(x.left()); 5022 auto rf = genarr(x.right()); 5023 return [=](IterSpace iters) { 5024 mlir::Value lhs = fir::getBase(lf(iters)); 5025 mlir::Value rhs = fir::getBase(rf(iters)); 5026 return Fortran::lower::genPow(builder, loc, ty, lhs, rhs); 5027 }; 5028 } 5029 template <int KIND> 5030 CC genarr(const Fortran::evaluate::ComplexConstructor<KIND> &x) { 5031 mlir::Location loc = getLoc(); 5032 auto lf = genarr(x.left()); 5033 auto rf = genarr(x.right()); 5034 return [=](IterSpace iters) -> ExtValue { 5035 mlir::Value lhs = fir::getBase(lf(iters)); 5036 mlir::Value rhs = fir::getBase(rf(iters)); 5037 return fir::factory::Complex{builder, loc}.createComplex(KIND, lhs, rhs); 5038 }; 5039 } 5040 5041 /// Fortran's concatenation operator `//`. 5042 template <int KIND> 5043 CC genarr(const Fortran::evaluate::Concat<KIND> &x) { 5044 mlir::Location loc = getLoc(); 5045 auto lf = genarr(x.left()); 5046 auto rf = genarr(x.right()); 5047 return [=](IterSpace iters) -> ExtValue { 5048 auto lhs = lf(iters); 5049 auto rhs = rf(iters); 5050 const fir::CharBoxValue *lchr = lhs.getCharBox(); 5051 const fir::CharBoxValue *rchr = rhs.getCharBox(); 5052 if (lchr && rchr) { 5053 return fir::factory::CharacterExprHelper{builder, loc} 5054 .createConcatenate(*lchr, *rchr); 5055 } 5056 TODO(loc, "concat on unexpected extended values"); 5057 return mlir::Value{}; 5058 }; 5059 } 5060 5061 template <int KIND> 5062 CC genarr(const Fortran::evaluate::SetLength<KIND> &x) { 5063 auto lf = genarr(x.left()); 5064 mlir::Value rhs = fir::getBase(asScalar(x.right())); 5065 return [=](IterSpace iters) -> ExtValue { 5066 mlir::Value lhs = fir::getBase(lf(iters)); 5067 return fir::CharBoxValue{lhs, rhs}; 5068 }; 5069 } 5070 5071 template <typename A> 5072 CC genarr(const Fortran::evaluate::Constant<A> &x) { 5073 if (/*explicitSpaceIsActive() &&*/ x.Rank() == 0) 5074 return genScalarAndForwardValue(x); 5075 mlir::Location loc = getLoc(); 5076 mlir::IndexType idxTy = builder.getIndexType(); 5077 mlir::Type arrTy = converter.genType(toEvExpr(x)); 5078 std::string globalName = Fortran::lower::mangle::mangleArrayLiteral(x); 5079 fir::GlobalOp global = builder.getNamedGlobal(globalName); 5080 if (!global) { 5081 mlir::Type symTy = arrTy; 5082 mlir::Type eleTy = symTy.cast<fir::SequenceType>().getEleTy(); 5083 // If we have a rank-1 array of integer, real, or logical, then we can 5084 // create a global array with the dense attribute. 5085 // 5086 // The mlir tensor type can only handle integer, real, or logical. It 5087 // does not currently support nested structures which is required for 5088 // complex. 5089 // 5090 // Also, we currently handle just rank-1 since tensor type assumes 5091 // row major array ordering. We will need to reorder the dimensions 5092 // in the tensor type to support Fortran's column major array ordering. 5093 // How to create this tensor type is to be determined. 5094 if (x.Rank() == 1 && 5095 eleTy.isa<fir::LogicalType, mlir::IntegerType, mlir::FloatType>()) 5096 global = Fortran::lower::createDenseGlobal( 5097 loc, arrTy, globalName, builder.createInternalLinkage(), true, 5098 toEvExpr(x), converter); 5099 // Note: If call to createDenseGlobal() returns 0, then call 5100 // createGlobalConstant() below. 5101 if (!global) 5102 global = builder.createGlobalConstant( 5103 loc, arrTy, globalName, 5104 [&](fir::FirOpBuilder &builder) { 5105 Fortran::lower::StatementContext stmtCtx( 5106 /*cleanupProhibited=*/true); 5107 fir::ExtendedValue result = 5108 Fortran::lower::createSomeInitializerExpression( 5109 loc, converter, toEvExpr(x), symMap, stmtCtx); 5110 mlir::Value castTo = 5111 builder.createConvert(loc, arrTy, fir::getBase(result)); 5112 builder.create<fir::HasValueOp>(loc, castTo); 5113 }, 5114 builder.createInternalLinkage()); 5115 } 5116 auto addr = builder.create<fir::AddrOfOp>(getLoc(), global.resultType(), 5117 global.getSymbol()); 5118 auto seqTy = global.getType().cast<fir::SequenceType>(); 5119 llvm::SmallVector<mlir::Value> extents; 5120 for (auto extent : seqTy.getShape()) 5121 extents.push_back(builder.createIntegerConstant(loc, idxTy, extent)); 5122 if (auto charTy = seqTy.getEleTy().dyn_cast<fir::CharacterType>()) { 5123 mlir::Value len = builder.createIntegerConstant(loc, builder.getI64Type(), 5124 charTy.getLen()); 5125 return genarr(fir::CharArrayBoxValue{addr, len, extents}); 5126 } 5127 return genarr(fir::ArrayBoxValue{addr, extents}); 5128 } 5129 5130 //===--------------------------------------------------------------------===// 5131 // A vector subscript expression may be wrapped with a cast to INTEGER*8. 5132 // Get rid of it here so the vector can be loaded. Add it back when 5133 // generating the elemental evaluation (inside the loop nest). 5134 5135 static Fortran::lower::SomeExpr 5136 ignoreEvConvert(const Fortran::evaluate::Expr<Fortran::evaluate::Type< 5137 Fortran::common::TypeCategory::Integer, 8>> &x) { 5138 return std::visit([&](const auto &v) { return ignoreEvConvert(v); }, x.u); 5139 } 5140 template <Fortran::common::TypeCategory FROM> 5141 static Fortran::lower::SomeExpr ignoreEvConvert( 5142 const Fortran::evaluate::Convert< 5143 Fortran::evaluate::Type<Fortran::common::TypeCategory::Integer, 8>, 5144 FROM> &x) { 5145 return toEvExpr(x.left()); 5146 } 5147 template <typename A> 5148 static Fortran::lower::SomeExpr ignoreEvConvert(const A &x) { 5149 return toEvExpr(x); 5150 } 5151 5152 //===--------------------------------------------------------------------===// 5153 // Get the `Se::Symbol*` for the subscript expression, `x`. This symbol can 5154 // be used to determine the lbound, ubound of the vector. 5155 5156 template <typename A> 5157 static const Fortran::semantics::Symbol * 5158 extractSubscriptSymbol(const Fortran::evaluate::Expr<A> &x) { 5159 return std::visit([&](const auto &v) { return extractSubscriptSymbol(v); }, 5160 x.u); 5161 } 5162 template <typename A> 5163 static const Fortran::semantics::Symbol * 5164 extractSubscriptSymbol(const Fortran::evaluate::Designator<A> &x) { 5165 return Fortran::evaluate::UnwrapWholeSymbolDataRef(x); 5166 } 5167 template <typename A> 5168 static const Fortran::semantics::Symbol *extractSubscriptSymbol(const A &x) { 5169 return nullptr; 5170 } 5171 5172 //===--------------------------------------------------------------------===// 5173 5174 /// Get the declared lower bound value of the array `x` in dimension `dim`. 5175 /// The argument `one` must be an ssa-value for the constant 1. 5176 mlir::Value getLBound(const ExtValue &x, unsigned dim, mlir::Value one) { 5177 return fir::factory::readLowerBound(builder, getLoc(), x, dim, one); 5178 } 5179 5180 /// Get the declared upper bound value of the array `x` in dimension `dim`. 5181 /// The argument `one` must be an ssa-value for the constant 1. 5182 mlir::Value getUBound(const ExtValue &x, unsigned dim, mlir::Value one) { 5183 mlir::Location loc = getLoc(); 5184 mlir::Value lb = getLBound(x, dim, one); 5185 mlir::Value extent = fir::factory::readExtent(builder, loc, x, dim); 5186 auto add = builder.create<mlir::arith::AddIOp>(loc, lb, extent); 5187 return builder.create<mlir::arith::SubIOp>(loc, add, one); 5188 } 5189 5190 /// Return the extent of the boxed array `x` in dimesion `dim`. 5191 mlir::Value getExtent(const ExtValue &x, unsigned dim) { 5192 return fir::factory::readExtent(builder, getLoc(), x, dim); 5193 } 5194 5195 template <typename A> 5196 ExtValue genArrayBase(const A &base) { 5197 ScalarExprLowering sel{getLoc(), converter, symMap, stmtCtx}; 5198 return base.IsSymbol() ? sel.gen(getFirstSym(base)) 5199 : sel.gen(base.GetComponent()); 5200 } 5201 5202 template <typename A> 5203 bool hasEvArrayRef(const A &x) { 5204 struct HasEvArrayRefHelper 5205 : public Fortran::evaluate::AnyTraverse<HasEvArrayRefHelper> { 5206 HasEvArrayRefHelper() 5207 : Fortran::evaluate::AnyTraverse<HasEvArrayRefHelper>(*this) {} 5208 using Fortran::evaluate::AnyTraverse<HasEvArrayRefHelper>::operator(); 5209 bool operator()(const Fortran::evaluate::ArrayRef &) const { 5210 return true; 5211 } 5212 } helper; 5213 return helper(x); 5214 } 5215 5216 CC genVectorSubscriptArrayFetch(const Fortran::lower::SomeExpr &expr, 5217 std::size_t dim) { 5218 PushSemantics(ConstituentSemantics::RefTransparent); 5219 auto saved = Fortran::common::ScopedSet(explicitSpace, nullptr); 5220 llvm::SmallVector<mlir::Value> savedDestShape = destShape; 5221 destShape.clear(); 5222 auto result = genarr(expr); 5223 if (destShape.empty()) 5224 TODO(getLoc(), "expected vector to have an extent"); 5225 assert(destShape.size() == 1 && "vector has rank > 1"); 5226 if (destShape[0] != savedDestShape[dim]) { 5227 // Not the same, so choose the smaller value. 5228 mlir::Location loc = getLoc(); 5229 auto cmp = builder.create<mlir::arith::CmpIOp>( 5230 loc, mlir::arith::CmpIPredicate::sgt, destShape[0], 5231 savedDestShape[dim]); 5232 auto sel = builder.create<mlir::arith::SelectOp>( 5233 loc, cmp, savedDestShape[dim], destShape[0]); 5234 savedDestShape[dim] = sel; 5235 destShape = savedDestShape; 5236 } 5237 return result; 5238 } 5239 5240 /// Generate an access by vector subscript using the index in the iteration 5241 /// vector at `dim`. 5242 mlir::Value genAccessByVector(mlir::Location loc, CC genArrFetch, 5243 IterSpace iters, std::size_t dim) { 5244 IterationSpace vecIters(iters, 5245 llvm::ArrayRef<mlir::Value>{iters.iterValue(dim)}); 5246 fir::ExtendedValue fetch = genArrFetch(vecIters); 5247 mlir::IndexType idxTy = builder.getIndexType(); 5248 return builder.createConvert(loc, idxTy, fir::getBase(fetch)); 5249 } 5250 5251 /// When we have an array reference, the expressions specified in each 5252 /// dimension may be slice operations (e.g. `i:j:k`), vectors, or simple 5253 /// (loop-invarianet) scalar expressions. This returns the base entity, the 5254 /// resulting type, and a continuation to adjust the default iteration space. 5255 void genSliceIndices(ComponentPath &cmptData, const ExtValue &arrayExv, 5256 const Fortran::evaluate::ArrayRef &x, bool atBase) { 5257 mlir::Location loc = getLoc(); 5258 mlir::IndexType idxTy = builder.getIndexType(); 5259 mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); 5260 llvm::SmallVector<mlir::Value> &trips = cmptData.trips; 5261 LLVM_DEBUG(llvm::dbgs() << "array: " << arrayExv << '\n'); 5262 auto &pc = cmptData.pc; 5263 const bool useTripsForSlice = !explicitSpaceIsActive(); 5264 const bool createDestShape = destShape.empty(); 5265 bool useSlice = false; 5266 std::size_t shapeIndex = 0; 5267 for (auto sub : llvm::enumerate(x.subscript())) { 5268 const std::size_t subsIndex = sub.index(); 5269 std::visit( 5270 Fortran::common::visitors{ 5271 [&](const Fortran::evaluate::Triplet &t) { 5272 mlir::Value lowerBound; 5273 if (auto optLo = t.lower()) 5274 lowerBound = fir::getBase(asScalar(*optLo)); 5275 else 5276 lowerBound = getLBound(arrayExv, subsIndex, one); 5277 lowerBound = builder.createConvert(loc, idxTy, lowerBound); 5278 mlir::Value stride = fir::getBase(asScalar(t.stride())); 5279 stride = builder.createConvert(loc, idxTy, stride); 5280 if (useTripsForSlice || createDestShape) { 5281 // Generate a slice operation for the triplet. The first and 5282 // second position of the triplet may be omitted, and the 5283 // declared lbound and/or ubound expression values, 5284 // respectively, should be used instead. 5285 trips.push_back(lowerBound); 5286 mlir::Value upperBound; 5287 if (auto optUp = t.upper()) 5288 upperBound = fir::getBase(asScalar(*optUp)); 5289 else 5290 upperBound = getUBound(arrayExv, subsIndex, one); 5291 upperBound = builder.createConvert(loc, idxTy, upperBound); 5292 trips.push_back(upperBound); 5293 trips.push_back(stride); 5294 if (createDestShape) { 5295 auto extent = builder.genExtentFromTriplet( 5296 loc, lowerBound, upperBound, stride, idxTy); 5297 destShape.push_back(extent); 5298 } 5299 useSlice = true; 5300 } 5301 if (!useTripsForSlice) { 5302 auto currentPC = pc; 5303 pc = [=](IterSpace iters) { 5304 IterationSpace newIters = currentPC(iters); 5305 mlir::Value impliedIter = newIters.iterValue(subsIndex); 5306 // FIXME: must use the lower bound of this component. 5307 auto arrLowerBound = 5308 atBase ? getLBound(arrayExv, subsIndex, one) : one; 5309 auto initial = builder.create<mlir::arith::SubIOp>( 5310 loc, lowerBound, arrLowerBound); 5311 auto prod = builder.create<mlir::arith::MulIOp>( 5312 loc, impliedIter, stride); 5313 auto result = 5314 builder.create<mlir::arith::AddIOp>(loc, initial, prod); 5315 newIters.setIndexValue(subsIndex, result); 5316 return newIters; 5317 }; 5318 } 5319 shapeIndex++; 5320 }, 5321 [&](const Fortran::evaluate::IndirectSubscriptIntegerExpr &ie) { 5322 const auto &e = ie.value(); // dereference 5323 if (isArray(e)) { 5324 // This is a vector subscript. Use the index values as read 5325 // from a vector to determine the temporary array value. 5326 // Note: 9.5.3.3.3(3) specifies undefined behavior for 5327 // multiple updates to any specific array element through a 5328 // vector subscript with replicated values. 5329 assert(!isBoxValue() && 5330 "fir.box cannot be created with vector subscripts"); 5331 auto arrExpr = ignoreEvConvert(e); 5332 if (createDestShape) { 5333 destShape.push_back(fir::getExtentAtDimension( 5334 arrayExv, builder, loc, subsIndex)); 5335 } 5336 auto genArrFetch = 5337 genVectorSubscriptArrayFetch(arrExpr, shapeIndex); 5338 auto currentPC = pc; 5339 pc = [=](IterSpace iters) { 5340 IterationSpace newIters = currentPC(iters); 5341 auto val = genAccessByVector(loc, genArrFetch, newIters, 5342 subsIndex); 5343 // Value read from vector subscript array and normalized 5344 // using the base array's lower bound value. 5345 mlir::Value lb = fir::factory::readLowerBound( 5346 builder, loc, arrayExv, subsIndex, one); 5347 auto origin = builder.create<mlir::arith::SubIOp>( 5348 loc, idxTy, val, lb); 5349 newIters.setIndexValue(subsIndex, origin); 5350 return newIters; 5351 }; 5352 if (useTripsForSlice) { 5353 LLVM_ATTRIBUTE_UNUSED auto vectorSubscriptShape = 5354 getShape(arrayOperands.back()); 5355 auto undef = builder.create<fir::UndefOp>(loc, idxTy); 5356 trips.push_back(undef); 5357 trips.push_back(undef); 5358 trips.push_back(undef); 5359 } 5360 shapeIndex++; 5361 } else { 5362 // This is a regular scalar subscript. 5363 if (useTripsForSlice) { 5364 // A regular scalar index, which does not yield an array 5365 // section. Use a degenerate slice operation 5366 // `(e:undef:undef)` in this dimension as a placeholder. 5367 // This does not necessarily change the rank of the original 5368 // array, so the iteration space must also be extended to 5369 // include this expression in this dimension to adjust to 5370 // the array's declared rank. 5371 mlir::Value v = fir::getBase(asScalar(e)); 5372 trips.push_back(v); 5373 auto undef = builder.create<fir::UndefOp>(loc, idxTy); 5374 trips.push_back(undef); 5375 trips.push_back(undef); 5376 auto currentPC = pc; 5377 // Cast `e` to index type. 5378 mlir::Value iv = builder.createConvert(loc, idxTy, v); 5379 // Normalize `e` by subtracting the declared lbound. 5380 mlir::Value lb = fir::factory::readLowerBound( 5381 builder, loc, arrayExv, subsIndex, one); 5382 mlir::Value ivAdj = 5383 builder.create<mlir::arith::SubIOp>(loc, idxTy, iv, lb); 5384 // Add lbound adjusted value of `e` to the iteration vector 5385 // (except when creating a box because the iteration vector 5386 // is empty). 5387 if (!isBoxValue()) 5388 pc = [=](IterSpace iters) { 5389 IterationSpace newIters = currentPC(iters); 5390 newIters.insertIndexValue(subsIndex, ivAdj); 5391 return newIters; 5392 }; 5393 } else { 5394 auto currentPC = pc; 5395 mlir::Value newValue = fir::getBase(asScalarArray(e)); 5396 mlir::Value result = 5397 builder.createConvert(loc, idxTy, newValue); 5398 mlir::Value lb = fir::factory::readLowerBound( 5399 builder, loc, arrayExv, subsIndex, one); 5400 result = builder.create<mlir::arith::SubIOp>(loc, idxTy, 5401 result, lb); 5402 pc = [=](IterSpace iters) { 5403 IterationSpace newIters = currentPC(iters); 5404 newIters.insertIndexValue(subsIndex, result); 5405 return newIters; 5406 }; 5407 } 5408 } 5409 }}, 5410 sub.value().u); 5411 } 5412 if (!useSlice) 5413 trips.clear(); 5414 } 5415 5416 static mlir::Type unwrapBoxEleTy(mlir::Type ty) { 5417 if (auto boxTy = ty.dyn_cast<fir::BoxType>()) 5418 return fir::unwrapRefType(boxTy.getEleTy()); 5419 return ty; 5420 } 5421 5422 llvm::SmallVector<mlir::Value> getShape(mlir::Type ty) { 5423 llvm::SmallVector<mlir::Value> result; 5424 ty = unwrapBoxEleTy(ty); 5425 mlir::Location loc = getLoc(); 5426 mlir::IndexType idxTy = builder.getIndexType(); 5427 for (auto extent : ty.cast<fir::SequenceType>().getShape()) { 5428 auto v = extent == fir::SequenceType::getUnknownExtent() 5429 ? builder.create<fir::UndefOp>(loc, idxTy).getResult() 5430 : builder.createIntegerConstant(loc, idxTy, extent); 5431 result.push_back(v); 5432 } 5433 return result; 5434 } 5435 5436 CC genarr(const Fortran::semantics::SymbolRef &sym, 5437 ComponentPath &components) { 5438 return genarr(sym.get(), components); 5439 } 5440 5441 ExtValue abstractArrayExtValue(mlir::Value val, mlir::Value len = {}) { 5442 return convertToArrayBoxValue(getLoc(), builder, val, len); 5443 } 5444 5445 CC genarr(const ExtValue &extMemref) { 5446 ComponentPath dummy(/*isImplicit=*/true); 5447 return genarr(extMemref, dummy); 5448 } 5449 5450 /// Base case of generating an array reference, 5451 CC genarr(const ExtValue &extMemref, ComponentPath &components) { 5452 mlir::Location loc = getLoc(); 5453 mlir::Value memref = fir::getBase(extMemref); 5454 mlir::Type arrTy = fir::dyn_cast_ptrOrBoxEleTy(memref.getType()); 5455 assert(arrTy.isa<fir::SequenceType>() && "memory ref must be an array"); 5456 mlir::Value shape = builder.createShape(loc, extMemref); 5457 mlir::Value slice; 5458 if (components.isSlice()) { 5459 if (isBoxValue() && components.substring) { 5460 // Append the substring operator to emboxing Op as it will become an 5461 // interior adjustment (add offset, adjust LEN) to the CHARACTER value 5462 // being referenced in the descriptor. 5463 llvm::SmallVector<mlir::Value> substringBounds; 5464 populateBounds(substringBounds, components.substring); 5465 // Convert to (offset, size) 5466 mlir::Type iTy = substringBounds[0].getType(); 5467 if (substringBounds.size() != 2) { 5468 fir::CharacterType charTy = 5469 fir::factory::CharacterExprHelper::getCharType(arrTy); 5470 if (charTy.hasConstantLen()) { 5471 mlir::IndexType idxTy = builder.getIndexType(); 5472 fir::CharacterType::LenType charLen = charTy.getLen(); 5473 mlir::Value lenValue = 5474 builder.createIntegerConstant(loc, idxTy, charLen); 5475 substringBounds.push_back(lenValue); 5476 } else { 5477 llvm::SmallVector<mlir::Value> typeparams = 5478 fir::getTypeParams(extMemref); 5479 substringBounds.push_back(typeparams.back()); 5480 } 5481 } 5482 // Convert the lower bound to 0-based substring. 5483 mlir::Value one = 5484 builder.createIntegerConstant(loc, substringBounds[0].getType(), 1); 5485 substringBounds[0] = 5486 builder.create<mlir::arith::SubIOp>(loc, substringBounds[0], one); 5487 // Convert the upper bound to a length. 5488 mlir::Value cast = builder.createConvert(loc, iTy, substringBounds[1]); 5489 mlir::Value zero = builder.createIntegerConstant(loc, iTy, 0); 5490 auto size = 5491 builder.create<mlir::arith::SubIOp>(loc, cast, substringBounds[0]); 5492 auto cmp = builder.create<mlir::arith::CmpIOp>( 5493 loc, mlir::arith::CmpIPredicate::sgt, size, zero); 5494 // size = MAX(upper - (lower - 1), 0) 5495 substringBounds[1] = 5496 builder.create<mlir::arith::SelectOp>(loc, cmp, size, zero); 5497 slice = builder.create<fir::SliceOp>(loc, components.trips, 5498 components.suffixComponents, 5499 substringBounds); 5500 } else { 5501 slice = builder.createSlice(loc, extMemref, components.trips, 5502 components.suffixComponents); 5503 } 5504 if (components.hasComponents()) { 5505 auto seqTy = arrTy.cast<fir::SequenceType>(); 5506 mlir::Type eleTy = 5507 fir::applyPathToType(seqTy.getEleTy(), components.suffixComponents); 5508 if (!eleTy) 5509 fir::emitFatalError(loc, "slicing path is ill-formed"); 5510 if (auto realTy = eleTy.dyn_cast<fir::RealType>()) 5511 eleTy = Fortran::lower::convertReal(realTy.getContext(), 5512 realTy.getFKind()); 5513 5514 // create the type of the projected array. 5515 arrTy = fir::SequenceType::get(seqTy.getShape(), eleTy); 5516 LLVM_DEBUG(llvm::dbgs() 5517 << "type of array projection from component slicing: " 5518 << eleTy << ", " << arrTy << '\n'); 5519 } 5520 } 5521 arrayOperands.push_back(ArrayOperand{memref, shape, slice}); 5522 if (destShape.empty()) 5523 destShape = getShape(arrayOperands.back()); 5524 if (isBoxValue()) { 5525 // Semantics are a reference to a boxed array. 5526 // This case just requires that an embox operation be created to box the 5527 // value. The value of the box is forwarded in the continuation. 5528 mlir::Type reduceTy = reduceRank(arrTy, slice); 5529 auto boxTy = fir::BoxType::get(reduceTy); 5530 if (components.substring) { 5531 // Adjust char length to substring size. 5532 fir::CharacterType charTy = 5533 fir::factory::CharacterExprHelper::getCharType(reduceTy); 5534 auto seqTy = reduceTy.cast<fir::SequenceType>(); 5535 // TODO: Use a constant for fir.char LEN if we can compute it. 5536 boxTy = fir::BoxType::get( 5537 fir::SequenceType::get(fir::CharacterType::getUnknownLen( 5538 builder.getContext(), charTy.getFKind()), 5539 seqTy.getDimension())); 5540 } 5541 mlir::Value embox = 5542 memref.getType().isa<fir::BoxType>() 5543 ? builder.create<fir::ReboxOp>(loc, boxTy, memref, shape, slice) 5544 .getResult() 5545 : builder 5546 .create<fir::EmboxOp>(loc, boxTy, memref, shape, slice, 5547 fir::getTypeParams(extMemref)) 5548 .getResult(); 5549 return [=](IterSpace) -> ExtValue { return fir::BoxValue(embox); }; 5550 } 5551 auto eleTy = arrTy.cast<fir::SequenceType>().getEleTy(); 5552 if (isReferentiallyOpaque()) { 5553 // Semantics are an opaque reference to an array. 5554 // This case forwards a continuation that will generate the address 5555 // arithmetic to the array element. This does not have copy-in/copy-out 5556 // semantics. No attempt to copy the array value will be made during the 5557 // interpretation of the Fortran statement. 5558 mlir::Type refEleTy = builder.getRefType(eleTy); 5559 return [=](IterSpace iters) -> ExtValue { 5560 // ArrayCoorOp does not expect zero based indices. 5561 llvm::SmallVector<mlir::Value> indices = fir::factory::originateIndices( 5562 loc, builder, memref.getType(), shape, iters.iterVec()); 5563 mlir::Value coor = builder.create<fir::ArrayCoorOp>( 5564 loc, refEleTy, memref, shape, slice, indices, 5565 fir::getTypeParams(extMemref)); 5566 if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) { 5567 llvm::SmallVector<mlir::Value> substringBounds; 5568 populateBounds(substringBounds, components.substring); 5569 if (!substringBounds.empty()) { 5570 mlir::Value dstLen = fir::factory::genLenOfCharacter( 5571 builder, loc, arrTy.cast<fir::SequenceType>(), memref, 5572 fir::getTypeParams(extMemref), iters.iterVec(), 5573 substringBounds); 5574 fir::CharBoxValue dstChar(coor, dstLen); 5575 return fir::factory::CharacterExprHelper{builder, loc} 5576 .createSubstring(dstChar, substringBounds); 5577 } 5578 } 5579 return fir::factory::arraySectionElementToExtendedValue( 5580 builder, loc, extMemref, coor, slice); 5581 }; 5582 } 5583 auto arrLoad = builder.create<fir::ArrayLoadOp>( 5584 loc, arrTy, memref, shape, slice, fir::getTypeParams(extMemref)); 5585 mlir::Value arrLd = arrLoad.getResult(); 5586 if (isProjectedCopyInCopyOut()) { 5587 // Semantics are projected copy-in copy-out. 5588 // The backing store of the destination of an array expression may be 5589 // partially modified. These updates are recorded in FIR by forwarding a 5590 // continuation that generates an `array_update` Op. The destination is 5591 // always loaded at the beginning of the statement and merged at the 5592 // end. 5593 destination = arrLoad; 5594 auto lambda = ccStoreToDest.hasValue() 5595 ? ccStoreToDest.getValue() 5596 : defaultStoreToDestination(components.substring); 5597 return [=](IterSpace iters) -> ExtValue { return lambda(iters); }; 5598 } 5599 if (isCustomCopyInCopyOut()) { 5600 // Create an array_modify to get the LHS element address and indicate 5601 // the assignment, the actual assignment must be implemented in 5602 // ccStoreToDest. 5603 destination = arrLoad; 5604 return [=](IterSpace iters) -> ExtValue { 5605 mlir::Value innerArg = iters.innerArgument(); 5606 mlir::Type resTy = innerArg.getType(); 5607 mlir::Type eleTy = fir::applyPathToType(resTy, iters.iterVec()); 5608 mlir::Type refEleTy = 5609 fir::isa_ref_type(eleTy) ? eleTy : builder.getRefType(eleTy); 5610 auto arrModify = builder.create<fir::ArrayModifyOp>( 5611 loc, mlir::TypeRange{refEleTy, resTy}, innerArg, iters.iterVec(), 5612 destination.getTypeparams()); 5613 return abstractArrayExtValue(arrModify.getResult(1)); 5614 }; 5615 } 5616 if (isCopyInCopyOut()) { 5617 // Semantics are copy-in copy-out. 5618 // The continuation simply forwards the result of the `array_load` Op, 5619 // which is the value of the array as it was when loaded. All data 5620 // references with rank > 0 in an array expression typically have 5621 // copy-in copy-out semantics. 5622 return [=](IterSpace) -> ExtValue { return arrLd; }; 5623 } 5624 mlir::Operation::operand_range arrLdTypeParams = arrLoad.getTypeparams(); 5625 if (isValueAttribute()) { 5626 // Semantics are value attribute. 5627 // Here the continuation will `array_fetch` a value from an array and 5628 // then store that value in a temporary. One can thus imitate pass by 5629 // value even when the call is pass by reference. 5630 return [=](IterSpace iters) -> ExtValue { 5631 mlir::Value base; 5632 mlir::Type eleTy = fir::applyPathToType(arrTy, iters.iterVec()); 5633 if (isAdjustedArrayElementType(eleTy)) { 5634 mlir::Type eleRefTy = builder.getRefType(eleTy); 5635 base = builder.create<fir::ArrayAccessOp>( 5636 loc, eleRefTy, arrLd, iters.iterVec(), arrLdTypeParams); 5637 } else { 5638 base = builder.create<fir::ArrayFetchOp>( 5639 loc, eleTy, arrLd, iters.iterVec(), arrLdTypeParams); 5640 } 5641 mlir::Value temp = builder.createTemporary( 5642 loc, base.getType(), 5643 llvm::ArrayRef<mlir::NamedAttribute>{ 5644 Fortran::lower::getAdaptToByRefAttr(builder)}); 5645 builder.create<fir::StoreOp>(loc, base, temp); 5646 return fir::factory::arraySectionElementToExtendedValue( 5647 builder, loc, extMemref, temp, slice); 5648 }; 5649 } 5650 // In the default case, the array reference forwards an `array_fetch` or 5651 // `array_access` Op in the continuation. 5652 return [=](IterSpace iters) -> ExtValue { 5653 mlir::Type eleTy = fir::applyPathToType(arrTy, iters.iterVec()); 5654 if (isAdjustedArrayElementType(eleTy)) { 5655 mlir::Type eleRefTy = builder.getRefType(eleTy); 5656 mlir::Value arrayOp = builder.create<fir::ArrayAccessOp>( 5657 loc, eleRefTy, arrLd, iters.iterVec(), arrLdTypeParams); 5658 if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) { 5659 llvm::SmallVector<mlir::Value> substringBounds; 5660 populateBounds(substringBounds, components.substring); 5661 if (!substringBounds.empty()) { 5662 mlir::Value dstLen = fir::factory::genLenOfCharacter( 5663 builder, loc, arrLoad, iters.iterVec(), substringBounds); 5664 fir::CharBoxValue dstChar(arrayOp, dstLen); 5665 return fir::factory::CharacterExprHelper{builder, loc} 5666 .createSubstring(dstChar, substringBounds); 5667 } 5668 } 5669 return fir::factory::arraySectionElementToExtendedValue( 5670 builder, loc, extMemref, arrayOp, slice); 5671 } 5672 auto arrFetch = builder.create<fir::ArrayFetchOp>( 5673 loc, eleTy, arrLd, iters.iterVec(), arrLdTypeParams); 5674 return fir::factory::arraySectionElementToExtendedValue( 5675 builder, loc, extMemref, arrFetch, slice); 5676 }; 5677 } 5678 5679 /// Given an optional fir.box, returns an fir.box that is the original one if 5680 /// it is present and it otherwise an unallocated box. 5681 /// Absent fir.box are implemented as a null pointer descriptor. Generated 5682 /// code may need to unconditionally read a fir.box that can be absent. 5683 /// This helper allows creating a fir.box that can be read in all cases 5684 /// outside of a fir.if (isPresent) region. However, the usages of the value 5685 /// read from such box should still only be done in a fir.if(isPresent). 5686 static fir::ExtendedValue 5687 absentBoxToUnalllocatedBox(fir::FirOpBuilder &builder, mlir::Location loc, 5688 const fir::ExtendedValue &exv, 5689 mlir::Value isPresent) { 5690 mlir::Value box = fir::getBase(exv); 5691 mlir::Type boxType = box.getType(); 5692 assert(boxType.isa<fir::BoxType>() && "argument must be a fir.box"); 5693 mlir::Value emptyBox = 5694 fir::factory::createUnallocatedBox(builder, loc, boxType, llvm::None); 5695 auto safeToReadBox = 5696 builder.create<mlir::arith::SelectOp>(loc, isPresent, box, emptyBox); 5697 return fir::substBase(exv, safeToReadBox); 5698 } 5699 5700 std::tuple<CC, mlir::Value, mlir::Type> 5701 genOptionalArrayFetch(const Fortran::lower::SomeExpr &expr) { 5702 assert(expr.Rank() > 0 && "expr must be an array"); 5703 mlir::Location loc = getLoc(); 5704 ExtValue optionalArg = asInquired(expr); 5705 mlir::Value isPresent = genActualIsPresentTest(builder, loc, optionalArg); 5706 // Generate an array load and access to an array that may be an absent 5707 // optional or an unallocated optional. 5708 mlir::Value base = getBase(optionalArg); 5709 const bool hasOptionalAttr = 5710 fir::valueHasFirAttribute(base, fir::getOptionalAttrName()); 5711 mlir::Type baseType = fir::unwrapRefType(base.getType()); 5712 const bool isBox = baseType.isa<fir::BoxType>(); 5713 const bool isAllocOrPtr = Fortran::evaluate::IsAllocatableOrPointerObject( 5714 expr, converter.getFoldingContext()); 5715 mlir::Type arrType = fir::unwrapPassByRefType(baseType); 5716 mlir::Type eleType = fir::unwrapSequenceType(arrType); 5717 ExtValue exv = optionalArg; 5718 if (hasOptionalAttr && isBox && !isAllocOrPtr) { 5719 // Elemental argument cannot be allocatable or pointers (C15100). 5720 // Hence, per 15.5.2.12 3 (8) and (9), the provided Allocatable and 5721 // Pointer optional arrays cannot be absent. The only kind of entities 5722 // that can get here are optional assumed shape and polymorphic entities. 5723 exv = absentBoxToUnalllocatedBox(builder, loc, exv, isPresent); 5724 } 5725 // All the properties can be read from any fir.box but the read values may 5726 // be undefined and should only be used inside a fir.if (canBeRead) region. 5727 if (const auto *mutableBox = exv.getBoxOf<fir::MutableBoxValue>()) 5728 exv = fir::factory::genMutableBoxRead(builder, loc, *mutableBox); 5729 5730 mlir::Value memref = fir::getBase(exv); 5731 mlir::Value shape = builder.createShape(loc, exv); 5732 mlir::Value noSlice; 5733 auto arrLoad = builder.create<fir::ArrayLoadOp>( 5734 loc, arrType, memref, shape, noSlice, fir::getTypeParams(exv)); 5735 mlir::Operation::operand_range arrLdTypeParams = arrLoad.getTypeparams(); 5736 mlir::Value arrLd = arrLoad.getResult(); 5737 // Mark the load to tell later passes it is unsafe to use this array_load 5738 // shape unconditionally. 5739 arrLoad->setAttr(fir::getOptionalAttrName(), builder.getUnitAttr()); 5740 5741 // Place the array as optional on the arrayOperands stack so that its 5742 // shape will only be used as a fallback to induce the implicit loop nest 5743 // (that is if there is no non optional array arguments). 5744 arrayOperands.push_back( 5745 ArrayOperand{memref, shape, noSlice, /*mayBeAbsent=*/true}); 5746 5747 // By value semantics. 5748 auto cc = [=](IterSpace iters) -> ExtValue { 5749 auto arrFetch = builder.create<fir::ArrayFetchOp>( 5750 loc, eleType, arrLd, iters.iterVec(), arrLdTypeParams); 5751 return fir::factory::arraySectionElementToExtendedValue( 5752 builder, loc, exv, arrFetch, noSlice); 5753 }; 5754 return {cc, isPresent, eleType}; 5755 } 5756 5757 /// Generate a continuation to pass \p expr to an OPTIONAL argument of an 5758 /// elemental procedure. This is meant to handle the cases where \p expr might 5759 /// be dynamically absent (i.e. when it is a POINTER, an ALLOCATABLE or an 5760 /// OPTIONAL variable). If p\ expr is guaranteed to be present genarr() can 5761 /// directly be called instead. 5762 CC genarrForwardOptionalArgumentToCall(const Fortran::lower::SomeExpr &expr) { 5763 mlir::Location loc = getLoc(); 5764 // Only by-value numerical and logical so far. 5765 if (semant != ConstituentSemantics::RefTransparent) 5766 TODO(loc, "optional arguments in user defined elemental procedures"); 5767 5768 // Handle scalar argument case (the if-then-else is generated outside of the 5769 // implicit loop nest). 5770 if (expr.Rank() == 0) { 5771 ExtValue optionalArg = asInquired(expr); 5772 mlir::Value isPresent = genActualIsPresentTest(builder, loc, optionalArg); 5773 mlir::Value elementValue = 5774 fir::getBase(genOptionalValue(builder, loc, optionalArg, isPresent)); 5775 return [=](IterSpace iters) -> ExtValue { return elementValue; }; 5776 } 5777 5778 CC cc; 5779 mlir::Value isPresent; 5780 mlir::Type eleType; 5781 std::tie(cc, isPresent, eleType) = genOptionalArrayFetch(expr); 5782 return [=](IterSpace iters) -> ExtValue { 5783 mlir::Value elementValue = 5784 builder 5785 .genIfOp(loc, {eleType}, isPresent, 5786 /*withElseRegion=*/true) 5787 .genThen([&]() { 5788 builder.create<fir::ResultOp>(loc, fir::getBase(cc(iters))); 5789 }) 5790 .genElse([&]() { 5791 mlir::Value zero = 5792 fir::factory::createZeroValue(builder, loc, eleType); 5793 builder.create<fir::ResultOp>(loc, zero); 5794 }) 5795 .getResults()[0]; 5796 return elementValue; 5797 }; 5798 } 5799 5800 /// Reduce the rank of a array to be boxed based on the slice's operands. 5801 static mlir::Type reduceRank(mlir::Type arrTy, mlir::Value slice) { 5802 if (slice) { 5803 auto slOp = mlir::dyn_cast<fir::SliceOp>(slice.getDefiningOp()); 5804 assert(slOp && "expected slice op"); 5805 auto seqTy = arrTy.dyn_cast<fir::SequenceType>(); 5806 assert(seqTy && "expected array type"); 5807 mlir::Operation::operand_range triples = slOp.getTriples(); 5808 fir::SequenceType::Shape shape; 5809 // reduce the rank for each invariant dimension 5810 for (unsigned i = 1, end = triples.size(); i < end; i += 3) 5811 if (!mlir::isa_and_nonnull<fir::UndefOp>(triples[i].getDefiningOp())) 5812 shape.push_back(fir::SequenceType::getUnknownExtent()); 5813 return fir::SequenceType::get(shape, seqTy.getEleTy()); 5814 } 5815 // not sliced, so no change in rank 5816 return arrTy; 5817 } 5818 5819 /// Example: <code>array%RE</code> 5820 CC genarr(const Fortran::evaluate::ComplexPart &x, 5821 ComponentPath &components) { 5822 components.reversePath.push_back(&x); 5823 return genarr(x.complex(), components); 5824 } 5825 5826 template <typename A> 5827 CC genSlicePath(const A &x, ComponentPath &components) { 5828 return genarr(x, components); 5829 } 5830 5831 CC genarr(const Fortran::evaluate::StaticDataObject::Pointer &, 5832 ComponentPath &components) { 5833 fir::emitFatalError(getLoc(), "substring of static array object"); 5834 } 5835 5836 /// Substrings (see 9.4.1) 5837 CC genarr(const Fortran::evaluate::Substring &x, ComponentPath &components) { 5838 components.substring = &x; 5839 return std::visit([&](const auto &v) { return genarr(v, components); }, 5840 x.parent()); 5841 } 5842 5843 template <typename T> 5844 CC genarr(const Fortran::evaluate::FunctionRef<T> &funRef) { 5845 // Note that it's possible that the function being called returns either an 5846 // array or a scalar. In the first case, use the element type of the array. 5847 return genProcRef( 5848 funRef, fir::unwrapSequenceType(converter.genType(toEvExpr(funRef)))); 5849 } 5850 5851 //===--------------------------------------------------------------------===// 5852 // Array construction 5853 //===--------------------------------------------------------------------===// 5854 5855 /// Target agnostic computation of the size of an element in the array. 5856 /// Returns the size in bytes with type `index` or a null Value if the element 5857 /// size is not constant. 5858 mlir::Value computeElementSize(const ExtValue &exv, mlir::Type eleTy, 5859 mlir::Type resTy) { 5860 mlir::Location loc = getLoc(); 5861 mlir::IndexType idxTy = builder.getIndexType(); 5862 mlir::Value multiplier = builder.createIntegerConstant(loc, idxTy, 1); 5863 if (fir::hasDynamicSize(eleTy)) { 5864 if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) { 5865 // Array of char with dynamic length parameter. Downcast to an array 5866 // of singleton char, and scale by the len type parameter from 5867 // `exv`. 5868 exv.match( 5869 [&](const fir::CharBoxValue &cb) { multiplier = cb.getLen(); }, 5870 [&](const fir::CharArrayBoxValue &cb) { multiplier = cb.getLen(); }, 5871 [&](const fir::BoxValue &box) { 5872 multiplier = fir::factory::CharacterExprHelper(builder, loc) 5873 .readLengthFromBox(box.getAddr()); 5874 }, 5875 [&](const fir::MutableBoxValue &box) { 5876 multiplier = fir::factory::CharacterExprHelper(builder, loc) 5877 .readLengthFromBox(box.getAddr()); 5878 }, 5879 [&](const auto &) { 5880 fir::emitFatalError(loc, 5881 "array constructor element has unknown size"); 5882 }); 5883 fir::CharacterType newEleTy = fir::CharacterType::getSingleton( 5884 eleTy.getContext(), charTy.getFKind()); 5885 if (auto seqTy = resTy.dyn_cast<fir::SequenceType>()) { 5886 assert(eleTy == seqTy.getEleTy()); 5887 resTy = fir::SequenceType::get(seqTy.getShape(), newEleTy); 5888 } 5889 eleTy = newEleTy; 5890 } else { 5891 TODO(loc, "dynamic sized type"); 5892 } 5893 } 5894 mlir::Type eleRefTy = builder.getRefType(eleTy); 5895 mlir::Type resRefTy = builder.getRefType(resTy); 5896 mlir::Value nullPtr = builder.createNullConstant(loc, resRefTy); 5897 auto offset = builder.create<fir::CoordinateOp>( 5898 loc, eleRefTy, nullPtr, mlir::ValueRange{multiplier}); 5899 return builder.createConvert(loc, idxTy, offset); 5900 } 5901 5902 /// Get the function signature of the LLVM memcpy intrinsic. 5903 mlir::FunctionType memcpyType() { 5904 return fir::factory::getLlvmMemcpy(builder).getFunctionType(); 5905 } 5906 5907 /// Create a call to the LLVM memcpy intrinsic. 5908 void createCallMemcpy(llvm::ArrayRef<mlir::Value> args) { 5909 mlir::Location loc = getLoc(); 5910 mlir::func::FuncOp memcpyFunc = fir::factory::getLlvmMemcpy(builder); 5911 mlir::SymbolRefAttr funcSymAttr = 5912 builder.getSymbolRefAttr(memcpyFunc.getName()); 5913 mlir::FunctionType funcTy = memcpyFunc.getFunctionType(); 5914 builder.create<fir::CallOp>(loc, funcTy.getResults(), funcSymAttr, args); 5915 } 5916 5917 // Construct code to check for a buffer overrun and realloc the buffer when 5918 // space is depleted. This is done between each item in the ac-value-list. 5919 mlir::Value growBuffer(mlir::Value mem, mlir::Value needed, 5920 mlir::Value bufferSize, mlir::Value buffSize, 5921 mlir::Value eleSz) { 5922 mlir::Location loc = getLoc(); 5923 mlir::func::FuncOp reallocFunc = fir::factory::getRealloc(builder); 5924 auto cond = builder.create<mlir::arith::CmpIOp>( 5925 loc, mlir::arith::CmpIPredicate::sle, bufferSize, needed); 5926 auto ifOp = builder.create<fir::IfOp>(loc, mem.getType(), cond, 5927 /*withElseRegion=*/true); 5928 auto insPt = builder.saveInsertionPoint(); 5929 builder.setInsertionPointToStart(&ifOp.getThenRegion().front()); 5930 // Not enough space, resize the buffer. 5931 mlir::IndexType idxTy = builder.getIndexType(); 5932 mlir::Value two = builder.createIntegerConstant(loc, idxTy, 2); 5933 auto newSz = builder.create<mlir::arith::MulIOp>(loc, needed, two); 5934 builder.create<fir::StoreOp>(loc, newSz, buffSize); 5935 mlir::Value byteSz = builder.create<mlir::arith::MulIOp>(loc, newSz, eleSz); 5936 mlir::SymbolRefAttr funcSymAttr = 5937 builder.getSymbolRefAttr(reallocFunc.getName()); 5938 mlir::FunctionType funcTy = reallocFunc.getFunctionType(); 5939 auto newMem = builder.create<fir::CallOp>( 5940 loc, funcTy.getResults(), funcSymAttr, 5941 llvm::ArrayRef<mlir::Value>{ 5942 builder.createConvert(loc, funcTy.getInputs()[0], mem), 5943 builder.createConvert(loc, funcTy.getInputs()[1], byteSz)}); 5944 mlir::Value castNewMem = 5945 builder.createConvert(loc, mem.getType(), newMem.getResult(0)); 5946 builder.create<fir::ResultOp>(loc, castNewMem); 5947 builder.setInsertionPointToStart(&ifOp.getElseRegion().front()); 5948 // Otherwise, just forward the buffer. 5949 builder.create<fir::ResultOp>(loc, mem); 5950 builder.restoreInsertionPoint(insPt); 5951 return ifOp.getResult(0); 5952 } 5953 5954 /// Copy the next value (or vector of values) into the array being 5955 /// constructed. 5956 mlir::Value copyNextArrayCtorSection(const ExtValue &exv, mlir::Value buffPos, 5957 mlir::Value buffSize, mlir::Value mem, 5958 mlir::Value eleSz, mlir::Type eleTy, 5959 mlir::Type eleRefTy, mlir::Type resTy) { 5960 mlir::Location loc = getLoc(); 5961 auto off = builder.create<fir::LoadOp>(loc, buffPos); 5962 auto limit = builder.create<fir::LoadOp>(loc, buffSize); 5963 mlir::IndexType idxTy = builder.getIndexType(); 5964 mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); 5965 5966 if (fir::isRecordWithAllocatableMember(eleTy)) 5967 TODO(loc, "deep copy on allocatable members"); 5968 5969 if (!eleSz) { 5970 // Compute the element size at runtime. 5971 assert(fir::hasDynamicSize(eleTy)); 5972 if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) { 5973 auto charBytes = 5974 builder.getKindMap().getCharacterBitsize(charTy.getFKind()) / 8; 5975 mlir::Value bytes = 5976 builder.createIntegerConstant(loc, idxTy, charBytes); 5977 mlir::Value length = fir::getLen(exv); 5978 if (!length) 5979 fir::emitFatalError(loc, "result is not boxed character"); 5980 eleSz = builder.create<mlir::arith::MulIOp>(loc, bytes, length); 5981 } else { 5982 TODO(loc, "PDT size"); 5983 // Will call the PDT's size function with the type parameters. 5984 } 5985 } 5986 5987 // Compute the coordinate using `fir.coordinate_of`, or, if the type has 5988 // dynamic size, generating the pointer arithmetic. 5989 auto computeCoordinate = [&](mlir::Value buff, mlir::Value off) { 5990 mlir::Type refTy = eleRefTy; 5991 if (fir::hasDynamicSize(eleTy)) { 5992 if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) { 5993 // Scale a simple pointer using dynamic length and offset values. 5994 auto chTy = fir::CharacterType::getSingleton(charTy.getContext(), 5995 charTy.getFKind()); 5996 refTy = builder.getRefType(chTy); 5997 mlir::Type toTy = builder.getRefType(builder.getVarLenSeqTy(chTy)); 5998 buff = builder.createConvert(loc, toTy, buff); 5999 off = builder.create<mlir::arith::MulIOp>(loc, off, eleSz); 6000 } else { 6001 TODO(loc, "PDT offset"); 6002 } 6003 } 6004 auto coor = builder.create<fir::CoordinateOp>(loc, refTy, buff, 6005 mlir::ValueRange{off}); 6006 return builder.createConvert(loc, eleRefTy, coor); 6007 }; 6008 6009 // Lambda to lower an abstract array box value. 6010 auto doAbstractArray = [&](const auto &v) { 6011 // Compute the array size. 6012 mlir::Value arrSz = one; 6013 for (auto ext : v.getExtents()) 6014 arrSz = builder.create<mlir::arith::MulIOp>(loc, arrSz, ext); 6015 6016 // Grow the buffer as needed. 6017 auto endOff = builder.create<mlir::arith::AddIOp>(loc, off, arrSz); 6018 mem = growBuffer(mem, endOff, limit, buffSize, eleSz); 6019 6020 // Copy the elements to the buffer. 6021 mlir::Value byteSz = 6022 builder.create<mlir::arith::MulIOp>(loc, arrSz, eleSz); 6023 auto buff = builder.createConvert(loc, fir::HeapType::get(resTy), mem); 6024 mlir::Value buffi = computeCoordinate(buff, off); 6025 llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments( 6026 builder, loc, memcpyType(), buffi, v.getAddr(), byteSz, 6027 /*volatile=*/builder.createBool(loc, false)); 6028 createCallMemcpy(args); 6029 6030 // Save the incremented buffer position. 6031 builder.create<fir::StoreOp>(loc, endOff, buffPos); 6032 }; 6033 6034 // Copy a trivial scalar value into the buffer. 6035 auto doTrivialScalar = [&](const ExtValue &v, mlir::Value len = {}) { 6036 // Increment the buffer position. 6037 auto plusOne = builder.create<mlir::arith::AddIOp>(loc, off, one); 6038 6039 // Grow the buffer as needed. 6040 mem = growBuffer(mem, plusOne, limit, buffSize, eleSz); 6041 6042 // Store the element in the buffer. 6043 mlir::Value buff = 6044 builder.createConvert(loc, fir::HeapType::get(resTy), mem); 6045 auto buffi = builder.create<fir::CoordinateOp>(loc, eleRefTy, buff, 6046 mlir::ValueRange{off}); 6047 fir::factory::genScalarAssignment( 6048 builder, loc, 6049 [&]() -> ExtValue { 6050 if (len) 6051 return fir::CharBoxValue(buffi, len); 6052 return buffi; 6053 }(), 6054 v); 6055 builder.create<fir::StoreOp>(loc, plusOne, buffPos); 6056 }; 6057 6058 // Copy the value. 6059 exv.match( 6060 [&](mlir::Value) { doTrivialScalar(exv); }, 6061 [&](const fir::CharBoxValue &v) { 6062 auto buffer = v.getBuffer(); 6063 if (fir::isa_char(buffer.getType())) { 6064 doTrivialScalar(exv, eleSz); 6065 } else { 6066 // Increment the buffer position. 6067 auto plusOne = builder.create<mlir::arith::AddIOp>(loc, off, one); 6068 6069 // Grow the buffer as needed. 6070 mem = growBuffer(mem, plusOne, limit, buffSize, eleSz); 6071 6072 // Store the element in the buffer. 6073 mlir::Value buff = 6074 builder.createConvert(loc, fir::HeapType::get(resTy), mem); 6075 mlir::Value buffi = computeCoordinate(buff, off); 6076 llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments( 6077 builder, loc, memcpyType(), buffi, v.getAddr(), eleSz, 6078 /*volatile=*/builder.createBool(loc, false)); 6079 createCallMemcpy(args); 6080 6081 builder.create<fir::StoreOp>(loc, plusOne, buffPos); 6082 } 6083 }, 6084 [&](const fir::ArrayBoxValue &v) { doAbstractArray(v); }, 6085 [&](const fir::CharArrayBoxValue &v) { doAbstractArray(v); }, 6086 [&](const auto &) { 6087 TODO(loc, "unhandled array constructor expression"); 6088 }); 6089 return mem; 6090 } 6091 6092 // Lower the expr cases in an ac-value-list. 6093 template <typename A> 6094 std::pair<ExtValue, bool> 6095 genArrayCtorInitializer(const Fortran::evaluate::Expr<A> &x, mlir::Type, 6096 mlir::Value, mlir::Value, mlir::Value, 6097 Fortran::lower::StatementContext &stmtCtx) { 6098 if (isArray(x)) 6099 return {lowerNewArrayExpression(converter, symMap, stmtCtx, toEvExpr(x)), 6100 /*needCopy=*/true}; 6101 return {asScalar(x), /*needCopy=*/true}; 6102 } 6103 6104 // Lower an ac-implied-do in an ac-value-list. 6105 template <typename A> 6106 std::pair<ExtValue, bool> 6107 genArrayCtorInitializer(const Fortran::evaluate::ImpliedDo<A> &x, 6108 mlir::Type resTy, mlir::Value mem, 6109 mlir::Value buffPos, mlir::Value buffSize, 6110 Fortran::lower::StatementContext &) { 6111 mlir::Location loc = getLoc(); 6112 mlir::IndexType idxTy = builder.getIndexType(); 6113 mlir::Value lo = 6114 builder.createConvert(loc, idxTy, fir::getBase(asScalar(x.lower()))); 6115 mlir::Value up = 6116 builder.createConvert(loc, idxTy, fir::getBase(asScalar(x.upper()))); 6117 mlir::Value step = 6118 builder.createConvert(loc, idxTy, fir::getBase(asScalar(x.stride()))); 6119 auto seqTy = resTy.template cast<fir::SequenceType>(); 6120 mlir::Type eleTy = fir::unwrapSequenceType(seqTy); 6121 auto loop = 6122 builder.create<fir::DoLoopOp>(loc, lo, up, step, /*unordered=*/false, 6123 /*finalCount=*/false, mem); 6124 // create a new binding for x.name(), to ac-do-variable, to the iteration 6125 // value. 6126 symMap.pushImpliedDoBinding(toStringRef(x.name()), loop.getInductionVar()); 6127 auto insPt = builder.saveInsertionPoint(); 6128 builder.setInsertionPointToStart(loop.getBody()); 6129 // Thread mem inside the loop via loop argument. 6130 mem = loop.getRegionIterArgs()[0]; 6131 6132 mlir::Type eleRefTy = builder.getRefType(eleTy); 6133 6134 // Any temps created in the loop body must be freed inside the loop body. 6135 stmtCtx.pushScope(); 6136 llvm::Optional<mlir::Value> charLen; 6137 for (const Fortran::evaluate::ArrayConstructorValue<A> &acv : x.values()) { 6138 auto [exv, copyNeeded] = std::visit( 6139 [&](const auto &v) { 6140 return genArrayCtorInitializer(v, resTy, mem, buffPos, buffSize, 6141 stmtCtx); 6142 }, 6143 acv.u); 6144 mlir::Value eleSz = computeElementSize(exv, eleTy, resTy); 6145 mem = copyNeeded ? copyNextArrayCtorSection(exv, buffPos, buffSize, mem, 6146 eleSz, eleTy, eleRefTy, resTy) 6147 : fir::getBase(exv); 6148 if (fir::isa_char(seqTy.getEleTy()) && !charLen.hasValue()) { 6149 charLen = builder.createTemporary(loc, builder.getI64Type()); 6150 mlir::Value castLen = 6151 builder.createConvert(loc, builder.getI64Type(), fir::getLen(exv)); 6152 builder.create<fir::StoreOp>(loc, castLen, charLen.getValue()); 6153 } 6154 } 6155 stmtCtx.finalize(/*popScope=*/true); 6156 6157 builder.create<fir::ResultOp>(loc, mem); 6158 builder.restoreInsertionPoint(insPt); 6159 mem = loop.getResult(0); 6160 symMap.popImpliedDoBinding(); 6161 llvm::SmallVector<mlir::Value> extents = { 6162 builder.create<fir::LoadOp>(loc, buffPos).getResult()}; 6163 6164 // Convert to extended value. 6165 if (fir::isa_char(seqTy.getEleTy())) { 6166 auto len = builder.create<fir::LoadOp>(loc, charLen.getValue()); 6167 return {fir::CharArrayBoxValue{mem, len, extents}, /*needCopy=*/false}; 6168 } 6169 return {fir::ArrayBoxValue{mem, extents}, /*needCopy=*/false}; 6170 } 6171 6172 // To simplify the handling and interaction between the various cases, array 6173 // constructors are always lowered to the incremental construction code 6174 // pattern, even if the extent of the array value is constant. After the 6175 // MemToReg pass and constant folding, the optimizer should be able to 6176 // determine that all the buffer overrun tests are false when the 6177 // incremental construction wasn't actually required. 6178 template <typename A> 6179 CC genarr(const Fortran::evaluate::ArrayConstructor<A> &x) { 6180 mlir::Location loc = getLoc(); 6181 auto evExpr = toEvExpr(x); 6182 mlir::Type resTy = translateSomeExprToFIRType(converter, evExpr); 6183 mlir::IndexType idxTy = builder.getIndexType(); 6184 auto seqTy = resTy.template cast<fir::SequenceType>(); 6185 mlir::Type eleTy = fir::unwrapSequenceType(resTy); 6186 mlir::Value buffSize = builder.createTemporary(loc, idxTy, ".buff.size"); 6187 mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0); 6188 mlir::Value buffPos = builder.createTemporary(loc, idxTy, ".buff.pos"); 6189 builder.create<fir::StoreOp>(loc, zero, buffPos); 6190 // Allocate space for the array to be constructed. 6191 mlir::Value mem; 6192 if (fir::hasDynamicSize(resTy)) { 6193 if (fir::hasDynamicSize(eleTy)) { 6194 // The size of each element may depend on a general expression. Defer 6195 // creating the buffer until after the expression is evaluated. 6196 mem = builder.createNullConstant(loc, builder.getRefType(eleTy)); 6197 builder.create<fir::StoreOp>(loc, zero, buffSize); 6198 } else { 6199 mlir::Value initBuffSz = 6200 builder.createIntegerConstant(loc, idxTy, clInitialBufferSize); 6201 mem = builder.create<fir::AllocMemOp>( 6202 loc, eleTy, /*typeparams=*/llvm::None, initBuffSz); 6203 builder.create<fir::StoreOp>(loc, initBuffSz, buffSize); 6204 } 6205 } else { 6206 mem = builder.create<fir::AllocMemOp>(loc, resTy); 6207 int64_t buffSz = 1; 6208 for (auto extent : seqTy.getShape()) 6209 buffSz *= extent; 6210 mlir::Value initBuffSz = 6211 builder.createIntegerConstant(loc, idxTy, buffSz); 6212 builder.create<fir::StoreOp>(loc, initBuffSz, buffSize); 6213 } 6214 // Compute size of element 6215 mlir::Type eleRefTy = builder.getRefType(eleTy); 6216 6217 // Populate the buffer with the elements, growing as necessary. 6218 llvm::Optional<mlir::Value> charLen; 6219 for (const auto &expr : x) { 6220 auto [exv, copyNeeded] = std::visit( 6221 [&](const auto &e) { 6222 return genArrayCtorInitializer(e, resTy, mem, buffPos, buffSize, 6223 stmtCtx); 6224 }, 6225 expr.u); 6226 mlir::Value eleSz = computeElementSize(exv, eleTy, resTy); 6227 mem = copyNeeded ? copyNextArrayCtorSection(exv, buffPos, buffSize, mem, 6228 eleSz, eleTy, eleRefTy, resTy) 6229 : fir::getBase(exv); 6230 if (fir::isa_char(seqTy.getEleTy()) && !charLen.hasValue()) { 6231 charLen = builder.createTemporary(loc, builder.getI64Type()); 6232 mlir::Value castLen = 6233 builder.createConvert(loc, builder.getI64Type(), fir::getLen(exv)); 6234 builder.create<fir::StoreOp>(loc, castLen, charLen.getValue()); 6235 } 6236 } 6237 mem = builder.createConvert(loc, fir::HeapType::get(resTy), mem); 6238 llvm::SmallVector<mlir::Value> extents = { 6239 builder.create<fir::LoadOp>(loc, buffPos)}; 6240 6241 // Cleanup the temporary. 6242 fir::FirOpBuilder *bldr = &converter.getFirOpBuilder(); 6243 stmtCtx.attachCleanup( 6244 [bldr, loc, mem]() { bldr->create<fir::FreeMemOp>(loc, mem); }); 6245 6246 // Return the continuation. 6247 if (fir::isa_char(seqTy.getEleTy())) { 6248 if (charLen.hasValue()) { 6249 auto len = builder.create<fir::LoadOp>(loc, charLen.getValue()); 6250 return genarr(fir::CharArrayBoxValue{mem, len, extents}); 6251 } 6252 return genarr(fir::CharArrayBoxValue{mem, zero, extents}); 6253 } 6254 return genarr(fir::ArrayBoxValue{mem, extents}); 6255 } 6256 6257 CC genarr(const Fortran::evaluate::ImpliedDoIndex &) { 6258 fir::emitFatalError(getLoc(), "implied do index cannot have rank > 0"); 6259 } 6260 CC genarr(const Fortran::evaluate::TypeParamInquiry &x) { 6261 TODO(getLoc(), "array expr type parameter inquiry"); 6262 return [](IterSpace iters) -> ExtValue { return mlir::Value{}; }; 6263 } 6264 CC genarr(const Fortran::evaluate::DescriptorInquiry &x) { 6265 TODO(getLoc(), "array expr descriptor inquiry"); 6266 return [](IterSpace iters) -> ExtValue { return mlir::Value{}; }; 6267 } 6268 CC genarr(const Fortran::evaluate::StructureConstructor &x) { 6269 TODO(getLoc(), "structure constructor"); 6270 return [](IterSpace iters) -> ExtValue { return mlir::Value{}; }; 6271 } 6272 6273 //===--------------------------------------------------------------------===// 6274 // LOCICAL operators (.NOT., .AND., .EQV., etc.) 6275 //===--------------------------------------------------------------------===// 6276 6277 template <int KIND> 6278 CC genarr(const Fortran::evaluate::Not<KIND> &x) { 6279 mlir::Location loc = getLoc(); 6280 mlir::IntegerType i1Ty = builder.getI1Type(); 6281 auto lambda = genarr(x.left()); 6282 mlir::Value truth = builder.createBool(loc, true); 6283 return [=](IterSpace iters) -> ExtValue { 6284 mlir::Value logical = fir::getBase(lambda(iters)); 6285 mlir::Value val = builder.createConvert(loc, i1Ty, logical); 6286 return builder.create<mlir::arith::XOrIOp>(loc, val, truth); 6287 }; 6288 } 6289 template <typename OP, typename A> 6290 CC createBinaryBoolOp(const A &x) { 6291 mlir::Location loc = getLoc(); 6292 mlir::IntegerType i1Ty = builder.getI1Type(); 6293 auto lf = genarr(x.left()); 6294 auto rf = genarr(x.right()); 6295 return [=](IterSpace iters) -> ExtValue { 6296 mlir::Value left = fir::getBase(lf(iters)); 6297 mlir::Value right = fir::getBase(rf(iters)); 6298 mlir::Value lhs = builder.createConvert(loc, i1Ty, left); 6299 mlir::Value rhs = builder.createConvert(loc, i1Ty, right); 6300 return builder.create<OP>(loc, lhs, rhs); 6301 }; 6302 } 6303 template <typename OP, typename A> 6304 CC createCompareBoolOp(mlir::arith::CmpIPredicate pred, const A &x) { 6305 mlir::Location loc = getLoc(); 6306 mlir::IntegerType i1Ty = builder.getI1Type(); 6307 auto lf = genarr(x.left()); 6308 auto rf = genarr(x.right()); 6309 return [=](IterSpace iters) -> ExtValue { 6310 mlir::Value left = fir::getBase(lf(iters)); 6311 mlir::Value right = fir::getBase(rf(iters)); 6312 mlir::Value lhs = builder.createConvert(loc, i1Ty, left); 6313 mlir::Value rhs = builder.createConvert(loc, i1Ty, right); 6314 return builder.create<OP>(loc, pred, lhs, rhs); 6315 }; 6316 } 6317 template <int KIND> 6318 CC genarr(const Fortran::evaluate::LogicalOperation<KIND> &x) { 6319 switch (x.logicalOperator) { 6320 case Fortran::evaluate::LogicalOperator::And: 6321 return createBinaryBoolOp<mlir::arith::AndIOp>(x); 6322 case Fortran::evaluate::LogicalOperator::Or: 6323 return createBinaryBoolOp<mlir::arith::OrIOp>(x); 6324 case Fortran::evaluate::LogicalOperator::Eqv: 6325 return createCompareBoolOp<mlir::arith::CmpIOp>( 6326 mlir::arith::CmpIPredicate::eq, x); 6327 case Fortran::evaluate::LogicalOperator::Neqv: 6328 return createCompareBoolOp<mlir::arith::CmpIOp>( 6329 mlir::arith::CmpIPredicate::ne, x); 6330 case Fortran::evaluate::LogicalOperator::Not: 6331 llvm_unreachable(".NOT. handled elsewhere"); 6332 } 6333 llvm_unreachable("unhandled case"); 6334 } 6335 6336 //===--------------------------------------------------------------------===// 6337 // Relational operators (<, <=, ==, etc.) 6338 //===--------------------------------------------------------------------===// 6339 6340 template <typename OP, typename PRED, typename A> 6341 CC createCompareOp(PRED pred, const A &x) { 6342 mlir::Location loc = getLoc(); 6343 auto lf = genarr(x.left()); 6344 auto rf = genarr(x.right()); 6345 return [=](IterSpace iters) -> ExtValue { 6346 mlir::Value lhs = fir::getBase(lf(iters)); 6347 mlir::Value rhs = fir::getBase(rf(iters)); 6348 return builder.create<OP>(loc, pred, lhs, rhs); 6349 }; 6350 } 6351 template <typename A> 6352 CC createCompareCharOp(mlir::arith::CmpIPredicate pred, const A &x) { 6353 mlir::Location loc = getLoc(); 6354 auto lf = genarr(x.left()); 6355 auto rf = genarr(x.right()); 6356 return [=](IterSpace iters) -> ExtValue { 6357 auto lhs = lf(iters); 6358 auto rhs = rf(iters); 6359 return fir::runtime::genCharCompare(builder, loc, pred, lhs, rhs); 6360 }; 6361 } 6362 template <int KIND> 6363 CC genarr(const Fortran::evaluate::Relational<Fortran::evaluate::Type< 6364 Fortran::common::TypeCategory::Integer, KIND>> &x) { 6365 return createCompareOp<mlir::arith::CmpIOp>(translateRelational(x.opr), x); 6366 } 6367 template <int KIND> 6368 CC genarr(const Fortran::evaluate::Relational<Fortran::evaluate::Type< 6369 Fortran::common::TypeCategory::Character, KIND>> &x) { 6370 return createCompareCharOp(translateRelational(x.opr), x); 6371 } 6372 template <int KIND> 6373 CC genarr(const Fortran::evaluate::Relational<Fortran::evaluate::Type< 6374 Fortran::common::TypeCategory::Real, KIND>> &x) { 6375 return createCompareOp<mlir::arith::CmpFOp>(translateFloatRelational(x.opr), 6376 x); 6377 } 6378 template <int KIND> 6379 CC genarr(const Fortran::evaluate::Relational<Fortran::evaluate::Type< 6380 Fortran::common::TypeCategory::Complex, KIND>> &x) { 6381 return createCompareOp<fir::CmpcOp>(translateFloatRelational(x.opr), x); 6382 } 6383 CC genarr( 6384 const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &r) { 6385 return std::visit([&](const auto &x) { return genarr(x); }, r.u); 6386 } 6387 6388 template <typename A> 6389 CC genarr(const Fortran::evaluate::Designator<A> &des) { 6390 ComponentPath components(des.Rank() > 0); 6391 return std::visit([&](const auto &x) { return genarr(x, components); }, 6392 des.u); 6393 } 6394 6395 /// Is the path component rank > 0? 6396 static bool ranked(const PathComponent &x) { 6397 return std::visit(Fortran::common::visitors{ 6398 [](const ImplicitSubscripts &) { return false; }, 6399 [](const auto *v) { return v->Rank() > 0; }}, 6400 x); 6401 } 6402 6403 //===-------------------------------------------------------------------===// 6404 // Array data references in an explicit iteration space. 6405 // 6406 // Use the base array that was loaded before the loop nest. 6407 //===-------------------------------------------------------------------===// 6408 6409 /// Lower the path (`revPath`, in reverse) to be appended to an array_fetch or 6410 /// array_update op. \p ty is the initial type of the array 6411 /// (reference). Returns the type of the element after application of the 6412 /// path in \p components. 6413 /// 6414 /// TODO: This needs to deal with array's with initial bounds other than 1. 6415 /// TODO: Thread type parameters correctly. 6416 mlir::Type lowerPath(const ExtValue &arrayExv, ComponentPath &components) { 6417 mlir::Location loc = getLoc(); 6418 mlir::Type ty = fir::getBase(arrayExv).getType(); 6419 auto &revPath = components.reversePath; 6420 ty = fir::unwrapPassByRefType(ty); 6421 bool prefix = true; 6422 auto addComponent = [&](mlir::Value v) { 6423 if (prefix) 6424 components.prefixComponents.push_back(v); 6425 else 6426 components.suffixComponents.push_back(v); 6427 }; 6428 mlir::IndexType idxTy = builder.getIndexType(); 6429 mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); 6430 bool atBase = true; 6431 auto saveSemant = semant; 6432 if (isProjectedCopyInCopyOut()) 6433 semant = ConstituentSemantics::RefTransparent; 6434 for (const auto &v : llvm::reverse(revPath)) { 6435 std::visit( 6436 Fortran::common::visitors{ 6437 [&](const ImplicitSubscripts &) { 6438 prefix = false; 6439 ty = fir::unwrapSequenceType(ty); 6440 }, 6441 [&](const Fortran::evaluate::ComplexPart *x) { 6442 assert(!prefix && "complex part must be at end"); 6443 mlir::Value offset = builder.createIntegerConstant( 6444 loc, builder.getI32Type(), 6445 x->part() == Fortran::evaluate::ComplexPart::Part::RE ? 0 6446 : 1); 6447 components.suffixComponents.push_back(offset); 6448 ty = fir::applyPathToType(ty, mlir::ValueRange{offset}); 6449 }, 6450 [&](const Fortran::evaluate::ArrayRef *x) { 6451 if (Fortran::lower::isRankedArrayAccess(*x)) { 6452 genSliceIndices(components, arrayExv, *x, atBase); 6453 } else { 6454 // Array access where the expressions are scalar and cannot 6455 // depend upon the implied iteration space. 6456 unsigned ssIndex = 0u; 6457 for (const auto &ss : x->subscript()) { 6458 std::visit( 6459 Fortran::common::visitors{ 6460 [&](const Fortran::evaluate:: 6461 IndirectSubscriptIntegerExpr &ie) { 6462 const auto &e = ie.value(); 6463 if (isArray(e)) 6464 fir::emitFatalError( 6465 loc, 6466 "multiple components along single path " 6467 "generating array subexpressions"); 6468 // Lower scalar index expression, append it to 6469 // subs. 6470 mlir::Value subscriptVal = 6471 fir::getBase(asScalarArray(e)); 6472 // arrayExv is the base array. It needs to reflect 6473 // the current array component instead. 6474 // FIXME: must use lower bound of this component, 6475 // not just the constant 1. 6476 mlir::Value lb = 6477 atBase ? fir::factory::readLowerBound( 6478 builder, loc, arrayExv, ssIndex, 6479 one) 6480 : one; 6481 mlir::Value val = builder.createConvert( 6482 loc, idxTy, subscriptVal); 6483 mlir::Value ivAdj = 6484 builder.create<mlir::arith::SubIOp>( 6485 loc, idxTy, val, lb); 6486 addComponent( 6487 builder.createConvert(loc, idxTy, ivAdj)); 6488 }, 6489 [&](const auto &) { 6490 fir::emitFatalError( 6491 loc, "multiple components along single path " 6492 "generating array subexpressions"); 6493 }}, 6494 ss.u); 6495 ssIndex++; 6496 } 6497 } 6498 ty = fir::unwrapSequenceType(ty); 6499 }, 6500 [&](const Fortran::evaluate::Component *x) { 6501 auto fieldTy = fir::FieldType::get(builder.getContext()); 6502 llvm::StringRef name = toStringRef(getLastSym(*x).name()); 6503 auto recTy = ty.cast<fir::RecordType>(); 6504 ty = recTy.getType(name); 6505 auto fld = builder.create<fir::FieldIndexOp>( 6506 loc, fieldTy, name, recTy, fir::getTypeParams(arrayExv)); 6507 addComponent(fld); 6508 }}, 6509 v); 6510 atBase = false; 6511 } 6512 semant = saveSemant; 6513 ty = fir::unwrapSequenceType(ty); 6514 components.applied = true; 6515 return ty; 6516 } 6517 6518 llvm::SmallVector<mlir::Value> genSubstringBounds(ComponentPath &components) { 6519 llvm::SmallVector<mlir::Value> result; 6520 if (components.substring) 6521 populateBounds(result, components.substring); 6522 return result; 6523 } 6524 6525 CC applyPathToArrayLoad(fir::ArrayLoadOp load, ComponentPath &components) { 6526 mlir::Location loc = getLoc(); 6527 auto revPath = components.reversePath; 6528 fir::ExtendedValue arrayExv = 6529 arrayLoadExtValue(builder, loc, load, {}, load); 6530 mlir::Type eleTy = lowerPath(arrayExv, components); 6531 auto currentPC = components.pc; 6532 auto pc = [=, prefix = components.prefixComponents, 6533 suffix = components.suffixComponents](IterSpace iters) { 6534 IterationSpace newIters = currentPC(iters); 6535 // Add path prefix and suffix. 6536 IterationSpace addIters(newIters, prefix, suffix); 6537 return addIters; 6538 }; 6539 components.pc = [=](IterSpace iters) { return iters; }; 6540 llvm::SmallVector<mlir::Value> substringBounds = 6541 genSubstringBounds(components); 6542 if (isProjectedCopyInCopyOut()) { 6543 destination = load; 6544 auto lambda = [=, esp = this->explicitSpace](IterSpace iters) mutable { 6545 mlir::Value innerArg = esp->findArgumentOfLoad(load); 6546 if (isAdjustedArrayElementType(eleTy)) { 6547 mlir::Type eleRefTy = builder.getRefType(eleTy); 6548 auto arrayOp = builder.create<fir::ArrayAccessOp>( 6549 loc, eleRefTy, innerArg, iters.iterVec(), load.getTypeparams()); 6550 if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) { 6551 mlir::Value dstLen = fir::factory::genLenOfCharacter( 6552 builder, loc, load, iters.iterVec(), substringBounds); 6553 fir::ArrayAmendOp amend = createCharArrayAmend( 6554 loc, builder, arrayOp, dstLen, iters.elementExv(), innerArg, 6555 substringBounds); 6556 return arrayLoadExtValue(builder, loc, load, iters.iterVec(), amend, 6557 dstLen); 6558 } else if (fir::isa_derived(eleTy)) { 6559 fir::ArrayAmendOp amend = 6560 createDerivedArrayAmend(loc, load, builder, arrayOp, 6561 iters.elementExv(), eleTy, innerArg); 6562 return arrayLoadExtValue(builder, loc, load, iters.iterVec(), 6563 amend); 6564 } 6565 assert(eleTy.isa<fir::SequenceType>()); 6566 TODO(loc, "array (as element) assignment"); 6567 } 6568 mlir::Value castedElement = 6569 builder.createConvert(loc, eleTy, iters.getElement()); 6570 auto update = builder.create<fir::ArrayUpdateOp>( 6571 loc, innerArg.getType(), innerArg, castedElement, iters.iterVec(), 6572 load.getTypeparams()); 6573 return arrayLoadExtValue(builder, loc, load, iters.iterVec(), update); 6574 }; 6575 return [=](IterSpace iters) mutable { return lambda(pc(iters)); }; 6576 } 6577 if (isCustomCopyInCopyOut()) { 6578 // Create an array_modify to get the LHS element address and indicate 6579 // the assignment, and create the call to the user defined assignment. 6580 destination = load; 6581 auto lambda = [=](IterSpace iters) mutable { 6582 mlir::Value innerArg = explicitSpace->findArgumentOfLoad(load); 6583 mlir::Type refEleTy = 6584 fir::isa_ref_type(eleTy) ? eleTy : builder.getRefType(eleTy); 6585 auto arrModify = builder.create<fir::ArrayModifyOp>( 6586 loc, mlir::TypeRange{refEleTy, innerArg.getType()}, innerArg, 6587 iters.iterVec(), load.getTypeparams()); 6588 return arrayLoadExtValue(builder, loc, load, iters.iterVec(), 6589 arrModify.getResult(1)); 6590 }; 6591 return [=](IterSpace iters) mutable { return lambda(pc(iters)); }; 6592 } 6593 auto lambda = [=, semant = this->semant](IterSpace iters) mutable { 6594 if (semant == ConstituentSemantics::RefOpaque || 6595 isAdjustedArrayElementType(eleTy)) { 6596 mlir::Type resTy = builder.getRefType(eleTy); 6597 // Use array element reference semantics. 6598 auto access = builder.create<fir::ArrayAccessOp>( 6599 loc, resTy, load, iters.iterVec(), load.getTypeparams()); 6600 mlir::Value newBase = access; 6601 if (fir::isa_char(eleTy)) { 6602 mlir::Value dstLen = fir::factory::genLenOfCharacter( 6603 builder, loc, load, iters.iterVec(), substringBounds); 6604 if (!substringBounds.empty()) { 6605 fir::CharBoxValue charDst{access, dstLen}; 6606 fir::factory::CharacterExprHelper helper{builder, loc}; 6607 charDst = helper.createSubstring(charDst, substringBounds); 6608 newBase = charDst.getAddr(); 6609 } 6610 return arrayLoadExtValue(builder, loc, load, iters.iterVec(), newBase, 6611 dstLen); 6612 } 6613 return arrayLoadExtValue(builder, loc, load, iters.iterVec(), newBase); 6614 } 6615 auto fetch = builder.create<fir::ArrayFetchOp>( 6616 loc, eleTy, load, iters.iterVec(), load.getTypeparams()); 6617 return arrayLoadExtValue(builder, loc, load, iters.iterVec(), fetch); 6618 }; 6619 return [=](IterSpace iters) mutable { 6620 auto newIters = pc(iters); 6621 return lambda(newIters); 6622 }; 6623 } 6624 6625 template <typename A> 6626 CC genImplicitArrayAccess(const A &x, ComponentPath &components) { 6627 components.reversePath.push_back(ImplicitSubscripts{}); 6628 ExtValue exv = asScalarRef(x); 6629 lowerPath(exv, components); 6630 auto lambda = genarr(exv, components); 6631 return [=](IterSpace iters) { return lambda(components.pc(iters)); }; 6632 } 6633 CC genImplicitArrayAccess(const Fortran::evaluate::NamedEntity &x, 6634 ComponentPath &components) { 6635 if (x.IsSymbol()) 6636 return genImplicitArrayAccess(getFirstSym(x), components); 6637 return genImplicitArrayAccess(x.GetComponent(), components); 6638 } 6639 6640 template <typename A> 6641 CC genAsScalar(const A &x) { 6642 mlir::Location loc = getLoc(); 6643 if (isProjectedCopyInCopyOut()) { 6644 return [=, &x, builder = &converter.getFirOpBuilder()]( 6645 IterSpace iters) -> ExtValue { 6646 ExtValue exv = asScalarRef(x); 6647 mlir::Value val = fir::getBase(exv); 6648 mlir::Type eleTy = fir::unwrapRefType(val.getType()); 6649 if (isAdjustedArrayElementType(eleTy)) { 6650 if (fir::isa_char(eleTy)) { 6651 fir::factory::CharacterExprHelper{*builder, loc}.createAssign( 6652 exv, iters.elementExv()); 6653 } else if (fir::isa_derived(eleTy)) { 6654 TODO(loc, "assignment of derived type"); 6655 } else { 6656 fir::emitFatalError(loc, "array type not expected in scalar"); 6657 } 6658 } else { 6659 builder->create<fir::StoreOp>(loc, iters.getElement(), val); 6660 } 6661 return exv; 6662 }; 6663 } 6664 return [=, &x](IterSpace) { return asScalar(x); }; 6665 } 6666 6667 CC genarr(const Fortran::semantics::Symbol &x, ComponentPath &components) { 6668 if (explicitSpaceIsActive()) { 6669 if (x.Rank() > 0) 6670 components.reversePath.push_back(ImplicitSubscripts{}); 6671 if (fir::ArrayLoadOp load = explicitSpace->findBinding(&x)) 6672 return applyPathToArrayLoad(load, components); 6673 } else { 6674 return genImplicitArrayAccess(x, components); 6675 } 6676 if (pathIsEmpty(components)) 6677 return genAsScalar(x); 6678 mlir::Location loc = getLoc(); 6679 return [=](IterSpace) -> ExtValue { 6680 fir::emitFatalError(loc, "reached symbol with path"); 6681 }; 6682 } 6683 6684 /// Lower a component path with or without rank. 6685 /// Example: <code>array%baz%qux%waldo</code> 6686 CC genarr(const Fortran::evaluate::Component &x, ComponentPath &components) { 6687 if (explicitSpaceIsActive()) { 6688 if (x.base().Rank() == 0 && x.Rank() > 0) 6689 components.reversePath.push_back(ImplicitSubscripts{}); 6690 if (fir::ArrayLoadOp load = explicitSpace->findBinding(&x)) 6691 return applyPathToArrayLoad(load, components); 6692 } else { 6693 if (x.base().Rank() == 0) 6694 return genImplicitArrayAccess(x, components); 6695 } 6696 bool atEnd = pathIsEmpty(components); 6697 if (!getLastSym(x).test(Fortran::semantics::Symbol::Flag::ParentComp)) 6698 // Skip parent components; their components are placed directly in the 6699 // object. 6700 components.reversePath.push_back(&x); 6701 auto result = genarr(x.base(), components); 6702 if (components.applied) 6703 return result; 6704 if (atEnd) 6705 return genAsScalar(x); 6706 mlir::Location loc = getLoc(); 6707 return [=](IterSpace) -> ExtValue { 6708 fir::emitFatalError(loc, "reached component with path"); 6709 }; 6710 } 6711 6712 /// Array reference with subscripts. If this has rank > 0, this is a form 6713 /// of an array section (slice). 6714 /// 6715 /// There are two "slicing" primitives that may be applied on a dimension by 6716 /// dimension basis: (1) triple notation and (2) vector addressing. Since 6717 /// dimensions can be selectively sliced, some dimensions may contain 6718 /// regular scalar expressions and those dimensions do not participate in 6719 /// the array expression evaluation. 6720 CC genarr(const Fortran::evaluate::ArrayRef &x, ComponentPath &components) { 6721 if (explicitSpaceIsActive()) { 6722 if (Fortran::lower::isRankedArrayAccess(x)) 6723 components.reversePath.push_back(ImplicitSubscripts{}); 6724 if (fir::ArrayLoadOp load = explicitSpace->findBinding(&x)) { 6725 components.reversePath.push_back(&x); 6726 return applyPathToArrayLoad(load, components); 6727 } 6728 } else { 6729 if (Fortran::lower::isRankedArrayAccess(x)) { 6730 components.reversePath.push_back(&x); 6731 return genImplicitArrayAccess(x.base(), components); 6732 } 6733 } 6734 bool atEnd = pathIsEmpty(components); 6735 components.reversePath.push_back(&x); 6736 auto result = genarr(x.base(), components); 6737 if (components.applied) 6738 return result; 6739 mlir::Location loc = getLoc(); 6740 if (atEnd) { 6741 if (x.Rank() == 0) 6742 return genAsScalar(x); 6743 fir::emitFatalError(loc, "expected scalar"); 6744 } 6745 return [=](IterSpace) -> ExtValue { 6746 fir::emitFatalError(loc, "reached arrayref with path"); 6747 }; 6748 } 6749 6750 CC genarr(const Fortran::evaluate::CoarrayRef &x, ComponentPath &components) { 6751 TODO(getLoc(), "coarray reference"); 6752 } 6753 6754 CC genarr(const Fortran::evaluate::NamedEntity &x, 6755 ComponentPath &components) { 6756 return x.IsSymbol() ? genarr(getFirstSym(x), components) 6757 : genarr(x.GetComponent(), components); 6758 } 6759 6760 CC genarr(const Fortran::evaluate::DataRef &x, ComponentPath &components) { 6761 return std::visit([&](const auto &v) { return genarr(v, components); }, 6762 x.u); 6763 } 6764 6765 bool pathIsEmpty(const ComponentPath &components) { 6766 return components.reversePath.empty(); 6767 } 6768 6769 explicit ArrayExprLowering(Fortran::lower::AbstractConverter &converter, 6770 Fortran::lower::StatementContext &stmtCtx, 6771 Fortran::lower::SymMap &symMap) 6772 : converter{converter}, builder{converter.getFirOpBuilder()}, 6773 stmtCtx{stmtCtx}, symMap{symMap} {} 6774 6775 explicit ArrayExprLowering(Fortran::lower::AbstractConverter &converter, 6776 Fortran::lower::StatementContext &stmtCtx, 6777 Fortran::lower::SymMap &symMap, 6778 ConstituentSemantics sem) 6779 : converter{converter}, builder{converter.getFirOpBuilder()}, 6780 stmtCtx{stmtCtx}, symMap{symMap}, semant{sem} {} 6781 6782 explicit ArrayExprLowering(Fortran::lower::AbstractConverter &converter, 6783 Fortran::lower::StatementContext &stmtCtx, 6784 Fortran::lower::SymMap &symMap, 6785 ConstituentSemantics sem, 6786 Fortran::lower::ExplicitIterSpace *expSpace, 6787 Fortran::lower::ImplicitIterSpace *impSpace) 6788 : converter{converter}, builder{converter.getFirOpBuilder()}, 6789 stmtCtx{stmtCtx}, symMap{symMap}, 6790 explicitSpace(expSpace->isActive() ? expSpace : nullptr), 6791 implicitSpace(impSpace->empty() ? nullptr : impSpace), semant{sem} { 6792 // Generate any mask expressions, as necessary. This is the compute step 6793 // that creates the effective masks. See 10.2.3.2 in particular. 6794 genMasks(); 6795 } 6796 6797 mlir::Location getLoc() { return converter.getCurrentLocation(); } 6798 6799 /// Array appears in a lhs context such that it is assigned after the rhs is 6800 /// fully evaluated. 6801 inline bool isCopyInCopyOut() { 6802 return semant == ConstituentSemantics::CopyInCopyOut; 6803 } 6804 6805 /// Array appears in a lhs (or temp) context such that a projected, 6806 /// discontiguous subspace of the array is assigned after the rhs is fully 6807 /// evaluated. That is, the rhs array value is merged into a section of the 6808 /// lhs array. 6809 inline bool isProjectedCopyInCopyOut() { 6810 return semant == ConstituentSemantics::ProjectedCopyInCopyOut; 6811 } 6812 6813 // ???: Do we still need this? 6814 inline bool isCustomCopyInCopyOut() { 6815 return semant == ConstituentSemantics::CustomCopyInCopyOut; 6816 } 6817 6818 /// Array appears in a context where it must be boxed. 6819 inline bool isBoxValue() { return semant == ConstituentSemantics::BoxValue; } 6820 6821 /// Array appears in a context where differences in the memory reference can 6822 /// be observable in the computational results. For example, an array 6823 /// element is passed to an impure procedure. 6824 inline bool isReferentiallyOpaque() { 6825 return semant == ConstituentSemantics::RefOpaque; 6826 } 6827 6828 /// Array appears in a context where it is passed as a VALUE argument. 6829 inline bool isValueAttribute() { 6830 return semant == ConstituentSemantics::ByValueArg; 6831 } 6832 6833 /// Can the loops over the expression be unordered? 6834 inline bool isUnordered() const { return unordered; } 6835 6836 void setUnordered(bool b) { unordered = b; } 6837 6838 Fortran::lower::AbstractConverter &converter; 6839 fir::FirOpBuilder &builder; 6840 Fortran::lower::StatementContext &stmtCtx; 6841 bool elementCtx = false; 6842 Fortran::lower::SymMap &symMap; 6843 /// The continuation to generate code to update the destination. 6844 llvm::Optional<CC> ccStoreToDest; 6845 llvm::Optional<std::function<void(llvm::ArrayRef<mlir::Value>)>> ccPrelude; 6846 llvm::Optional<std::function<fir::ArrayLoadOp(llvm::ArrayRef<mlir::Value>)>> 6847 ccLoadDest; 6848 /// The destination is the loaded array into which the results will be 6849 /// merged. 6850 fir::ArrayLoadOp destination; 6851 /// The shape of the destination. 6852 llvm::SmallVector<mlir::Value> destShape; 6853 /// List of arrays in the expression that have been loaded. 6854 llvm::SmallVector<ArrayOperand> arrayOperands; 6855 /// If there is a user-defined iteration space, explicitShape will hold the 6856 /// information from the front end. 6857 Fortran::lower::ExplicitIterSpace *explicitSpace = nullptr; 6858 Fortran::lower::ImplicitIterSpace *implicitSpace = nullptr; 6859 ConstituentSemantics semant = ConstituentSemantics::RefTransparent; 6860 // Can the array expression be evaluated in any order? 6861 // Will be set to false if any of the expression parts prevent this. 6862 bool unordered = true; 6863 }; 6864 } // namespace 6865 6866 fir::ExtendedValue Fortran::lower::createSomeExtendedExpression( 6867 mlir::Location loc, Fortran::lower::AbstractConverter &converter, 6868 const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap, 6869 Fortran::lower::StatementContext &stmtCtx) { 6870 LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "expr: ") << '\n'); 6871 return ScalarExprLowering{loc, converter, symMap, stmtCtx}.genval(expr); 6872 } 6873 6874 fir::GlobalOp Fortran::lower::createDenseGlobal( 6875 mlir::Location loc, mlir::Type symTy, llvm::StringRef globalName, 6876 mlir::StringAttr linkage, bool isConst, 6877 const Fortran::lower::SomeExpr &expr, 6878 Fortran::lower::AbstractConverter &converter) { 6879 6880 Fortran::lower::StatementContext stmtCtx(/*prohibited=*/true); 6881 Fortran::lower::SymMap emptyMap; 6882 InitializerData initData(/*genRawVals=*/true); 6883 ScalarExprLowering sel(loc, converter, emptyMap, stmtCtx, 6884 /*initializer=*/&initData); 6885 sel.genval(expr); 6886 6887 size_t sz = initData.rawVals.size(); 6888 llvm::ArrayRef<mlir::Attribute> ar = {initData.rawVals.data(), sz}; 6889 6890 mlir::RankedTensorType tensorTy; 6891 auto &builder = converter.getFirOpBuilder(); 6892 mlir::Type iTy = initData.rawType; 6893 if (!iTy) 6894 return 0; // array extent is probably 0 in this case, so just return 0. 6895 tensorTy = mlir::RankedTensorType::get(sz, iTy); 6896 auto init = mlir::DenseElementsAttr::get(tensorTy, ar); 6897 return builder.createGlobal(loc, symTy, globalName, linkage, init, isConst); 6898 } 6899 6900 fir::ExtendedValue Fortran::lower::createSomeInitializerExpression( 6901 mlir::Location loc, Fortran::lower::AbstractConverter &converter, 6902 const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap, 6903 Fortran::lower::StatementContext &stmtCtx) { 6904 LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "expr: ") << '\n'); 6905 InitializerData initData; // needed for initializations 6906 return ScalarExprLowering{loc, converter, symMap, stmtCtx, 6907 /*initializer=*/&initData} 6908 .genval(expr); 6909 } 6910 6911 fir::ExtendedValue Fortran::lower::createSomeExtendedAddress( 6912 mlir::Location loc, Fortran::lower::AbstractConverter &converter, 6913 const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap, 6914 Fortran::lower::StatementContext &stmtCtx) { 6915 LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "address: ") << '\n'); 6916 return ScalarExprLowering(loc, converter, symMap, stmtCtx).gen(expr); 6917 } 6918 6919 fir::ExtendedValue Fortran::lower::createInitializerAddress( 6920 mlir::Location loc, Fortran::lower::AbstractConverter &converter, 6921 const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap, 6922 Fortran::lower::StatementContext &stmtCtx) { 6923 LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "address: ") << '\n'); 6924 InitializerData init; 6925 return ScalarExprLowering(loc, converter, symMap, stmtCtx, &init).gen(expr); 6926 } 6927 6928 void Fortran::lower::createSomeArrayAssignment( 6929 Fortran::lower::AbstractConverter &converter, 6930 const Fortran::lower::SomeExpr &lhs, const Fortran::lower::SomeExpr &rhs, 6931 Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx) { 6932 LLVM_DEBUG(lhs.AsFortran(llvm::dbgs() << "onto array: ") << '\n'; 6933 rhs.AsFortran(llvm::dbgs() << "assign expression: ") << '\n';); 6934 ArrayExprLowering::lowerArrayAssignment(converter, symMap, stmtCtx, lhs, rhs); 6935 } 6936 6937 void Fortran::lower::createSomeArrayAssignment( 6938 Fortran::lower::AbstractConverter &converter, const fir::ExtendedValue &lhs, 6939 const Fortran::lower::SomeExpr &rhs, Fortran::lower::SymMap &symMap, 6940 Fortran::lower::StatementContext &stmtCtx) { 6941 LLVM_DEBUG(llvm::dbgs() << "onto array: " << lhs << '\n'; 6942 rhs.AsFortran(llvm::dbgs() << "assign expression: ") << '\n';); 6943 ArrayExprLowering::lowerArrayAssignment(converter, symMap, stmtCtx, lhs, rhs); 6944 } 6945 void Fortran::lower::createSomeArrayAssignment( 6946 Fortran::lower::AbstractConverter &converter, const fir::ExtendedValue &lhs, 6947 const fir::ExtendedValue &rhs, Fortran::lower::SymMap &symMap, 6948 Fortran::lower::StatementContext &stmtCtx) { 6949 LLVM_DEBUG(llvm::dbgs() << "onto array: " << lhs << '\n'; 6950 llvm::dbgs() << "assign expression: " << rhs << '\n';); 6951 ArrayExprLowering::lowerArrayAssignment(converter, symMap, stmtCtx, lhs, rhs); 6952 } 6953 6954 void Fortran::lower::createAnyMaskedArrayAssignment( 6955 Fortran::lower::AbstractConverter &converter, 6956 const Fortran::lower::SomeExpr &lhs, const Fortran::lower::SomeExpr &rhs, 6957 Fortran::lower::ExplicitIterSpace &explicitSpace, 6958 Fortran::lower::ImplicitIterSpace &implicitSpace, 6959 Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx) { 6960 LLVM_DEBUG(lhs.AsFortran(llvm::dbgs() << "onto array: ") << '\n'; 6961 rhs.AsFortran(llvm::dbgs() << "assign expression: ") 6962 << " given the explicit iteration space:\n" 6963 << explicitSpace << "\n and implied mask conditions:\n" 6964 << implicitSpace << '\n';); 6965 ArrayExprLowering::lowerAnyMaskedArrayAssignment( 6966 converter, symMap, stmtCtx, lhs, rhs, explicitSpace, implicitSpace); 6967 } 6968 6969 void Fortran::lower::createAllocatableArrayAssignment( 6970 Fortran::lower::AbstractConverter &converter, 6971 const Fortran::lower::SomeExpr &lhs, const Fortran::lower::SomeExpr &rhs, 6972 Fortran::lower::ExplicitIterSpace &explicitSpace, 6973 Fortran::lower::ImplicitIterSpace &implicitSpace, 6974 Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx) { 6975 LLVM_DEBUG(lhs.AsFortran(llvm::dbgs() << "defining array: ") << '\n'; 6976 rhs.AsFortran(llvm::dbgs() << "assign expression: ") 6977 << " given the explicit iteration space:\n" 6978 << explicitSpace << "\n and implied mask conditions:\n" 6979 << implicitSpace << '\n';); 6980 ArrayExprLowering::lowerAllocatableArrayAssignment( 6981 converter, symMap, stmtCtx, lhs, rhs, explicitSpace, implicitSpace); 6982 } 6983 6984 fir::ExtendedValue Fortran::lower::createSomeArrayTempValue( 6985 Fortran::lower::AbstractConverter &converter, 6986 const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap, 6987 Fortran::lower::StatementContext &stmtCtx) { 6988 LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "array value: ") << '\n'); 6989 return ArrayExprLowering::lowerNewArrayExpression(converter, symMap, stmtCtx, 6990 expr); 6991 } 6992 6993 void Fortran::lower::createLazyArrayTempValue( 6994 Fortran::lower::AbstractConverter &converter, 6995 const Fortran::lower::SomeExpr &expr, mlir::Value raggedHeader, 6996 Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx) { 6997 LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "array value: ") << '\n'); 6998 ArrayExprLowering::lowerLazyArrayExpression(converter, symMap, stmtCtx, expr, 6999 raggedHeader); 7000 } 7001 7002 fir::ExtendedValue 7003 Fortran::lower::createSomeArrayBox(Fortran::lower::AbstractConverter &converter, 7004 const Fortran::lower::SomeExpr &expr, 7005 Fortran::lower::SymMap &symMap, 7006 Fortran::lower::StatementContext &stmtCtx) { 7007 LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "box designator: ") << '\n'); 7008 return ArrayExprLowering::lowerBoxedArrayExpression(converter, symMap, 7009 stmtCtx, expr); 7010 } 7011 7012 fir::MutableBoxValue Fortran::lower::createMutableBox( 7013 mlir::Location loc, Fortran::lower::AbstractConverter &converter, 7014 const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap) { 7015 // MutableBox lowering StatementContext does not need to be propagated 7016 // to the caller because the result value is a variable, not a temporary 7017 // expression. The StatementContext clean-up can occur before using the 7018 // resulting MutableBoxValue. Variables of all other types are handled in the 7019 // bridge. 7020 Fortran::lower::StatementContext dummyStmtCtx; 7021 return ScalarExprLowering{loc, converter, symMap, dummyStmtCtx} 7022 .genMutableBoxValue(expr); 7023 } 7024 7025 fir::ExtendedValue Fortran::lower::createBoxValue( 7026 mlir::Location loc, Fortran::lower::AbstractConverter &converter, 7027 const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap, 7028 Fortran::lower::StatementContext &stmtCtx) { 7029 if (expr.Rank() > 0 && Fortran::evaluate::IsVariable(expr) && 7030 !Fortran::evaluate::HasVectorSubscript(expr)) 7031 return Fortran::lower::createSomeArrayBox(converter, expr, symMap, stmtCtx); 7032 fir::ExtendedValue addr = Fortran::lower::createSomeExtendedAddress( 7033 loc, converter, expr, symMap, stmtCtx); 7034 return fir::BoxValue(converter.getFirOpBuilder().createBox(loc, addr)); 7035 } 7036 7037 mlir::Value Fortran::lower::createSubroutineCall( 7038 AbstractConverter &converter, const evaluate::ProcedureRef &call, 7039 ExplicitIterSpace &explicitIterSpace, ImplicitIterSpace &implicitIterSpace, 7040 SymMap &symMap, StatementContext &stmtCtx, bool isUserDefAssignment) { 7041 mlir::Location loc = converter.getCurrentLocation(); 7042 7043 if (isUserDefAssignment) { 7044 assert(call.arguments().size() == 2); 7045 const auto *lhs = call.arguments()[0].value().UnwrapExpr(); 7046 const auto *rhs = call.arguments()[1].value().UnwrapExpr(); 7047 assert(lhs && rhs && 7048 "user defined assignment arguments must be expressions"); 7049 if (call.IsElemental() && lhs->Rank() > 0) { 7050 // Elemental user defined assignment has special requirements to deal with 7051 // LHS/RHS overlaps. See 10.2.1.5 p2. 7052 ArrayExprLowering::lowerElementalUserAssignment( 7053 converter, symMap, stmtCtx, explicitIterSpace, implicitIterSpace, 7054 call); 7055 } else if (explicitIterSpace.isActive() && lhs->Rank() == 0) { 7056 // Scalar defined assignment (elemental or not) in a FORALL context. 7057 mlir::func::FuncOp func = 7058 Fortran::lower::CallerInterface(call, converter).getFuncOp(); 7059 ArrayExprLowering::lowerScalarUserAssignment( 7060 converter, symMap, stmtCtx, explicitIterSpace, func, *lhs, *rhs); 7061 } else if (explicitIterSpace.isActive()) { 7062 // TODO: need to array fetch/modify sub-arrays? 7063 TODO(loc, "non elemental user defined array assignment inside FORALL"); 7064 } else { 7065 if (!implicitIterSpace.empty()) 7066 fir::emitFatalError( 7067 loc, 7068 "C1032: user defined assignment inside WHERE must be elemental"); 7069 // Non elemental user defined assignment outside of FORALL and WHERE. 7070 // FIXME: The non elemental user defined assignment case with array 7071 // arguments must be take into account potential overlap. So far the front 7072 // end does not add parentheses around the RHS argument in the call as it 7073 // should according to 15.4.3.4.3 p2. 7074 Fortran::lower::createSomeExtendedExpression( 7075 loc, converter, toEvExpr(call), symMap, stmtCtx); 7076 } 7077 return {}; 7078 } 7079 7080 assert(implicitIterSpace.empty() && !explicitIterSpace.isActive() && 7081 "subroutine calls are not allowed inside WHERE and FORALL"); 7082 7083 if (isElementalProcWithArrayArgs(call)) { 7084 ArrayExprLowering::lowerElementalSubroutine(converter, symMap, stmtCtx, 7085 toEvExpr(call)); 7086 return {}; 7087 } 7088 // Simple subroutine call, with potential alternate return. 7089 auto res = Fortran::lower::createSomeExtendedExpression( 7090 loc, converter, toEvExpr(call), symMap, stmtCtx); 7091 return fir::getBase(res); 7092 } 7093 7094 template <typename A> 7095 fir::ArrayLoadOp genArrayLoad(mlir::Location loc, 7096 Fortran::lower::AbstractConverter &converter, 7097 fir::FirOpBuilder &builder, const A *x, 7098 Fortran::lower::SymMap &symMap, 7099 Fortran::lower::StatementContext &stmtCtx) { 7100 auto exv = ScalarExprLowering{loc, converter, symMap, stmtCtx}.gen(*x); 7101 mlir::Value addr = fir::getBase(exv); 7102 mlir::Value shapeOp = builder.createShape(loc, exv); 7103 mlir::Type arrTy = fir::dyn_cast_ptrOrBoxEleTy(addr.getType()); 7104 return builder.create<fir::ArrayLoadOp>(loc, arrTy, addr, shapeOp, 7105 /*slice=*/mlir::Value{}, 7106 fir::getTypeParams(exv)); 7107 } 7108 template <> 7109 fir::ArrayLoadOp 7110 genArrayLoad(mlir::Location loc, Fortran::lower::AbstractConverter &converter, 7111 fir::FirOpBuilder &builder, const Fortran::evaluate::ArrayRef *x, 7112 Fortran::lower::SymMap &symMap, 7113 Fortran::lower::StatementContext &stmtCtx) { 7114 if (x->base().IsSymbol()) 7115 return genArrayLoad(loc, converter, builder, &getLastSym(x->base()), symMap, 7116 stmtCtx); 7117 return genArrayLoad(loc, converter, builder, &x->base().GetComponent(), 7118 symMap, stmtCtx); 7119 } 7120 7121 void Fortran::lower::createArrayLoads( 7122 Fortran::lower::AbstractConverter &converter, 7123 Fortran::lower::ExplicitIterSpace &esp, Fortran::lower::SymMap &symMap) { 7124 std::size_t counter = esp.getCounter(); 7125 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 7126 mlir::Location loc = converter.getCurrentLocation(); 7127 Fortran::lower::StatementContext &stmtCtx = esp.stmtContext(); 7128 // Gen the fir.array_load ops. 7129 auto genLoad = [&](const auto *x) -> fir::ArrayLoadOp { 7130 return genArrayLoad(loc, converter, builder, x, symMap, stmtCtx); 7131 }; 7132 if (esp.lhsBases[counter].hasValue()) { 7133 auto &base = esp.lhsBases[counter].getValue(); 7134 auto load = std::visit(genLoad, base); 7135 esp.initialArgs.push_back(load); 7136 esp.resetInnerArgs(); 7137 esp.bindLoad(base, load); 7138 } 7139 for (const auto &base : esp.rhsBases[counter]) 7140 esp.bindLoad(base, std::visit(genLoad, base)); 7141 } 7142 7143 void Fortran::lower::createArrayMergeStores( 7144 Fortran::lower::AbstractConverter &converter, 7145 Fortran::lower::ExplicitIterSpace &esp) { 7146 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 7147 mlir::Location loc = converter.getCurrentLocation(); 7148 builder.setInsertionPointAfter(esp.getOuterLoop()); 7149 // Gen the fir.array_merge_store ops for all LHS arrays. 7150 for (auto i : llvm::enumerate(esp.getOuterLoop().getResults())) 7151 if (llvm::Optional<fir::ArrayLoadOp> ldOpt = esp.getLhsLoad(i.index())) { 7152 fir::ArrayLoadOp load = ldOpt.getValue(); 7153 builder.create<fir::ArrayMergeStoreOp>(loc, load, i.value(), 7154 load.getMemref(), load.getSlice(), 7155 load.getTypeparams()); 7156 } 7157 if (esp.loopCleanup.hasValue()) { 7158 esp.loopCleanup.getValue()(builder); 7159 esp.loopCleanup = llvm::None; 7160 } 7161 esp.initialArgs.clear(); 7162 esp.innerArgs.clear(); 7163 esp.outerLoop = llvm::None; 7164 esp.resetBindings(); 7165 esp.incrementCounter(); 7166 } 7167 7168 mlir::Value Fortran::lower::genMaxWithZero(fir::FirOpBuilder &builder, 7169 mlir::Location loc, 7170 mlir::Value value) { 7171 mlir::Value zero = builder.createIntegerConstant(loc, value.getType(), 0); 7172 if (mlir::Operation *definingOp = value.getDefiningOp()) 7173 if (auto cst = mlir::dyn_cast<mlir::arith::ConstantOp>(definingOp)) 7174 if (auto intAttr = cst.getValue().dyn_cast<mlir::IntegerAttr>()) 7175 return intAttr.getInt() < 0 ? zero : value; 7176 return Fortran::lower::genMax(builder, loc, 7177 llvm::SmallVector<mlir::Value>{value, zero}); 7178 } 7179