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

source code of flang/lib/Lower/ConvertExprToHLFIR.cpp