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