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