1 //===-- ConvertExprToHLFIR.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/ConvertExprToHLFIR.h" 14 #include "flang/Evaluate/shape.h" 15 #include "flang/Lower/AbstractConverter.h" 16 #include "flang/Lower/Allocatable.h" 17 #include "flang/Lower/CallInterface.h" 18 #include "flang/Lower/ConvertArrayConstructor.h" 19 #include "flang/Lower/ConvertCall.h" 20 #include "flang/Lower/ConvertConstant.h" 21 #include "flang/Lower/ConvertProcedureDesignator.h" 22 #include "flang/Lower/ConvertType.h" 23 #include "flang/Lower/ConvertVariable.h" 24 #include "flang/Lower/StatementContext.h" 25 #include "flang/Lower/SymbolMap.h" 26 #include "flang/Optimizer/Builder/Complex.h" 27 #include "flang/Optimizer/Builder/IntrinsicCall.h" 28 #include "flang/Optimizer/Builder/MutableBox.h" 29 #include "flang/Optimizer/Builder/Runtime/Character.h" 30 #include "flang/Optimizer/Builder/Runtime/Derived.h" 31 #include "flang/Optimizer/Builder/Runtime/Pointer.h" 32 #include "flang/Optimizer/Builder/Todo.h" 33 #include "flang/Optimizer/HLFIR/HLFIROps.h" 34 #include "llvm/ADT/TypeSwitch.h" 35 #include <optional> 36 37 namespace { 38 39 /// Lower Designators to HLFIR. 40 class HlfirDesignatorBuilder { 41 private: 42 /// Internal entry point on the rightest part of a evaluate::Designator. 43 template <typename T> 44 hlfir::EntityWithAttributes 45 genLeafPartRef(const T &designatorNode, 46 bool vectorSubscriptDesignatorToValue) { 47 hlfir::EntityWithAttributes result = gen(designatorNode); 48 if (vectorSubscriptDesignatorToValue) 49 return turnVectorSubscriptedDesignatorIntoValue(result); 50 return result; 51 } 52 53 hlfir::EntityWithAttributes 54 genDesignatorExpr(const Fortran::lower::SomeExpr &designatorExpr, 55 bool vectorSubscriptDesignatorToValue = true); 56 57 public: 58 HlfirDesignatorBuilder(mlir::Location loc, 59 Fortran::lower::AbstractConverter &converter, 60 Fortran::lower::SymMap &symMap, 61 Fortran::lower::StatementContext &stmtCtx) 62 : converter{converter}, symMap{symMap}, stmtCtx{stmtCtx}, loc{loc} {} 63 64 /// Public entry points to lower a Designator<T> (given its .u member, to 65 /// avoid the template arguments which does not matter here). 66 /// This lowers a designator to an hlfir variable SSA value (that can be 67 /// assigned to), except for vector subscripted designators that are 68 /// lowered by default to hlfir.expr value since they cannot be 69 /// represented as HLFIR variable SSA values. 70 71 // Character designators variant contains substrings 72 using CharacterDesignators = 73 decltype(Fortran::evaluate::Designator<Fortran::evaluate::Type< 74 Fortran::evaluate::TypeCategory::Character, 1>>::u); 75 hlfir::EntityWithAttributes 76 gen(const CharacterDesignators &designatorVariant, 77 bool vectorSubscriptDesignatorToValue = true) { 78 return std::visit( 79 [&](const auto &x) -> hlfir::EntityWithAttributes { 80 return genLeafPartRef(x, vectorSubscriptDesignatorToValue); 81 }, 82 designatorVariant); 83 } 84 // Character designators variant contains complex parts 85 using RealDesignators = 86 decltype(Fortran::evaluate::Designator<Fortran::evaluate::Type< 87 Fortran::evaluate::TypeCategory::Real, 4>>::u); 88 hlfir::EntityWithAttributes 89 gen(const RealDesignators &designatorVariant, 90 bool vectorSubscriptDesignatorToValue = true) { 91 return std::visit( 92 [&](const auto &x) -> hlfir::EntityWithAttributes { 93 return genLeafPartRef(x, vectorSubscriptDesignatorToValue); 94 }, 95 designatorVariant); 96 } 97 // All other designators are similar 98 using OtherDesignators = 99 decltype(Fortran::evaluate::Designator<Fortran::evaluate::Type< 100 Fortran::evaluate::TypeCategory::Integer, 4>>::u); 101 hlfir::EntityWithAttributes 102 gen(const OtherDesignators &designatorVariant, 103 bool vectorSubscriptDesignatorToValue = true) { 104 return std::visit( 105 [&](const auto &x) -> hlfir::EntityWithAttributes { 106 return genLeafPartRef(x, vectorSubscriptDesignatorToValue); 107 }, 108 designatorVariant); 109 } 110 111 hlfir::EntityWithAttributes 112 genNamedEntity(const Fortran::evaluate::NamedEntity &namedEntity, 113 bool vectorSubscriptDesignatorToValue = true) { 114 if (namedEntity.IsSymbol()) 115 return genLeafPartRef( 116 Fortran::evaluate::SymbolRef{namedEntity.GetLastSymbol()}, 117 vectorSubscriptDesignatorToValue); 118 return genLeafPartRef(namedEntity.GetComponent(), 119 vectorSubscriptDesignatorToValue); 120 } 121 122 /// Public entry point to lower a vector subscripted designator to 123 /// an hlfir::ElementalAddrOp. 124 hlfir::ElementalAddrOp convertVectorSubscriptedExprToElementalAddr( 125 const Fortran::lower::SomeExpr &designatorExpr); 126 127 mlir::Value genComponentShape(const Fortran::semantics::Symbol &componentSym, 128 mlir::Type fieldType) { 129 // For pointers and allocatable components, the 130 // shape is deferred and should not be loaded now to preserve 131 // pointer/allocatable aspects. 132 if (componentSym.Rank() == 0 || 133 Fortran::semantics::IsAllocatableOrObjectPointer(&componentSym) || 134 Fortran::semantics::IsProcedurePointer(&componentSym)) 135 return mlir::Value{}; 136 137 fir::FirOpBuilder &builder = getBuilder(); 138 mlir::Location loc = getLoc(); 139 mlir::Type idxTy = builder.getIndexType(); 140 llvm::SmallVector<mlir::Value> extents; 141 auto seqTy = mlir::cast<fir::SequenceType>( 142 hlfir::getFortranElementOrSequenceType(fieldType)); 143 for (auto extent : seqTy.getShape()) { 144 if (extent == fir::SequenceType::getUnknownExtent()) { 145 // We have already generated invalid hlfir.declare 146 // without the type parameters and probably invalid storage 147 // for the variable (e.g. fir.alloca without type parameters). 148 // So this TODO here is a little bit late, but it matches 149 // the non-HLFIR path. 150 TODO(loc, "array component shape depending on length parameters"); 151 } 152 extents.push_back(builder.createIntegerConstant(loc, idxTy, extent)); 153 } 154 if (!mayHaveNonDefaultLowerBounds(componentSym)) 155 return builder.create<fir::ShapeOp>(loc, extents); 156 157 llvm::SmallVector<mlir::Value> lbounds; 158 if (const auto *objDetails = 159 componentSym.detailsIf<Fortran::semantics::ObjectEntityDetails>()) 160 for (const Fortran::semantics::ShapeSpec &bounds : objDetails->shape()) 161 if (auto lb = bounds.lbound().GetExplicit()) 162 if (auto constant = Fortran::evaluate::ToInt64(*lb)) 163 lbounds.push_back( 164 builder.createIntegerConstant(loc, idxTy, *constant)); 165 assert(extents.size() == lbounds.size() && 166 "extents and lower bounds must match"); 167 return builder.genShape(loc, lbounds, extents); 168 } 169 170 fir::FortranVariableOpInterface 171 gen(const Fortran::evaluate::DataRef &dataRef) { 172 return std::visit( 173 Fortran::common::visitors{[&](const auto &x) { return gen(x); }}, 174 dataRef.u); 175 } 176 177 private: 178 /// Struct that is filled while visiting a part-ref (in the "visit" member 179 /// function) before the top level "gen" generates an hlfir.declare for the 180 /// part ref. It contains the lowered pieces of the part-ref that will 181 /// become the operands of an hlfir.declare. 182 struct PartInfo { 183 std::optional<hlfir::Entity> base; 184 std::string componentName{}; 185 mlir::Value componentShape; 186 hlfir::DesignateOp::Subscripts subscripts; 187 std::optional<bool> complexPart; 188 mlir::Value resultShape; 189 llvm::SmallVector<mlir::Value> typeParams; 190 llvm::SmallVector<mlir::Value, 2> substring; 191 }; 192 193 // Given the value type of a designator (T or fir.array<T>) and the front-end 194 // node for the designator, compute the memory type (fir.class, fir.ref, or 195 // fir.box)... 196 template <typename T> 197 mlir::Type computeDesignatorType(mlir::Type resultValueType, 198 PartInfo &partInfo, 199 const T &designatorNode) { 200 // Get base's shape if its a sequence type with no previously computed 201 // result shape 202 if (partInfo.base && mlir::isa<fir::SequenceType>(resultValueType) && 203 !partInfo.resultShape) 204 partInfo.resultShape = 205 hlfir::genShape(getLoc(), getBuilder(), *partInfo.base); 206 // Dynamic type of polymorphic base must be kept if the designator is 207 // polymorphic. 208 if (isPolymorphic(designatorNode)) 209 return fir::ClassType::get(resultValueType); 210 // Character scalar with dynamic length needs a fir.boxchar to hold the 211 // designator length. 212 auto charType = mlir::dyn_cast<fir::CharacterType>(resultValueType); 213 if (charType && charType.hasDynamicLen()) 214 return fir::BoxCharType::get(charType.getContext(), charType.getFKind()); 215 // Arrays with non default lower bounds or dynamic length or dynamic extent 216 // need a fir.box to hold the dynamic or lower bound information. 217 if (fir::hasDynamicSize(resultValueType) || 218 mayHaveNonDefaultLowerBounds(partInfo)) 219 return fir::BoxType::get(resultValueType); 220 // Non simply contiguous ref require a fir.box to carry the byte stride. 221 if (mlir::isa<fir::SequenceType>(resultValueType) && 222 !Fortran::evaluate::IsSimplyContiguous( 223 designatorNode, getConverter().getFoldingContext())) 224 return fir::BoxType::get(resultValueType); 225 // Other designators can be handled as raw addresses. 226 return fir::ReferenceType::get(resultValueType); 227 } 228 229 template <typename T> 230 static bool isPolymorphic(const T &designatorNode) { 231 if constexpr (!std::is_same_v<T, Fortran::evaluate::Substring>) { 232 return Fortran::semantics::IsPolymorphic(designatorNode.GetLastSymbol()); 233 } 234 return false; 235 } 236 237 template <typename T> 238 /// Generate an hlfir.designate for a part-ref given a filled PartInfo and the 239 /// FIR type for this part-ref. 240 fir::FortranVariableOpInterface genDesignate(mlir::Type resultValueType, 241 PartInfo &partInfo, 242 const T &designatorNode) { 243 mlir::Type designatorType = 244 computeDesignatorType(resultValueType, partInfo, designatorNode); 245 return genDesignate(designatorType, partInfo, /*attributes=*/{}); 246 } 247 fir::FortranVariableOpInterface 248 genDesignate(mlir::Type designatorType, PartInfo &partInfo, 249 fir::FortranVariableFlagsAttr attributes) { 250 fir::FirOpBuilder &builder = getBuilder(); 251 // Once a part with vector subscripts has been lowered, the following 252 // hlfir.designator (for the parts on the right of the designator) must 253 // be lowered inside the hlfir.elemental_addr because they depend on the 254 // hlfir.elemental_addr indices. 255 // All the subsequent Fortran indices however, should be lowered before 256 // the hlfir.elemental_addr because they should only be evaluated once, 257 // hence, the insertion point is restored outside of the 258 // hlfir.elemental_addr after generating the hlfir.designate. Example: in 259 // "X(VECTOR)%COMP(FOO(), BAR())", the calls to bar() and foo() must be 260 // generated outside of the hlfir.elemental, but the related hlfir.designate 261 // that depends on the scalar hlfir.designate of X(VECTOR) that was 262 // generated inside the hlfir.elemental_addr should be generated in the 263 // hlfir.elemental_addr. 264 if (auto elementalAddrOp = getVectorSubscriptElementAddrOp()) 265 builder.setInsertionPointToEnd(&elementalAddrOp->getBody().front()); 266 auto designate = builder.create<hlfir::DesignateOp>( 267 getLoc(), designatorType, partInfo.base.value().getBase(), 268 partInfo.componentName, partInfo.componentShape, partInfo.subscripts, 269 partInfo.substring, partInfo.complexPart, partInfo.resultShape, 270 partInfo.typeParams, attributes); 271 if (auto elementalAddrOp = getVectorSubscriptElementAddrOp()) 272 builder.setInsertionPoint(*elementalAddrOp); 273 return mlir::cast<fir::FortranVariableOpInterface>( 274 designate.getOperation()); 275 } 276 277 fir::FortranVariableOpInterface 278 gen(const Fortran::evaluate::SymbolRef &symbolRef) { 279 if (std::optional<fir::FortranVariableOpInterface> varDef = 280 getSymMap().lookupVariableDefinition(symbolRef)) { 281 if (symbolRef->test(Fortran::semantics::Symbol::Flag::CrayPointee)) { 282 // The pointee is represented with a descriptor inheriting 283 // the shape and type parameters of the pointee. 284 // We have to update the base_addr to point to the current 285 // value of the Cray pointer variable. 286 fir::FirOpBuilder &builder = getBuilder(); 287 fir::FortranVariableOpInterface ptrVar = 288 gen(Fortran::semantics::GetCrayPointer(symbolRef)); 289 mlir::Value ptrAddr = ptrVar.getBase(); 290 291 // Reinterpret the reference to a Cray pointer so that 292 // we have a pointer-compatible value after loading 293 // the Cray pointer value. 294 mlir::Type refPtrType = builder.getRefType( 295 fir::PointerType::get(fir::dyn_cast_ptrEleTy(ptrAddr.getType()))); 296 mlir::Value cast = builder.createConvert(loc, refPtrType, ptrAddr); 297 mlir::Value ptrVal = builder.create<fir::LoadOp>(loc, cast); 298 299 // Update the base_addr to the value of the Cray pointer. 300 // This is a hacky way to do the update, and it may harm 301 // performance around Cray pointer references. 302 // TODO: we should introduce an operation that updates 303 // just the base_addr of the given box. The CodeGen 304 // will just convert it into a single store. 305 fir::runtime::genPointerAssociateScalar(builder, loc, varDef->getBase(), 306 ptrVal); 307 } 308 return *varDef; 309 } 310 llvm::errs() << *symbolRef << "\n"; 311 TODO(getLoc(), "lowering symbol to HLFIR"); 312 } 313 314 fir::FortranVariableOpInterface 315 gen(const Fortran::semantics::Symbol &symbol) { 316 Fortran::evaluate::SymbolRef symref{symbol}; 317 return gen(symref); 318 } 319 320 fir::FortranVariableOpInterface 321 gen(const Fortran::evaluate::Component &component) { 322 if (Fortran::semantics::IsAllocatableOrPointer(component.GetLastSymbol())) 323 return genWholeAllocatableOrPointerComponent(component); 324 PartInfo partInfo; 325 mlir::Type resultType = visit(component, partInfo); 326 return genDesignate(resultType, partInfo, component); 327 } 328 329 fir::FortranVariableOpInterface 330 gen(const Fortran::evaluate::ArrayRef &arrayRef) { 331 PartInfo partInfo; 332 mlir::Type resultType = visit(arrayRef, partInfo); 333 return genDesignate(resultType, partInfo, arrayRef); 334 } 335 336 fir::FortranVariableOpInterface 337 gen(const Fortran::evaluate::CoarrayRef &coarrayRef) { 338 TODO(getLoc(), "coarray: lowering a reference to a coarray object"); 339 } 340 341 mlir::Type visit(const Fortran::evaluate::CoarrayRef &, PartInfo &) { 342 TODO(getLoc(), "coarray: lowering a reference to a coarray object"); 343 } 344 345 fir::FortranVariableOpInterface 346 gen(const Fortran::evaluate::ComplexPart &complexPart) { 347 PartInfo partInfo; 348 fir::factory::Complex cmplxHelper(getBuilder(), getLoc()); 349 350 bool complexBit = 351 complexPart.part() == Fortran::evaluate::ComplexPart::Part::IM; 352 partInfo.complexPart = {complexBit}; 353 354 mlir::Type resultType = visit(complexPart.complex(), partInfo); 355 356 // Determine complex part type 357 mlir::Type base = hlfir::getFortranElementType(resultType); 358 mlir::Type cmplxValueType = cmplxHelper.getComplexPartType(base); 359 mlir::Type designatorType = changeElementType(resultType, cmplxValueType); 360 361 return genDesignate(designatorType, partInfo, complexPart); 362 } 363 364 fir::FortranVariableOpInterface 365 gen(const Fortran::evaluate::Substring &substring) { 366 PartInfo partInfo; 367 mlir::Type baseStringType = std::visit( 368 [&](const auto &x) { return visit(x, partInfo); }, substring.parent()); 369 assert(partInfo.typeParams.size() == 1 && "expect base string length"); 370 // Compute the substring lower and upper bound. 371 partInfo.substring.push_back(genSubscript(substring.lower())); 372 if (Fortran::evaluate::MaybeExtentExpr upperBound = substring.upper()) 373 partInfo.substring.push_back(genSubscript(*upperBound)); 374 else 375 partInfo.substring.push_back(partInfo.typeParams[0]); 376 fir::FirOpBuilder &builder = getBuilder(); 377 mlir::Location loc = getLoc(); 378 mlir::Type idxTy = builder.getIndexType(); 379 partInfo.substring[0] = 380 builder.createConvert(loc, idxTy, partInfo.substring[0]); 381 partInfo.substring[1] = 382 builder.createConvert(loc, idxTy, partInfo.substring[1]); 383 // Try using constant length if available. mlir::arith folding would 384 // most likely be able to fold "max(ub-lb+1,0)" too, but getting 385 // the constant length in the FIR types would be harder. 386 std::optional<int64_t> cstLen = 387 Fortran::evaluate::ToInt64(Fortran::evaluate::Fold( 388 getConverter().getFoldingContext(), substring.LEN())); 389 if (cstLen) { 390 partInfo.typeParams[0] = 391 builder.createIntegerConstant(loc, idxTy, *cstLen); 392 } else { 393 // Compute "len = max(ub-lb+1,0)" (Fortran 2018 9.4.1). 394 mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); 395 auto boundsDiff = builder.create<mlir::arith::SubIOp>( 396 loc, partInfo.substring[1], partInfo.substring[0]); 397 auto rawLen = builder.create<mlir::arith::AddIOp>(loc, boundsDiff, one); 398 partInfo.typeParams[0] = 399 fir::factory::genMaxWithZero(builder, loc, rawLen); 400 } 401 auto kind = mlir::cast<fir::CharacterType>( 402 hlfir::getFortranElementType(baseStringType)) 403 .getFKind(); 404 auto newCharTy = fir::CharacterType::get( 405 baseStringType.getContext(), kind, 406 cstLen ? *cstLen : fir::CharacterType::unknownLen()); 407 mlir::Type resultType = changeElementType(baseStringType, newCharTy); 408 return genDesignate(resultType, partInfo, substring); 409 } 410 411 static mlir::Type changeElementType(mlir::Type type, mlir::Type newEleTy) { 412 return llvm::TypeSwitch<mlir::Type, mlir::Type>(type) 413 .Case<fir::SequenceType>([&](fir::SequenceType seqTy) -> mlir::Type { 414 return fir::SequenceType::get(seqTy.getShape(), newEleTy); 415 }) 416 .Case<fir::PointerType, fir::HeapType, fir::ReferenceType, fir::BoxType, 417 fir::ClassType>([&](auto t) -> mlir::Type { 418 using FIRT = decltype(t); 419 return FIRT::get(changeElementType(t.getEleTy(), newEleTy)); 420 }) 421 .Default([newEleTy](mlir::Type t) -> mlir::Type { return newEleTy; }); 422 } 423 424 fir::FortranVariableOpInterface genWholeAllocatableOrPointerComponent( 425 const Fortran::evaluate::Component &component) { 426 // Generate whole allocatable or pointer component reference. The 427 // hlfir.designate result will be a pointer/allocatable. 428 PartInfo partInfo; 429 mlir::Type componentType = visitComponentImpl(component, partInfo).second; 430 mlir::Type designatorType = fir::ReferenceType::get(componentType); 431 fir::FortranVariableFlagsAttr attributes = 432 Fortran::lower::translateSymbolAttributes(getBuilder().getContext(), 433 component.GetLastSymbol()); 434 return genDesignate(designatorType, partInfo, attributes); 435 } 436 437 mlir::Type visit(const Fortran::evaluate::DataRef &dataRef, 438 PartInfo &partInfo) { 439 return std::visit([&](const auto &x) { return visit(x, partInfo); }, 440 dataRef.u); 441 } 442 443 mlir::Type 444 visit(const Fortran::evaluate::StaticDataObject::Pointer &staticObject, 445 PartInfo &partInfo) { 446 fir::FirOpBuilder &builder = getBuilder(); 447 mlir::Location loc = getLoc(); 448 std::optional<std::string> string = staticObject->AsString(); 449 // TODO: see if StaticDataObject can be replaced by something based on 450 // Constant<T> to avoid dealing with endianness here for KIND>1. 451 // This will also avoid making string copies here. 452 if (!string) 453 TODO(loc, "StaticDataObject::Pointer substring with kind > 1"); 454 fir::ExtendedValue exv = 455 fir::factory::createStringLiteral(builder, getLoc(), *string); 456 auto flags = fir::FortranVariableFlagsAttr::get( 457 builder.getContext(), fir::FortranVariableFlagsEnum::parameter); 458 partInfo.base = hlfir::genDeclare(loc, builder, exv, ".stringlit", flags); 459 partInfo.typeParams.push_back(fir::getLen(exv)); 460 return partInfo.base->getElementOrSequenceType(); 461 } 462 463 mlir::Type visit(const Fortran::evaluate::SymbolRef &symbolRef, 464 PartInfo &partInfo) { 465 // A symbol is only visited if there is a following array, substring, or 466 // complex reference. If the entity is a pointer or allocatable, this 467 // reference designates the target, so the pointer, allocatable must be 468 // dereferenced here. 469 partInfo.base = 470 hlfir::derefPointersAndAllocatables(loc, getBuilder(), gen(symbolRef)); 471 hlfir::genLengthParameters(loc, getBuilder(), *partInfo.base, 472 partInfo.typeParams); 473 return partInfo.base->getElementOrSequenceType(); 474 } 475 476 mlir::Type visit(const Fortran::evaluate::ArrayRef &arrayRef, 477 PartInfo &partInfo) { 478 mlir::Type baseType; 479 if (const auto *component = arrayRef.base().UnwrapComponent()) { 480 // Pointers and allocatable components must be dereferenced since the 481 // array ref designates the target (this is done in "visit"). Other 482 // components need special care to deal with the array%array_comp(indices) 483 // case. 484 if (Fortran::semantics::IsAllocatableOrObjectPointer( 485 &component->GetLastSymbol())) 486 baseType = visit(*component, partInfo); 487 else 488 baseType = hlfir::getFortranElementOrSequenceType( 489 visitComponentImpl(*component, partInfo).second); 490 } else { 491 baseType = visit(arrayRef.base().GetLastSymbol(), partInfo); 492 } 493 494 fir::FirOpBuilder &builder = getBuilder(); 495 mlir::Location loc = getLoc(); 496 mlir::Type idxTy = builder.getIndexType(); 497 llvm::SmallVector<std::pair<mlir::Value, mlir::Value>> bounds; 498 auto getBaseBounds = [&](unsigned i) { 499 if (bounds.empty()) { 500 if (partInfo.componentName.empty()) { 501 bounds = hlfir::genBounds(loc, builder, partInfo.base.value()); 502 } else { 503 assert( 504 partInfo.componentShape && 505 "implicit array section bounds must come from component shape"); 506 bounds = hlfir::genBounds(loc, builder, partInfo.componentShape); 507 } 508 assert(!bounds.empty() && 509 "failed to compute implicit array section bounds"); 510 } 511 return bounds[i]; 512 }; 513 auto frontEndResultShape = 514 Fortran::evaluate::GetShape(converter.getFoldingContext(), arrayRef); 515 auto tryGettingExtentFromFrontEnd = 516 [&](unsigned dim) -> std::pair<mlir::Value, fir::SequenceType::Extent> { 517 // Use constant extent if possible. The main advantage to do this now 518 // is to get the best FIR array types as possible while lowering. 519 if (frontEndResultShape) 520 if (auto maybeI64 = 521 Fortran::evaluate::ToInt64(frontEndResultShape->at(dim))) 522 return {builder.createIntegerConstant(loc, idxTy, *maybeI64), 523 *maybeI64}; 524 return {mlir::Value{}, fir::SequenceType::getUnknownExtent()}; 525 }; 526 llvm::SmallVector<mlir::Value> resultExtents; 527 fir::SequenceType::Shape resultTypeShape; 528 bool sawVectorSubscripts = false; 529 for (auto subscript : llvm::enumerate(arrayRef.subscript())) { 530 if (const auto *triplet = 531 std::get_if<Fortran::evaluate::Triplet>(&subscript.value().u)) { 532 mlir::Value lb, ub; 533 if (const auto &lbExpr = triplet->lower()) 534 lb = genSubscript(*lbExpr); 535 else 536 lb = getBaseBounds(subscript.index()).first; 537 if (const auto &ubExpr = triplet->upper()) 538 ub = genSubscript(*ubExpr); 539 else 540 ub = getBaseBounds(subscript.index()).second; 541 lb = builder.createConvert(loc, idxTy, lb); 542 ub = builder.createConvert(loc, idxTy, ub); 543 mlir::Value stride = genSubscript(triplet->stride()); 544 stride = builder.createConvert(loc, idxTy, stride); 545 auto [extentValue, shapeExtent] = 546 tryGettingExtentFromFrontEnd(resultExtents.size()); 547 resultTypeShape.push_back(shapeExtent); 548 if (!extentValue) 549 extentValue = 550 builder.genExtentFromTriplet(loc, lb, ub, stride, idxTy); 551 resultExtents.push_back(extentValue); 552 partInfo.subscripts.emplace_back( 553 hlfir::DesignateOp::Triplet{lb, ub, stride}); 554 } else { 555 const auto &expr = 556 std::get<Fortran::evaluate::IndirectSubscriptIntegerExpr>( 557 subscript.value().u) 558 .value(); 559 hlfir::Entity subscript = genSubscript(expr); 560 partInfo.subscripts.push_back(subscript); 561 if (expr.Rank() > 0) { 562 sawVectorSubscripts = true; 563 auto [extentValue, shapeExtent] = 564 tryGettingExtentFromFrontEnd(resultExtents.size()); 565 resultTypeShape.push_back(shapeExtent); 566 if (!extentValue) 567 extentValue = hlfir::genExtent(loc, builder, subscript, /*dim=*/0); 568 resultExtents.push_back(extentValue); 569 } 570 } 571 } 572 assert(resultExtents.size() == resultTypeShape.size() && 573 "inconsistent hlfir.designate shape"); 574 575 // For vector subscripts, create an hlfir.elemental_addr and continue 576 // lowering the designator inside it as if it was addressing an element of 577 // the vector subscripts. 578 if (sawVectorSubscripts) 579 return createVectorSubscriptElementAddrOp(partInfo, baseType, 580 resultExtents); 581 582 mlir::Type resultType = mlir::cast<fir::SequenceType>(baseType).getEleTy(); 583 if (!resultTypeShape.empty()) { 584 // Ranked array section. The result shape comes from the array section 585 // subscripts. 586 resultType = fir::SequenceType::get(resultTypeShape, resultType); 587 assert(!partInfo.resultShape && 588 "Fortran designator can only have one ranked part"); 589 partInfo.resultShape = builder.genShape(loc, resultExtents); 590 } else if (!partInfo.componentName.empty() && 591 partInfo.base.value().isArray()) { 592 // This is an array%array_comp(indices) reference. Keep the 593 // shape of the base array and not the array_comp. 594 auto compBaseTy = partInfo.base->getElementOrSequenceType(); 595 resultType = changeElementType(compBaseTy, resultType); 596 assert(!partInfo.resultShape && "should not have been computed already"); 597 partInfo.resultShape = hlfir::genShape(loc, builder, *partInfo.base); 598 } 599 return resultType; 600 } 601 602 static bool 603 mayHaveNonDefaultLowerBounds(const Fortran::semantics::Symbol &componentSym) { 604 if (const auto *objDetails = 605 componentSym.detailsIf<Fortran::semantics::ObjectEntityDetails>()) 606 for (const Fortran::semantics::ShapeSpec &bounds : objDetails->shape()) 607 if (auto lb = bounds.lbound().GetExplicit()) 608 if (auto constant = Fortran::evaluate::ToInt64(*lb)) 609 if (!constant || *constant != 1) 610 return true; 611 return false; 612 } 613 static bool mayHaveNonDefaultLowerBounds(const PartInfo &partInfo) { 614 return partInfo.resultShape && 615 mlir::isa<fir::ShiftType, fir::ShapeShiftType>( 616 partInfo.resultShape.getType()); 617 } 618 619 mlir::Type visit(const Fortran::evaluate::Component &component, 620 PartInfo &partInfo) { 621 if (Fortran::semantics::IsAllocatableOrPointer(component.GetLastSymbol())) { 622 // In a visit, the following reference will address the target. Insert 623 // the dereference here. 624 partInfo.base = genWholeAllocatableOrPointerComponent(component); 625 partInfo.base = hlfir::derefPointersAndAllocatables(loc, getBuilder(), 626 *partInfo.base); 627 hlfir::genLengthParameters(loc, getBuilder(), *partInfo.base, 628 partInfo.typeParams); 629 return partInfo.base->getElementOrSequenceType(); 630 } 631 // This function must be called from contexts where the component is not the 632 // base of an ArrayRef. In these cases, the component cannot be an array 633 // if the base is an array. The code below determines the shape of the 634 // component reference if any. 635 auto [baseType, componentType] = visitComponentImpl(component, partInfo); 636 mlir::Type componentBaseType = 637 hlfir::getFortranElementOrSequenceType(componentType); 638 if (partInfo.base.value().isArray()) { 639 // For array%scalar_comp, the result shape is 640 // the one of the base. Compute it here. Note that the lower bounds of the 641 // base are not the ones of the resulting reference (that are default 642 // ones). 643 partInfo.resultShape = hlfir::genShape(loc, getBuilder(), *partInfo.base); 644 assert(!partInfo.componentShape && 645 "Fortran designators can only have one ranked part"); 646 return changeElementType(baseType, componentBaseType); 647 } 648 649 if (partInfo.complexPart && partInfo.componentShape) { 650 // Treat ...array_comp%im/re as ...array_comp(:,:,...)%im/re 651 // so that the codegen has the full slice triples for the component 652 // readily available. 653 fir::FirOpBuilder &builder = getBuilder(); 654 mlir::Type idxTy = builder.getIndexType(); 655 mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); 656 657 llvm::SmallVector<mlir::Value> resultExtents; 658 // Collect <lb, ub> pairs from the component shape. 659 auto bounds = hlfir::genBounds(loc, builder, partInfo.componentShape); 660 for (auto &boundPair : bounds) { 661 // The default subscripts are <lb, ub, 1>: 662 partInfo.subscripts.emplace_back(hlfir::DesignateOp::Triplet{ 663 boundPair.first, boundPair.second, one}); 664 auto extentValue = builder.genExtentFromTriplet( 665 loc, boundPair.first, boundPair.second, one, idxTy); 666 resultExtents.push_back(extentValue); 667 } 668 // The result shape is: <max((ub - lb + 1) / 1, 0), ...>. 669 partInfo.resultShape = builder.genShape(loc, resultExtents); 670 return componentBaseType; 671 } 672 673 // scalar%array_comp or scalar%scalar. In any case the shape of this 674 // part-ref is coming from the component. 675 partInfo.resultShape = partInfo.componentShape; 676 partInfo.componentShape = {}; 677 return componentBaseType; 678 } 679 680 // Returns the <BaseType, ComponentType> pair, computes partInfo.base, 681 // partInfo.componentShape and partInfo.typeParams, but does not set the 682 // partInfo.resultShape yet. The result shape will be computed after 683 // processing a following ArrayRef, if any, and in "visit" otherwise. 684 std::pair<mlir::Type, mlir::Type> 685 visitComponentImpl(const Fortran::evaluate::Component &component, 686 PartInfo &partInfo) { 687 fir::FirOpBuilder &builder = getBuilder(); 688 // Break the Designator visit here: if the base is an array-ref, a 689 // coarray-ref, or another component, this creates another hlfir.designate 690 // for it. hlfir.designate is not meant to represent more than one 691 // part-ref. 692 partInfo.base = gen(component.base()); 693 // If the base is an allocatable/pointer, dereference it here since the 694 // component ref designates its target. 695 partInfo.base = 696 hlfir::derefPointersAndAllocatables(loc, builder, *partInfo.base); 697 assert(partInfo.typeParams.empty() && "should not have been computed yet"); 698 699 hlfir::genLengthParameters(getLoc(), getBuilder(), *partInfo.base, 700 partInfo.typeParams); 701 mlir::Type baseType = partInfo.base->getElementOrSequenceType(); 702 703 // Lower the information about the component (type, length parameters and 704 // shape). 705 const Fortran::semantics::Symbol &componentSym = component.GetLastSymbol(); 706 partInfo.componentName = converter.getRecordTypeFieldName(componentSym); 707 auto recordType = 708 mlir::cast<fir::RecordType>(hlfir::getFortranElementType(baseType)); 709 if (recordType.isDependentType()) 710 TODO(getLoc(), "Designate derived type with length parameters in HLFIR"); 711 mlir::Type fieldType = recordType.getType(partInfo.componentName); 712 assert(fieldType && "component name is not known"); 713 mlir::Type fieldBaseType = 714 hlfir::getFortranElementOrSequenceType(fieldType); 715 partInfo.componentShape = genComponentShape(componentSym, fieldBaseType); 716 717 mlir::Type fieldEleType = hlfir::getFortranElementType(fieldBaseType); 718 if (fir::isRecordWithTypeParameters(fieldEleType)) 719 TODO(loc, 720 "lower a component that is a parameterized derived type to HLFIR"); 721 if (auto charTy = mlir::dyn_cast<fir::CharacterType>(fieldEleType)) { 722 mlir::Location loc = getLoc(); 723 mlir::Type idxTy = builder.getIndexType(); 724 if (charTy.hasConstantLen()) 725 partInfo.typeParams.push_back( 726 builder.createIntegerConstant(loc, idxTy, charTy.getLen())); 727 else if (!Fortran::semantics::IsAllocatableOrObjectPointer(&componentSym)) 728 TODO(loc, "compute character length of automatic character component " 729 "in a PDT"); 730 // Otherwise, the length of the component is deferred and will only 731 // be read when the component is dereferenced. 732 } 733 return {baseType, fieldType}; 734 } 735 736 // Compute: "lb + (i-1)*step". 737 mlir::Value computeTripletPosition(mlir::Location loc, 738 fir::FirOpBuilder &builder, 739 hlfir::DesignateOp::Triplet &triplet, 740 mlir::Value oneBasedIndex) { 741 mlir::Type idxTy = builder.getIndexType(); 742 mlir::Value lb = builder.createConvert(loc, idxTy, std::get<0>(triplet)); 743 mlir::Value step = builder.createConvert(loc, idxTy, std::get<2>(triplet)); 744 mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); 745 oneBasedIndex = builder.createConvert(loc, idxTy, oneBasedIndex); 746 mlir::Value zeroBased = 747 builder.create<mlir::arith::SubIOp>(loc, oneBasedIndex, one); 748 mlir::Value offset = 749 builder.create<mlir::arith::MulIOp>(loc, zeroBased, step); 750 return builder.create<mlir::arith::AddIOp>(loc, lb, offset); 751 } 752 753 /// Create an hlfir.element_addr operation to deal with vector subscripted 754 /// entities. This transforms the current vector subscripted array-ref into a 755 /// a scalar array-ref that is addressing the vector subscripted part given 756 /// the one based indices of the hlfir.element_addr. 757 /// The rest of the designator lowering will continue lowering any further 758 /// parts inside the hlfir.elemental as a scalar reference. 759 /// At the end of the designator lowering, the hlfir.elemental_addr will 760 /// be turned into an hlfir.elemental value, unless the caller of this 761 /// utility requested to get the hlfir.elemental_addr instead of lowering 762 /// the designator to an mlir::Value. 763 mlir::Type createVectorSubscriptElementAddrOp( 764 PartInfo &partInfo, mlir::Type baseType, 765 llvm::ArrayRef<mlir::Value> resultExtents) { 766 fir::FirOpBuilder &builder = getBuilder(); 767 mlir::Value shape = builder.genShape(loc, resultExtents); 768 // The type parameters to be added on the hlfir.elemental_addr are the ones 769 // of the whole designator (not the ones of the vector subscripted part). 770 // These are not yet known and will be added when finalizing the designator 771 // lowering. 772 // The resulting designator may be polymorphic, in which case the resulting 773 // type is the base of the vector subscripted part because 774 // allocatable/pointer components cannot be referenced after a vector 775 // subscripted part. Set the mold to the current base. It will be erased if 776 // the resulting designator is not polymorphic. 777 assert(partInfo.base.has_value() && 778 "vector subscripted part must have a base"); 779 mlir::Value mold = *partInfo.base; 780 auto elementalAddrOp = builder.create<hlfir::ElementalAddrOp>( 781 loc, shape, mold, mlir::ValueRange{}, 782 /*isUnordered=*/true); 783 setVectorSubscriptElementAddrOp(elementalAddrOp); 784 builder.setInsertionPointToEnd(&elementalAddrOp.getBody().front()); 785 mlir::Region::BlockArgListType indices = elementalAddrOp.getIndices(); 786 auto indicesIterator = indices.begin(); 787 auto getNextOneBasedIndex = [&]() -> mlir::Value { 788 assert(indicesIterator != indices.end() && "ill formed ElementalAddrOp"); 789 return *(indicesIterator++); 790 }; 791 // Transform the designator into a scalar designator computing the vector 792 // subscripted entity element address given one based indices (for the shape 793 // of the vector subscripted designator). 794 for (hlfir::DesignateOp::Subscript &subscript : partInfo.subscripts) { 795 if (auto *triplet = 796 std::get_if<hlfir::DesignateOp::Triplet>(&subscript)) { 797 // subscript = (lb + (i-1)*step) 798 mlir::Value scalarSubscript = computeTripletPosition( 799 loc, builder, *triplet, getNextOneBasedIndex()); 800 subscript = scalarSubscript; 801 } else { 802 hlfir::Entity valueSubscript{std::get<mlir::Value>(subscript)}; 803 if (valueSubscript.isScalar()) 804 continue; 805 // subscript = vector(i + (vector_lb-1)) 806 hlfir::Entity scalarSubscript = hlfir::getElementAt( 807 loc, builder, valueSubscript, {getNextOneBasedIndex()}); 808 scalarSubscript = 809 hlfir::loadTrivialScalar(loc, builder, scalarSubscript); 810 subscript = scalarSubscript; 811 } 812 } 813 builder.setInsertionPoint(elementalAddrOp); 814 return mlir::cast<fir::SequenceType>(baseType).getEleTy(); 815 } 816 817 /// Yield the designator for the final part-ref inside the 818 /// hlfir.elemental_addr. 819 void finalizeElementAddrOp(hlfir::ElementalAddrOp elementalAddrOp, 820 hlfir::EntityWithAttributes elementAddr) { 821 fir::FirOpBuilder &builder = getBuilder(); 822 builder.setInsertionPointToEnd(&elementalAddrOp.getBody().front()); 823 if (!elementAddr.isPolymorphic()) 824 elementalAddrOp.getMoldMutable().clear(); 825 builder.create<hlfir::YieldOp>(loc, elementAddr); 826 builder.setInsertionPointAfter(elementalAddrOp); 827 } 828 829 /// If the lowered designator has vector subscripts turn it into an 830 /// ElementalOp, otherwise, return the lowered designator. This should 831 /// only be called if the user did not request to get the 832 /// hlfir.elemental_addr. In Fortran, vector subscripted designators are only 833 /// writable on the left-hand side of an assignment and in input IO 834 /// statements. Otherwise, they are not variables (cannot be modified, their 835 /// value is taken at the place they appear). 836 hlfir::EntityWithAttributes turnVectorSubscriptedDesignatorIntoValue( 837 hlfir::EntityWithAttributes loweredDesignator) { 838 std::optional<hlfir::ElementalAddrOp> elementalAddrOp = 839 getVectorSubscriptElementAddrOp(); 840 if (!elementalAddrOp) 841 return loweredDesignator; 842 finalizeElementAddrOp(*elementalAddrOp, loweredDesignator); 843 // This vector subscript designator is only being read, transform the 844 // hlfir.elemental_addr into an hlfir.elemental. The content of the 845 // hlfir.elemental_addr is cloned, and the resulting address is loaded to 846 // get the new element value. 847 fir::FirOpBuilder &builder = getBuilder(); 848 mlir::Location loc = getLoc(); 849 mlir::Value elemental = 850 hlfir::cloneToElementalOp(loc, builder, *elementalAddrOp); 851 (*elementalAddrOp)->erase(); 852 setVectorSubscriptElementAddrOp(std::nullopt); 853 fir::FirOpBuilder *bldr = &builder; 854 getStmtCtx().attachCleanup( 855 [=]() { bldr->create<hlfir::DestroyOp>(loc, elemental); }); 856 return hlfir::EntityWithAttributes{elemental}; 857 } 858 859 /// Lower a subscript expression. If it is a scalar subscript that is a 860 /// variable, it is loaded into an integer value. If it is an array (for 861 /// vector subscripts) it is dereferenced if this is an allocatable or 862 /// pointer. 863 template <typename T> 864 hlfir::Entity genSubscript(const Fortran::evaluate::Expr<T> &expr); 865 866 const std::optional<hlfir::ElementalAddrOp> & 867 getVectorSubscriptElementAddrOp() const { 868 return vectorSubscriptElementAddrOp; 869 } 870 void setVectorSubscriptElementAddrOp( 871 std::optional<hlfir::ElementalAddrOp> elementalAddrOp) { 872 vectorSubscriptElementAddrOp = elementalAddrOp; 873 } 874 875 mlir::Location getLoc() const { return loc; } 876 Fortran::lower::AbstractConverter &getConverter() { return converter; } 877 fir::FirOpBuilder &getBuilder() { return converter.getFirOpBuilder(); } 878 Fortran::lower::SymMap &getSymMap() { return symMap; } 879 Fortran::lower::StatementContext &getStmtCtx() { return stmtCtx; } 880 881 Fortran::lower::AbstractConverter &converter; 882 Fortran::lower::SymMap &symMap; 883 Fortran::lower::StatementContext &stmtCtx; 884 // If there is a vector subscript, an elementalAddrOp is created 885 // to compute the address of the designator elements. 886 std::optional<hlfir::ElementalAddrOp> vectorSubscriptElementAddrOp{}; 887 mlir::Location loc; 888 }; 889 890 hlfir::EntityWithAttributes HlfirDesignatorBuilder::genDesignatorExpr( 891 const Fortran::lower::SomeExpr &designatorExpr, 892 bool vectorSubscriptDesignatorToValue) { 893 // Expr<SomeType> plumbing to unwrap Designator<T> and call 894 // gen(Designator<T>.u). 895 return std::visit( 896 [&](const auto &x) -> hlfir::EntityWithAttributes { 897 using T = std::decay_t<decltype(x)>; 898 if constexpr (Fortran::common::HasMember< 899 T, Fortran::lower::CategoryExpression>) { 900 if constexpr (T::Result::category == 901 Fortran::common::TypeCategory::Derived) { 902 return gen(std::get<Fortran::evaluate::Designator< 903 Fortran::evaluate::SomeDerived>>(x.u) 904 .u, 905 vectorSubscriptDesignatorToValue); 906 } else { 907 return std::visit( 908 [&](const auto &preciseKind) { 909 using TK = 910 typename std::decay_t<decltype(preciseKind)>::Result; 911 return gen( 912 std::get<Fortran::evaluate::Designator<TK>>(preciseKind.u) 913 .u, 914 vectorSubscriptDesignatorToValue); 915 }, 916 x.u); 917 } 918 } else { 919 fir::emitFatalError(loc, "unexpected typeless Designator"); 920 } 921 }, 922 designatorExpr.u); 923 } 924 925 hlfir::ElementalAddrOp 926 HlfirDesignatorBuilder::convertVectorSubscriptedExprToElementalAddr( 927 const Fortran::lower::SomeExpr &designatorExpr) { 928 929 hlfir::EntityWithAttributes elementAddrEntity = genDesignatorExpr( 930 designatorExpr, /*vectorSubscriptDesignatorToValue=*/false); 931 assert(getVectorSubscriptElementAddrOp().has_value() && 932 "expected vector subscripts"); 933 hlfir::ElementalAddrOp elementalAddrOp = *getVectorSubscriptElementAddrOp(); 934 // Now that the type parameters have been computed, add then to the 935 // hlfir.elemental_addr. 936 fir::FirOpBuilder &builder = getBuilder(); 937 llvm::SmallVector<mlir::Value, 1> lengths; 938 hlfir::genLengthParameters(loc, builder, elementAddrEntity, lengths); 939 if (!lengths.empty()) 940 elementalAddrOp.getTypeparamsMutable().assign(lengths); 941 if (!elementAddrEntity.isPolymorphic()) 942 elementalAddrOp.getMoldMutable().clear(); 943 // Create the hlfir.yield terminator inside the hlfir.elemental_body. 944 builder.setInsertionPointToEnd(&elementalAddrOp.getBody().front()); 945 builder.create<hlfir::YieldOp>(loc, elementAddrEntity); 946 builder.setInsertionPointAfter(elementalAddrOp); 947 // Reset the HlfirDesignatorBuilder state, in case it is used on a new 948 // designator. 949 setVectorSubscriptElementAddrOp(std::nullopt); 950 return elementalAddrOp; 951 } 952 953 //===--------------------------------------------------------------------===// 954 // Binary Operation implementation 955 //===--------------------------------------------------------------------===// 956 957 template <typename T> 958 struct BinaryOp {}; 959 960 #undef GENBIN 961 #define GENBIN(GenBinEvOp, GenBinTyCat, GenBinFirOp) \ 962 template <int KIND> \ 963 struct BinaryOp<Fortran::evaluate::GenBinEvOp<Fortran::evaluate::Type< \ 964 Fortran::common::TypeCategory::GenBinTyCat, KIND>>> { \ 965 using Op = Fortran::evaluate::GenBinEvOp<Fortran::evaluate::Type< \ 966 Fortran::common::TypeCategory::GenBinTyCat, KIND>>; \ 967 static hlfir::EntityWithAttributes gen(mlir::Location loc, \ 968 fir::FirOpBuilder &builder, \ 969 const Op &, hlfir::Entity lhs, \ 970 hlfir::Entity rhs) { \ 971 return hlfir::EntityWithAttributes{ \ 972 builder.create<GenBinFirOp>(loc, lhs, rhs)}; \ 973 } \ 974 }; 975 976 GENBIN(Add, Integer, mlir::arith::AddIOp) 977 GENBIN(Add, Real, mlir::arith::AddFOp) 978 GENBIN(Add, Complex, fir::AddcOp) 979 GENBIN(Subtract, Integer, mlir::arith::SubIOp) 980 GENBIN(Subtract, Real, mlir::arith::SubFOp) 981 GENBIN(Subtract, Complex, fir::SubcOp) 982 GENBIN(Multiply, Integer, mlir::arith::MulIOp) 983 GENBIN(Multiply, Real, mlir::arith::MulFOp) 984 GENBIN(Multiply, Complex, fir::MulcOp) 985 GENBIN(Divide, Integer, mlir::arith::DivSIOp) 986 GENBIN(Divide, Real, mlir::arith::DivFOp) 987 988 template <int KIND> 989 struct BinaryOp<Fortran::evaluate::Divide< 990 Fortran::evaluate::Type<Fortran::common::TypeCategory::Complex, KIND>>> { 991 using Op = Fortran::evaluate::Divide< 992 Fortran::evaluate::Type<Fortran::common::TypeCategory::Complex, KIND>>; 993 static hlfir::EntityWithAttributes gen(mlir::Location loc, 994 fir::FirOpBuilder &builder, const Op &, 995 hlfir::Entity lhs, hlfir::Entity rhs) { 996 mlir::Type ty = Fortran::lower::getFIRType( 997 builder.getContext(), Fortran::common::TypeCategory::Complex, KIND, 998 /*params=*/std::nullopt); 999 return hlfir::EntityWithAttributes{ 1000 fir::genDivC(builder, loc, ty, lhs, rhs)}; 1001 } 1002 }; 1003 1004 template <Fortran::common::TypeCategory TC, int KIND> 1005 struct BinaryOp<Fortran::evaluate::Power<Fortran::evaluate::Type<TC, KIND>>> { 1006 using Op = Fortran::evaluate::Power<Fortran::evaluate::Type<TC, KIND>>; 1007 static hlfir::EntityWithAttributes gen(mlir::Location loc, 1008 fir::FirOpBuilder &builder, const Op &, 1009 hlfir::Entity lhs, hlfir::Entity rhs) { 1010 mlir::Type ty = Fortran::lower::getFIRType(builder.getContext(), TC, KIND, 1011 /*params=*/std::nullopt); 1012 return hlfir::EntityWithAttributes{fir::genPow(builder, loc, ty, lhs, rhs)}; 1013 } 1014 }; 1015 1016 template <Fortran::common::TypeCategory TC, int KIND> 1017 struct BinaryOp< 1018 Fortran::evaluate::RealToIntPower<Fortran::evaluate::Type<TC, KIND>>> { 1019 using Op = 1020 Fortran::evaluate::RealToIntPower<Fortran::evaluate::Type<TC, KIND>>; 1021 static hlfir::EntityWithAttributes gen(mlir::Location loc, 1022 fir::FirOpBuilder &builder, const Op &, 1023 hlfir::Entity lhs, hlfir::Entity rhs) { 1024 mlir::Type ty = Fortran::lower::getFIRType(builder.getContext(), TC, KIND, 1025 /*params=*/std::nullopt); 1026 return hlfir::EntityWithAttributes{fir::genPow(builder, loc, ty, lhs, rhs)}; 1027 } 1028 }; 1029 1030 template <Fortran::common::TypeCategory TC, int KIND> 1031 struct BinaryOp< 1032 Fortran::evaluate::Extremum<Fortran::evaluate::Type<TC, KIND>>> { 1033 using Op = Fortran::evaluate::Extremum<Fortran::evaluate::Type<TC, KIND>>; 1034 static hlfir::EntityWithAttributes gen(mlir::Location loc, 1035 fir::FirOpBuilder &builder, 1036 const Op &op, hlfir::Entity lhs, 1037 hlfir::Entity rhs) { 1038 llvm::SmallVector<mlir::Value, 2> args{lhs, rhs}; 1039 fir::ExtendedValue res = op.ordering == Fortran::evaluate::Ordering::Greater 1040 ? fir::genMax(builder, loc, args) 1041 : fir::genMin(builder, loc, args); 1042 return hlfir::EntityWithAttributes{fir::getBase(res)}; 1043 } 1044 }; 1045 1046 // evaluate::Extremum is only created by the front-end when building compiler 1047 // generated expressions (like when folding LEN() or shape/bounds inquiries). 1048 // MIN and MAX are represented as evaluate::ProcedureRef and are not going 1049 // through here. So far the frontend does not generate character Extremum so 1050 // there is no way to test it. 1051 template <int KIND> 1052 struct BinaryOp<Fortran::evaluate::Extremum< 1053 Fortran::evaluate::Type<Fortran::common::TypeCategory::Character, KIND>>> { 1054 using Op = Fortran::evaluate::Extremum< 1055 Fortran::evaluate::Type<Fortran::common::TypeCategory::Character, KIND>>; 1056 static hlfir::EntityWithAttributes gen(mlir::Location loc, 1057 fir::FirOpBuilder &, const Op &, 1058 hlfir::Entity, hlfir::Entity) { 1059 fir::emitFatalError(loc, "Fortran::evaluate::Extremum are unexpected"); 1060 } 1061 static void genResultTypeParams(mlir::Location loc, fir::FirOpBuilder &, 1062 hlfir::Entity, hlfir::Entity, 1063 llvm::SmallVectorImpl<mlir::Value> &) { 1064 fir::emitFatalError(loc, "Fortran::evaluate::Extremum are unexpected"); 1065 } 1066 }; 1067 1068 /// Convert parser's INTEGER relational operators to MLIR. 1069 static mlir::arith::CmpIPredicate 1070 translateRelational(Fortran::common::RelationalOperator rop) { 1071 switch (rop) { 1072 case Fortran::common::RelationalOperator::LT: 1073 return mlir::arith::CmpIPredicate::slt; 1074 case Fortran::common::RelationalOperator::LE: 1075 return mlir::arith::CmpIPredicate::sle; 1076 case Fortran::common::RelationalOperator::EQ: 1077 return mlir::arith::CmpIPredicate::eq; 1078 case Fortran::common::RelationalOperator::NE: 1079 return mlir::arith::CmpIPredicate::ne; 1080 case Fortran::common::RelationalOperator::GT: 1081 return mlir::arith::CmpIPredicate::sgt; 1082 case Fortran::common::RelationalOperator::GE: 1083 return mlir::arith::CmpIPredicate::sge; 1084 } 1085 llvm_unreachable("unhandled INTEGER relational operator"); 1086 } 1087 1088 /// Convert parser's REAL relational operators to MLIR. 1089 /// The choice of order (O prefix) vs unorder (U prefix) follows Fortran 2018 1090 /// requirements in the IEEE context (table 17.1 of F2018). This choice is 1091 /// also applied in other contexts because it is easier and in line with 1092 /// other Fortran compilers. 1093 /// FIXME: The signaling/quiet aspect of the table 17.1 requirement is not 1094 /// fully enforced. FIR and LLVM `fcmp` instructions do not give any guarantee 1095 /// whether the comparison will signal or not in case of quiet NaN argument. 1096 static mlir::arith::CmpFPredicate 1097 translateFloatRelational(Fortran::common::RelationalOperator rop) { 1098 switch (rop) { 1099 case Fortran::common::RelationalOperator::LT: 1100 return mlir::arith::CmpFPredicate::OLT; 1101 case Fortran::common::RelationalOperator::LE: 1102 return mlir::arith::CmpFPredicate::OLE; 1103 case Fortran::common::RelationalOperator::EQ: 1104 return mlir::arith::CmpFPredicate::OEQ; 1105 case Fortran::common::RelationalOperator::NE: 1106 return mlir::arith::CmpFPredicate::UNE; 1107 case Fortran::common::RelationalOperator::GT: 1108 return mlir::arith::CmpFPredicate::OGT; 1109 case Fortran::common::RelationalOperator::GE: 1110 return mlir::arith::CmpFPredicate::OGE; 1111 } 1112 llvm_unreachable("unhandled REAL relational operator"); 1113 } 1114 1115 template <int KIND> 1116 struct BinaryOp<Fortran::evaluate::Relational< 1117 Fortran::evaluate::Type<Fortran::common::TypeCategory::Integer, KIND>>> { 1118 using Op = Fortran::evaluate::Relational< 1119 Fortran::evaluate::Type<Fortran::common::TypeCategory::Integer, KIND>>; 1120 static hlfir::EntityWithAttributes gen(mlir::Location loc, 1121 fir::FirOpBuilder &builder, 1122 const Op &op, hlfir::Entity lhs, 1123 hlfir::Entity rhs) { 1124 auto cmp = builder.create<mlir::arith::CmpIOp>( 1125 loc, translateRelational(op.opr), lhs, rhs); 1126 return hlfir::EntityWithAttributes{cmp}; 1127 } 1128 }; 1129 1130 template <int KIND> 1131 struct BinaryOp<Fortran::evaluate::Relational< 1132 Fortran::evaluate::Type<Fortran::common::TypeCategory::Real, KIND>>> { 1133 using Op = Fortran::evaluate::Relational< 1134 Fortran::evaluate::Type<Fortran::common::TypeCategory::Real, KIND>>; 1135 static hlfir::EntityWithAttributes gen(mlir::Location loc, 1136 fir::FirOpBuilder &builder, 1137 const Op &op, hlfir::Entity lhs, 1138 hlfir::Entity rhs) { 1139 auto cmp = builder.create<mlir::arith::CmpFOp>( 1140 loc, translateFloatRelational(op.opr), lhs, rhs); 1141 return hlfir::EntityWithAttributes{cmp}; 1142 } 1143 }; 1144 1145 template <int KIND> 1146 struct BinaryOp<Fortran::evaluate::Relational< 1147 Fortran::evaluate::Type<Fortran::common::TypeCategory::Complex, KIND>>> { 1148 using Op = Fortran::evaluate::Relational< 1149 Fortran::evaluate::Type<Fortran::common::TypeCategory::Complex, KIND>>; 1150 static hlfir::EntityWithAttributes gen(mlir::Location loc, 1151 fir::FirOpBuilder &builder, 1152 const Op &op, hlfir::Entity lhs, 1153 hlfir::Entity rhs) { 1154 auto cmp = builder.create<fir::CmpcOp>( 1155 loc, translateFloatRelational(op.opr), lhs, rhs); 1156 return hlfir::EntityWithAttributes{cmp}; 1157 } 1158 }; 1159 1160 template <int KIND> 1161 struct BinaryOp<Fortran::evaluate::Relational< 1162 Fortran::evaluate::Type<Fortran::common::TypeCategory::Character, KIND>>> { 1163 using Op = Fortran::evaluate::Relational< 1164 Fortran::evaluate::Type<Fortran::common::TypeCategory::Character, KIND>>; 1165 static hlfir::EntityWithAttributes gen(mlir::Location loc, 1166 fir::FirOpBuilder &builder, 1167 const Op &op, hlfir::Entity lhs, 1168 hlfir::Entity rhs) { 1169 auto [lhsExv, lhsCleanUp] = 1170 hlfir::translateToExtendedValue(loc, builder, lhs); 1171 auto [rhsExv, rhsCleanUp] = 1172 hlfir::translateToExtendedValue(loc, builder, rhs); 1173 auto cmp = fir::runtime::genCharCompare( 1174 builder, loc, translateRelational(op.opr), lhsExv, rhsExv); 1175 if (lhsCleanUp) 1176 (*lhsCleanUp)(); 1177 if (rhsCleanUp) 1178 (*rhsCleanUp)(); 1179 return hlfir::EntityWithAttributes{cmp}; 1180 } 1181 }; 1182 1183 template <int KIND> 1184 struct BinaryOp<Fortran::evaluate::LogicalOperation<KIND>> { 1185 using Op = Fortran::evaluate::LogicalOperation<KIND>; 1186 static hlfir::EntityWithAttributes gen(mlir::Location loc, 1187 fir::FirOpBuilder &builder, 1188 const Op &op, hlfir::Entity lhs, 1189 hlfir::Entity rhs) { 1190 mlir::Type i1Type = builder.getI1Type(); 1191 mlir::Value i1Lhs = builder.createConvert(loc, i1Type, lhs); 1192 mlir::Value i1Rhs = builder.createConvert(loc, i1Type, rhs); 1193 switch (op.logicalOperator) { 1194 case Fortran::evaluate::LogicalOperator::And: 1195 return hlfir::EntityWithAttributes{ 1196 builder.create<mlir::arith::AndIOp>(loc, i1Lhs, i1Rhs)}; 1197 case Fortran::evaluate::LogicalOperator::Or: 1198 return hlfir::EntityWithAttributes{ 1199 builder.create<mlir::arith::OrIOp>(loc, i1Lhs, i1Rhs)}; 1200 case Fortran::evaluate::LogicalOperator::Eqv: 1201 return hlfir::EntityWithAttributes{builder.create<mlir::arith::CmpIOp>( 1202 loc, mlir::arith::CmpIPredicate::eq, i1Lhs, i1Rhs)}; 1203 case Fortran::evaluate::LogicalOperator::Neqv: 1204 return hlfir::EntityWithAttributes{builder.create<mlir::arith::CmpIOp>( 1205 loc, mlir::arith::CmpIPredicate::ne, i1Lhs, i1Rhs)}; 1206 case Fortran::evaluate::LogicalOperator::Not: 1207 // lib/evaluate expression for .NOT. is Fortran::evaluate::Not<KIND>. 1208 llvm_unreachable(".NOT. is not a binary operator"); 1209 } 1210 llvm_unreachable("unhandled logical operation"); 1211 } 1212 }; 1213 1214 template <int KIND> 1215 struct BinaryOp<Fortran::evaluate::ComplexConstructor<KIND>> { 1216 using Op = Fortran::evaluate::ComplexConstructor<KIND>; 1217 static hlfir::EntityWithAttributes gen(mlir::Location loc, 1218 fir::FirOpBuilder &builder, const Op &, 1219 hlfir::Entity lhs, hlfir::Entity rhs) { 1220 mlir::Value res = 1221 fir::factory::Complex{builder, loc}.createComplex(KIND, lhs, rhs); 1222 return hlfir::EntityWithAttributes{res}; 1223 } 1224 }; 1225 1226 template <int KIND> 1227 struct BinaryOp<Fortran::evaluate::SetLength<KIND>> { 1228 using Op = Fortran::evaluate::SetLength<KIND>; 1229 static hlfir::EntityWithAttributes gen(mlir::Location loc, 1230 fir::FirOpBuilder &builder, const Op &, 1231 hlfir::Entity string, 1232 hlfir::Entity length) { 1233 // The input length may be a user input and needs to be sanitized as per 1234 // Fortran 2018 7.4.4.2 point 5. 1235 mlir::Value safeLength = fir::factory::genMaxWithZero(builder, loc, length); 1236 return hlfir::EntityWithAttributes{ 1237 builder.create<hlfir::SetLengthOp>(loc, string, safeLength)}; 1238 } 1239 static void 1240 genResultTypeParams(mlir::Location, fir::FirOpBuilder &, hlfir::Entity, 1241 hlfir::Entity rhs, 1242 llvm::SmallVectorImpl<mlir::Value> &resultTypeParams) { 1243 resultTypeParams.push_back(rhs); 1244 } 1245 }; 1246 1247 template <int KIND> 1248 struct BinaryOp<Fortran::evaluate::Concat<KIND>> { 1249 using Op = Fortran::evaluate::Concat<KIND>; 1250 hlfir::EntityWithAttributes gen(mlir::Location loc, 1251 fir::FirOpBuilder &builder, const Op &, 1252 hlfir::Entity lhs, hlfir::Entity rhs) { 1253 assert(len && "genResultTypeParams must have been called"); 1254 auto concat = 1255 builder.create<hlfir::ConcatOp>(loc, mlir::ValueRange{lhs, rhs}, len); 1256 return hlfir::EntityWithAttributes{concat.getResult()}; 1257 } 1258 void 1259 genResultTypeParams(mlir::Location loc, fir::FirOpBuilder &builder, 1260 hlfir::Entity lhs, hlfir::Entity rhs, 1261 llvm::SmallVectorImpl<mlir::Value> &resultTypeParams) { 1262 llvm::SmallVector<mlir::Value> lengths; 1263 hlfir::genLengthParameters(loc, builder, lhs, lengths); 1264 hlfir::genLengthParameters(loc, builder, rhs, lengths); 1265 assert(lengths.size() == 2 && "lacks rhs or lhs length"); 1266 mlir::Type idxType = builder.getIndexType(); 1267 mlir::Value lhsLen = builder.createConvert(loc, idxType, lengths[0]); 1268 mlir::Value rhsLen = builder.createConvert(loc, idxType, lengths[1]); 1269 len = builder.create<mlir::arith::AddIOp>(loc, lhsLen, rhsLen); 1270 resultTypeParams.push_back(len); 1271 } 1272 1273 private: 1274 mlir::Value len{}; 1275 }; 1276 1277 //===--------------------------------------------------------------------===// 1278 // Unary Operation implementation 1279 //===--------------------------------------------------------------------===// 1280 1281 template <typename T> 1282 struct UnaryOp {}; 1283 1284 template <int KIND> 1285 struct UnaryOp<Fortran::evaluate::Not<KIND>> { 1286 using Op = Fortran::evaluate::Not<KIND>; 1287 static hlfir::EntityWithAttributes gen(mlir::Location loc, 1288 fir::FirOpBuilder &builder, const Op &, 1289 hlfir::Entity lhs) { 1290 mlir::Value one = builder.createBool(loc, true); 1291 mlir::Value val = builder.createConvert(loc, builder.getI1Type(), lhs); 1292 return hlfir::EntityWithAttributes{ 1293 builder.create<mlir::arith::XOrIOp>(loc, val, one)}; 1294 } 1295 }; 1296 1297 template <int KIND> 1298 struct UnaryOp<Fortran::evaluate::Negate< 1299 Fortran::evaluate::Type<Fortran::common::TypeCategory::Integer, KIND>>> { 1300 using Op = Fortran::evaluate::Negate< 1301 Fortran::evaluate::Type<Fortran::common::TypeCategory::Integer, KIND>>; 1302 static hlfir::EntityWithAttributes gen(mlir::Location loc, 1303 fir::FirOpBuilder &builder, const Op &, 1304 hlfir::Entity lhs) { 1305 // Like LLVM, integer negation is the binary op "0 - value" 1306 mlir::Type type = Fortran::lower::getFIRType( 1307 builder.getContext(), Fortran::common::TypeCategory::Integer, KIND, 1308 /*params=*/std::nullopt); 1309 mlir::Value zero = builder.createIntegerConstant(loc, type, 0); 1310 return hlfir::EntityWithAttributes{ 1311 builder.create<mlir::arith::SubIOp>(loc, zero, lhs)}; 1312 } 1313 }; 1314 1315 template <int KIND> 1316 struct UnaryOp<Fortran::evaluate::Negate< 1317 Fortran::evaluate::Type<Fortran::common::TypeCategory::Real, KIND>>> { 1318 using Op = Fortran::evaluate::Negate< 1319 Fortran::evaluate::Type<Fortran::common::TypeCategory::Real, KIND>>; 1320 static hlfir::EntityWithAttributes gen(mlir::Location loc, 1321 fir::FirOpBuilder &builder, const Op &, 1322 hlfir::Entity lhs) { 1323 return hlfir::EntityWithAttributes{ 1324 builder.create<mlir::arith::NegFOp>(loc, lhs)}; 1325 } 1326 }; 1327 1328 template <int KIND> 1329 struct UnaryOp<Fortran::evaluate::Negate< 1330 Fortran::evaluate::Type<Fortran::common::TypeCategory::Complex, KIND>>> { 1331 using Op = Fortran::evaluate::Negate< 1332 Fortran::evaluate::Type<Fortran::common::TypeCategory::Complex, KIND>>; 1333 static hlfir::EntityWithAttributes gen(mlir::Location loc, 1334 fir::FirOpBuilder &builder, const Op &, 1335 hlfir::Entity lhs) { 1336 return hlfir::EntityWithAttributes{builder.create<fir::NegcOp>(loc, lhs)}; 1337 } 1338 }; 1339 1340 template <int KIND> 1341 struct UnaryOp<Fortran::evaluate::ComplexComponent<KIND>> { 1342 using Op = Fortran::evaluate::ComplexComponent<KIND>; 1343 static hlfir::EntityWithAttributes gen(mlir::Location loc, 1344 fir::FirOpBuilder &builder, 1345 const Op &op, hlfir::Entity lhs) { 1346 mlir::Value res = fir::factory::Complex{builder, loc}.extractComplexPart( 1347 lhs, op.isImaginaryPart); 1348 return hlfir::EntityWithAttributes{res}; 1349 } 1350 }; 1351 1352 template <typename T> 1353 struct UnaryOp<Fortran::evaluate::Parentheses<T>> { 1354 using Op = Fortran::evaluate::Parentheses<T>; 1355 static hlfir::EntityWithAttributes gen(mlir::Location loc, 1356 fir::FirOpBuilder &builder, 1357 const Op &op, hlfir::Entity lhs) { 1358 if (lhs.isVariable()) 1359 return hlfir::EntityWithAttributes{ 1360 builder.create<hlfir::AsExprOp>(loc, lhs)}; 1361 return hlfir::EntityWithAttributes{ 1362 builder.create<hlfir::NoReassocOp>(loc, lhs.getType(), lhs)}; 1363 } 1364 1365 static void 1366 genResultTypeParams(mlir::Location loc, fir::FirOpBuilder &builder, 1367 hlfir::Entity lhs, 1368 llvm::SmallVectorImpl<mlir::Value> &resultTypeParams) { 1369 hlfir::genLengthParameters(loc, builder, lhs, resultTypeParams); 1370 } 1371 }; 1372 1373 template <Fortran::common::TypeCategory TC1, int KIND, 1374 Fortran::common::TypeCategory TC2> 1375 struct UnaryOp< 1376 Fortran::evaluate::Convert<Fortran::evaluate::Type<TC1, KIND>, TC2>> { 1377 using Op = 1378 Fortran::evaluate::Convert<Fortran::evaluate::Type<TC1, KIND>, TC2>; 1379 static hlfir::EntityWithAttributes gen(mlir::Location loc, 1380 fir::FirOpBuilder &builder, const Op &, 1381 hlfir::Entity lhs) { 1382 if constexpr (TC1 == Fortran::common::TypeCategory::Character && 1383 TC2 == TC1) { 1384 return hlfir::convertCharacterKind(loc, builder, lhs, KIND); 1385 } 1386 mlir::Type type = Fortran::lower::getFIRType(builder.getContext(), TC1, 1387 KIND, /*params=*/std::nullopt); 1388 mlir::Value res = builder.convertWithSemantics(loc, type, lhs); 1389 return hlfir::EntityWithAttributes{res}; 1390 } 1391 1392 static void 1393 genResultTypeParams(mlir::Location loc, fir::FirOpBuilder &builder, 1394 hlfir::Entity lhs, 1395 llvm::SmallVectorImpl<mlir::Value> &resultTypeParams) { 1396 hlfir::genLengthParameters(loc, builder, lhs, resultTypeParams); 1397 } 1398 }; 1399 1400 static bool hasDeferredCharacterLength(const Fortran::semantics::Symbol &sym) { 1401 const Fortran::semantics::DeclTypeSpec *type = sym.GetType(); 1402 return type && 1403 type->category() == 1404 Fortran::semantics::DeclTypeSpec::Category::Character && 1405 type->characterTypeSpec().length().isDeferred(); 1406 } 1407 1408 /// Lower Expr to HLFIR. 1409 class HlfirBuilder { 1410 public: 1411 HlfirBuilder(mlir::Location loc, Fortran::lower::AbstractConverter &converter, 1412 Fortran::lower::SymMap &symMap, 1413 Fortran::lower::StatementContext &stmtCtx) 1414 : converter{converter}, symMap{symMap}, stmtCtx{stmtCtx}, loc{loc} {} 1415 1416 template <typename T> 1417 hlfir::EntityWithAttributes gen(const Fortran::evaluate::Expr<T> &expr) { 1418 if (const Fortran::lower::ExprToValueMap *map = 1419 getConverter().getExprOverrides()) { 1420 if constexpr (std::is_same_v<T, Fortran::evaluate::SomeType>) { 1421 if (auto match = map->find(&expr); match != map->end()) 1422 return hlfir::EntityWithAttributes{match->second}; 1423 } else { 1424 Fortran::lower::SomeExpr someExpr = toEvExpr(expr); 1425 if (auto match = map->find(&someExpr); match != map->end()) 1426 return hlfir::EntityWithAttributes{match->second}; 1427 } 1428 } 1429 return std::visit([&](const auto &x) { return gen(x); }, expr.u); 1430 } 1431 1432 private: 1433 hlfir::EntityWithAttributes 1434 gen(const Fortran::evaluate::BOZLiteralConstant &expr) { 1435 TODO(getLoc(), "BOZ"); 1436 } 1437 1438 hlfir::EntityWithAttributes gen(const Fortran::evaluate::NullPointer &expr) { 1439 auto nullop = getBuilder().create<hlfir::NullOp>(getLoc()); 1440 return mlir::cast<fir::FortranVariableOpInterface>(nullop.getOperation()); 1441 } 1442 1443 hlfir::EntityWithAttributes 1444 gen(const Fortran::evaluate::ProcedureDesignator &proc) { 1445 return Fortran::lower::convertProcedureDesignatorToHLFIR( 1446 getLoc(), getConverter(), proc, getSymMap(), getStmtCtx()); 1447 } 1448 1449 hlfir::EntityWithAttributes gen(const Fortran::evaluate::ProcedureRef &expr) { 1450 Fortran::evaluate::ProcedureDesignator proc{expr.proc()}; 1451 auto procTy{Fortran::lower::translateSignature(proc, getConverter())}; 1452 auto result = Fortran::lower::convertCallToHLFIR(getLoc(), getConverter(), 1453 expr, procTy.getResult(0), 1454 getSymMap(), getStmtCtx()); 1455 assert(result.has_value()); 1456 return *result; 1457 } 1458 1459 template <typename T> 1460 hlfir::EntityWithAttributes 1461 gen(const Fortran::evaluate::Designator<T> &designator) { 1462 return HlfirDesignatorBuilder(getLoc(), getConverter(), getSymMap(), 1463 getStmtCtx()) 1464 .gen(designator.u); 1465 } 1466 1467 template <typename T> 1468 hlfir::EntityWithAttributes 1469 gen(const Fortran::evaluate::FunctionRef<T> &expr) { 1470 mlir::Type resType = 1471 Fortran::lower::TypeBuilder<T>::genType(getConverter(), expr); 1472 auto result = Fortran::lower::convertCallToHLFIR( 1473 getLoc(), getConverter(), expr, resType, getSymMap(), getStmtCtx()); 1474 assert(result.has_value()); 1475 return *result; 1476 } 1477 1478 template <typename T> 1479 hlfir::EntityWithAttributes gen(const Fortran::evaluate::Constant<T> &expr) { 1480 mlir::Location loc = getLoc(); 1481 fir::FirOpBuilder &builder = getBuilder(); 1482 fir::ExtendedValue exv = Fortran::lower::convertConstant( 1483 converter, loc, expr, /*outlineBigConstantInReadOnlyMemory=*/true); 1484 if (const auto *scalarBox = exv.getUnboxed()) 1485 if (fir::isa_trivial(scalarBox->getType())) 1486 return hlfir::EntityWithAttributes(*scalarBox); 1487 if (auto addressOf = fir::getBase(exv).getDefiningOp<fir::AddrOfOp>()) { 1488 auto flags = fir::FortranVariableFlagsAttr::get( 1489 builder.getContext(), fir::FortranVariableFlagsEnum::parameter); 1490 return hlfir::genDeclare( 1491 loc, builder, exv, 1492 addressOf.getSymbol().getRootReference().getValue(), flags); 1493 } 1494 fir::emitFatalError(loc, "Constant<T> was lowered to unexpected format"); 1495 } 1496 1497 template <typename T> 1498 hlfir::EntityWithAttributes 1499 gen(const Fortran::evaluate::ArrayConstructor<T> &arrayCtor) { 1500 return Fortran::lower::ArrayConstructorBuilder<T>::gen( 1501 getLoc(), getConverter(), arrayCtor, getSymMap(), getStmtCtx()); 1502 } 1503 1504 template <typename D, typename R, typename O> 1505 hlfir::EntityWithAttributes 1506 gen(const Fortran::evaluate::Operation<D, R, O> &op) { 1507 auto &builder = getBuilder(); 1508 mlir::Location loc = getLoc(); 1509 const int rank = op.Rank(); 1510 UnaryOp<D> unaryOp; 1511 auto left = hlfir::loadTrivialScalar(loc, builder, gen(op.left())); 1512 llvm::SmallVector<mlir::Value, 1> typeParams; 1513 if constexpr (R::category == Fortran::common::TypeCategory::Character) { 1514 unaryOp.genResultTypeParams(loc, builder, left, typeParams); 1515 } 1516 if (rank == 0) 1517 return unaryOp.gen(loc, builder, op.derived(), left); 1518 1519 // Elemental expression. 1520 mlir::Type elementType; 1521 if constexpr (R::category == Fortran::common::TypeCategory::Derived) { 1522 if (op.derived().GetType().IsUnlimitedPolymorphic()) 1523 elementType = mlir::NoneType::get(builder.getContext()); 1524 else 1525 elementType = Fortran::lower::translateDerivedTypeToFIRType( 1526 getConverter(), op.derived().GetType().GetDerivedTypeSpec()); 1527 } else { 1528 elementType = 1529 Fortran::lower::getFIRType(builder.getContext(), R::category, R::kind, 1530 /*params=*/std::nullopt); 1531 } 1532 mlir::Value shape = hlfir::genShape(loc, builder, left); 1533 auto genKernel = [&op, &left, &unaryOp]( 1534 mlir::Location l, fir::FirOpBuilder &b, 1535 mlir::ValueRange oneBasedIndices) -> hlfir::Entity { 1536 auto leftElement = hlfir::getElementAt(l, b, left, oneBasedIndices); 1537 auto leftVal = hlfir::loadTrivialScalar(l, b, leftElement); 1538 return unaryOp.gen(l, b, op.derived(), leftVal); 1539 }; 1540 mlir::Value elemental = hlfir::genElementalOp( 1541 loc, builder, elementType, shape, typeParams, genKernel, 1542 /*isUnordered=*/true, left.isPolymorphic() ? left : mlir::Value{}); 1543 fir::FirOpBuilder *bldr = &builder; 1544 getStmtCtx().attachCleanup( 1545 [=]() { bldr->create<hlfir::DestroyOp>(loc, elemental); }); 1546 return hlfir::EntityWithAttributes{elemental}; 1547 } 1548 1549 template <typename D, typename R, typename LO, typename RO> 1550 hlfir::EntityWithAttributes 1551 gen(const Fortran::evaluate::Operation<D, R, LO, RO> &op) { 1552 auto &builder = getBuilder(); 1553 mlir::Location loc = getLoc(); 1554 const int rank = op.Rank(); 1555 BinaryOp<D> binaryOp; 1556 auto left = hlfir::loadTrivialScalar(loc, builder, gen(op.left())); 1557 auto right = hlfir::loadTrivialScalar(loc, builder, gen(op.right())); 1558 llvm::SmallVector<mlir::Value, 1> typeParams; 1559 if constexpr (R::category == Fortran::common::TypeCategory::Character) { 1560 binaryOp.genResultTypeParams(loc, builder, left, right, typeParams); 1561 } 1562 if (rank == 0) 1563 return binaryOp.gen(loc, builder, op.derived(), left, right); 1564 1565 // Elemental expression. 1566 mlir::Type elementType = 1567 Fortran::lower::getFIRType(builder.getContext(), R::category, R::kind, 1568 /*params=*/std::nullopt); 1569 // TODO: "merge" shape, get cst shape from front-end if possible. 1570 mlir::Value shape; 1571 if (left.isArray()) { 1572 shape = hlfir::genShape(loc, builder, left); 1573 } else { 1574 assert(right.isArray() && "must have at least one array operand"); 1575 shape = hlfir::genShape(loc, builder, right); 1576 } 1577 auto genKernel = [&op, &left, &right, &binaryOp]( 1578 mlir::Location l, fir::FirOpBuilder &b, 1579 mlir::ValueRange oneBasedIndices) -> hlfir::Entity { 1580 auto leftElement = hlfir::getElementAt(l, b, left, oneBasedIndices); 1581 auto rightElement = hlfir::getElementAt(l, b, right, oneBasedIndices); 1582 auto leftVal = hlfir::loadTrivialScalar(l, b, leftElement); 1583 auto rightVal = hlfir::loadTrivialScalar(l, b, rightElement); 1584 return binaryOp.gen(l, b, op.derived(), leftVal, rightVal); 1585 }; 1586 mlir::Value elemental = hlfir::genElementalOp(loc, builder, elementType, 1587 shape, typeParams, genKernel, 1588 /*isUnordered=*/true); 1589 fir::FirOpBuilder *bldr = &builder; 1590 getStmtCtx().attachCleanup( 1591 [=]() { bldr->create<hlfir::DestroyOp>(loc, elemental); }); 1592 return hlfir::EntityWithAttributes{elemental}; 1593 } 1594 1595 hlfir::EntityWithAttributes 1596 gen(const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &op) { 1597 return std::visit([&](const auto &x) { return gen(x); }, op.u); 1598 } 1599 1600 hlfir::EntityWithAttributes gen(const Fortran::evaluate::TypeParamInquiry &) { 1601 TODO(getLoc(), "lowering type parameter inquiry to HLFIR"); 1602 } 1603 1604 hlfir::EntityWithAttributes 1605 gen(const Fortran::evaluate::DescriptorInquiry &desc) { 1606 mlir::Location loc = getLoc(); 1607 auto &builder = getBuilder(); 1608 hlfir::EntityWithAttributes entity = 1609 HlfirDesignatorBuilder(getLoc(), getConverter(), getSymMap(), 1610 getStmtCtx()) 1611 .genNamedEntity(desc.base()); 1612 using ResTy = Fortran::evaluate::DescriptorInquiry::Result; 1613 mlir::Type resultType = 1614 getConverter().genType(ResTy::category, ResTy::kind); 1615 auto castResult = [&](mlir::Value v) { 1616 return hlfir::EntityWithAttributes{ 1617 builder.createConvert(loc, resultType, v)}; 1618 }; 1619 switch (desc.field()) { 1620 case Fortran::evaluate::DescriptorInquiry::Field::Len: 1621 return castResult(hlfir::genCharLength(loc, builder, entity)); 1622 case Fortran::evaluate::DescriptorInquiry::Field::LowerBound: 1623 return castResult( 1624 hlfir::genLBound(loc, builder, entity, desc.dimension())); 1625 case Fortran::evaluate::DescriptorInquiry::Field::Extent: 1626 return castResult( 1627 hlfir::genExtent(loc, builder, entity, desc.dimension())); 1628 case Fortran::evaluate::DescriptorInquiry::Field::Rank: 1629 return castResult(hlfir::genRank(loc, builder, entity, resultType)); 1630 case Fortran::evaluate::DescriptorInquiry::Field::Stride: 1631 // So far the front end does not generate this inquiry. 1632 TODO(loc, "stride inquiry"); 1633 } 1634 llvm_unreachable("unknown descriptor inquiry"); 1635 } 1636 1637 hlfir::EntityWithAttributes 1638 gen(const Fortran::evaluate::ImpliedDoIndex &var) { 1639 mlir::Value value = symMap.lookupImpliedDo(toStringRef(var.name)); 1640 if (!value) 1641 fir::emitFatalError(getLoc(), "ac-do-variable has no binding"); 1642 // The index value generated by the implied-do has Index type, 1643 // while computations based on it inside the loop body are using 1644 // the original data type. So we need to cast it appropriately. 1645 mlir::Type varTy = getConverter().genType(toEvExpr(var)); 1646 value = getBuilder().createConvert(getLoc(), varTy, value); 1647 return hlfir::EntityWithAttributes{value}; 1648 } 1649 1650 static bool 1651 isDerivedTypeWithLenParameters(const Fortran::semantics::Symbol &sym) { 1652 if (const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType()) 1653 if (const Fortran::semantics::DerivedTypeSpec *derived = 1654 declTy->AsDerived()) 1655 return Fortran::semantics::CountLenParameters(*derived) > 0; 1656 return false; 1657 } 1658 1659 // Construct an entity holding the value specified by the 1660 // StructureConstructor. The initialization of the temporary entity 1661 // is done component by component with the help of HLFIR operations 1662 // DesignateOp and AssignOp. 1663 hlfir::EntityWithAttributes 1664 gen(const Fortran::evaluate::StructureConstructor &ctor) { 1665 mlir::Location loc = getLoc(); 1666 fir::FirOpBuilder &builder = getBuilder(); 1667 mlir::Type ty = translateSomeExprToFIRType(converter, toEvExpr(ctor)); 1668 auto recTy = mlir::cast<fir::RecordType>(ty); 1669 1670 if (recTy.isDependentType()) 1671 TODO(loc, "structure constructor for derived type with length parameters " 1672 "in HLFIR"); 1673 1674 // Allocate scalar temporary that will be initialized 1675 // with the values specified by the constructor. 1676 mlir::Value storagePtr = builder.createTemporary(loc, recTy); 1677 auto varOp = hlfir::EntityWithAttributes{builder.create<hlfir::DeclareOp>( 1678 loc, storagePtr, "ctor.temp", /*shape=*/nullptr, 1679 /*typeparams=*/mlir::ValueRange{}, /*dummy_scope=*/nullptr, 1680 fir::FortranVariableFlagsAttr{})}; 1681 1682 // Initialize any components that need initialization. 1683 mlir::Value box = builder.createBox(loc, fir::ExtendedValue{varOp}); 1684 fir::runtime::genDerivedTypeInitialize(builder, loc, box); 1685 1686 // StructureConstructor values may relate to name of components in parent 1687 // types. These components cannot be addressed directly, the parent 1688 // components must be addressed first. The loop below creates all the 1689 // required chains of hlfir.designate to address the parent components so 1690 // that the StructureConstructor can later be lowered by addressing these 1691 // parent components if needed. Note: the front-end orders the components in 1692 // structure constructors. The code below relies on the component to appear 1693 // in order. 1694 using ValueAndParent = std::tuple<const Fortran::lower::SomeExpr &, 1695 const Fortran::semantics::Symbol &, 1696 hlfir::EntityWithAttributes>; 1697 llvm::SmallVector<ValueAndParent> valuesAndParents; 1698 Fortran::lower::ComponentReverseIterator compIterator( 1699 ctor.result().derivedTypeSpec()); 1700 hlfir::EntityWithAttributes currentParent = varOp; 1701 for (const auto &value : llvm::reverse(ctor.values())) { 1702 const Fortran::semantics::Symbol &compSym = *value.first; 1703 while (!compIterator.lookup(compSym.name())) { 1704 const auto &parentType = compIterator.advanceToParentType(); 1705 llvm::StringRef parentName = toStringRef(parentType.name()); 1706 auto baseRecTy = mlir::cast<fir::RecordType>( 1707 hlfir::getFortranElementType(currentParent.getType())); 1708 auto parentCompType = baseRecTy.getType(parentName); 1709 assert(parentCompType && "failed to retrieve parent component type"); 1710 mlir::Type designatorType = builder.getRefType(parentCompType); 1711 mlir::Value newParent = builder.create<hlfir::DesignateOp>( 1712 loc, designatorType, currentParent, parentName, 1713 /*compShape=*/mlir::Value{}, hlfir::DesignateOp::Subscripts{}, 1714 /*substring=*/mlir::ValueRange{}, 1715 /*complexPart=*/std::nullopt, 1716 /*shape=*/mlir::Value{}, /*typeParams=*/mlir::ValueRange{}, 1717 fir::FortranVariableFlagsAttr{}); 1718 currentParent = hlfir::EntityWithAttributes{newParent}; 1719 } 1720 valuesAndParents.emplace_back( 1721 ValueAndParent{value.second.value(), compSym, currentParent}); 1722 } 1723 1724 HlfirDesignatorBuilder designatorBuilder(loc, converter, symMap, stmtCtx); 1725 for (const auto &iter : llvm::reverse(valuesAndParents)) { 1726 auto &sym = std::get<const Fortran::semantics::Symbol &>(iter); 1727 auto &expr = std::get<const Fortran::lower::SomeExpr &>(iter); 1728 auto &baseOp = std::get<hlfir::EntityWithAttributes>(iter); 1729 std::string name = converter.getRecordTypeFieldName(sym); 1730 1731 // Generate DesignateOp for the component. 1732 // The designator's result type is just a reference to the component type, 1733 // because the whole component is being designated. 1734 auto baseRecTy = mlir::cast<fir::RecordType>( 1735 hlfir::getFortranElementType(baseOp.getType())); 1736 auto compType = baseRecTy.getType(name); 1737 assert(compType && "failed to retrieve component type"); 1738 mlir::Value compShape = 1739 designatorBuilder.genComponentShape(sym, compType); 1740 mlir::Type designatorType = builder.getRefType(compType); 1741 1742 mlir::Type fieldElemType = hlfir::getFortranElementType(compType); 1743 llvm::SmallVector<mlir::Value, 1> typeParams; 1744 if (auto charType = mlir::dyn_cast<fir::CharacterType>(fieldElemType)) { 1745 if (charType.hasConstantLen()) { 1746 mlir::Type idxType = builder.getIndexType(); 1747 typeParams.push_back( 1748 builder.createIntegerConstant(loc, idxType, charType.getLen())); 1749 } else if (!hasDeferredCharacterLength(sym)) { 1750 // If the length is not deferred, this is a parametrized derived type 1751 // where the character length depends on the derived type length 1752 // parameters. Otherwise, this is a pointer/allocatable component and 1753 // the length will be set during the assignment. 1754 TODO(loc, "automatic character component in structure constructor"); 1755 } 1756 } 1757 1758 // Convert component symbol attributes to variable attributes. 1759 fir::FortranVariableFlagsAttr attrs = 1760 Fortran::lower::translateSymbolAttributes(builder.getContext(), sym); 1761 1762 // Get the component designator. 1763 auto lhs = builder.create<hlfir::DesignateOp>( 1764 loc, designatorType, baseOp, name, compShape, 1765 hlfir::DesignateOp::Subscripts{}, 1766 /*substring=*/mlir::ValueRange{}, 1767 /*complexPart=*/std::nullopt, 1768 /*shape=*/compShape, typeParams, attrs); 1769 1770 if (attrs && bitEnumContainsAny(attrs.getFlags(), 1771 fir::FortranVariableFlagsEnum::pointer)) { 1772 if (Fortran::semantics::IsProcedure(sym)) { 1773 // Procedure pointer components. 1774 if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>( 1775 expr)) { 1776 auto boxTy{ 1777 Fortran::lower::getUntypedBoxProcType(builder.getContext())}; 1778 hlfir::Entity rhs( 1779 fir::factory::createNullBoxProc(builder, loc, boxTy)); 1780 builder.createStoreWithConvert(loc, rhs, lhs); 1781 continue; 1782 } 1783 hlfir::Entity rhs(getBase(Fortran::lower::convertExprToAddress( 1784 loc, converter, expr, symMap, stmtCtx))); 1785 builder.createStoreWithConvert(loc, rhs, lhs); 1786 continue; 1787 } 1788 // Pointer component construction is just a copy of the box contents. 1789 fir::ExtendedValue lhsExv = 1790 hlfir::translateToExtendedValue(loc, builder, lhs); 1791 auto *toBox = lhsExv.getBoxOf<fir::MutableBoxValue>(); 1792 if (!toBox) 1793 fir::emitFatalError(loc, "pointer component designator could not be " 1794 "lowered to mutable box"); 1795 Fortran::lower::associateMutableBox(converter, loc, *toBox, expr, 1796 /*lbounds=*/std::nullopt, stmtCtx); 1797 continue; 1798 } 1799 1800 // Use generic assignment for all the other cases. 1801 bool allowRealloc = 1802 attrs && 1803 bitEnumContainsAny(attrs.getFlags(), 1804 fir::FortranVariableFlagsEnum::allocatable); 1805 // If the component is allocatable, then we have to check 1806 // whether the RHS value is allocatable or not. 1807 // If it is not allocatable, then AssignOp can be used directly. 1808 // If it is allocatable, then using AssignOp for unallocated RHS 1809 // will cause illegal dereference. When an unallocated allocatable 1810 // value is used to construct an allocatable component, the component 1811 // must just stay unallocated (see Fortran 2018 7.5.10 point 7). 1812 1813 // If the component is allocatable and RHS is NULL() expression, then 1814 // we can just skip it: the LHS must remain unallocated with its 1815 // defined rank. 1816 if (allowRealloc && 1817 Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(expr)) 1818 continue; 1819 1820 bool keepLhsLength = false; 1821 if (allowRealloc) 1822 if (const Fortran::semantics::DeclTypeSpec *declType = sym.GetType()) 1823 keepLhsLength = 1824 declType->category() == 1825 Fortran::semantics::DeclTypeSpec::Category::Character && 1826 !declType->characterTypeSpec().length().isDeferred(); 1827 // Handle special case when the initializer expression is 1828 // '{%SET_LENGTH(x,const_kind)}'. In structure constructor, 1829 // SET_LENGTH is used for initializers of non-allocatable character 1830 // components so that the front-end can better 1831 // fold and work with these structure constructors. 1832 // Here, they are just noise since the assignment semantics will deal 1833 // with any length mismatch, and creating an extra temp with the lhs 1834 // length is useless. 1835 // TODO: should this be moved into an hlfir.assign + hlfir.set_length 1836 // pattern rewrite? 1837 hlfir::Entity rhs = gen(expr); 1838 if (auto set_length = rhs.getDefiningOp<hlfir::SetLengthOp>()) 1839 rhs = hlfir::Entity{set_length.getString()}; 1840 1841 // lambda to generate `lhs = rhs` and deal with potential rhs implicit 1842 // cast 1843 auto genAssign = [&] { 1844 rhs = hlfir::loadTrivialScalar(loc, builder, rhs); 1845 auto rhsCastAndCleanup = 1846 hlfir::genTypeAndKindConvert(loc, builder, rhs, lhs.getType(), 1847 /*preserveLowerBounds=*/allowRealloc); 1848 builder.create<hlfir::AssignOp>(loc, rhsCastAndCleanup.first, lhs, 1849 allowRealloc, 1850 allowRealloc ? keepLhsLength : false, 1851 /*temporary_lhs=*/true); 1852 if (rhsCastAndCleanup.second) 1853 (*rhsCastAndCleanup.second)(); 1854 }; 1855 1856 if (!allowRealloc || !rhs.isMutableBox()) { 1857 genAssign(); 1858 continue; 1859 } 1860 1861 auto [rhsExv, cleanup] = 1862 hlfir::translateToExtendedValue(loc, builder, rhs); 1863 assert(!cleanup && "unexpected cleanup"); 1864 auto *fromBox = rhsExv.getBoxOf<fir::MutableBoxValue>(); 1865 if (!fromBox) 1866 fir::emitFatalError(loc, "allocatable entity could not be lowered " 1867 "to mutable box"); 1868 mlir::Value isAlloc = 1869 fir::factory::genIsAllocatedOrAssociatedTest(builder, loc, *fromBox); 1870 builder.genIfThen(loc, isAlloc).genThen(genAssign).end(); 1871 } 1872 1873 if (fir::isRecordWithAllocatableMember(recTy)) { 1874 // Deallocate allocatable components without calling final subroutines. 1875 // The Fortran 2018 section 9.7.3.2 about deallocation is not ruling 1876 // about the fate of allocatable components of structure constructors, 1877 // and there is no behavior consensus in other compilers. 1878 fir::FirOpBuilder *bldr = &builder; 1879 getStmtCtx().attachCleanup([=]() { 1880 fir::runtime::genDerivedTypeDestroyWithoutFinalization(*bldr, loc, box); 1881 }); 1882 } 1883 return varOp; 1884 } 1885 1886 mlir::Location getLoc() const { return loc; } 1887 Fortran::lower::AbstractConverter &getConverter() { return converter; } 1888 fir::FirOpBuilder &getBuilder() { return converter.getFirOpBuilder(); } 1889 Fortran::lower::SymMap &getSymMap() { return symMap; } 1890 Fortran::lower::StatementContext &getStmtCtx() { return stmtCtx; } 1891 1892 Fortran::lower::AbstractConverter &converter; 1893 Fortran::lower::SymMap &symMap; 1894 Fortran::lower::StatementContext &stmtCtx; 1895 mlir::Location loc; 1896 }; 1897 1898 template <typename T> 1899 hlfir::Entity 1900 HlfirDesignatorBuilder::genSubscript(const Fortran::evaluate::Expr<T> &expr) { 1901 auto loweredExpr = 1902 HlfirBuilder(getLoc(), getConverter(), getSymMap(), getStmtCtx()) 1903 .gen(expr); 1904 fir::FirOpBuilder &builder = getBuilder(); 1905 // Skip constant conversions that litters designators and makes generated 1906 // IR harder to read: directly use index constants for constant subscripts. 1907 mlir::Type idxTy = builder.getIndexType(); 1908 if (!loweredExpr.isArray() && loweredExpr.getType() != idxTy) 1909 if (auto cstIndex = fir::getIntIfConstant(loweredExpr)) 1910 return hlfir::EntityWithAttributes{ 1911 builder.createIntegerConstant(getLoc(), idxTy, *cstIndex)}; 1912 return hlfir::loadTrivialScalar(loc, builder, loweredExpr); 1913 } 1914 1915 } // namespace 1916 1917 hlfir::EntityWithAttributes Fortran::lower::convertExprToHLFIR( 1918 mlir::Location loc, Fortran::lower::AbstractConverter &converter, 1919 const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap, 1920 Fortran::lower::StatementContext &stmtCtx) { 1921 return HlfirBuilder(loc, converter, symMap, stmtCtx).gen(expr); 1922 } 1923 1924 fir::ExtendedValue Fortran::lower::convertToBox( 1925 mlir::Location loc, Fortran::lower::AbstractConverter &converter, 1926 hlfir::Entity entity, Fortran::lower::StatementContext &stmtCtx, 1927 mlir::Type fortranType) { 1928 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 1929 auto [exv, cleanup] = hlfir::convertToBox(loc, builder, entity, fortranType); 1930 if (cleanup) 1931 stmtCtx.attachCleanup(*cleanup); 1932 return exv; 1933 } 1934 1935 fir::ExtendedValue Fortran::lower::convertExprToBox( 1936 mlir::Location loc, Fortran::lower::AbstractConverter &converter, 1937 const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap, 1938 Fortran::lower::StatementContext &stmtCtx) { 1939 hlfir::EntityWithAttributes loweredExpr = 1940 HlfirBuilder(loc, converter, symMap, stmtCtx).gen(expr); 1941 return convertToBox(loc, converter, loweredExpr, stmtCtx, 1942 converter.genType(expr)); 1943 } 1944 1945 fir::ExtendedValue Fortran::lower::convertToAddress( 1946 mlir::Location loc, Fortran::lower::AbstractConverter &converter, 1947 hlfir::Entity entity, Fortran::lower::StatementContext &stmtCtx, 1948 mlir::Type fortranType) { 1949 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 1950 auto [exv, cleanup] = 1951 hlfir::convertToAddress(loc, builder, entity, fortranType); 1952 if (cleanup) 1953 stmtCtx.attachCleanup(*cleanup); 1954 return exv; 1955 } 1956 1957 fir::ExtendedValue Fortran::lower::convertExprToAddress( 1958 mlir::Location loc, Fortran::lower::AbstractConverter &converter, 1959 const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap, 1960 Fortran::lower::StatementContext &stmtCtx) { 1961 hlfir::EntityWithAttributes loweredExpr = 1962 HlfirBuilder(loc, converter, symMap, stmtCtx).gen(expr); 1963 return convertToAddress(loc, converter, loweredExpr, stmtCtx, 1964 converter.genType(expr)); 1965 } 1966 1967 fir::ExtendedValue Fortran::lower::convertToValue( 1968 mlir::Location loc, Fortran::lower::AbstractConverter &converter, 1969 hlfir::Entity entity, Fortran::lower::StatementContext &stmtCtx) { 1970 auto &builder = converter.getFirOpBuilder(); 1971 auto [exv, cleanup] = hlfir::convertToValue(loc, builder, entity); 1972 if (cleanup) 1973 stmtCtx.attachCleanup(*cleanup); 1974 return exv; 1975 } 1976 1977 fir::ExtendedValue Fortran::lower::convertExprToValue( 1978 mlir::Location loc, Fortran::lower::AbstractConverter &converter, 1979 const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap, 1980 Fortran::lower::StatementContext &stmtCtx) { 1981 hlfir::EntityWithAttributes loweredExpr = 1982 HlfirBuilder(loc, converter, symMap, stmtCtx).gen(expr); 1983 return convertToValue(loc, converter, loweredExpr, stmtCtx); 1984 } 1985 1986 fir::ExtendedValue Fortran::lower::convertDataRefToValue( 1987 mlir::Location loc, Fortran::lower::AbstractConverter &converter, 1988 const Fortran::evaluate::DataRef &dataRef, Fortran::lower::SymMap &symMap, 1989 Fortran::lower::StatementContext &stmtCtx) { 1990 fir::FortranVariableOpInterface loweredExpr = 1991 HlfirDesignatorBuilder(loc, converter, symMap, stmtCtx).gen(dataRef); 1992 return convertToValue(loc, converter, loweredExpr, stmtCtx); 1993 } 1994 1995 fir::MutableBoxValue Fortran::lower::convertExprToMutableBox( 1996 mlir::Location loc, Fortran::lower::AbstractConverter &converter, 1997 const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap) { 1998 // Pointers and Allocatable cannot be temporary expressions. Temporaries may 1999 // be created while lowering it (e.g. if any indices expression of a 2000 // designator create temporaries), but they can be destroyed before using the 2001 // lowered pointer or allocatable; 2002 Fortran::lower::StatementContext localStmtCtx; 2003 hlfir::EntityWithAttributes loweredExpr = 2004 HlfirBuilder(loc, converter, symMap, localStmtCtx).gen(expr); 2005 fir::ExtendedValue exv = Fortran::lower::translateToExtendedValue( 2006 loc, converter.getFirOpBuilder(), loweredExpr, localStmtCtx); 2007 auto *mutableBox = exv.getBoxOf<fir::MutableBoxValue>(); 2008 assert(mutableBox && "expression could not be lowered to mutable box"); 2009 return *mutableBox; 2010 } 2011 2012 hlfir::ElementalAddrOp 2013 Fortran::lower::convertVectorSubscriptedExprToElementalAddr( 2014 mlir::Location loc, Fortran::lower::AbstractConverter &converter, 2015 const Fortran::lower::SomeExpr &designatorExpr, 2016 Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx) { 2017 return HlfirDesignatorBuilder(loc, converter, symMap, stmtCtx) 2018 .convertVectorSubscriptedExprToElementalAddr(designatorExpr); 2019 } 2020