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/Evaluate/fold.h" 15 #include "flang/Evaluate/traverse.h" 16 #include "flang/Lower/AbstractConverter.h" 17 #include "flang/Lower/CallInterface.h" 18 #include "flang/Lower/ComponentPath.h" 19 #include "flang/Lower/ConvertType.h" 20 #include "flang/Lower/ConvertVariable.h" 21 #include "flang/Lower/DumpEvaluateExpr.h" 22 #include "flang/Lower/IntrinsicCall.h" 23 #include "flang/Lower/StatementContext.h" 24 #include "flang/Lower/SymbolMap.h" 25 #include "flang/Lower/Todo.h" 26 #include "flang/Optimizer/Builder/Complex.h" 27 #include "flang/Optimizer/Builder/Factory.h" 28 #include "flang/Optimizer/Builder/MutableBox.h" 29 #include "flang/Optimizer/Dialect/FIROpsSupport.h" 30 #include "flang/Semantics/expression.h" 31 #include "flang/Semantics/symbol.h" 32 #include "flang/Semantics/tools.h" 33 #include "flang/Semantics/type.h" 34 #include "mlir/Dialect/StandardOps/IR/Ops.h" 35 #include "llvm/Support/Debug.h" 36 37 #define DEBUG_TYPE "flang-lower-expr" 38 39 //===----------------------------------------------------------------------===// 40 // The composition and structure of Fortran::evaluate::Expr is defined in 41 // the various header files in include/flang/Evaluate. You are referred 42 // there for more information on these data structures. Generally speaking, 43 // these data structures are a strongly typed family of abstract data types 44 // that, composed as trees, describe the syntax of Fortran expressions. 45 // 46 // This part of the bridge can traverse these tree structures and lower them 47 // to the correct FIR representation in SSA form. 48 //===----------------------------------------------------------------------===// 49 50 /// The various semantics of a program constituent (or a part thereof) as it may 51 /// appear in an expression. 52 /// 53 /// Given the following Fortran declarations. 54 /// ```fortran 55 /// REAL :: v1, v2, v3 56 /// REAL, POINTER :: vp1 57 /// REAL :: a1(c), a2(c) 58 /// REAL ELEMENTAL FUNCTION f1(arg) ! array -> array 59 /// FUNCTION f2(arg) ! array -> array 60 /// vp1 => v3 ! 1 61 /// v1 = v2 * vp1 ! 2 62 /// a1 = a1 + a2 ! 3 63 /// a1 = f1(a2) ! 4 64 /// a1 = f2(a2) ! 5 65 /// ``` 66 /// 67 /// In line 1, `vp1` is a BoxAddr to copy a box value into. The box value is 68 /// constructed from the DataAddr of `v3`. 69 /// In line 2, `v1` is a DataAddr to copy a value into. The value is constructed 70 /// from the DataValue of `v2` and `vp1`. DataValue is implicitly a double 71 /// dereference in the `vp1` case. 72 /// In line 3, `a1` and `a2` on the rhs are RefTransparent. The `a1` on the lhs 73 /// is CopyInCopyOut as `a1` is replaced elementally by the additions. 74 /// In line 4, `a2` can be RefTransparent, ByValueArg, RefOpaque, or BoxAddr if 75 /// `arg` is declared as C-like pass-by-value, VALUE, INTENT(?), or ALLOCATABLE/ 76 /// POINTER, respectively. `a1` on the lhs is CopyInCopyOut. 77 /// In line 5, `a2` may be DataAddr or BoxAddr assuming f2 is transformational. 78 /// `a1` on the lhs is again CopyInCopyOut. 79 enum class ConstituentSemantics { 80 // Scalar data reference semantics. 81 // 82 // For these let `v` be the location in memory of a variable with value `x` 83 DataValue, // refers to the value `x` 84 DataAddr, // refers to the address `v` 85 BoxValue, // refers to a box value containing `v` 86 BoxAddr, // refers to the address of a box value containing `v` 87 88 // Array data reference semantics. 89 // 90 // For these let `a` be the location in memory of a sequence of value `[xs]`. 91 // Let `x_i` be the `i`-th value in the sequence `[xs]`. 92 93 // Referentially transparent. Refers to the array's value, `[xs]`. 94 RefTransparent, 95 // Refers to an ephemeral address `tmp` containing value `x_i` (15.5.2.3.p7 96 // note 2). (Passing a copy by reference to simulate pass-by-value.) 97 ByValueArg, 98 // Refers to the merge of array value `[xs]` with another array value `[ys]`. 99 // This merged array value will be written into memory location `a`. 100 CopyInCopyOut, 101 // Similar to CopyInCopyOut but `a` may be a transient projection (rather than 102 // a whole array). 103 ProjectedCopyInCopyOut, 104 // Similar to ProjectedCopyInCopyOut, except the merge value is not assigned 105 // automatically by the framework. Instead, and address for `[xs]` is made 106 // accessible so that custom assignments to `[xs]` can be implemented. 107 CustomCopyInCopyOut, 108 // Referentially opaque. Refers to the address of `x_i`. 109 RefOpaque 110 }; 111 112 /// Place \p exv in memory if it is not already a memory reference. If 113 /// \p forceValueType is provided, the value is first casted to the provided 114 /// type before being stored (this is mainly intended for logicals whose value 115 /// may be `i1` but needed to be stored as Fortran logicals). 116 static fir::ExtendedValue 117 placeScalarValueInMemory(fir::FirOpBuilder &builder, mlir::Location loc, 118 const fir::ExtendedValue &exv, 119 mlir::Type storageType) { 120 mlir::Value valBase = fir::getBase(exv); 121 if (fir::conformsWithPassByRef(valBase.getType())) 122 return exv; 123 124 assert(!fir::hasDynamicSize(storageType) && 125 "only expect statically sized scalars to be by value"); 126 127 // Since `a` is not itself a valid referent, determine its value and 128 // create a temporary location at the beginning of the function for 129 // referencing. 130 mlir::Value val = builder.createConvert(loc, storageType, valBase); 131 mlir::Value temp = builder.createTemporary( 132 loc, storageType, 133 llvm::ArrayRef<mlir::NamedAttribute>{ 134 Fortran::lower::getAdaptToByRefAttr(builder)}); 135 builder.create<fir::StoreOp>(loc, val, temp); 136 return fir::substBase(exv, temp); 137 } 138 139 /// Is this a variable wrapped in parentheses? 140 template <typename A> 141 static bool isParenthesizedVariable(const A &) { 142 return false; 143 } 144 template <typename T> 145 static bool isParenthesizedVariable(const Fortran::evaluate::Expr<T> &expr) { 146 using ExprVariant = decltype(Fortran::evaluate::Expr<T>::u); 147 using Parentheses = Fortran::evaluate::Parentheses<T>; 148 if constexpr (Fortran::common::HasMember<Parentheses, ExprVariant>) { 149 if (const auto *parentheses = std::get_if<Parentheses>(&expr.u)) 150 return Fortran::evaluate::IsVariable(parentheses->left()); 151 return false; 152 } else { 153 return std::visit([&](const auto &x) { return isParenthesizedVariable(x); }, 154 expr.u); 155 } 156 } 157 158 /// Generate a load of a value from an address. Beware that this will lose 159 /// any dynamic type information for polymorphic entities (note that unlimited 160 /// polymorphic cannot be loaded and must not be provided here). 161 static fir::ExtendedValue genLoad(fir::FirOpBuilder &builder, 162 mlir::Location loc, 163 const fir::ExtendedValue &addr) { 164 return addr.match( 165 [](const fir::CharBoxValue &box) -> fir::ExtendedValue { return box; }, 166 [&](const fir::UnboxedValue &v) -> fir::ExtendedValue { 167 if (fir::unwrapRefType(fir::getBase(v).getType()) 168 .isa<fir::RecordType>()) 169 return v; 170 return builder.create<fir::LoadOp>(loc, fir::getBase(v)); 171 }, 172 [&](const fir::MutableBoxValue &box) -> fir::ExtendedValue { 173 TODO(loc, "genLoad for MutableBoxValue"); 174 }, 175 [&](const fir::BoxValue &box) -> fir::ExtendedValue { 176 TODO(loc, "genLoad for BoxValue"); 177 }, 178 [&](const auto &) -> fir::ExtendedValue { 179 fir::emitFatalError( 180 loc, "attempting to load whole array or procedure address"); 181 }); 182 } 183 184 /// Is this a call to an elemental procedure with at least one array argument? 185 static bool 186 isElementalProcWithArrayArgs(const Fortran::evaluate::ProcedureRef &procRef) { 187 if (procRef.IsElemental()) 188 for (const std::optional<Fortran::evaluate::ActualArgument> &arg : 189 procRef.arguments()) 190 if (arg && arg->Rank() != 0) 191 return true; 192 return false; 193 } 194 template <typename T> 195 static bool isElementalProcWithArrayArgs(const Fortran::evaluate::Expr<T> &) { 196 return false; 197 } 198 template <> 199 bool isElementalProcWithArrayArgs(const Fortran::lower::SomeExpr &x) { 200 if (const auto *procRef = std::get_if<Fortran::evaluate::ProcedureRef>(&x.u)) 201 return isElementalProcWithArrayArgs(*procRef); 202 return false; 203 } 204 205 /// If \p arg is the address of a function with a denoted host-association tuple 206 /// argument, then return the host-associations tuple value of the current 207 /// procedure. Otherwise, return nullptr. 208 static mlir::Value 209 argumentHostAssocs(Fortran::lower::AbstractConverter &converter, 210 mlir::Value arg) { 211 if (auto addr = mlir::dyn_cast_or_null<fir::AddrOfOp>(arg.getDefiningOp())) { 212 auto &builder = converter.getFirOpBuilder(); 213 if (auto funcOp = builder.getNamedFunction(addr.getSymbol())) 214 if (fir::anyFuncArgsHaveAttr(funcOp, fir::getHostAssocAttrName())) 215 return converter.hostAssocTupleValue(); 216 } 217 return {}; 218 } 219 220 namespace { 221 222 /// Lowering of Fortran::evaluate::Expr<T> expressions 223 class ScalarExprLowering { 224 public: 225 using ExtValue = fir::ExtendedValue; 226 227 explicit ScalarExprLowering(mlir::Location loc, 228 Fortran::lower::AbstractConverter &converter, 229 Fortran::lower::SymMap &symMap, 230 Fortran::lower::StatementContext &stmtCtx) 231 : location{loc}, converter{converter}, 232 builder{converter.getFirOpBuilder()}, stmtCtx{stmtCtx}, symMap{symMap} { 233 } 234 235 ExtValue genExtAddr(const Fortran::lower::SomeExpr &expr) { 236 return gen(expr); 237 } 238 239 /// Lower `expr` to be passed as a fir.box argument. Do not create a temp 240 /// for the expr if it is a variable that can be described as a fir.box. 241 ExtValue genBoxArg(const Fortran::lower::SomeExpr &expr) { 242 bool saveUseBoxArg = useBoxArg; 243 useBoxArg = true; 244 ExtValue result = gen(expr); 245 useBoxArg = saveUseBoxArg; 246 return result; 247 } 248 249 ExtValue genExtValue(const Fortran::lower::SomeExpr &expr) { 250 return genval(expr); 251 } 252 253 /// Lower an expression that is a pointer or an allocatable to a 254 /// MutableBoxValue. 255 fir::MutableBoxValue 256 genMutableBoxValue(const Fortran::lower::SomeExpr &expr) { 257 // Pointers and allocatables can only be: 258 // - a simple designator "x" 259 // - a component designator "a%b(i,j)%x" 260 // - a function reference "foo()" 261 // - result of NULL() or NULL(MOLD) intrinsic. 262 // NULL() requires some context to be lowered, so it is not handled 263 // here and must be lowered according to the context where it appears. 264 ExtValue exv = std::visit( 265 [&](const auto &x) { return genMutableBoxValueImpl(x); }, expr.u); 266 const fir::MutableBoxValue *mutableBox = 267 exv.getBoxOf<fir::MutableBoxValue>(); 268 if (!mutableBox) 269 fir::emitFatalError(getLoc(), "expr was not lowered to MutableBoxValue"); 270 return *mutableBox; 271 } 272 273 template <typename T> 274 ExtValue genMutableBoxValueImpl(const T &) { 275 // NULL() case should not be handled here. 276 fir::emitFatalError(getLoc(), "NULL() must be lowered in its context"); 277 } 278 279 template <typename T> 280 ExtValue 281 genMutableBoxValueImpl(const Fortran::evaluate::FunctionRef<T> &funRef) { 282 return genRawProcedureRef(funRef, converter.genType(toEvExpr(funRef))); 283 } 284 285 template <typename T> 286 ExtValue 287 genMutableBoxValueImpl(const Fortran::evaluate::Designator<T> &designator) { 288 return std::visit( 289 Fortran::common::visitors{ 290 [&](const Fortran::evaluate::SymbolRef &sym) -> ExtValue { 291 return symMap.lookupSymbol(*sym).toExtendedValue(); 292 }, 293 [&](const Fortran::evaluate::Component &comp) -> ExtValue { 294 return genComponent(comp); 295 }, 296 [&](const auto &) -> ExtValue { 297 fir::emitFatalError(getLoc(), 298 "not an allocatable or pointer designator"); 299 }}, 300 designator.u); 301 } 302 303 template <typename T> 304 ExtValue genMutableBoxValueImpl(const Fortran::evaluate::Expr<T> &expr) { 305 return std::visit([&](const auto &x) { return genMutableBoxValueImpl(x); }, 306 expr.u); 307 } 308 309 mlir::Location getLoc() { return location; } 310 311 template <typename A> 312 mlir::Value genunbox(const A &expr) { 313 ExtValue e = genval(expr); 314 if (const fir::UnboxedValue *r = e.getUnboxed()) 315 return *r; 316 fir::emitFatalError(getLoc(), "unboxed expression expected"); 317 } 318 319 /// Generate an integral constant of `value` 320 template <int KIND> 321 mlir::Value genIntegerConstant(mlir::MLIRContext *context, 322 std::int64_t value) { 323 mlir::Type type = 324 converter.genType(Fortran::common::TypeCategory::Integer, KIND); 325 return builder.createIntegerConstant(getLoc(), type, value); 326 } 327 328 /// Generate a logical/boolean constant of `value` 329 mlir::Value genBoolConstant(bool value) { 330 return builder.createBool(getLoc(), value); 331 } 332 333 /// Generate a real constant with a value `value`. 334 template <int KIND> 335 mlir::Value genRealConstant(mlir::MLIRContext *context, 336 const llvm::APFloat &value) { 337 mlir::Type fltTy = Fortran::lower::convertReal(context, KIND); 338 return builder.createRealConstant(getLoc(), fltTy, value); 339 } 340 341 /// Returns a reference to a symbol or its box/boxChar descriptor if it has 342 /// one. 343 ExtValue gen(Fortran::semantics::SymbolRef sym) { 344 if (Fortran::lower::SymbolBox val = symMap.lookupSymbol(sym)) 345 return val.match([&val](auto &) { return val.toExtendedValue(); }); 346 LLVM_DEBUG(llvm::dbgs() 347 << "unknown symbol: " << sym << "\nmap: " << symMap << '\n'); 348 fir::emitFatalError(getLoc(), "symbol is not mapped to any IR value"); 349 } 350 351 ExtValue genLoad(const ExtValue &exv) { 352 return ::genLoad(builder, getLoc(), exv); 353 } 354 355 ExtValue genval(Fortran::semantics::SymbolRef sym) { 356 ExtValue var = gen(sym); 357 if (const fir::UnboxedValue *s = var.getUnboxed()) 358 if (fir::isReferenceLike(s->getType())) 359 return genLoad(*s); 360 return var; 361 } 362 363 ExtValue genval(const Fortran::evaluate::BOZLiteralConstant &) { 364 TODO(getLoc(), "genval BOZ"); 365 } 366 367 /// Return indirection to function designated in ProcedureDesignator. 368 /// The type of the function indirection is not guaranteed to match the one 369 /// of the ProcedureDesignator due to Fortran implicit typing rules. 370 ExtValue genval(const Fortran::evaluate::ProcedureDesignator &proc) { 371 TODO(getLoc(), "genval ProcedureDesignator"); 372 } 373 374 ExtValue genval(const Fortran::evaluate::NullPointer &) { 375 TODO(getLoc(), "genval NullPointer"); 376 } 377 378 ExtValue genval(const Fortran::evaluate::StructureConstructor &ctor) { 379 TODO(getLoc(), "genval StructureConstructor"); 380 } 381 382 /// Lowering of an <i>ac-do-variable</i>, which is not a Symbol. 383 ExtValue genval(const Fortran::evaluate::ImpliedDoIndex &var) { 384 TODO(getLoc(), "genval ImpliedDoIndex"); 385 } 386 387 ExtValue genval(const Fortran::evaluate::DescriptorInquiry &desc) { 388 TODO(getLoc(), "genval DescriptorInquiry"); 389 } 390 391 ExtValue genval(const Fortran::evaluate::TypeParamInquiry &) { 392 TODO(getLoc(), "genval TypeParamInquiry"); 393 } 394 395 template <int KIND> 396 ExtValue genval(const Fortran::evaluate::ComplexComponent<KIND> &part) { 397 TODO(getLoc(), "genval ComplexComponent"); 398 } 399 400 template <int KIND> 401 ExtValue genval(const Fortran::evaluate::Negate<Fortran::evaluate::Type< 402 Fortran::common::TypeCategory::Integer, KIND>> &op) { 403 mlir::Value input = genunbox(op.left()); 404 // Like LLVM, integer negation is the binary op "0 - value" 405 mlir::Value zero = genIntegerConstant<KIND>(builder.getContext(), 0); 406 return builder.create<mlir::arith::SubIOp>(getLoc(), zero, input); 407 } 408 409 template <int KIND> 410 ExtValue genval(const Fortran::evaluate::Negate<Fortran::evaluate::Type< 411 Fortran::common::TypeCategory::Real, KIND>> &op) { 412 return builder.create<mlir::arith::NegFOp>(getLoc(), genunbox(op.left())); 413 } 414 template <int KIND> 415 ExtValue genval(const Fortran::evaluate::Negate<Fortran::evaluate::Type< 416 Fortran::common::TypeCategory::Complex, KIND>> &op) { 417 return builder.create<fir::NegcOp>(getLoc(), genunbox(op.left())); 418 } 419 420 template <typename OpTy> 421 mlir::Value createBinaryOp(const ExtValue &left, const ExtValue &right) { 422 assert(fir::isUnboxedValue(left) && fir::isUnboxedValue(right)); 423 mlir::Value lhs = fir::getBase(left); 424 mlir::Value rhs = fir::getBase(right); 425 assert(lhs.getType() == rhs.getType() && "types must be the same"); 426 return builder.create<OpTy>(getLoc(), lhs, rhs); 427 } 428 429 template <typename OpTy, typename A> 430 mlir::Value createBinaryOp(const A &ex) { 431 ExtValue left = genval(ex.left()); 432 return createBinaryOp<OpTy>(left, genval(ex.right())); 433 } 434 435 #undef GENBIN 436 #define GENBIN(GenBinEvOp, GenBinTyCat, GenBinFirOp) \ 437 template <int KIND> \ 438 ExtValue genval(const Fortran::evaluate::GenBinEvOp<Fortran::evaluate::Type< \ 439 Fortran::common::TypeCategory::GenBinTyCat, KIND>> &x) { \ 440 return createBinaryOp<GenBinFirOp>(x); \ 441 } 442 443 GENBIN(Add, Integer, mlir::arith::AddIOp) 444 GENBIN(Add, Real, mlir::arith::AddFOp) 445 GENBIN(Add, Complex, fir::AddcOp) 446 GENBIN(Subtract, Integer, mlir::arith::SubIOp) 447 GENBIN(Subtract, Real, mlir::arith::SubFOp) 448 GENBIN(Subtract, Complex, fir::SubcOp) 449 GENBIN(Multiply, Integer, mlir::arith::MulIOp) 450 GENBIN(Multiply, Real, mlir::arith::MulFOp) 451 GENBIN(Multiply, Complex, fir::MulcOp) 452 GENBIN(Divide, Integer, mlir::arith::DivSIOp) 453 GENBIN(Divide, Real, mlir::arith::DivFOp) 454 GENBIN(Divide, Complex, fir::DivcOp) 455 456 template <Fortran::common::TypeCategory TC, int KIND> 457 ExtValue genval( 458 const Fortran::evaluate::Power<Fortran::evaluate::Type<TC, KIND>> &op) { 459 TODO(getLoc(), "genval Power"); 460 } 461 462 template <Fortran::common::TypeCategory TC, int KIND> 463 ExtValue genval( 464 const Fortran::evaluate::RealToIntPower<Fortran::evaluate::Type<TC, KIND>> 465 &op) { 466 TODO(getLoc(), "genval RealToInt"); 467 } 468 469 template <int KIND> 470 ExtValue genval(const Fortran::evaluate::ComplexConstructor<KIND> &op) { 471 mlir::Value realPartValue = genunbox(op.left()); 472 return fir::factory::Complex{builder, getLoc()}.createComplex( 473 KIND, realPartValue, genunbox(op.right())); 474 } 475 476 template <int KIND> 477 ExtValue genval(const Fortran::evaluate::Concat<KIND> &op) { 478 TODO(getLoc(), "genval Concat<KIND>"); 479 } 480 481 /// MIN and MAX operations 482 template <Fortran::common::TypeCategory TC, int KIND> 483 ExtValue 484 genval(const Fortran::evaluate::Extremum<Fortran::evaluate::Type<TC, KIND>> 485 &op) { 486 TODO(getLoc(), "genval Extremum<TC, KIND>"); 487 } 488 489 template <int KIND> 490 ExtValue genval(const Fortran::evaluate::SetLength<KIND> &x) { 491 TODO(getLoc(), "genval SetLength<KIND>"); 492 } 493 494 template <int KIND> 495 ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type< 496 Fortran::common::TypeCategory::Integer, KIND>> &op) { 497 TODO(getLoc(), "genval integer comparison"); 498 } 499 template <int KIND> 500 ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type< 501 Fortran::common::TypeCategory::Real, KIND>> &op) { 502 TODO(getLoc(), "genval real comparison"); 503 } 504 template <int KIND> 505 ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type< 506 Fortran::common::TypeCategory::Complex, KIND>> &op) { 507 TODO(getLoc(), "genval complex comparison"); 508 } 509 template <int KIND> 510 ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type< 511 Fortran::common::TypeCategory::Character, KIND>> &op) { 512 TODO(getLoc(), "genval char comparison"); 513 } 514 515 ExtValue 516 genval(const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &op) { 517 TODO(getLoc(), "genval comparison"); 518 } 519 520 template <Fortran::common::TypeCategory TC1, int KIND, 521 Fortran::common::TypeCategory TC2> 522 ExtValue 523 genval(const Fortran::evaluate::Convert<Fortran::evaluate::Type<TC1, KIND>, 524 TC2> &convert) { 525 mlir::Type ty = converter.genType(TC1, KIND); 526 mlir::Value operand = genunbox(convert.left()); 527 return builder.convertWithSemantics(getLoc(), ty, operand); 528 } 529 530 template <typename A> 531 ExtValue genval(const Fortran::evaluate::Parentheses<A> &op) { 532 TODO(getLoc(), "genval parentheses<A>"); 533 } 534 535 template <int KIND> 536 ExtValue genval(const Fortran::evaluate::Not<KIND> &op) { 537 TODO(getLoc(), "genval Not<KIND>"); 538 } 539 540 template <int KIND> 541 ExtValue genval(const Fortran::evaluate::LogicalOperation<KIND> &op) { 542 TODO(getLoc(), "genval LogicalOperation<KIND>"); 543 } 544 545 /// Convert a scalar literal constant to IR. 546 template <Fortran::common::TypeCategory TC, int KIND> 547 ExtValue genScalarLit( 548 const Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>> 549 &value) { 550 if constexpr (TC == Fortran::common::TypeCategory::Integer) { 551 return genIntegerConstant<KIND>(builder.getContext(), value.ToInt64()); 552 } else if constexpr (TC == Fortran::common::TypeCategory::Logical) { 553 return genBoolConstant(value.IsTrue()); 554 } else if constexpr (TC == Fortran::common::TypeCategory::Real) { 555 std::string str = value.DumpHexadecimal(); 556 if constexpr (KIND == 2) { 557 llvm::APFloat floatVal{llvm::APFloatBase::IEEEhalf(), str}; 558 return genRealConstant<KIND>(builder.getContext(), floatVal); 559 } else if constexpr (KIND == 3) { 560 llvm::APFloat floatVal{llvm::APFloatBase::BFloat(), str}; 561 return genRealConstant<KIND>(builder.getContext(), floatVal); 562 } else if constexpr (KIND == 4) { 563 llvm::APFloat floatVal{llvm::APFloatBase::IEEEsingle(), str}; 564 return genRealConstant<KIND>(builder.getContext(), floatVal); 565 } else if constexpr (KIND == 10) { 566 llvm::APFloat floatVal{llvm::APFloatBase::x87DoubleExtended(), str}; 567 return genRealConstant<KIND>(builder.getContext(), floatVal); 568 } else if constexpr (KIND == 16) { 569 llvm::APFloat floatVal{llvm::APFloatBase::IEEEquad(), str}; 570 return genRealConstant<KIND>(builder.getContext(), floatVal); 571 } else { 572 // convert everything else to double 573 llvm::APFloat floatVal{llvm::APFloatBase::IEEEdouble(), str}; 574 return genRealConstant<KIND>(builder.getContext(), floatVal); 575 } 576 } else if constexpr (TC == Fortran::common::TypeCategory::Complex) { 577 using TR = 578 Fortran::evaluate::Type<Fortran::common::TypeCategory::Real, KIND>; 579 Fortran::evaluate::ComplexConstructor<KIND> ctor( 580 Fortran::evaluate::Expr<TR>{ 581 Fortran::evaluate::Constant<TR>{value.REAL()}}, 582 Fortran::evaluate::Expr<TR>{ 583 Fortran::evaluate::Constant<TR>{value.AIMAG()}}); 584 return genunbox(ctor); 585 } else /*constexpr*/ { 586 llvm_unreachable("unhandled constant"); 587 } 588 } 589 590 /// Convert a ascii scalar literal CHARACTER to IR. (specialization) 591 ExtValue 592 genAsciiScalarLit(const Fortran::evaluate::Scalar<Fortran::evaluate::Type< 593 Fortran::common::TypeCategory::Character, 1>> &value, 594 int64_t len) { 595 assert(value.size() == static_cast<std::uint64_t>(len) && 596 "value.size() doesn't match with len"); 597 return fir::factory::createStringLiteral(builder, getLoc(), value); 598 } 599 600 template <Fortran::common::TypeCategory TC, int KIND> 601 ExtValue 602 genval(const Fortran::evaluate::Constant<Fortran::evaluate::Type<TC, KIND>> 603 &con) { 604 if (con.Rank() > 0) 605 TODO(getLoc(), "genval array constant"); 606 std::optional<Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>>> 607 opt = con.GetScalarValue(); 608 assert(opt.has_value() && "constant has no value"); 609 if constexpr (TC == Fortran::common::TypeCategory::Character) { 610 if constexpr (KIND == 1) 611 return genAsciiScalarLit(opt.value(), con.LEN()); 612 TODO(getLoc(), "genval for Character with KIND != 1"); 613 } else { 614 return genScalarLit<TC, KIND>(opt.value()); 615 } 616 } 617 618 fir::ExtendedValue genval( 619 const Fortran::evaluate::Constant<Fortran::evaluate::SomeDerived> &con) { 620 TODO(getLoc(), "genval constant derived"); 621 } 622 623 template <typename A> 624 ExtValue genval(const Fortran::evaluate::ArrayConstructor<A> &) { 625 TODO(getLoc(), "genval ArrayConstructor<A>"); 626 } 627 628 ExtValue gen(const Fortran::evaluate::ComplexPart &x) { 629 TODO(getLoc(), "gen ComplexPart"); 630 } 631 ExtValue genval(const Fortran::evaluate::ComplexPart &x) { 632 TODO(getLoc(), "genval ComplexPart"); 633 } 634 635 ExtValue gen(const Fortran::evaluate::Substring &s) { 636 TODO(getLoc(), "gen Substring"); 637 } 638 ExtValue genval(const Fortran::evaluate::Substring &ss) { 639 TODO(getLoc(), "genval Substring"); 640 } 641 642 ExtValue genval(const Fortran::evaluate::Subscript &subs) { 643 if (auto *s = std::get_if<Fortran::evaluate::IndirectSubscriptIntegerExpr>( 644 &subs.u)) { 645 if (s->value().Rank() > 0) 646 fir::emitFatalError(getLoc(), "vector subscript is not scalar"); 647 return {genval(s->value())}; 648 } 649 fir::emitFatalError(getLoc(), "subscript triple notation is not scalar"); 650 } 651 652 ExtValue genSubscript(const Fortran::evaluate::Subscript &subs) { 653 return genval(subs); 654 } 655 656 ExtValue gen(const Fortran::evaluate::DataRef &dref) { 657 TODO(getLoc(), "gen DataRef"); 658 } 659 ExtValue genval(const Fortran::evaluate::DataRef &dref) { 660 TODO(getLoc(), "genval DataRef"); 661 } 662 663 // Helper function to turn the Component structure into a list of nested 664 // components, ordered from largest/leftmost to smallest/rightmost: 665 // - where only the smallest/rightmost item may be allocatable or a pointer 666 // (nested allocatable/pointer components require nested coordinate_of ops) 667 // - that does not contain any parent components 668 // (the front end places parent components directly in the object) 669 // Return the object used as the base coordinate for the component chain. 670 static Fortran::evaluate::DataRef const * 671 reverseComponents(const Fortran::evaluate::Component &cmpt, 672 std::list<const Fortran::evaluate::Component *> &list) { 673 if (!cmpt.GetLastSymbol().test( 674 Fortran::semantics::Symbol::Flag::ParentComp)) 675 list.push_front(&cmpt); 676 return std::visit( 677 Fortran::common::visitors{ 678 [&](const Fortran::evaluate::Component &x) { 679 if (Fortran::semantics::IsAllocatableOrPointer(x.GetLastSymbol())) 680 return &cmpt.base(); 681 return reverseComponents(x, list); 682 }, 683 [&](auto &) { return &cmpt.base(); }, 684 }, 685 cmpt.base().u); 686 } 687 688 // Return the coordinate of the component reference 689 ExtValue genComponent(const Fortran::evaluate::Component &cmpt) { 690 std::list<const Fortran::evaluate::Component *> list; 691 const Fortran::evaluate::DataRef *base = reverseComponents(cmpt, list); 692 llvm::SmallVector<mlir::Value> coorArgs; 693 ExtValue obj = gen(*base); 694 mlir::Type ty = fir::dyn_cast_ptrOrBoxEleTy(fir::getBase(obj).getType()); 695 mlir::Location loc = getLoc(); 696 auto fldTy = fir::FieldType::get(&converter.getMLIRContext()); 697 // FIXME: need to thread the LEN type parameters here. 698 for (const Fortran::evaluate::Component *field : list) { 699 auto recTy = ty.cast<fir::RecordType>(); 700 const Fortran::semantics::Symbol &sym = field->GetLastSymbol(); 701 llvm::StringRef name = toStringRef(sym.name()); 702 coorArgs.push_back(builder.create<fir::FieldIndexOp>( 703 loc, fldTy, name, recTy, fir::getTypeParams(obj))); 704 ty = recTy.getType(name); 705 } 706 ty = builder.getRefType(ty); 707 return fir::factory::componentToExtendedValue( 708 builder, loc, 709 builder.create<fir::CoordinateOp>(loc, ty, fir::getBase(obj), 710 coorArgs)); 711 } 712 713 ExtValue gen(const Fortran::evaluate::Component &cmpt) { 714 TODO(getLoc(), "gen Component"); 715 } 716 ExtValue genval(const Fortran::evaluate::Component &cmpt) { 717 TODO(getLoc(), "genval Component"); 718 } 719 720 ExtValue genval(const Fortran::semantics::Bound &bound) { 721 TODO(getLoc(), "genval Bound"); 722 } 723 724 /// Return lower bounds of \p box in dimension \p dim. The returned value 725 /// has type \ty. 726 mlir::Value getLBound(const ExtValue &box, unsigned dim, mlir::Type ty) { 727 assert(box.rank() > 0 && "must be an array"); 728 mlir::Location loc = getLoc(); 729 mlir::Value one = builder.createIntegerConstant(loc, ty, 1); 730 mlir::Value lb = fir::factory::readLowerBound(builder, loc, box, dim, one); 731 return builder.createConvert(loc, ty, lb); 732 } 733 734 /// Lower an ArrayRef to a fir.coordinate_of given its lowered base. 735 ExtValue genCoordinateOp(const ExtValue &array, 736 const Fortran::evaluate::ArrayRef &aref) { 737 mlir::Location loc = getLoc(); 738 // References to array of rank > 1 with non constant shape that are not 739 // fir.box must be collapsed into an offset computation in lowering already. 740 // The same is needed with dynamic length character arrays of all ranks. 741 mlir::Type baseType = 742 fir::dyn_cast_ptrOrBoxEleTy(fir::getBase(array).getType()); 743 if ((array.rank() > 1 && fir::hasDynamicSize(baseType)) || 744 fir::characterWithDynamicLen(fir::unwrapSequenceType(baseType))) 745 if (!array.getBoxOf<fir::BoxValue>()) 746 TODO(getLoc(), "genOffsetAndCoordinateOp"); 747 // Generate a fir.coordinate_of with zero based array indexes. 748 llvm::SmallVector<mlir::Value> args; 749 for (const auto &subsc : llvm::enumerate(aref.subscript())) { 750 ExtValue subVal = genSubscript(subsc.value()); 751 assert(fir::isUnboxedValue(subVal) && "subscript must be simple scalar"); 752 mlir::Value val = fir::getBase(subVal); 753 mlir::Type ty = val.getType(); 754 mlir::Value lb = getLBound(array, subsc.index(), ty); 755 args.push_back(builder.create<mlir::arith::SubIOp>(loc, ty, val, lb)); 756 } 757 758 mlir::Value base = fir::getBase(array); 759 auto seqTy = 760 fir::dyn_cast_ptrOrBoxEleTy(base.getType()).cast<fir::SequenceType>(); 761 assert(args.size() == seqTy.getDimension()); 762 mlir::Type ty = builder.getRefType(seqTy.getEleTy()); 763 auto addr = builder.create<fir::CoordinateOp>(loc, ty, base, args); 764 return fir::factory::arrayElementToExtendedValue(builder, loc, array, addr); 765 } 766 767 ExtValue gen(const Fortran::evaluate::ArrayRef &aref) { 768 ExtValue base = aref.base().IsSymbol() ? gen(aref.base().GetFirstSymbol()) 769 : gen(aref.base().GetComponent()); 770 return genCoordinateOp(base, aref); 771 } 772 ExtValue genval(const Fortran::evaluate::ArrayRef &aref) { 773 TODO(getLoc(), "genval ArrayRef"); 774 } 775 776 ExtValue gen(const Fortran::evaluate::CoarrayRef &coref) { 777 TODO(getLoc(), "gen CoarrayRef"); 778 } 779 ExtValue genval(const Fortran::evaluate::CoarrayRef &coref) { 780 TODO(getLoc(), "genval CoarrayRef"); 781 } 782 783 template <typename A> 784 ExtValue gen(const Fortran::evaluate::Designator<A> &des) { 785 return std::visit([&](const auto &x) { return gen(x); }, des.u); 786 } 787 template <typename A> 788 ExtValue genval(const Fortran::evaluate::Designator<A> &des) { 789 return std::visit([&](const auto &x) { return genval(x); }, des.u); 790 } 791 792 mlir::Type genType(const Fortran::evaluate::DynamicType &dt) { 793 if (dt.category() != Fortran::common::TypeCategory::Derived) 794 return converter.genType(dt.category(), dt.kind()); 795 TODO(getLoc(), "genType Derived Type"); 796 } 797 798 /// Lower a function reference 799 template <typename A> 800 ExtValue genFunctionRef(const Fortran::evaluate::FunctionRef<A> &funcRef) { 801 if (!funcRef.GetType().has_value()) 802 fir::emitFatalError(getLoc(), "internal: a function must have a type"); 803 mlir::Type resTy = genType(*funcRef.GetType()); 804 return genProcedureRef(funcRef, {resTy}); 805 } 806 807 /// Lower function call `funcRef` and return a reference to the resultant 808 /// value. This is required for lowering expressions such as `f1(f2(v))`. 809 template <typename A> 810 ExtValue gen(const Fortran::evaluate::FunctionRef<A> &funcRef) { 811 TODO(getLoc(), "gen FunctionRef<A>"); 812 } 813 814 /// helper to detect statement functions 815 static bool 816 isStatementFunctionCall(const Fortran::evaluate::ProcedureRef &procRef) { 817 if (const Fortran::semantics::Symbol *symbol = procRef.proc().GetSymbol()) 818 if (const auto *details = 819 symbol->detailsIf<Fortran::semantics::SubprogramDetails>()) 820 return details->stmtFunction().has_value(); 821 return false; 822 } 823 824 /// Helper to package a Value and its properties into an ExtendedValue. 825 static ExtValue toExtendedValue(mlir::Location loc, mlir::Value base, 826 llvm::ArrayRef<mlir::Value> extents, 827 llvm::ArrayRef<mlir::Value> lengths) { 828 mlir::Type type = base.getType(); 829 if (type.isa<fir::BoxType>()) 830 return fir::BoxValue(base, /*lbounds=*/{}, lengths, extents); 831 type = fir::unwrapRefType(type); 832 if (type.isa<fir::BoxType>()) 833 return fir::MutableBoxValue(base, lengths, /*mutableProperties*/ {}); 834 if (auto seqTy = type.dyn_cast<fir::SequenceType>()) { 835 if (seqTy.getDimension() != extents.size()) 836 fir::emitFatalError(loc, "incorrect number of extents for array"); 837 if (seqTy.getEleTy().isa<fir::CharacterType>()) { 838 if (lengths.empty()) 839 fir::emitFatalError(loc, "missing length for character"); 840 assert(lengths.size() == 1); 841 return fir::CharArrayBoxValue(base, lengths[0], extents); 842 } 843 return fir::ArrayBoxValue(base, extents); 844 } 845 if (type.isa<fir::CharacterType>()) { 846 if (lengths.empty()) 847 fir::emitFatalError(loc, "missing length for character"); 848 assert(lengths.size() == 1); 849 return fir::CharBoxValue(base, lengths[0]); 850 } 851 return base; 852 } 853 854 // Find the argument that corresponds to the host associations. 855 // Verify some assumptions about how the signature was built here. 856 [[maybe_unused]] static unsigned findHostAssocTuplePos(mlir::FuncOp fn) { 857 // Scan the argument list from last to first as the host associations are 858 // appended for now. 859 for (unsigned i = fn.getNumArguments(); i > 0; --i) 860 if (fn.getArgAttr(i - 1, fir::getHostAssocAttrName())) { 861 // Host assoc tuple must be last argument (for now). 862 assert(i == fn.getNumArguments() && "tuple must be last"); 863 return i - 1; 864 } 865 llvm_unreachable("anyFuncArgsHaveAttr failed"); 866 } 867 868 /// Lower a non-elemental procedure reference and read allocatable and pointer 869 /// results into normal values. 870 ExtValue genProcedureRef(const Fortran::evaluate::ProcedureRef &procRef, 871 llvm::Optional<mlir::Type> resultType) { 872 ExtValue res = genRawProcedureRef(procRef, resultType); 873 return res; 874 } 875 876 /// Given a call site for which the arguments were already lowered, generate 877 /// the call and return the result. This function deals with explicit result 878 /// allocation and lowering if needed. It also deals with passing the host 879 /// link to internal procedures. 880 ExtValue genCallOpAndResult(Fortran::lower::CallerInterface &caller, 881 mlir::FunctionType callSiteType, 882 llvm::Optional<mlir::Type> resultType) { 883 mlir::Location loc = getLoc(); 884 using PassBy = Fortran::lower::CallerInterface::PassEntityBy; 885 // Handle cases where caller must allocate the result or a fir.box for it. 886 bool mustPopSymMap = false; 887 if (caller.mustMapInterfaceSymbols()) { 888 symMap.pushScope(); 889 mustPopSymMap = true; 890 Fortran::lower::mapCallInterfaceSymbols(converter, caller, symMap); 891 } 892 // If this is an indirect call, retrieve the function address. Also retrieve 893 // the result length if this is a character function (note that this length 894 // will be used only if there is no explicit length in the local interface). 895 mlir::Value funcPointer; 896 mlir::Value charFuncPointerLength; 897 if (caller.getIfIndirectCallSymbol()) { 898 TODO(loc, "genCallOpAndResult indirect call"); 899 } 900 901 mlir::IndexType idxTy = builder.getIndexType(); 902 auto lowerSpecExpr = [&](const auto &expr) -> mlir::Value { 903 return builder.createConvert( 904 loc, idxTy, fir::getBase(converter.genExprValue(expr, stmtCtx))); 905 }; 906 llvm::SmallVector<mlir::Value> resultLengths; 907 auto allocatedResult = [&]() -> llvm::Optional<ExtValue> { 908 llvm::SmallVector<mlir::Value> extents; 909 llvm::SmallVector<mlir::Value> lengths; 910 if (!caller.callerAllocateResult()) 911 return {}; 912 mlir::Type type = caller.getResultStorageType(); 913 if (type.isa<fir::SequenceType>()) 914 caller.walkResultExtents([&](const Fortran::lower::SomeExpr &e) { 915 extents.emplace_back(lowerSpecExpr(e)); 916 }); 917 caller.walkResultLengths([&](const Fortran::lower::SomeExpr &e) { 918 lengths.emplace_back(lowerSpecExpr(e)); 919 }); 920 921 // Result length parameters should not be provided to box storage 922 // allocation and save_results, but they are still useful information to 923 // keep in the ExtendedValue if non-deferred. 924 if (!type.isa<fir::BoxType>()) { 925 if (fir::isa_char(fir::unwrapSequenceType(type)) && lengths.empty()) { 926 // Calling an assumed length function. This is only possible if this 927 // is a call to a character dummy procedure. 928 if (!charFuncPointerLength) 929 fir::emitFatalError(loc, "failed to retrieve character function " 930 "length while calling it"); 931 lengths.push_back(charFuncPointerLength); 932 } 933 resultLengths = lengths; 934 } 935 936 if (!extents.empty() || !lengths.empty()) { 937 TODO(loc, "genCallOpResult extents and length"); 938 } 939 mlir::Value temp = 940 builder.createTemporary(loc, type, ".result", extents, resultLengths); 941 return toExtendedValue(loc, temp, extents, lengths); 942 }(); 943 944 if (mustPopSymMap) 945 symMap.popScope(); 946 947 // Place allocated result or prepare the fir.save_result arguments. 948 mlir::Value arrayResultShape; 949 if (allocatedResult) { 950 if (std::optional<Fortran::lower::CallInterface< 951 Fortran::lower::CallerInterface>::PassedEntity> 952 resultArg = caller.getPassedResult()) { 953 if (resultArg->passBy == PassBy::AddressAndLength) 954 caller.placeAddressAndLengthInput(*resultArg, 955 fir::getBase(*allocatedResult), 956 fir::getLen(*allocatedResult)); 957 else if (resultArg->passBy == PassBy::BaseAddress) 958 caller.placeInput(*resultArg, fir::getBase(*allocatedResult)); 959 else 960 fir::emitFatalError( 961 loc, "only expect character scalar result to be passed by ref"); 962 } else { 963 assert(caller.mustSaveResult()); 964 arrayResultShape = allocatedResult->match( 965 [&](const fir::CharArrayBoxValue &) { 966 return builder.createShape(loc, *allocatedResult); 967 }, 968 [&](const fir::ArrayBoxValue &) { 969 return builder.createShape(loc, *allocatedResult); 970 }, 971 [&](const auto &) { return mlir::Value{}; }); 972 } 973 } 974 975 // In older Fortran, procedure argument types are inferred. This may lead 976 // different view of what the function signature is in different locations. 977 // Casts are inserted as needed below to accommodate this. 978 979 // The mlir::FuncOp type prevails, unless it has a different number of 980 // arguments which can happen in legal program if it was passed as a dummy 981 // procedure argument earlier with no further type information. 982 mlir::SymbolRefAttr funcSymbolAttr; 983 bool addHostAssociations = false; 984 if (!funcPointer) { 985 mlir::FunctionType funcOpType = caller.getFuncOp().getType(); 986 mlir::SymbolRefAttr symbolAttr = 987 builder.getSymbolRefAttr(caller.getMangledName()); 988 if (callSiteType.getNumResults() == funcOpType.getNumResults() && 989 callSiteType.getNumInputs() + 1 == funcOpType.getNumInputs() && 990 fir::anyFuncArgsHaveAttr(caller.getFuncOp(), 991 fir::getHostAssocAttrName())) { 992 // The number of arguments is off by one, and we're lowering a function 993 // with host associations. Modify call to include host associations 994 // argument by appending the value at the end of the operands. 995 assert(funcOpType.getInput(findHostAssocTuplePos(caller.getFuncOp())) == 996 converter.hostAssocTupleValue().getType()); 997 addHostAssociations = true; 998 } 999 if (!addHostAssociations && 1000 (callSiteType.getNumResults() != funcOpType.getNumResults() || 1001 callSiteType.getNumInputs() != funcOpType.getNumInputs())) { 1002 // Deal with argument number mismatch by making a function pointer so 1003 // that function type cast can be inserted. Do not emit a warning here 1004 // because this can happen in legal program if the function is not 1005 // defined here and it was first passed as an argument without any more 1006 // information. 1007 funcPointer = 1008 builder.create<fir::AddrOfOp>(loc, funcOpType, symbolAttr); 1009 } else if (callSiteType.getResults() != funcOpType.getResults()) { 1010 // Implicit interface result type mismatch are not standard Fortran, but 1011 // some compilers are not complaining about it. The front end is not 1012 // protecting lowering from this currently. Support this with a 1013 // discouraging warning. 1014 LLVM_DEBUG(mlir::emitWarning( 1015 loc, "a return type mismatch is not standard compliant and may " 1016 "lead to undefined behavior.")); 1017 // Cast the actual function to the current caller implicit type because 1018 // that is the behavior we would get if we could not see the definition. 1019 funcPointer = 1020 builder.create<fir::AddrOfOp>(loc, funcOpType, symbolAttr); 1021 } else { 1022 funcSymbolAttr = symbolAttr; 1023 } 1024 } 1025 1026 mlir::FunctionType funcType = 1027 funcPointer ? callSiteType : caller.getFuncOp().getType(); 1028 llvm::SmallVector<mlir::Value> operands; 1029 // First operand of indirect call is the function pointer. Cast it to 1030 // required function type for the call to handle procedures that have a 1031 // compatible interface in Fortran, but that have different signatures in 1032 // FIR. 1033 if (funcPointer) { 1034 operands.push_back( 1035 funcPointer.getType().isa<fir::BoxProcType>() 1036 ? builder.create<fir::BoxAddrOp>(loc, funcType, funcPointer) 1037 : builder.createConvert(loc, funcType, funcPointer)); 1038 } 1039 1040 // Deal with potential mismatches in arguments types. Passing an array to a 1041 // scalar argument should for instance be tolerated here. 1042 bool callingImplicitInterface = caller.canBeCalledViaImplicitInterface(); 1043 for (auto [fst, snd] : 1044 llvm::zip(caller.getInputs(), funcType.getInputs())) { 1045 // When passing arguments to a procedure that can be called an implicit 1046 // interface, allow character actual arguments to be passed to dummy 1047 // arguments of any type and vice versa 1048 mlir::Value cast; 1049 auto *context = builder.getContext(); 1050 if (snd.isa<fir::BoxProcType>() && 1051 fst.getType().isa<mlir::FunctionType>()) { 1052 auto funcTy = mlir::FunctionType::get(context, llvm::None, llvm::None); 1053 auto boxProcTy = builder.getBoxProcType(funcTy); 1054 if (mlir::Value host = argumentHostAssocs(converter, fst)) { 1055 cast = builder.create<fir::EmboxProcOp>( 1056 loc, boxProcTy, llvm::ArrayRef<mlir::Value>{fst, host}); 1057 } else { 1058 cast = builder.create<fir::EmboxProcOp>(loc, boxProcTy, fst); 1059 } 1060 } else { 1061 cast = builder.convertWithSemantics(loc, snd, fst, 1062 callingImplicitInterface); 1063 } 1064 operands.push_back(cast); 1065 } 1066 1067 // Add host associations as necessary. 1068 if (addHostAssociations) 1069 operands.push_back(converter.hostAssocTupleValue()); 1070 1071 auto call = builder.create<fir::CallOp>(loc, funcType.getResults(), 1072 funcSymbolAttr, operands); 1073 1074 if (caller.mustSaveResult()) 1075 builder.create<fir::SaveResultOp>( 1076 loc, call.getResult(0), fir::getBase(allocatedResult.getValue()), 1077 arrayResultShape, resultLengths); 1078 1079 if (allocatedResult) { 1080 allocatedResult->match( 1081 [&](const fir::MutableBoxValue &box) { 1082 if (box.isAllocatable()) { 1083 TODO(loc, "allocatedResult for allocatable"); 1084 } 1085 }, 1086 [](const auto &) {}); 1087 return *allocatedResult; 1088 } 1089 1090 if (!resultType.hasValue()) 1091 return mlir::Value{}; // subroutine call 1092 // For now, Fortran return values are implemented with a single MLIR 1093 // function return value. 1094 assert(call.getNumResults() == 1 && 1095 "Expected exactly one result in FUNCTION call"); 1096 return call.getResult(0); 1097 } 1098 1099 /// Like genExtAddr, but ensure the address returned is a temporary even if \p 1100 /// expr is variable inside parentheses. 1101 ExtValue genTempExtAddr(const Fortran::lower::SomeExpr &expr) { 1102 // In general, genExtAddr might not create a temp for variable inside 1103 // parentheses to avoid creating array temporary in sub-expressions. It only 1104 // ensures the sub-expression is not re-associated with other parts of the 1105 // expression. In the call semantics, there is a difference between expr and 1106 // variable (see R1524). For expressions, a variable storage must not be 1107 // argument associated since it could be modified inside the call, or the 1108 // variable could also be modified by other means during the call. 1109 if (!isParenthesizedVariable(expr)) 1110 return genExtAddr(expr); 1111 mlir::Location loc = getLoc(); 1112 if (expr.Rank() > 0) 1113 TODO(loc, "genTempExtAddr array"); 1114 return genExtValue(expr).match( 1115 [&](const fir::CharBoxValue &boxChar) -> ExtValue { 1116 TODO(loc, "genTempExtAddr CharBoxValue"); 1117 }, 1118 [&](const fir::UnboxedValue &v) -> ExtValue { 1119 mlir::Type type = v.getType(); 1120 mlir::Value value = v; 1121 if (fir::isa_ref_type(type)) 1122 value = builder.create<fir::LoadOp>(loc, value); 1123 mlir::Value temp = builder.createTemporary(loc, value.getType()); 1124 builder.create<fir::StoreOp>(loc, value, temp); 1125 return temp; 1126 }, 1127 [&](const fir::BoxValue &x) -> ExtValue { 1128 // Derived type scalar that may be polymorphic. 1129 assert(!x.hasRank() && x.isDerived()); 1130 if (x.isDerivedWithLengthParameters()) 1131 fir::emitFatalError( 1132 loc, "making temps for derived type with length parameters"); 1133 // TODO: polymorphic aspects should be kept but for now the temp 1134 // created always has the declared type. 1135 mlir::Value var = 1136 fir::getBase(fir::factory::readBoxValue(builder, loc, x)); 1137 auto value = builder.create<fir::LoadOp>(loc, var); 1138 mlir::Value temp = builder.createTemporary(loc, value.getType()); 1139 builder.create<fir::StoreOp>(loc, value, temp); 1140 return temp; 1141 }, 1142 [&](const auto &) -> ExtValue { 1143 fir::emitFatalError(loc, "expr is not a scalar value"); 1144 }); 1145 } 1146 1147 /// Helper structure to track potential copy-in of non contiguous variable 1148 /// argument into a contiguous temp. It is used to deallocate the temp that 1149 /// may have been created as well as to the copy-out from the temp to the 1150 /// variable after the call. 1151 struct CopyOutPair { 1152 ExtValue var; 1153 ExtValue temp; 1154 // Flag to indicate if the argument may have been modified by the 1155 // callee, in which case it must be copied-out to the variable. 1156 bool argMayBeModifiedByCall; 1157 // Optional boolean value that, if present and false, prevents 1158 // the copy-out and temp deallocation. 1159 llvm::Optional<mlir::Value> restrictCopyAndFreeAtRuntime; 1160 }; 1161 using CopyOutPairs = llvm::SmallVector<CopyOutPair, 4>; 1162 1163 /// Helper to read any fir::BoxValue into other fir::ExtendedValue categories 1164 /// not based on fir.box. 1165 /// This will lose any non contiguous stride information and dynamic type and 1166 /// should only be called if \p exv is known to be contiguous or if its base 1167 /// address will be replaced by a contiguous one. If \p exv is not a 1168 /// fir::BoxValue, this is a no-op. 1169 ExtValue readIfBoxValue(const ExtValue &exv) { 1170 if (const auto *box = exv.getBoxOf<fir::BoxValue>()) 1171 return fir::factory::readBoxValue(builder, getLoc(), *box); 1172 return exv; 1173 } 1174 1175 /// Lower a non-elemental procedure reference. 1176 ExtValue genRawProcedureRef(const Fortran::evaluate::ProcedureRef &procRef, 1177 llvm::Optional<mlir::Type> resultType) { 1178 mlir::Location loc = getLoc(); 1179 if (isElementalProcWithArrayArgs(procRef)) 1180 fir::emitFatalError(loc, "trying to lower elemental procedure with array " 1181 "arguments as normal procedure"); 1182 if (const Fortran::evaluate::SpecificIntrinsic *intrinsic = 1183 procRef.proc().GetSpecificIntrinsic()) 1184 return genIntrinsicRef(procRef, *intrinsic, resultType); 1185 1186 if (isStatementFunctionCall(procRef)) 1187 TODO(loc, "Lower statement function call"); 1188 1189 Fortran::lower::CallerInterface caller(procRef, converter); 1190 using PassBy = Fortran::lower::CallerInterface::PassEntityBy; 1191 1192 llvm::SmallVector<fir::MutableBoxValue> mutableModifiedByCall; 1193 // List of <var, temp> where temp must be copied into var after the call. 1194 CopyOutPairs copyOutPairs; 1195 1196 mlir::FunctionType callSiteType = caller.genFunctionType(); 1197 1198 // Lower the actual arguments and map the lowered values to the dummy 1199 // arguments. 1200 for (const Fortran::lower::CallInterface< 1201 Fortran::lower::CallerInterface>::PassedEntity &arg : 1202 caller.getPassedArguments()) { 1203 const auto *actual = arg.entity; 1204 mlir::Type argTy = callSiteType.getInput(arg.firArgument); 1205 if (!actual) { 1206 // Optional dummy argument for which there is no actual argument. 1207 caller.placeInput(arg, builder.create<fir::AbsentOp>(loc, argTy)); 1208 continue; 1209 } 1210 const auto *expr = actual->UnwrapExpr(); 1211 if (!expr) 1212 TODO(loc, "assumed type actual argument lowering"); 1213 1214 if (arg.passBy == PassBy::Value) { 1215 ExtValue argVal = genval(*expr); 1216 if (!fir::isUnboxedValue(argVal)) 1217 fir::emitFatalError( 1218 loc, "internal error: passing non trivial value by value"); 1219 caller.placeInput(arg, fir::getBase(argVal)); 1220 continue; 1221 } 1222 1223 if (arg.passBy == PassBy::MutableBox) { 1224 TODO(loc, "arg passby MutableBox"); 1225 } 1226 const bool actualArgIsVariable = Fortran::evaluate::IsVariable(*expr); 1227 if (arg.passBy == PassBy::BaseAddress || arg.passBy == PassBy::BoxChar) { 1228 auto argAddr = [&]() -> ExtValue { 1229 ExtValue baseAddr; 1230 if (actualArgIsVariable && arg.isOptional()) { 1231 if (Fortran::evaluate::IsAllocatableOrPointerObject( 1232 *expr, converter.getFoldingContext())) { 1233 TODO(loc, "Allocatable or pointer argument"); 1234 } 1235 if (const Fortran::semantics::Symbol *wholeSymbol = 1236 Fortran::evaluate::UnwrapWholeSymbolOrComponentDataRef( 1237 *expr)) 1238 if (Fortran::semantics::IsOptional(*wholeSymbol)) { 1239 TODO(loc, "procedureref optional arg"); 1240 } 1241 // Fall through: The actual argument can safely be 1242 // copied-in/copied-out without any care if needed. 1243 } 1244 if (actualArgIsVariable && expr->Rank() > 0) { 1245 TODO(loc, "procedureref arrays"); 1246 } 1247 // Actual argument is a non optional/non pointer/non allocatable 1248 // scalar. 1249 if (actualArgIsVariable) 1250 return genExtAddr(*expr); 1251 // Actual argument is not a variable. Make sure a variable address is 1252 // not passed. 1253 return genTempExtAddr(*expr); 1254 }(); 1255 // Scalar and contiguous expressions may be lowered to a fir.box, 1256 // either to account for potential polymorphism, or because lowering 1257 // did not account for some contiguity hints. 1258 // Here, polymorphism does not matter (an entity of the declared type 1259 // is passed, not one of the dynamic type), and the expr is known to 1260 // be simply contiguous, so it is safe to unbox it and pass the 1261 // address without making a copy. 1262 argAddr = readIfBoxValue(argAddr); 1263 1264 if (arg.passBy == PassBy::BaseAddress) { 1265 caller.placeInput(arg, fir::getBase(argAddr)); 1266 } else { 1267 TODO(loc, "procedureref PassBy::BoxChar"); 1268 } 1269 } else if (arg.passBy == PassBy::Box) { 1270 // Before lowering to an address, handle the allocatable/pointer actual 1271 // argument to optional fir.box dummy. It is legal to pass 1272 // unallocated/disassociated entity to an optional. In this case, an 1273 // absent fir.box must be created instead of a fir.box with a null value 1274 // (Fortran 2018 15.5.2.12 point 1). 1275 if (arg.isOptional() && Fortran::evaluate::IsAllocatableOrPointerObject( 1276 *expr, converter.getFoldingContext())) { 1277 TODO(loc, "optional allocatable or pointer argument"); 1278 } else { 1279 // Make sure a variable address is only passed if the expression is 1280 // actually a variable. 1281 mlir::Value box = 1282 actualArgIsVariable 1283 ? builder.createBox(loc, genBoxArg(*expr)) 1284 : builder.createBox(getLoc(), genTempExtAddr(*expr)); 1285 caller.placeInput(arg, box); 1286 } 1287 } else if (arg.passBy == PassBy::AddressAndLength) { 1288 ExtValue argRef = genExtAddr(*expr); 1289 caller.placeAddressAndLengthInput(arg, fir::getBase(argRef), 1290 fir::getLen(argRef)); 1291 } else if (arg.passBy == PassBy::CharProcTuple) { 1292 TODO(loc, "procedureref CharProcTuple"); 1293 } else { 1294 TODO(loc, "pass by value in non elemental function call"); 1295 } 1296 } 1297 1298 ExtValue result = genCallOpAndResult(caller, callSiteType, resultType); 1299 1300 // // Copy-out temps that were created for non contiguous variable arguments 1301 // if 1302 // // needed. 1303 // for (const auto ©OutPair : copyOutPairs) 1304 // genCopyOut(copyOutPair); 1305 1306 return result; 1307 } 1308 1309 template <typename A> 1310 ExtValue genval(const Fortran::evaluate::FunctionRef<A> &funcRef) { 1311 ExtValue result = genFunctionRef(funcRef); 1312 if (result.rank() == 0 && fir::isa_ref_type(fir::getBase(result).getType())) 1313 return genLoad(result); 1314 return result; 1315 } 1316 1317 ExtValue genval(const Fortran::evaluate::ProcedureRef &procRef) { 1318 llvm::Optional<mlir::Type> resTy; 1319 if (procRef.hasAlternateReturns()) 1320 resTy = builder.getIndexType(); 1321 return genProcedureRef(procRef, resTy); 1322 } 1323 1324 /// Generate a call to an intrinsic function. 1325 ExtValue 1326 genIntrinsicRef(const Fortran::evaluate::ProcedureRef &procRef, 1327 const Fortran::evaluate::SpecificIntrinsic &intrinsic, 1328 llvm::Optional<mlir::Type> resultType) { 1329 llvm::SmallVector<ExtValue> operands; 1330 1331 llvm::StringRef name = intrinsic.name; 1332 mlir::Location loc = getLoc(); 1333 1334 const Fortran::lower::IntrinsicArgumentLoweringRules *argLowering = 1335 Fortran::lower::getIntrinsicArgumentLowering(name); 1336 for (const auto &[arg, dummy] : 1337 llvm::zip(procRef.arguments(), 1338 intrinsic.characteristics.value().dummyArguments)) { 1339 auto *expr = Fortran::evaluate::UnwrapExpr<Fortran::lower::SomeExpr>(arg); 1340 if (!expr) { 1341 // Absent optional. 1342 operands.emplace_back(Fortran::lower::getAbsentIntrinsicArgument()); 1343 continue; 1344 } 1345 if (!argLowering) { 1346 // No argument lowering instruction, lower by value. 1347 operands.emplace_back(genval(*expr)); 1348 continue; 1349 } 1350 // Ad-hoc argument lowering handling. 1351 Fortran::lower::ArgLoweringRule argRules = 1352 Fortran::lower::lowerIntrinsicArgumentAs(loc, *argLowering, 1353 dummy.name); 1354 switch (argRules.lowerAs) { 1355 case Fortran::lower::LowerIntrinsicArgAs::Value: 1356 operands.emplace_back(genval(*expr)); 1357 continue; 1358 case Fortran::lower::LowerIntrinsicArgAs::Addr: 1359 TODO(getLoc(), "argument lowering for Addr"); 1360 continue; 1361 case Fortran::lower::LowerIntrinsicArgAs::Box: 1362 TODO(getLoc(), "argument lowering for Box"); 1363 continue; 1364 case Fortran::lower::LowerIntrinsicArgAs::Inquired: 1365 TODO(getLoc(), "argument lowering for Inquired"); 1366 continue; 1367 } 1368 llvm_unreachable("bad switch"); 1369 } 1370 // Let the intrinsic library lower the intrinsic procedure call 1371 return Fortran::lower::genIntrinsicCall(builder, getLoc(), name, resultType, 1372 operands); 1373 } 1374 1375 template <typename A> 1376 ExtValue genval(const Fortran::evaluate::Expr<A> &x) { 1377 if (isScalar(x)) 1378 return std::visit([&](const auto &e) { return genval(e); }, x.u); 1379 TODO(getLoc(), "genval Expr<A> arrays"); 1380 } 1381 1382 /// Helper to detect Transformational function reference. 1383 template <typename T> 1384 bool isTransformationalRef(const T &) { 1385 return false; 1386 } 1387 template <typename T> 1388 bool isTransformationalRef(const Fortran::evaluate::FunctionRef<T> &funcRef) { 1389 return !funcRef.IsElemental() && funcRef.Rank(); 1390 } 1391 template <typename T> 1392 bool isTransformationalRef(Fortran::evaluate::Expr<T> expr) { 1393 return std::visit([&](const auto &e) { return isTransformationalRef(e); }, 1394 expr.u); 1395 } 1396 1397 template <typename A> 1398 ExtValue gen(const Fortran::evaluate::Expr<A> &x) { 1399 // Whole array symbols or components, and results of transformational 1400 // functions already have a storage and the scalar expression lowering path 1401 // is used to not create a new temporary storage. 1402 if (isScalar(x) || 1403 Fortran::evaluate::UnwrapWholeSymbolOrComponentDataRef(x) || 1404 isTransformationalRef(x)) 1405 return std::visit([&](const auto &e) { return genref(e); }, x.u); 1406 TODO(getLoc(), "gen Expr non-scalar"); 1407 } 1408 1409 template <typename A> 1410 bool isScalar(const A &x) { 1411 return x.Rank() == 0; 1412 } 1413 1414 template <int KIND> 1415 ExtValue genval(const Fortran::evaluate::Expr<Fortran::evaluate::Type< 1416 Fortran::common::TypeCategory::Logical, KIND>> &exp) { 1417 return std::visit([&](const auto &e) { return genval(e); }, exp.u); 1418 } 1419 1420 using RefSet = 1421 std::tuple<Fortran::evaluate::ComplexPart, Fortran::evaluate::Substring, 1422 Fortran::evaluate::DataRef, Fortran::evaluate::Component, 1423 Fortran::evaluate::ArrayRef, Fortran::evaluate::CoarrayRef, 1424 Fortran::semantics::SymbolRef>; 1425 template <typename A> 1426 static constexpr bool inRefSet = Fortran::common::HasMember<A, RefSet>; 1427 1428 template <typename A, typename = std::enable_if_t<inRefSet<A>>> 1429 ExtValue genref(const A &a) { 1430 return gen(a); 1431 } 1432 template <typename A> 1433 ExtValue genref(const A &a) { 1434 mlir::Type storageType = converter.genType(toEvExpr(a)); 1435 return placeScalarValueInMemory(builder, getLoc(), genval(a), storageType); 1436 } 1437 1438 template <typename A, template <typename> typename T, 1439 typename B = std::decay_t<T<A>>, 1440 std::enable_if_t< 1441 std::is_same_v<B, Fortran::evaluate::Expr<A>> || 1442 std::is_same_v<B, Fortran::evaluate::Designator<A>> || 1443 std::is_same_v<B, Fortran::evaluate::FunctionRef<A>>, 1444 bool> = true> 1445 ExtValue genref(const T<A> &x) { 1446 return gen(x); 1447 } 1448 1449 private: 1450 mlir::Location location; 1451 Fortran::lower::AbstractConverter &converter; 1452 fir::FirOpBuilder &builder; 1453 Fortran::lower::StatementContext &stmtCtx; 1454 Fortran::lower::SymMap &symMap; 1455 bool useBoxArg = false; // expression lowered as argument 1456 }; 1457 } // namespace 1458 1459 // Helper for changing the semantics in a given context. Preserves the current 1460 // semantics which is resumed when the "push" goes out of scope. 1461 #define PushSemantics(PushVal) \ 1462 [[maybe_unused]] auto pushSemanticsLocalVariable##__LINE__ = \ 1463 Fortran::common::ScopedSet(semant, PushVal); 1464 1465 static bool isAdjustedArrayElementType(mlir::Type t) { 1466 return fir::isa_char(t) || fir::isa_derived(t) || t.isa<fir::SequenceType>(); 1467 } 1468 1469 /// Build an ExtendedValue from a fir.array<?x...?xT> without actually setting 1470 /// the actual extents and lengths. This is only to allow their propagation as 1471 /// ExtendedValue without triggering verifier failures when propagating 1472 /// character/arrays as unboxed values. Only the base of the resulting 1473 /// ExtendedValue should be used, it is undefined to use the length or extents 1474 /// of the extended value returned, 1475 inline static fir::ExtendedValue 1476 convertToArrayBoxValue(mlir::Location loc, fir::FirOpBuilder &builder, 1477 mlir::Value val, mlir::Value len) { 1478 mlir::Type ty = fir::unwrapRefType(val.getType()); 1479 mlir::IndexType idxTy = builder.getIndexType(); 1480 auto seqTy = ty.cast<fir::SequenceType>(); 1481 auto undef = builder.create<fir::UndefOp>(loc, idxTy); 1482 llvm::SmallVector<mlir::Value> extents(seqTy.getDimension(), undef); 1483 if (fir::isa_char(seqTy.getEleTy())) 1484 return fir::CharArrayBoxValue(val, len ? len : undef, extents); 1485 return fir::ArrayBoxValue(val, extents); 1486 } 1487 1488 //===----------------------------------------------------------------------===// 1489 // 1490 // Lowering of array expressions. 1491 // 1492 //===----------------------------------------------------------------------===// 1493 1494 namespace { 1495 class ArrayExprLowering { 1496 using ExtValue = fir::ExtendedValue; 1497 1498 /// Structure to keep track of lowered array operands in the 1499 /// array expression. Useful to later deduce the shape of the 1500 /// array expression. 1501 struct ArrayOperand { 1502 /// Array base (can be a fir.box). 1503 mlir::Value memref; 1504 /// ShapeOp, ShapeShiftOp or ShiftOp 1505 mlir::Value shape; 1506 /// SliceOp 1507 mlir::Value slice; 1508 /// Can this operand be absent ? 1509 bool mayBeAbsent = false; 1510 }; 1511 1512 using ImplicitSubscripts = Fortran::lower::details::ImplicitSubscripts; 1513 using PathComponent = Fortran::lower::PathComponent; 1514 1515 /// Active iteration space. 1516 using IterationSpace = Fortran::lower::IterationSpace; 1517 using IterSpace = const Fortran::lower::IterationSpace &; 1518 1519 /// Current continuation. Function that will generate IR for a single 1520 /// iteration of the pending iterative loop structure. 1521 using CC = Fortran::lower::GenerateElementalArrayFunc; 1522 1523 /// Projection continuation. Function that will project one iteration space 1524 /// into another. 1525 using PC = std::function<IterationSpace(IterSpace)>; 1526 using ArrayBaseTy = 1527 std::variant<std::monostate, const Fortran::evaluate::ArrayRef *, 1528 const Fortran::evaluate::DataRef *>; 1529 using ComponentPath = Fortran::lower::ComponentPath; 1530 1531 public: 1532 //===--------------------------------------------------------------------===// 1533 // Regular array assignment 1534 //===--------------------------------------------------------------------===// 1535 1536 /// Entry point for array assignments. Both the left-hand and right-hand sides 1537 /// can either be ExtendedValue or evaluate::Expr. 1538 template <typename TL, typename TR> 1539 static void lowerArrayAssignment(Fortran::lower::AbstractConverter &converter, 1540 Fortran::lower::SymMap &symMap, 1541 Fortran::lower::StatementContext &stmtCtx, 1542 const TL &lhs, const TR &rhs) { 1543 ArrayExprLowering ael{converter, stmtCtx, symMap, 1544 ConstituentSemantics::CopyInCopyOut}; 1545 ael.lowerArrayAssignment(lhs, rhs); 1546 } 1547 1548 template <typename TL, typename TR> 1549 void lowerArrayAssignment(const TL &lhs, const TR &rhs) { 1550 mlir::Location loc = getLoc(); 1551 /// Here the target subspace is not necessarily contiguous. The ArrayUpdate 1552 /// continuation is implicitly returned in `ccStoreToDest` and the ArrayLoad 1553 /// in `destination`. 1554 PushSemantics(ConstituentSemantics::ProjectedCopyInCopyOut); 1555 ccStoreToDest = genarr(lhs); 1556 determineShapeOfDest(lhs); 1557 semant = ConstituentSemantics::RefTransparent; 1558 ExtValue exv = lowerArrayExpression(rhs); 1559 if (explicitSpaceIsActive()) { 1560 explicitSpace->finalizeContext(); 1561 builder.create<fir::ResultOp>(loc, fir::getBase(exv)); 1562 } else { 1563 builder.create<fir::ArrayMergeStoreOp>( 1564 loc, destination, fir::getBase(exv), destination.getMemref(), 1565 destination.getSlice(), destination.getTypeparams()); 1566 } 1567 } 1568 1569 //===--------------------------------------------------------------------===// 1570 // Array assignment to allocatable array 1571 //===--------------------------------------------------------------------===// 1572 1573 /// Entry point for assignment to allocatable array. 1574 static void lowerAllocatableArrayAssignment( 1575 Fortran::lower::AbstractConverter &converter, 1576 Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx, 1577 const Fortran::lower::SomeExpr &lhs, const Fortran::lower::SomeExpr &rhs, 1578 Fortran::lower::ExplicitIterSpace &explicitSpace, 1579 Fortran::lower::ImplicitIterSpace &implicitSpace) { 1580 ArrayExprLowering ael(converter, stmtCtx, symMap, 1581 ConstituentSemantics::CopyInCopyOut, &explicitSpace, 1582 &implicitSpace); 1583 ael.lowerAllocatableArrayAssignment(lhs, rhs); 1584 } 1585 1586 /// Assignment to allocatable array. 1587 /// 1588 /// The semantics are reverse that of a "regular" array assignment. The rhs 1589 /// defines the iteration space of the computation and the lhs is 1590 /// resized/reallocated to fit if necessary. 1591 void lowerAllocatableArrayAssignment(const Fortran::lower::SomeExpr &lhs, 1592 const Fortran::lower::SomeExpr &rhs) { 1593 // With assignment to allocatable, we want to lower the rhs first and use 1594 // its shape to determine if we need to reallocate, etc. 1595 mlir::Location loc = getLoc(); 1596 // FIXME: If the lhs is in an explicit iteration space, the assignment may 1597 // be to an array of allocatable arrays rather than a single allocatable 1598 // array. 1599 fir::MutableBoxValue mutableBox = 1600 createMutableBox(loc, converter, lhs, symMap); 1601 mlir::Type resultTy = converter.genType(rhs); 1602 if (rhs.Rank() > 0) 1603 determineShapeOfDest(rhs); 1604 auto rhsCC = [&]() { 1605 PushSemantics(ConstituentSemantics::RefTransparent); 1606 return genarr(rhs); 1607 }(); 1608 1609 llvm::SmallVector<mlir::Value> lengthParams; 1610 // Currently no safe way to gather length from rhs (at least for 1611 // character, it cannot be taken from array_loads since it may be 1612 // changed by concatenations). 1613 if ((mutableBox.isCharacter() && !mutableBox.hasNonDeferredLenParams()) || 1614 mutableBox.isDerivedWithLengthParameters()) 1615 TODO(loc, "gather rhs length parameters in assignment to allocatable"); 1616 1617 // The allocatable must take lower bounds from the expr if it is 1618 // reallocated and the right hand side is not a scalar. 1619 const bool takeLboundsIfRealloc = rhs.Rank() > 0; 1620 llvm::SmallVector<mlir::Value> lbounds; 1621 // When the reallocated LHS takes its lower bounds from the RHS, 1622 // they will be non default only if the RHS is a whole array 1623 // variable. Otherwise, lbounds is left empty and default lower bounds 1624 // will be used. 1625 if (takeLboundsIfRealloc && 1626 Fortran::evaluate::UnwrapWholeSymbolOrComponentDataRef(rhs)) { 1627 assert(arrayOperands.size() == 1 && 1628 "lbounds can only come from one array"); 1629 std::vector<mlir::Value> lbs = 1630 fir::factory::getOrigins(arrayOperands[0].shape); 1631 lbounds.append(lbs.begin(), lbs.end()); 1632 } 1633 fir::factory::MutableBoxReallocation realloc = 1634 fir::factory::genReallocIfNeeded(builder, loc, mutableBox, destShape, 1635 lengthParams); 1636 // Create ArrayLoad for the mutable box and save it into `destination`. 1637 PushSemantics(ConstituentSemantics::ProjectedCopyInCopyOut); 1638 ccStoreToDest = genarr(realloc.newValue); 1639 // If the rhs is scalar, get shape from the allocatable ArrayLoad. 1640 if (destShape.empty()) 1641 destShape = getShape(destination); 1642 // Finish lowering the loop nest. 1643 assert(destination && "destination must have been set"); 1644 ExtValue exv = lowerArrayExpression(rhsCC, resultTy); 1645 if (explicitSpaceIsActive()) { 1646 explicitSpace->finalizeContext(); 1647 builder.create<fir::ResultOp>(loc, fir::getBase(exv)); 1648 } else { 1649 builder.create<fir::ArrayMergeStoreOp>( 1650 loc, destination, fir::getBase(exv), destination.getMemref(), 1651 destination.getSlice(), destination.getTypeparams()); 1652 } 1653 fir::factory::finalizeRealloc(builder, loc, mutableBox, lbounds, 1654 takeLboundsIfRealloc, realloc); 1655 } 1656 1657 /// Entry point into lowering an expression with rank. This entry point is for 1658 /// lowering a rhs expression, for example. (RefTransparent semantics.) 1659 static ExtValue 1660 lowerNewArrayExpression(Fortran::lower::AbstractConverter &converter, 1661 Fortran::lower::SymMap &symMap, 1662 Fortran::lower::StatementContext &stmtCtx, 1663 const Fortran::lower::SomeExpr &expr) { 1664 ArrayExprLowering ael{converter, stmtCtx, symMap}; 1665 ael.determineShapeOfDest(expr); 1666 ExtValue loopRes = ael.lowerArrayExpression(expr); 1667 fir::ArrayLoadOp dest = ael.destination; 1668 mlir::Value tempRes = dest.getMemref(); 1669 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 1670 mlir::Location loc = converter.getCurrentLocation(); 1671 builder.create<fir::ArrayMergeStoreOp>(loc, dest, fir::getBase(loopRes), 1672 tempRes, dest.getSlice(), 1673 dest.getTypeparams()); 1674 1675 auto arrTy = 1676 fir::dyn_cast_ptrEleTy(tempRes.getType()).cast<fir::SequenceType>(); 1677 if (auto charTy = 1678 arrTy.getEleTy().template dyn_cast<fir::CharacterType>()) { 1679 if (fir::characterWithDynamicLen(charTy)) 1680 TODO(loc, "CHARACTER does not have constant LEN"); 1681 mlir::Value len = builder.createIntegerConstant( 1682 loc, builder.getCharacterLengthType(), charTy.getLen()); 1683 return fir::CharArrayBoxValue(tempRes, len, dest.getExtents()); 1684 } 1685 return fir::ArrayBoxValue(tempRes, dest.getExtents()); 1686 } 1687 1688 // FIXME: should take multiple inner arguments. 1689 std::pair<IterationSpace, mlir::OpBuilder::InsertPoint> 1690 genImplicitLoops(mlir::ValueRange shape, mlir::Value innerArg) { 1691 mlir::Location loc = getLoc(); 1692 mlir::IndexType idxTy = builder.getIndexType(); 1693 mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); 1694 mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0); 1695 llvm::SmallVector<mlir::Value> loopUppers; 1696 1697 // Convert any implied shape to closed interval form. The fir.do_loop will 1698 // run from 0 to `extent - 1` inclusive. 1699 for (auto extent : shape) 1700 loopUppers.push_back( 1701 builder.create<mlir::arith::SubIOp>(loc, extent, one)); 1702 1703 // Iteration space is created with outermost columns, innermost rows 1704 llvm::SmallVector<fir::DoLoopOp> loops; 1705 1706 const std::size_t loopDepth = loopUppers.size(); 1707 llvm::SmallVector<mlir::Value> ivars; 1708 1709 for (auto i : llvm::enumerate(llvm::reverse(loopUppers))) { 1710 if (i.index() > 0) { 1711 assert(!loops.empty()); 1712 builder.setInsertionPointToStart(loops.back().getBody()); 1713 } 1714 fir::DoLoopOp loop; 1715 if (innerArg) { 1716 loop = builder.create<fir::DoLoopOp>( 1717 loc, zero, i.value(), one, isUnordered(), 1718 /*finalCount=*/false, mlir::ValueRange{innerArg}); 1719 innerArg = loop.getRegionIterArgs().front(); 1720 if (explicitSpaceIsActive()) 1721 explicitSpace->setInnerArg(0, innerArg); 1722 } else { 1723 loop = builder.create<fir::DoLoopOp>(loc, zero, i.value(), one, 1724 isUnordered(), 1725 /*finalCount=*/false); 1726 } 1727 ivars.push_back(loop.getInductionVar()); 1728 loops.push_back(loop); 1729 } 1730 1731 if (innerArg) 1732 for (std::remove_const_t<decltype(loopDepth)> i = 0; i + 1 < loopDepth; 1733 ++i) { 1734 builder.setInsertionPointToEnd(loops[i].getBody()); 1735 builder.create<fir::ResultOp>(loc, loops[i + 1].getResult(0)); 1736 } 1737 1738 // Move insertion point to the start of the innermost loop in the nest. 1739 builder.setInsertionPointToStart(loops.back().getBody()); 1740 // Set `afterLoopNest` to just after the entire loop nest. 1741 auto currPt = builder.saveInsertionPoint(); 1742 builder.setInsertionPointAfter(loops[0]); 1743 auto afterLoopNest = builder.saveInsertionPoint(); 1744 builder.restoreInsertionPoint(currPt); 1745 1746 // Put the implicit loop variables in row to column order to match FIR's 1747 // Ops. (The loops were constructed from outermost column to innermost 1748 // row.) 1749 mlir::Value outerRes = loops[0].getResult(0); 1750 return {IterationSpace(innerArg, outerRes, llvm::reverse(ivars)), 1751 afterLoopNest}; 1752 } 1753 1754 /// Build the iteration space into which the array expression will be 1755 /// lowered. The resultType is used to create a temporary, if needed. 1756 std::pair<IterationSpace, mlir::OpBuilder::InsertPoint> 1757 genIterSpace(mlir::Type resultType) { 1758 mlir::Location loc = getLoc(); 1759 llvm::SmallVector<mlir::Value> shape = genIterationShape(); 1760 if (!destination) { 1761 // Allocate storage for the result if it is not already provided. 1762 destination = createAndLoadSomeArrayTemp(resultType, shape); 1763 } 1764 1765 // Generate the lazy mask allocation, if one was given. 1766 if (ccPrelude.hasValue()) 1767 ccPrelude.getValue()(shape); 1768 1769 // Now handle the implicit loops. 1770 mlir::Value inner = explicitSpaceIsActive() 1771 ? explicitSpace->getInnerArgs().front() 1772 : destination.getResult(); 1773 auto [iters, afterLoopNest] = genImplicitLoops(shape, inner); 1774 mlir::Value innerArg = iters.innerArgument(); 1775 1776 // Generate the mask conditional structure, if there are masks. Unlike the 1777 // explicit masks, which are interleaved, these mask expression appear in 1778 // the innermost loop. 1779 if (implicitSpaceHasMasks()) { 1780 // Recover the cached condition from the mask buffer. 1781 auto genCond = [&](Fortran::lower::FrontEndExpr e, IterSpace iters) { 1782 return implicitSpace->getBoundClosure(e)(iters); 1783 }; 1784 1785 // Handle the negated conditions in topological order of the WHERE 1786 // clauses. See 10.2.3.2p4 as to why this control structure is produced. 1787 for (llvm::SmallVector<Fortran::lower::FrontEndExpr> maskExprs : 1788 implicitSpace->getMasks()) { 1789 const std::size_t size = maskExprs.size() - 1; 1790 auto genFalseBlock = [&](const auto *e, auto &&cond) { 1791 auto ifOp = builder.create<fir::IfOp>( 1792 loc, mlir::TypeRange{innerArg.getType()}, fir::getBase(cond), 1793 /*withElseRegion=*/true); 1794 builder.create<fir::ResultOp>(loc, ifOp.getResult(0)); 1795 builder.setInsertionPointToStart(&ifOp.getThenRegion().front()); 1796 builder.create<fir::ResultOp>(loc, innerArg); 1797 builder.setInsertionPointToStart(&ifOp.getElseRegion().front()); 1798 }; 1799 auto genTrueBlock = [&](const auto *e, auto &&cond) { 1800 auto ifOp = builder.create<fir::IfOp>( 1801 loc, mlir::TypeRange{innerArg.getType()}, fir::getBase(cond), 1802 /*withElseRegion=*/true); 1803 builder.create<fir::ResultOp>(loc, ifOp.getResult(0)); 1804 builder.setInsertionPointToStart(&ifOp.getElseRegion().front()); 1805 builder.create<fir::ResultOp>(loc, innerArg); 1806 builder.setInsertionPointToStart(&ifOp.getThenRegion().front()); 1807 }; 1808 for (std::remove_const_t<decltype(size)> i = 0; i < size; ++i) 1809 if (const auto *e = maskExprs[i]) 1810 genFalseBlock(e, genCond(e, iters)); 1811 1812 // The last condition is either non-negated or unconditionally negated. 1813 if (const auto *e = maskExprs[size]) 1814 genTrueBlock(e, genCond(e, iters)); 1815 } 1816 } 1817 1818 // We're ready to lower the body (an assignment statement) for this context 1819 // of loop nests at this point. 1820 return {iters, afterLoopNest}; 1821 } 1822 1823 fir::ArrayLoadOp 1824 createAndLoadSomeArrayTemp(mlir::Type type, 1825 llvm::ArrayRef<mlir::Value> shape) { 1826 if (ccLoadDest.hasValue()) 1827 return ccLoadDest.getValue()(shape); 1828 auto seqTy = type.dyn_cast<fir::SequenceType>(); 1829 assert(seqTy && "must be an array"); 1830 mlir::Location loc = getLoc(); 1831 // TODO: Need to thread the length parameters here. For character, they may 1832 // differ from the operands length (e.g concatenation). So the array loads 1833 // type parameters are not enough. 1834 if (auto charTy = seqTy.getEleTy().dyn_cast<fir::CharacterType>()) 1835 if (charTy.hasDynamicLen()) 1836 TODO(loc, "character array expression temp with dynamic length"); 1837 if (auto recTy = seqTy.getEleTy().dyn_cast<fir::RecordType>()) 1838 if (recTy.getNumLenParams() > 0) 1839 TODO(loc, "derived type array expression temp with length parameters"); 1840 mlir::Value temp = seqTy.hasConstantShape() 1841 ? builder.create<fir::AllocMemOp>(loc, type) 1842 : builder.create<fir::AllocMemOp>( 1843 loc, type, ".array.expr", llvm::None, shape); 1844 fir::FirOpBuilder *bldr = &converter.getFirOpBuilder(); 1845 stmtCtx.attachCleanup( 1846 [bldr, loc, temp]() { bldr->create<fir::FreeMemOp>(loc, temp); }); 1847 mlir::Value shapeOp = genShapeOp(shape); 1848 return builder.create<fir::ArrayLoadOp>(loc, seqTy, temp, shapeOp, 1849 /*slice=*/mlir::Value{}, 1850 llvm::None); 1851 } 1852 1853 static fir::ShapeOp genShapeOp(mlir::Location loc, fir::FirOpBuilder &builder, 1854 llvm::ArrayRef<mlir::Value> shape) { 1855 mlir::IndexType idxTy = builder.getIndexType(); 1856 llvm::SmallVector<mlir::Value> idxShape; 1857 for (auto s : shape) 1858 idxShape.push_back(builder.createConvert(loc, idxTy, s)); 1859 auto shapeTy = fir::ShapeType::get(builder.getContext(), idxShape.size()); 1860 return builder.create<fir::ShapeOp>(loc, shapeTy, idxShape); 1861 } 1862 1863 fir::ShapeOp genShapeOp(llvm::ArrayRef<mlir::Value> shape) { 1864 return genShapeOp(getLoc(), builder, shape); 1865 } 1866 1867 //===--------------------------------------------------------------------===// 1868 // Expression traversal and lowering. 1869 //===--------------------------------------------------------------------===// 1870 1871 /// Lower the expression, \p x, in a scalar context. 1872 template <typename A> 1873 ExtValue asScalar(const A &x) { 1874 return ScalarExprLowering{getLoc(), converter, symMap, stmtCtx}.genval(x); 1875 } 1876 1877 /// Lower the expression in a scalar context to a memory reference. 1878 template <typename A> 1879 ExtValue asScalarRef(const A &x) { 1880 return ScalarExprLowering{getLoc(), converter, symMap, stmtCtx}.gen(x); 1881 } 1882 1883 // An expression with non-zero rank is an array expression. 1884 template <typename A> 1885 bool isArray(const A &x) const { 1886 return x.Rank() != 0; 1887 } 1888 1889 /// If there were temporaries created for this element evaluation, finalize 1890 /// and deallocate the resources now. This should be done just prior the the 1891 /// fir::ResultOp at the end of the innermost loop. 1892 void finalizeElementCtx() { 1893 if (elementCtx) { 1894 stmtCtx.finalize(/*popScope=*/true); 1895 elementCtx = false; 1896 } 1897 } 1898 1899 template <typename A> 1900 CC genScalarAndForwardValue(const A &x) { 1901 ExtValue result = asScalar(x); 1902 return [=](IterSpace) { return result; }; 1903 } 1904 1905 template <typename A, typename = std::enable_if_t<Fortran::common::HasMember< 1906 A, Fortran::evaluate::TypelessExpression>>> 1907 CC genarr(const A &x) { 1908 return genScalarAndForwardValue(x); 1909 } 1910 1911 template <typename A> 1912 CC genarr(const Fortran::evaluate::Expr<A> &x) { 1913 LLVM_DEBUG(Fortran::lower::DumpEvaluateExpr::dump(llvm::dbgs(), x)); 1914 if (isArray(x) || explicitSpaceIsActive() || 1915 isElementalProcWithArrayArgs(x)) 1916 return std::visit([&](const auto &e) { return genarr(e); }, x.u); 1917 return genScalarAndForwardValue(x); 1918 } 1919 1920 template <Fortran::common::TypeCategory TC1, int KIND, 1921 Fortran::common::TypeCategory TC2> 1922 CC genarr(const Fortran::evaluate::Convert<Fortran::evaluate::Type<TC1, KIND>, 1923 TC2> &x) { 1924 TODO(getLoc(), ""); 1925 } 1926 1927 template <int KIND> 1928 CC genarr(const Fortran::evaluate::ComplexComponent<KIND> &x) { 1929 TODO(getLoc(), ""); 1930 } 1931 1932 template <typename T> 1933 CC genarr(const Fortran::evaluate::Parentheses<T> &x) { 1934 TODO(getLoc(), ""); 1935 } 1936 1937 template <int KIND> 1938 CC genarr(const Fortran::evaluate::Negate<Fortran::evaluate::Type< 1939 Fortran::common::TypeCategory::Integer, KIND>> &x) { 1940 TODO(getLoc(), ""); 1941 } 1942 1943 template <int KIND> 1944 CC genarr(const Fortran::evaluate::Negate<Fortran::evaluate::Type< 1945 Fortran::common::TypeCategory::Real, KIND>> &x) { 1946 TODO(getLoc(), ""); 1947 } 1948 template <int KIND> 1949 CC genarr(const Fortran::evaluate::Negate<Fortran::evaluate::Type< 1950 Fortran::common::TypeCategory::Complex, KIND>> &x) { 1951 TODO(getLoc(), ""); 1952 } 1953 1954 #undef GENBIN 1955 #define GENBIN(GenBinEvOp, GenBinTyCat, GenBinFirOp) \ 1956 template <int KIND> \ 1957 CC genarr(const Fortran::evaluate::GenBinEvOp<Fortran::evaluate::Type< \ 1958 Fortran::common::TypeCategory::GenBinTyCat, KIND>> &x) { \ 1959 TODO(getLoc(), "genarr Binary"); \ 1960 } 1961 1962 GENBIN(Add, Integer, mlir::arith::AddIOp) 1963 GENBIN(Add, Real, mlir::arith::AddFOp) 1964 GENBIN(Add, Complex, fir::AddcOp) 1965 GENBIN(Subtract, Integer, mlir::arith::SubIOp) 1966 GENBIN(Subtract, Real, mlir::arith::SubFOp) 1967 GENBIN(Subtract, Complex, fir::SubcOp) 1968 GENBIN(Multiply, Integer, mlir::arith::MulIOp) 1969 GENBIN(Multiply, Real, mlir::arith::MulFOp) 1970 GENBIN(Multiply, Complex, fir::MulcOp) 1971 GENBIN(Divide, Integer, mlir::arith::DivSIOp) 1972 GENBIN(Divide, Real, mlir::arith::DivFOp) 1973 GENBIN(Divide, Complex, fir::DivcOp) 1974 1975 template <Fortran::common::TypeCategory TC, int KIND> 1976 CC genarr( 1977 const Fortran::evaluate::Power<Fortran::evaluate::Type<TC, KIND>> &x) { 1978 TODO(getLoc(), "genarr "); 1979 } 1980 template <Fortran::common::TypeCategory TC, int KIND> 1981 CC genarr( 1982 const Fortran::evaluate::Extremum<Fortran::evaluate::Type<TC, KIND>> &x) { 1983 TODO(getLoc(), "genarr "); 1984 } 1985 template <Fortran::common::TypeCategory TC, int KIND> 1986 CC genarr( 1987 const Fortran::evaluate::RealToIntPower<Fortran::evaluate::Type<TC, KIND>> 1988 &x) { 1989 TODO(getLoc(), "genarr "); 1990 } 1991 template <int KIND> 1992 CC genarr(const Fortran::evaluate::ComplexConstructor<KIND> &x) { 1993 TODO(getLoc(), "genarr "); 1994 } 1995 1996 template <int KIND> 1997 CC genarr(const Fortran::evaluate::Concat<KIND> &x) { 1998 TODO(getLoc(), "genarr "); 1999 } 2000 2001 template <int KIND> 2002 CC genarr(const Fortran::evaluate::SetLength<KIND> &x) { 2003 TODO(getLoc(), "genarr "); 2004 } 2005 2006 template <typename A> 2007 CC genarr(const Fortran::evaluate::Constant<A> &x) { 2008 TODO(getLoc(), "genarr "); 2009 } 2010 2011 CC genarr(const Fortran::semantics::SymbolRef &sym, 2012 ComponentPath &components) { 2013 return genarr(sym.get(), components); 2014 } 2015 2016 ExtValue abstractArrayExtValue(mlir::Value val, mlir::Value len = {}) { 2017 return convertToArrayBoxValue(getLoc(), builder, val, len); 2018 } 2019 2020 CC genarr(const ExtValue &extMemref) { 2021 ComponentPath dummy(/*isImplicit=*/true); 2022 return genarr(extMemref, dummy); 2023 } 2024 2025 template <typename A> 2026 CC genarr(const Fortran::evaluate::ArrayConstructor<A> &x) { 2027 TODO(getLoc(), "genarr ArrayConstructor<A>"); 2028 } 2029 2030 CC genarr(const Fortran::evaluate::ImpliedDoIndex &) { 2031 TODO(getLoc(), "genarr ImpliedDoIndex"); 2032 } 2033 2034 CC genarr(const Fortran::evaluate::TypeParamInquiry &x) { 2035 TODO(getLoc(), "genarr TypeParamInquiry"); 2036 } 2037 2038 CC genarr(const Fortran::evaluate::DescriptorInquiry &x) { 2039 TODO(getLoc(), "genarr DescriptorInquiry"); 2040 } 2041 2042 CC genarr(const Fortran::evaluate::StructureConstructor &x) { 2043 TODO(getLoc(), "genarr StructureConstructor"); 2044 } 2045 2046 template <int KIND> 2047 CC genarr(const Fortran::evaluate::Not<KIND> &x) { 2048 TODO(getLoc(), "genarr Not"); 2049 } 2050 2051 template <int KIND> 2052 CC genarr(const Fortran::evaluate::LogicalOperation<KIND> &x) { 2053 TODO(getLoc(), "genarr LogicalOperation"); 2054 } 2055 2056 template <int KIND> 2057 CC genarr(const Fortran::evaluate::Relational<Fortran::evaluate::Type< 2058 Fortran::common::TypeCategory::Integer, KIND>> &x) { 2059 TODO(getLoc(), "genarr Relational Integer"); 2060 } 2061 template <int KIND> 2062 CC genarr(const Fortran::evaluate::Relational<Fortran::evaluate::Type< 2063 Fortran::common::TypeCategory::Character, KIND>> &x) { 2064 TODO(getLoc(), "genarr Relational Character"); 2065 } 2066 template <int KIND> 2067 CC genarr(const Fortran::evaluate::Relational<Fortran::evaluate::Type< 2068 Fortran::common::TypeCategory::Real, KIND>> &x) { 2069 TODO(getLoc(), "genarr Relational Real"); 2070 } 2071 template <int KIND> 2072 CC genarr(const Fortran::evaluate::Relational<Fortran::evaluate::Type< 2073 Fortran::common::TypeCategory::Complex, KIND>> &x) { 2074 TODO(getLoc(), "genarr Relational Complex"); 2075 } 2076 CC genarr( 2077 const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &r) { 2078 TODO(getLoc(), "genarr Relational SomeType"); 2079 } 2080 2081 template <typename A> 2082 CC genarr(const Fortran::evaluate::Designator<A> &des) { 2083 ComponentPath components(des.Rank() > 0); 2084 return std::visit([&](const auto &x) { return genarr(x, components); }, 2085 des.u); 2086 } 2087 2088 template <typename T> 2089 CC genarr(const Fortran::evaluate::FunctionRef<T> &funRef) { 2090 TODO(getLoc(), "genarr FunctionRef"); 2091 } 2092 2093 template <typename A> 2094 CC genImplicitArrayAccess(const A &x, ComponentPath &components) { 2095 components.reversePath.push_back(ImplicitSubscripts{}); 2096 ExtValue exv = asScalarRef(x); 2097 // lowerPath(exv, components); 2098 auto lambda = genarr(exv, components); 2099 return [=](IterSpace iters) { return lambda(components.pc(iters)); }; 2100 } 2101 CC genImplicitArrayAccess(const Fortran::evaluate::NamedEntity &x, 2102 ComponentPath &components) { 2103 if (x.IsSymbol()) 2104 return genImplicitArrayAccess(x.GetFirstSymbol(), components); 2105 return genImplicitArrayAccess(x.GetComponent(), components); 2106 } 2107 2108 template <typename A> 2109 CC genAsScalar(const A &x) { 2110 mlir::Location loc = getLoc(); 2111 if (isProjectedCopyInCopyOut()) { 2112 return [=, &x, builder = &converter.getFirOpBuilder()]( 2113 IterSpace iters) -> ExtValue { 2114 ExtValue exv = asScalarRef(x); 2115 mlir::Value val = fir::getBase(exv); 2116 mlir::Type eleTy = fir::unwrapRefType(val.getType()); 2117 if (isAdjustedArrayElementType(eleTy)) { 2118 if (fir::isa_char(eleTy)) { 2119 TODO(getLoc(), "assignment of character type"); 2120 } else if (fir::isa_derived(eleTy)) { 2121 TODO(loc, "assignment of derived type"); 2122 } else { 2123 fir::emitFatalError(loc, "array type not expected in scalar"); 2124 } 2125 } else { 2126 builder->create<fir::StoreOp>(loc, iters.getElement(), val); 2127 } 2128 return exv; 2129 }; 2130 } 2131 return [=, &x](IterSpace) { return asScalar(x); }; 2132 } 2133 2134 CC genarr(const Fortran::semantics::Symbol &x, ComponentPath &components) { 2135 if (explicitSpaceIsActive()) { 2136 TODO(getLoc(), "genarr Symbol explicitSpace"); 2137 } else { 2138 return genImplicitArrayAccess(x, components); 2139 } 2140 } 2141 2142 CC genarr(const Fortran::evaluate::Component &x, ComponentPath &components) { 2143 TODO(getLoc(), "genarr Component"); 2144 } 2145 2146 CC genarr(const Fortran::evaluate::ArrayRef &x, ComponentPath &components) { 2147 TODO(getLoc(), "genar ArrayRef"); 2148 } 2149 2150 CC genarr(const Fortran::evaluate::CoarrayRef &x, ComponentPath &components) { 2151 TODO(getLoc(), "coarray reference"); 2152 } 2153 2154 CC genarr(const Fortran::evaluate::NamedEntity &x, 2155 ComponentPath &components) { 2156 return x.IsSymbol() ? genarr(x.GetFirstSymbol(), components) 2157 : genarr(x.GetComponent(), components); 2158 } 2159 2160 CC genarr(const Fortran::evaluate::DataRef &x, ComponentPath &components) { 2161 return std::visit([&](const auto &v) { return genarr(v, components); }, 2162 x.u); 2163 } 2164 2165 CC genarr(const Fortran::evaluate::ComplexPart &x, 2166 ComponentPath &components) { 2167 TODO(getLoc(), "genarr ComplexPart"); 2168 } 2169 2170 CC genarr(const Fortran::evaluate::StaticDataObject::Pointer &, 2171 ComponentPath &components) { 2172 TODO(getLoc(), "genarr StaticDataObject::Pointer"); 2173 } 2174 2175 /// Substrings (see 9.4.1) 2176 CC genarr(const Fortran::evaluate::Substring &x, ComponentPath &components) { 2177 TODO(getLoc(), "genarr Substring"); 2178 } 2179 2180 /// Base case of generating an array reference, 2181 CC genarr(const ExtValue &extMemref, ComponentPath &components) { 2182 mlir::Location loc = getLoc(); 2183 mlir::Value memref = fir::getBase(extMemref); 2184 mlir::Type arrTy = fir::dyn_cast_ptrOrBoxEleTy(memref.getType()); 2185 assert(arrTy.isa<fir::SequenceType>() && "memory ref must be an array"); 2186 mlir::Value shape = builder.createShape(loc, extMemref); 2187 mlir::Value slice; 2188 if (components.isSlice()) { 2189 TODO(loc, "genarr with Slices"); 2190 } 2191 arrayOperands.push_back(ArrayOperand{memref, shape, slice}); 2192 if (destShape.empty()) 2193 destShape = getShape(arrayOperands.back()); 2194 if (isBoxValue()) { 2195 TODO(loc, "genarr BoxValue"); 2196 } 2197 if (isReferentiallyOpaque()) { 2198 TODO(loc, "genarr isReferentiallyOpaque"); 2199 } 2200 auto arrLoad = builder.create<fir::ArrayLoadOp>( 2201 loc, arrTy, memref, shape, slice, fir::getTypeParams(extMemref)); 2202 mlir::Value arrLd = arrLoad.getResult(); 2203 if (isProjectedCopyInCopyOut()) { 2204 // Semantics are projected copy-in copy-out. 2205 // The backing store of the destination of an array expression may be 2206 // partially modified. These updates are recorded in FIR by forwarding a 2207 // continuation that generates an `array_update` Op. The destination is 2208 // always loaded at the beginning of the statement and merged at the 2209 // end. 2210 destination = arrLoad; 2211 auto lambda = ccStoreToDest.hasValue() 2212 ? ccStoreToDest.getValue() 2213 : defaultStoreToDestination(components.substring); 2214 return [=](IterSpace iters) -> ExtValue { return lambda(iters); }; 2215 } 2216 if (isCustomCopyInCopyOut()) { 2217 TODO(loc, "isCustomCopyInCopyOut"); 2218 } 2219 if (isCopyInCopyOut()) { 2220 // Semantics are copy-in copy-out. 2221 // The continuation simply forwards the result of the `array_load` Op, 2222 // which is the value of the array as it was when loaded. All data 2223 // references with rank > 0 in an array expression typically have 2224 // copy-in copy-out semantics. 2225 return [=](IterSpace) -> ExtValue { return arrLd; }; 2226 } 2227 mlir::Operation::operand_range arrLdTypeParams = arrLoad.getTypeparams(); 2228 if (isValueAttribute()) { 2229 // Semantics are value attribute. 2230 // Here the continuation will `array_fetch` a value from an array and 2231 // then store that value in a temporary. One can thus imitate pass by 2232 // value even when the call is pass by reference. 2233 return [=](IterSpace iters) -> ExtValue { 2234 mlir::Value base; 2235 mlir::Type eleTy = fir::applyPathToType(arrTy, iters.iterVec()); 2236 if (isAdjustedArrayElementType(eleTy)) { 2237 mlir::Type eleRefTy = builder.getRefType(eleTy); 2238 base = builder.create<fir::ArrayAccessOp>( 2239 loc, eleRefTy, arrLd, iters.iterVec(), arrLdTypeParams); 2240 } else { 2241 base = builder.create<fir::ArrayFetchOp>( 2242 loc, eleTy, arrLd, iters.iterVec(), arrLdTypeParams); 2243 } 2244 mlir::Value temp = builder.createTemporary( 2245 loc, base.getType(), 2246 llvm::ArrayRef<mlir::NamedAttribute>{ 2247 Fortran::lower::getAdaptToByRefAttr(builder)}); 2248 builder.create<fir::StoreOp>(loc, base, temp); 2249 return fir::factory::arraySectionElementToExtendedValue( 2250 builder, loc, extMemref, temp, slice); 2251 }; 2252 } 2253 // In the default case, the array reference forwards an `array_fetch` or 2254 // `array_access` Op in the continuation. 2255 return [=](IterSpace iters) -> ExtValue { 2256 mlir::Type eleTy = fir::applyPathToType(arrTy, iters.iterVec()); 2257 if (isAdjustedArrayElementType(eleTy)) { 2258 mlir::Type eleRefTy = builder.getRefType(eleTy); 2259 mlir::Value arrayOp = builder.create<fir::ArrayAccessOp>( 2260 loc, eleRefTy, arrLd, iters.iterVec(), arrLdTypeParams); 2261 if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) { 2262 llvm::SmallVector<mlir::Value> substringBounds; 2263 populateBounds(substringBounds, components.substring); 2264 if (!substringBounds.empty()) { 2265 // mlir::Value dstLen = fir::factory::genLenOfCharacter( 2266 // builder, loc, arrLoad, iters.iterVec(), substringBounds); 2267 // fir::CharBoxValue dstChar(arrayOp, dstLen); 2268 // return fir::factory::CharacterExprHelper{builder, loc} 2269 // .createSubstring(dstChar, substringBounds); 2270 } 2271 } 2272 return fir::factory::arraySectionElementToExtendedValue( 2273 builder, loc, extMemref, arrayOp, slice); 2274 } 2275 auto arrFetch = builder.create<fir::ArrayFetchOp>( 2276 loc, eleTy, arrLd, iters.iterVec(), arrLdTypeParams); 2277 return fir::factory::arraySectionElementToExtendedValue( 2278 builder, loc, extMemref, arrFetch, slice); 2279 }; 2280 } 2281 2282 /// Reduce the rank of a array to be boxed based on the slice's operands. 2283 static mlir::Type reduceRank(mlir::Type arrTy, mlir::Value slice) { 2284 if (slice) { 2285 auto slOp = mlir::dyn_cast<fir::SliceOp>(slice.getDefiningOp()); 2286 assert(slOp && "expected slice op"); 2287 auto seqTy = arrTy.dyn_cast<fir::SequenceType>(); 2288 assert(seqTy && "expected array type"); 2289 mlir::Operation::operand_range triples = slOp.getTriples(); 2290 fir::SequenceType::Shape shape; 2291 // reduce the rank for each invariant dimension 2292 for (unsigned i = 1, end = triples.size(); i < end; i += 3) 2293 if (!mlir::isa_and_nonnull<fir::UndefOp>(triples[i].getDefiningOp())) 2294 shape.push_back(fir::SequenceType::getUnknownExtent()); 2295 return fir::SequenceType::get(shape, seqTy.getEleTy()); 2296 } 2297 // not sliced, so no change in rank 2298 return arrTy; 2299 } 2300 2301 private: 2302 void determineShapeOfDest(const fir::ExtendedValue &lhs) { 2303 destShape = fir::factory::getExtents(builder, getLoc(), lhs); 2304 } 2305 2306 void determineShapeOfDest(const Fortran::lower::SomeExpr &lhs) { 2307 if (!destShape.empty()) 2308 return; 2309 // if (explicitSpaceIsActive() && determineShapeWithSlice(lhs)) 2310 // return; 2311 mlir::Type idxTy = builder.getIndexType(); 2312 mlir::Location loc = getLoc(); 2313 if (std::optional<Fortran::evaluate::ConstantSubscripts> constantShape = 2314 Fortran::evaluate::GetConstantExtents(converter.getFoldingContext(), 2315 lhs)) 2316 for (Fortran::common::ConstantSubscript extent : *constantShape) 2317 destShape.push_back(builder.createIntegerConstant(loc, idxTy, extent)); 2318 } 2319 2320 ExtValue lowerArrayExpression(const Fortran::lower::SomeExpr &exp) { 2321 mlir::Type resTy = converter.genType(exp); 2322 return std::visit( 2323 [&](const auto &e) { return lowerArrayExpression(genarr(e), resTy); }, 2324 exp.u); 2325 } 2326 ExtValue lowerArrayExpression(const ExtValue &exv) { 2327 assert(!explicitSpace); 2328 mlir::Type resTy = fir::unwrapPassByRefType(fir::getBase(exv).getType()); 2329 return lowerArrayExpression(genarr(exv), resTy); 2330 } 2331 2332 void populateBounds(llvm::SmallVectorImpl<mlir::Value> &bounds, 2333 const Fortran::evaluate::Substring *substring) { 2334 if (!substring) 2335 return; 2336 bounds.push_back(fir::getBase(asScalar(substring->lower()))); 2337 if (auto upper = substring->upper()) 2338 bounds.push_back(fir::getBase(asScalar(*upper))); 2339 } 2340 2341 /// Default store to destination implementation. 2342 /// This implements the default case, which is to assign the value in 2343 /// `iters.element` into the destination array, `iters.innerArgument`. Handles 2344 /// by value and by reference assignment. 2345 CC defaultStoreToDestination(const Fortran::evaluate::Substring *substring) { 2346 return [=](IterSpace iterSpace) -> ExtValue { 2347 mlir::Location loc = getLoc(); 2348 mlir::Value innerArg = iterSpace.innerArgument(); 2349 fir::ExtendedValue exv = iterSpace.elementExv(); 2350 mlir::Type arrTy = innerArg.getType(); 2351 mlir::Type eleTy = fir::applyPathToType(arrTy, iterSpace.iterVec()); 2352 if (isAdjustedArrayElementType(eleTy)) { 2353 TODO(loc, "isAdjustedArrayElementType"); 2354 } 2355 // By value semantics. The element is being assigned by value. 2356 mlir::Value ele = builder.createConvert(loc, eleTy, fir::getBase(exv)); 2357 auto update = builder.create<fir::ArrayUpdateOp>( 2358 loc, arrTy, innerArg, ele, iterSpace.iterVec(), 2359 destination.getTypeparams()); 2360 return abstractArrayExtValue(update); 2361 }; 2362 } 2363 2364 /// For an elemental array expression. 2365 /// 1. Lower the scalars and array loads. 2366 /// 2. Create the iteration space. 2367 /// 3. Create the element-by-element computation in the loop. 2368 /// 4. Return the resulting array value. 2369 /// If no destination was set in the array context, a temporary of 2370 /// \p resultTy will be created to hold the evaluated expression. 2371 /// Otherwise, \p resultTy is ignored and the expression is evaluated 2372 /// in the destination. \p f is a continuation built from an 2373 /// evaluate::Expr or an ExtendedValue. 2374 ExtValue lowerArrayExpression(CC f, mlir::Type resultTy) { 2375 mlir::Location loc = getLoc(); 2376 auto [iterSpace, insPt] = genIterSpace(resultTy); 2377 auto exv = f(iterSpace); 2378 iterSpace.setElement(std::move(exv)); 2379 auto lambda = ccStoreToDest.hasValue() 2380 ? ccStoreToDest.getValue() 2381 : defaultStoreToDestination(/*substring=*/nullptr); 2382 mlir::Value updVal = fir::getBase(lambda(iterSpace)); 2383 finalizeElementCtx(); 2384 builder.create<fir::ResultOp>(loc, updVal); 2385 builder.restoreInsertionPoint(insPt); 2386 return abstractArrayExtValue(iterSpace.outerResult()); 2387 } 2388 2389 /// Get the shape from an ArrayOperand. The shape of the array is adjusted if 2390 /// the array was sliced. 2391 llvm::SmallVector<mlir::Value> getShape(ArrayOperand array) { 2392 // if (array.slice) 2393 // return computeSliceShape(array.slice); 2394 if (array.memref.getType().isa<fir::BoxType>()) 2395 return fir::factory::readExtents(builder, getLoc(), 2396 fir::BoxValue{array.memref}); 2397 std::vector<mlir::Value, std::allocator<mlir::Value>> extents = 2398 fir::factory::getExtents(array.shape); 2399 return {extents.begin(), extents.end()}; 2400 } 2401 2402 /// Get the shape from an ArrayLoad. 2403 llvm::SmallVector<mlir::Value> getShape(fir::ArrayLoadOp arrayLoad) { 2404 return getShape(ArrayOperand{arrayLoad.getMemref(), arrayLoad.getShape(), 2405 arrayLoad.getSlice()}); 2406 } 2407 2408 /// Returns the first array operand that may not be absent. If all 2409 /// array operands may be absent, return the first one. 2410 const ArrayOperand &getInducingShapeArrayOperand() const { 2411 assert(!arrayOperands.empty()); 2412 for (const ArrayOperand &op : arrayOperands) 2413 if (!op.mayBeAbsent) 2414 return op; 2415 // If all arrays operand appears in optional position, then none of them 2416 // is allowed to be absent as per 15.5.2.12 point 3. (6). Just pick the 2417 // first operands. 2418 // TODO: There is an opportunity to add a runtime check here that 2419 // this array is present as required. 2420 return arrayOperands[0]; 2421 } 2422 2423 /// Generate the shape of the iteration space over the array expression. The 2424 /// iteration space may be implicit, explicit, or both. If it is implied it is 2425 /// based on the destination and operand array loads, or an optional 2426 /// Fortran::evaluate::Shape from the front end. If the shape is explicit, 2427 /// this returns any implicit shape component, if it exists. 2428 llvm::SmallVector<mlir::Value> genIterationShape() { 2429 // Use the precomputed destination shape. 2430 if (!destShape.empty()) 2431 return destShape; 2432 // Otherwise, use the destination's shape. 2433 if (destination) 2434 return getShape(destination); 2435 // Otherwise, use the first ArrayLoad operand shape. 2436 if (!arrayOperands.empty()) 2437 return getShape(getInducingShapeArrayOperand()); 2438 fir::emitFatalError(getLoc(), 2439 "failed to compute the array expression shape"); 2440 } 2441 2442 bool explicitSpaceIsActive() const { 2443 return explicitSpace && explicitSpace->isActive(); 2444 } 2445 2446 bool implicitSpaceHasMasks() const { 2447 return implicitSpace && !implicitSpace->empty(); 2448 } 2449 2450 explicit ArrayExprLowering(Fortran::lower::AbstractConverter &converter, 2451 Fortran::lower::StatementContext &stmtCtx, 2452 Fortran::lower::SymMap &symMap) 2453 : converter{converter}, builder{converter.getFirOpBuilder()}, 2454 stmtCtx{stmtCtx}, symMap{symMap} {} 2455 2456 explicit ArrayExprLowering(Fortran::lower::AbstractConverter &converter, 2457 Fortran::lower::StatementContext &stmtCtx, 2458 Fortran::lower::SymMap &symMap, 2459 ConstituentSemantics sem) 2460 : converter{converter}, builder{converter.getFirOpBuilder()}, 2461 stmtCtx{stmtCtx}, symMap{symMap}, semant{sem} {} 2462 2463 explicit ArrayExprLowering(Fortran::lower::AbstractConverter &converter, 2464 Fortran::lower::StatementContext &stmtCtx, 2465 Fortran::lower::SymMap &symMap, 2466 ConstituentSemantics sem, 2467 Fortran::lower::ExplicitIterSpace *expSpace, 2468 Fortran::lower::ImplicitIterSpace *impSpace) 2469 : converter{converter}, builder{converter.getFirOpBuilder()}, 2470 stmtCtx{stmtCtx}, symMap{symMap}, 2471 explicitSpace(expSpace->isActive() ? expSpace : nullptr), 2472 implicitSpace(impSpace->empty() ? nullptr : impSpace), semant{sem} { 2473 // Generate any mask expressions, as necessary. This is the compute step 2474 // that creates the effective masks. See 10.2.3.2 in particular. 2475 // genMasks(); 2476 } 2477 2478 mlir::Location getLoc() { return converter.getCurrentLocation(); } 2479 2480 /// Array appears in a lhs context such that it is assigned after the rhs is 2481 /// fully evaluated. 2482 inline bool isCopyInCopyOut() { 2483 return semant == ConstituentSemantics::CopyInCopyOut; 2484 } 2485 2486 /// Array appears in a lhs (or temp) context such that a projected, 2487 /// discontiguous subspace of the array is assigned after the rhs is fully 2488 /// evaluated. That is, the rhs array value is merged into a section of the 2489 /// lhs array. 2490 inline bool isProjectedCopyInCopyOut() { 2491 return semant == ConstituentSemantics::ProjectedCopyInCopyOut; 2492 } 2493 2494 inline bool isCustomCopyInCopyOut() { 2495 return semant == ConstituentSemantics::CustomCopyInCopyOut; 2496 } 2497 2498 /// Array appears in a context where it must be boxed. 2499 inline bool isBoxValue() { return semant == ConstituentSemantics::BoxValue; } 2500 2501 /// Array appears in a context where differences in the memory reference can 2502 /// be observable in the computational results. For example, an array 2503 /// element is passed to an impure procedure. 2504 inline bool isReferentiallyOpaque() { 2505 return semant == ConstituentSemantics::RefOpaque; 2506 } 2507 2508 /// Array appears in a context where it is passed as a VALUE argument. 2509 inline bool isValueAttribute() { 2510 return semant == ConstituentSemantics::ByValueArg; 2511 } 2512 2513 /// Can the loops over the expression be unordered? 2514 inline bool isUnordered() const { return unordered; } 2515 2516 void setUnordered(bool b) { unordered = b; } 2517 2518 Fortran::lower::AbstractConverter &converter; 2519 fir::FirOpBuilder &builder; 2520 Fortran::lower::StatementContext &stmtCtx; 2521 bool elementCtx = false; 2522 Fortran::lower::SymMap &symMap; 2523 /// The continuation to generate code to update the destination. 2524 llvm::Optional<CC> ccStoreToDest; 2525 llvm::Optional<std::function<void(llvm::ArrayRef<mlir::Value>)>> ccPrelude; 2526 llvm::Optional<std::function<fir::ArrayLoadOp(llvm::ArrayRef<mlir::Value>)>> 2527 ccLoadDest; 2528 /// The destination is the loaded array into which the results will be 2529 /// merged. 2530 fir::ArrayLoadOp destination; 2531 /// The shape of the destination. 2532 llvm::SmallVector<mlir::Value> destShape; 2533 /// List of arrays in the expression that have been loaded. 2534 llvm::SmallVector<ArrayOperand> arrayOperands; 2535 /// If there is a user-defined iteration space, explicitShape will hold the 2536 /// information from the front end. 2537 Fortran::lower::ExplicitIterSpace *explicitSpace = nullptr; 2538 Fortran::lower::ImplicitIterSpace *implicitSpace = nullptr; 2539 ConstituentSemantics semant = ConstituentSemantics::RefTransparent; 2540 // Can the array expression be evaluated in any order? 2541 // Will be set to false if any of the expression parts prevent this. 2542 bool unordered = true; 2543 }; 2544 } // namespace 2545 2546 fir::ExtendedValue Fortran::lower::createSomeExtendedExpression( 2547 mlir::Location loc, Fortran::lower::AbstractConverter &converter, 2548 const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap, 2549 Fortran::lower::StatementContext &stmtCtx) { 2550 LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "expr: ") << '\n'); 2551 return ScalarExprLowering{loc, converter, symMap, stmtCtx}.genval(expr); 2552 } 2553 2554 fir::ExtendedValue Fortran::lower::createSomeExtendedAddress( 2555 mlir::Location loc, Fortran::lower::AbstractConverter &converter, 2556 const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap, 2557 Fortran::lower::StatementContext &stmtCtx) { 2558 LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "address: ") << '\n'); 2559 return ScalarExprLowering{loc, converter, symMap, stmtCtx}.gen(expr); 2560 } 2561 2562 fir::MutableBoxValue Fortran::lower::createMutableBox( 2563 mlir::Location loc, Fortran::lower::AbstractConverter &converter, 2564 const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap) { 2565 // MutableBox lowering StatementContext does not need to be propagated 2566 // to the caller because the result value is a variable, not a temporary 2567 // expression. The StatementContext clean-up can occur before using the 2568 // resulting MutableBoxValue. Variables of all other types are handled in the 2569 // bridge. 2570 Fortran::lower::StatementContext dummyStmtCtx; 2571 return ScalarExprLowering{loc, converter, symMap, dummyStmtCtx} 2572 .genMutableBoxValue(expr); 2573 } 2574 2575 mlir::Value Fortran::lower::createSubroutineCall( 2576 AbstractConverter &converter, const evaluate::ProcedureRef &call, 2577 SymMap &symMap, StatementContext &stmtCtx) { 2578 mlir::Location loc = converter.getCurrentLocation(); 2579 2580 // Simple subroutine call, with potential alternate return. 2581 auto res = Fortran::lower::createSomeExtendedExpression( 2582 loc, converter, toEvExpr(call), symMap, stmtCtx); 2583 return fir::getBase(res); 2584 } 2585 2586 void Fortran::lower::createSomeArrayAssignment( 2587 Fortran::lower::AbstractConverter &converter, 2588 const Fortran::lower::SomeExpr &lhs, const Fortran::lower::SomeExpr &rhs, 2589 Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx) { 2590 LLVM_DEBUG(lhs.AsFortran(llvm::dbgs() << "onto array: ") << '\n'; 2591 rhs.AsFortran(llvm::dbgs() << "assign expression: ") << '\n';); 2592 ArrayExprLowering::lowerArrayAssignment(converter, symMap, stmtCtx, lhs, rhs); 2593 } 2594 2595 void Fortran::lower::createSomeArrayAssignment( 2596 Fortran::lower::AbstractConverter &converter, const fir::ExtendedValue &lhs, 2597 const fir::ExtendedValue &rhs, Fortran::lower::SymMap &symMap, 2598 Fortran::lower::StatementContext &stmtCtx) { 2599 LLVM_DEBUG(llvm::dbgs() << "onto array: " << lhs << '\n'; 2600 llvm::dbgs() << "assign expression: " << rhs << '\n';); 2601 ArrayExprLowering::lowerArrayAssignment(converter, symMap, stmtCtx, lhs, rhs); 2602 } 2603 2604 void Fortran::lower::createAllocatableArrayAssignment( 2605 Fortran::lower::AbstractConverter &converter, 2606 const Fortran::lower::SomeExpr &lhs, const Fortran::lower::SomeExpr &rhs, 2607 Fortran::lower::ExplicitIterSpace &explicitSpace, 2608 Fortran::lower::ImplicitIterSpace &implicitSpace, 2609 Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx) { 2610 LLVM_DEBUG(lhs.AsFortran(llvm::dbgs() << "defining array: ") << '\n'; 2611 rhs.AsFortran(llvm::dbgs() << "assign expression: ") 2612 << " given the explicit iteration space:\n" 2613 << explicitSpace << "\n and implied mask conditions:\n" 2614 << implicitSpace << '\n';); 2615 ArrayExprLowering::lowerAllocatableArrayAssignment( 2616 converter, symMap, stmtCtx, lhs, rhs, explicitSpace, implicitSpace); 2617 } 2618