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