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/real.h" 16 #include "flang/Evaluate/traverse.h" 17 #include "flang/Lower/AbstractConverter.h" 18 #include "flang/Lower/IntrinsicCall.h" 19 #include "flang/Lower/SymbolMap.h" 20 #include "flang/Lower/Todo.h" 21 #include "flang/Semantics/expression.h" 22 #include "flang/Semantics/symbol.h" 23 #include "flang/Semantics/tools.h" 24 #include "flang/Semantics/type.h" 25 #include "mlir/Dialect/StandardOps/IR/Ops.h" 26 #include "llvm/Support/Debug.h" 27 28 #define DEBUG_TYPE "flang-lower-expr" 29 30 //===----------------------------------------------------------------------===// 31 // The composition and structure of Fortran::evaluate::Expr is defined in 32 // the various header files in include/flang/Evaluate. You are referred 33 // there for more information on these data structures. Generally speaking, 34 // these data structures are a strongly typed family of abstract data types 35 // that, composed as trees, describe the syntax of Fortran expressions. 36 // 37 // This part of the bridge can traverse these tree structures and lower them 38 // to the correct FIR representation in SSA form. 39 //===----------------------------------------------------------------------===// 40 41 /// Place \p exv in memory if it is not already a memory reference. If 42 /// \p forceValueType is provided, the value is first casted to the provided 43 /// type before being stored (this is mainly intended for logicals whose value 44 /// may be `i1` but needed to be stored as Fortran logicals). 45 static fir::ExtendedValue 46 placeScalarValueInMemory(fir::FirOpBuilder &builder, mlir::Location loc, 47 const fir::ExtendedValue &exv, 48 mlir::Type storageType) { 49 mlir::Value valBase = fir::getBase(exv); 50 if (fir::conformsWithPassByRef(valBase.getType())) 51 return exv; 52 53 assert(!fir::hasDynamicSize(storageType) && 54 "only expect statically sized scalars to be by value"); 55 56 // Since `a` is not itself a valid referent, determine its value and 57 // create a temporary location at the beginning of the function for 58 // referencing. 59 mlir::Value val = builder.createConvert(loc, storageType, valBase); 60 mlir::Value temp = builder.createTemporary( 61 loc, storageType, 62 llvm::ArrayRef<mlir::NamedAttribute>{ 63 Fortran::lower::getAdaptToByRefAttr(builder)}); 64 builder.create<fir::StoreOp>(loc, val, temp); 65 return fir::substBase(exv, temp); 66 } 67 68 /// Generate a load of a value from an address. Beware that this will lose 69 /// any dynamic type information for polymorphic entities (note that unlimited 70 /// polymorphic cannot be loaded and must not be provided here). 71 static fir::ExtendedValue genLoad(fir::FirOpBuilder &builder, 72 mlir::Location loc, 73 const fir::ExtendedValue &addr) { 74 return addr.match( 75 [](const fir::CharBoxValue &box) -> fir::ExtendedValue { return box; }, 76 [&](const fir::UnboxedValue &v) -> fir::ExtendedValue { 77 if (fir::unwrapRefType(fir::getBase(v).getType()) 78 .isa<fir::RecordType>()) 79 return v; 80 return builder.create<fir::LoadOp>(loc, fir::getBase(v)); 81 }, 82 [&](const fir::MutableBoxValue &box) -> fir::ExtendedValue { 83 TODO(loc, "genLoad for MutableBoxValue"); 84 }, 85 [&](const fir::BoxValue &box) -> fir::ExtendedValue { 86 TODO(loc, "genLoad for BoxValue"); 87 }, 88 [&](const auto &) -> fir::ExtendedValue { 89 fir::emitFatalError( 90 loc, "attempting to load whole array or procedure address"); 91 }); 92 } 93 94 /// Is this a call to an elemental procedure with at least one array argument? 95 static bool 96 isElementalProcWithArrayArgs(const Fortran::evaluate::ProcedureRef &procRef) { 97 if (procRef.IsElemental()) 98 for (const std::optional<Fortran::evaluate::ActualArgument> &arg : 99 procRef.arguments()) 100 if (arg && arg->Rank() != 0) 101 return true; 102 return false; 103 } 104 namespace { 105 106 /// Lowering of Fortran::evaluate::Expr<T> expressions 107 class ScalarExprLowering { 108 public: 109 using ExtValue = fir::ExtendedValue; 110 111 explicit ScalarExprLowering(mlir::Location loc, 112 Fortran::lower::AbstractConverter &converter, 113 Fortran::lower::SymMap &symMap) 114 : location{loc}, converter{converter}, 115 builder{converter.getFirOpBuilder()}, symMap{symMap} {} 116 117 mlir::Location getLoc() { return location; } 118 119 template <typename A> 120 mlir::Value genunbox(const A &expr) { 121 ExtValue e = genval(expr); 122 if (const fir::UnboxedValue *r = e.getUnboxed()) 123 return *r; 124 fir::emitFatalError(getLoc(), "unboxed expression expected"); 125 } 126 127 /// Generate an integral constant of `value` 128 template <int KIND> 129 mlir::Value genIntegerConstant(mlir::MLIRContext *context, 130 std::int64_t value) { 131 mlir::Type type = 132 converter.genType(Fortran::common::TypeCategory::Integer, KIND); 133 return builder.createIntegerConstant(getLoc(), type, value); 134 } 135 136 /// Generate a logical/boolean constant of `value` 137 mlir::Value genBoolConstant(bool value) { 138 return builder.createBool(getLoc(), value); 139 } 140 141 /// Returns a reference to a symbol or its box/boxChar descriptor if it has 142 /// one. 143 ExtValue gen(Fortran::semantics::SymbolRef sym) { 144 if (Fortran::lower::SymbolBox val = symMap.lookupSymbol(sym)) 145 return val.match([&val](auto &) { return val.toExtendedValue(); }); 146 LLVM_DEBUG(llvm::dbgs() 147 << "unknown symbol: " << sym << "\nmap: " << symMap << '\n'); 148 fir::emitFatalError(getLoc(), "symbol is not mapped to any IR value"); 149 } 150 151 ExtValue genLoad(const ExtValue &exv) { 152 return ::genLoad(builder, getLoc(), exv); 153 } 154 155 ExtValue genval(Fortran::semantics::SymbolRef sym) { 156 ExtValue var = gen(sym); 157 if (const fir::UnboxedValue *s = var.getUnboxed()) 158 if (fir::isReferenceLike(s->getType())) 159 return genLoad(*s); 160 return var; 161 } 162 163 ExtValue genval(const Fortran::evaluate::BOZLiteralConstant &) { 164 TODO(getLoc(), "genval BOZ"); 165 } 166 167 /// Return indirection to function designated in ProcedureDesignator. 168 /// The type of the function indirection is not guaranteed to match the one 169 /// of the ProcedureDesignator due to Fortran implicit typing rules. 170 ExtValue genval(const Fortran::evaluate::ProcedureDesignator &proc) { 171 TODO(getLoc(), "genval ProcedureDesignator"); 172 } 173 174 ExtValue genval(const Fortran::evaluate::NullPointer &) { 175 TODO(getLoc(), "genval NullPointer"); 176 } 177 178 ExtValue genval(const Fortran::evaluate::StructureConstructor &ctor) { 179 TODO(getLoc(), "genval StructureConstructor"); 180 } 181 182 /// Lowering of an <i>ac-do-variable</i>, which is not a Symbol. 183 ExtValue genval(const Fortran::evaluate::ImpliedDoIndex &var) { 184 TODO(getLoc(), "genval ImpliedDoIndex"); 185 } 186 187 ExtValue genval(const Fortran::evaluate::DescriptorInquiry &desc) { 188 TODO(getLoc(), "genval DescriptorInquiry"); 189 } 190 191 ExtValue genval(const Fortran::evaluate::TypeParamInquiry &) { 192 TODO(getLoc(), "genval TypeParamInquiry"); 193 } 194 195 template <int KIND> 196 ExtValue genval(const Fortran::evaluate::ComplexComponent<KIND> &part) { 197 TODO(getLoc(), "genval ComplexComponent"); 198 } 199 200 template <int KIND> 201 ExtValue genval(const Fortran::evaluate::Negate<Fortran::evaluate::Type< 202 Fortran::common::TypeCategory::Integer, KIND>> &op) { 203 mlir::Value input = genunbox(op.left()); 204 // Like LLVM, integer negation is the binary op "0 - value" 205 mlir::Value zero = genIntegerConstant<KIND>(builder.getContext(), 0); 206 return builder.create<mlir::arith::SubIOp>(getLoc(), zero, input); 207 } 208 209 template <int KIND> 210 ExtValue genval(const Fortran::evaluate::Negate<Fortran::evaluate::Type< 211 Fortran::common::TypeCategory::Real, KIND>> &op) { 212 return builder.create<mlir::arith::NegFOp>(getLoc(), genunbox(op.left())); 213 } 214 template <int KIND> 215 ExtValue genval(const Fortran::evaluate::Negate<Fortran::evaluate::Type< 216 Fortran::common::TypeCategory::Complex, KIND>> &op) { 217 return builder.create<fir::NegcOp>(getLoc(), genunbox(op.left())); 218 } 219 220 template <typename OpTy> 221 mlir::Value createBinaryOp(const ExtValue &left, const ExtValue &right) { 222 assert(fir::isUnboxedValue(left) && fir::isUnboxedValue(right)); 223 mlir::Value lhs = fir::getBase(left); 224 mlir::Value rhs = fir::getBase(right); 225 assert(lhs.getType() == rhs.getType() && "types must be the same"); 226 return builder.create<OpTy>(getLoc(), lhs, rhs); 227 } 228 229 template <typename OpTy, typename A> 230 mlir::Value createBinaryOp(const A &ex) { 231 ExtValue left = genval(ex.left()); 232 return createBinaryOp<OpTy>(left, genval(ex.right())); 233 } 234 235 #undef GENBIN 236 #define GENBIN(GenBinEvOp, GenBinTyCat, GenBinFirOp) \ 237 template <int KIND> \ 238 ExtValue genval(const Fortran::evaluate::GenBinEvOp<Fortran::evaluate::Type< \ 239 Fortran::common::TypeCategory::GenBinTyCat, KIND>> &x) { \ 240 return createBinaryOp<GenBinFirOp>(x); \ 241 } 242 243 GENBIN(Add, Integer, mlir::arith::AddIOp) 244 GENBIN(Add, Real, mlir::arith::AddFOp) 245 GENBIN(Add, Complex, fir::AddcOp) 246 GENBIN(Subtract, Integer, mlir::arith::SubIOp) 247 GENBIN(Subtract, Real, mlir::arith::SubFOp) 248 GENBIN(Subtract, Complex, fir::SubcOp) 249 GENBIN(Multiply, Integer, mlir::arith::MulIOp) 250 GENBIN(Multiply, Real, mlir::arith::MulFOp) 251 GENBIN(Multiply, Complex, fir::MulcOp) 252 GENBIN(Divide, Integer, mlir::arith::DivSIOp) 253 GENBIN(Divide, Real, mlir::arith::DivFOp) 254 GENBIN(Divide, Complex, fir::DivcOp) 255 256 template <Fortran::common::TypeCategory TC, int KIND> 257 ExtValue genval( 258 const Fortran::evaluate::Power<Fortran::evaluate::Type<TC, KIND>> &op) { 259 TODO(getLoc(), "genval Power"); 260 } 261 262 template <Fortran::common::TypeCategory TC, int KIND> 263 ExtValue genval( 264 const Fortran::evaluate::RealToIntPower<Fortran::evaluate::Type<TC, KIND>> 265 &op) { 266 TODO(getLoc(), "genval RealToInt"); 267 } 268 269 template <int KIND> 270 ExtValue genval(const Fortran::evaluate::ComplexConstructor<KIND> &op) { 271 TODO(getLoc(), "genval ComplexConstructor"); 272 } 273 274 template <int KIND> 275 ExtValue genval(const Fortran::evaluate::Concat<KIND> &op) { 276 TODO(getLoc(), "genval Concat<KIND>"); 277 } 278 279 /// MIN and MAX operations 280 template <Fortran::common::TypeCategory TC, int KIND> 281 ExtValue 282 genval(const Fortran::evaluate::Extremum<Fortran::evaluate::Type<TC, KIND>> 283 &op) { 284 TODO(getLoc(), "genval Extremum<TC, KIND>"); 285 } 286 287 template <int KIND> 288 ExtValue genval(const Fortran::evaluate::SetLength<KIND> &x) { 289 TODO(getLoc(), "genval SetLength<KIND>"); 290 } 291 292 template <int KIND> 293 ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type< 294 Fortran::common::TypeCategory::Integer, KIND>> &op) { 295 TODO(getLoc(), "genval integer comparison"); 296 } 297 template <int KIND> 298 ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type< 299 Fortran::common::TypeCategory::Real, KIND>> &op) { 300 TODO(getLoc(), "genval real comparison"); 301 } 302 template <int KIND> 303 ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type< 304 Fortran::common::TypeCategory::Complex, KIND>> &op) { 305 TODO(getLoc(), "genval complex comparison"); 306 } 307 template <int KIND> 308 ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type< 309 Fortran::common::TypeCategory::Character, KIND>> &op) { 310 TODO(getLoc(), "genval char comparison"); 311 } 312 313 ExtValue 314 genval(const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &op) { 315 TODO(getLoc(), "genval comparison"); 316 } 317 318 template <Fortran::common::TypeCategory TC1, int KIND, 319 Fortran::common::TypeCategory TC2> 320 ExtValue 321 genval(const Fortran::evaluate::Convert<Fortran::evaluate::Type<TC1, KIND>, 322 TC2> &convert) { 323 mlir::Type ty = converter.genType(TC1, KIND); 324 mlir::Value operand = genunbox(convert.left()); 325 return builder.convertWithSemantics(getLoc(), ty, operand); 326 } 327 328 template <typename A> 329 ExtValue genval(const Fortran::evaluate::Parentheses<A> &op) { 330 TODO(getLoc(), "genval parentheses<A>"); 331 } 332 333 template <int KIND> 334 ExtValue genval(const Fortran::evaluate::Not<KIND> &op) { 335 TODO(getLoc(), "genval Not<KIND>"); 336 } 337 338 template <int KIND> 339 ExtValue genval(const Fortran::evaluate::LogicalOperation<KIND> &op) { 340 TODO(getLoc(), "genval LogicalOperation<KIND>"); 341 } 342 343 /// Convert a scalar literal constant to IR. 344 template <Fortran::common::TypeCategory TC, int KIND> 345 ExtValue genScalarLit( 346 const Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>> 347 &value) { 348 if constexpr (TC == Fortran::common::TypeCategory::Integer) { 349 return genIntegerConstant<KIND>(builder.getContext(), value.ToInt64()); 350 } else if constexpr (TC == Fortran::common::TypeCategory::Logical) { 351 return genBoolConstant(value.IsTrue()); 352 } else if constexpr (TC == Fortran::common::TypeCategory::Real) { 353 TODO(getLoc(), "genval real constant"); 354 } else if constexpr (TC == Fortran::common::TypeCategory::Complex) { 355 TODO(getLoc(), "genval complex constant"); 356 } else /*constexpr*/ { 357 llvm_unreachable("unhandled constant"); 358 } 359 } 360 361 /// Convert a ascii scalar literal CHARACTER to IR. (specialization) 362 ExtValue 363 genAsciiScalarLit(const Fortran::evaluate::Scalar<Fortran::evaluate::Type< 364 Fortran::common::TypeCategory::Character, 1>> &value, 365 int64_t len) { 366 assert(value.size() == static_cast<std::uint64_t>(len) && 367 "value.size() doesn't match with len"); 368 return fir::factory::createStringLiteral(builder, getLoc(), value); 369 } 370 371 template <Fortran::common::TypeCategory TC, int KIND> 372 ExtValue 373 genval(const Fortran::evaluate::Constant<Fortran::evaluate::Type<TC, KIND>> 374 &con) { 375 if (con.Rank() > 0) 376 TODO(getLoc(), "genval array constant"); 377 std::optional<Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>>> 378 opt = con.GetScalarValue(); 379 assert(opt.has_value() && "constant has no value"); 380 if constexpr (TC == Fortran::common::TypeCategory::Character) { 381 if constexpr (KIND == 1) 382 return genAsciiScalarLit(opt.value(), con.LEN()); 383 TODO(getLoc(), "genval for Character with KIND != 1"); 384 } else { 385 return genScalarLit<TC, KIND>(opt.value()); 386 } 387 } 388 389 fir::ExtendedValue genval( 390 const Fortran::evaluate::Constant<Fortran::evaluate::SomeDerived> &con) { 391 TODO(getLoc(), "genval constant derived"); 392 } 393 394 template <typename A> 395 ExtValue genval(const Fortran::evaluate::ArrayConstructor<A> &) { 396 TODO(getLoc(), "genval ArrayConstructor<A>"); 397 } 398 399 ExtValue gen(const Fortran::evaluate::ComplexPart &x) { 400 TODO(getLoc(), "gen ComplexPart"); 401 } 402 ExtValue genval(const Fortran::evaluate::ComplexPart &x) { 403 TODO(getLoc(), "genval ComplexPart"); 404 } 405 406 ExtValue gen(const Fortran::evaluate::Substring &s) { 407 TODO(getLoc(), "gen Substring"); 408 } 409 ExtValue genval(const Fortran::evaluate::Substring &ss) { 410 TODO(getLoc(), "genval Substring"); 411 } 412 413 ExtValue genval(const Fortran::evaluate::Subscript &subs) { 414 TODO(getLoc(), "genval Subscript"); 415 } 416 417 ExtValue gen(const Fortran::evaluate::DataRef &dref) { 418 TODO(getLoc(), "gen DataRef"); 419 } 420 ExtValue genval(const Fortran::evaluate::DataRef &dref) { 421 TODO(getLoc(), "genval DataRef"); 422 } 423 424 ExtValue gen(const Fortran::evaluate::Component &cmpt) { 425 TODO(getLoc(), "gen Component"); 426 } 427 ExtValue genval(const Fortran::evaluate::Component &cmpt) { 428 TODO(getLoc(), "genval Component"); 429 } 430 431 ExtValue genval(const Fortran::semantics::Bound &bound) { 432 TODO(getLoc(), "genval Bound"); 433 } 434 435 ExtValue gen(const Fortran::evaluate::ArrayRef &aref) { 436 TODO(getLoc(), "gen ArrayRef"); 437 } 438 ExtValue genval(const Fortran::evaluate::ArrayRef &aref) { 439 TODO(getLoc(), "genval ArrayRef"); 440 } 441 442 ExtValue gen(const Fortran::evaluate::CoarrayRef &coref) { 443 TODO(getLoc(), "gen CoarrayRef"); 444 } 445 ExtValue genval(const Fortran::evaluate::CoarrayRef &coref) { 446 TODO(getLoc(), "genval CoarrayRef"); 447 } 448 449 template <typename A> 450 ExtValue gen(const Fortran::evaluate::Designator<A> &des) { 451 return std::visit([&](const auto &x) { return gen(x); }, des.u); 452 } 453 template <typename A> 454 ExtValue genval(const Fortran::evaluate::Designator<A> &des) { 455 return std::visit([&](const auto &x) { return genval(x); }, des.u); 456 } 457 458 mlir::Type genType(const Fortran::evaluate::DynamicType &dt) { 459 if (dt.category() != Fortran::common::TypeCategory::Derived) 460 return converter.genType(dt.category(), dt.kind()); 461 TODO(getLoc(), "genType Derived Type"); 462 } 463 464 /// Lower a function reference 465 template <typename A> 466 ExtValue genFunctionRef(const Fortran::evaluate::FunctionRef<A> &funcRef) { 467 if (!funcRef.GetType().has_value()) 468 fir::emitFatalError(getLoc(), "internal: a function must have a type"); 469 mlir::Type resTy = genType(*funcRef.GetType()); 470 return genProcedureRef(funcRef, {resTy}); 471 } 472 473 /// Lower function call `funcRef` and return a reference to the resultant 474 /// value. This is required for lowering expressions such as `f1(f2(v))`. 475 template <typename A> 476 ExtValue gen(const Fortran::evaluate::FunctionRef<A> &funcRef) { 477 TODO(getLoc(), "gen FunctionRef<A>"); 478 } 479 480 template <typename A> 481 ExtValue genval(const Fortran::evaluate::FunctionRef<A> &funcRef) { 482 ExtValue result = genFunctionRef(funcRef); 483 if (result.rank() == 0 && fir::isa_ref_type(fir::getBase(result).getType())) 484 return genLoad(result); 485 return result; 486 } 487 488 ExtValue genval(const Fortran::evaluate::ProcedureRef &procRef) { 489 TODO(getLoc(), "genval ProcedureRef"); 490 } 491 492 /// Generate a call to an intrinsic function. 493 ExtValue 494 genIntrinsicRef(const Fortran::evaluate::ProcedureRef &procRef, 495 const Fortran::evaluate::SpecificIntrinsic &intrinsic, 496 llvm::Optional<mlir::Type> resultType) { 497 llvm::SmallVector<ExtValue> operands; 498 499 llvm::StringRef name = intrinsic.name; 500 mlir::Location loc = getLoc(); 501 502 const Fortran::lower::IntrinsicArgumentLoweringRules *argLowering = 503 Fortran::lower::getIntrinsicArgumentLowering(name); 504 for (const auto &[arg, dummy] : 505 llvm::zip(procRef.arguments(), 506 intrinsic.characteristics.value().dummyArguments)) { 507 auto *expr = Fortran::evaluate::UnwrapExpr<Fortran::lower::SomeExpr>(arg); 508 if (!expr) { 509 // Absent optional. 510 operands.emplace_back(Fortran::lower::getAbsentIntrinsicArgument()); 511 continue; 512 } 513 if (!argLowering) { 514 // No argument lowering instruction, lower by value. 515 operands.emplace_back(genval(*expr)); 516 continue; 517 } 518 // Ad-hoc argument lowering handling. 519 Fortran::lower::ArgLoweringRule argRules = 520 Fortran::lower::lowerIntrinsicArgumentAs(loc, *argLowering, 521 dummy.name); 522 switch (argRules.lowerAs) { 523 case Fortran::lower::LowerIntrinsicArgAs::Value: 524 operands.emplace_back(genval(*expr)); 525 continue; 526 case Fortran::lower::LowerIntrinsicArgAs::Addr: 527 TODO(getLoc(), "argument lowering for Addr"); 528 continue; 529 case Fortran::lower::LowerIntrinsicArgAs::Box: 530 TODO(getLoc(), "argument lowering for Box"); 531 continue; 532 case Fortran::lower::LowerIntrinsicArgAs::Inquired: 533 TODO(getLoc(), "argument lowering for Inquired"); 534 continue; 535 } 536 llvm_unreachable("bad switch"); 537 } 538 // Let the intrinsic library lower the intrinsic procedure call 539 return Fortran::lower::genIntrinsicCall(builder, getLoc(), name, resultType, 540 operands); 541 } 542 543 template <typename A> 544 ExtValue genval(const Fortran::evaluate::Expr<A> &x) { 545 if (isScalar(x)) 546 return std::visit([&](const auto &e) { return genval(e); }, x.u); 547 TODO(getLoc(), "genval Expr<A> arrays"); 548 } 549 550 /// Lower a non-elemental procedure reference. 551 // TODO: Handle read allocatable and pointer results. 552 ExtValue genProcedureRef(const Fortran::evaluate::ProcedureRef &procRef, 553 llvm::Optional<mlir::Type> resultType) { 554 ExtValue res = genRawProcedureRef(procRef, resultType); 555 return res; 556 } 557 558 /// Lower a non-elemental procedure reference. 559 ExtValue genRawProcedureRef(const Fortran::evaluate::ProcedureRef &procRef, 560 llvm::Optional<mlir::Type> resultType) { 561 mlir::Location loc = getLoc(); 562 if (isElementalProcWithArrayArgs(procRef)) 563 fir::emitFatalError(loc, "trying to lower elemental procedure with array " 564 "arguments as normal procedure"); 565 if (const Fortran::evaluate::SpecificIntrinsic *intrinsic = 566 procRef.proc().GetSpecificIntrinsic()) 567 return genIntrinsicRef(procRef, *intrinsic, resultType); 568 569 return {}; 570 } 571 572 /// Helper to detect Transformational function reference. 573 template <typename T> 574 bool isTransformationalRef(const T &) { 575 return false; 576 } 577 template <typename T> 578 bool isTransformationalRef(const Fortran::evaluate::FunctionRef<T> &funcRef) { 579 return !funcRef.IsElemental() && funcRef.Rank(); 580 } 581 template <typename T> 582 bool isTransformationalRef(Fortran::evaluate::Expr<T> expr) { 583 return std::visit([&](const auto &e) { return isTransformationalRef(e); }, 584 expr.u); 585 } 586 587 template <typename A> 588 ExtValue gen(const Fortran::evaluate::Expr<A> &x) { 589 // Whole array symbols or components, and results of transformational 590 // functions already have a storage and the scalar expression lowering path 591 // is used to not create a new temporary storage. 592 if (isScalar(x) || 593 Fortran::evaluate::UnwrapWholeSymbolOrComponentDataRef(x) || 594 isTransformationalRef(x)) 595 return std::visit([&](const auto &e) { return genref(e); }, x.u); 596 TODO(getLoc(), "gen Expr non-scalar"); 597 } 598 599 template <typename A> 600 bool isScalar(const A &x) { 601 return x.Rank() == 0; 602 } 603 604 template <int KIND> 605 ExtValue genval(const Fortran::evaluate::Expr<Fortran::evaluate::Type< 606 Fortran::common::TypeCategory::Logical, KIND>> &exp) { 607 return std::visit([&](const auto &e) { return genval(e); }, exp.u); 608 } 609 610 using RefSet = 611 std::tuple<Fortran::evaluate::ComplexPart, Fortran::evaluate::Substring, 612 Fortran::evaluate::DataRef, Fortran::evaluate::Component, 613 Fortran::evaluate::ArrayRef, Fortran::evaluate::CoarrayRef, 614 Fortran::semantics::SymbolRef>; 615 template <typename A> 616 static constexpr bool inRefSet = Fortran::common::HasMember<A, RefSet>; 617 618 template <typename A, typename = std::enable_if_t<inRefSet<A>>> 619 ExtValue genref(const A &a) { 620 return gen(a); 621 } 622 template <typename A> 623 ExtValue genref(const A &a) { 624 mlir::Type storageType = converter.genType(toEvExpr(a)); 625 return placeScalarValueInMemory(builder, getLoc(), genval(a), storageType); 626 } 627 628 template <typename A, template <typename> typename T, 629 typename B = std::decay_t<T<A>>, 630 std::enable_if_t< 631 std::is_same_v<B, Fortran::evaluate::Expr<A>> || 632 std::is_same_v<B, Fortran::evaluate::Designator<A>> || 633 std::is_same_v<B, Fortran::evaluate::FunctionRef<A>>, 634 bool> = true> 635 ExtValue genref(const T<A> &x) { 636 return gen(x); 637 } 638 639 private: 640 mlir::Location location; 641 Fortran::lower::AbstractConverter &converter; 642 fir::FirOpBuilder &builder; 643 Fortran::lower::SymMap &symMap; 644 }; 645 } // namespace 646 647 fir::ExtendedValue Fortran::lower::createSomeExtendedExpression( 648 mlir::Location loc, Fortran::lower::AbstractConverter &converter, 649 const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap) { 650 LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "expr: ") << '\n'); 651 return ScalarExprLowering{loc, converter, symMap}.genval(expr); 652 } 653 654 fir::ExtendedValue Fortran::lower::createSomeExtendedAddress( 655 mlir::Location loc, Fortran::lower::AbstractConverter &converter, 656 const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap) { 657 LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "address: ") << '\n'); 658 return ScalarExprLowering{loc, converter, symMap}.gen(expr); 659 } 660