xref: /llvm-project/flang/lib/Optimizer/Builder/HLFIRTools.cpp (revision 71ff486bee1b089c78f5b8175fef16f99fcebe19)
1 //===-- HLFIRTools.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 // Tools to manipulate HLFIR variable and expressions
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "flang/Optimizer/Builder/HLFIRTools.h"
14 #include "flang/Optimizer/Builder/Character.h"
15 #include "flang/Optimizer/Builder/FIRBuilder.h"
16 #include "flang/Optimizer/Builder/MutableBox.h"
17 #include "flang/Optimizer/Builder/Runtime/Allocatable.h"
18 #include "flang/Optimizer/Builder/Todo.h"
19 #include "flang/Optimizer/HLFIR/HLFIROps.h"
20 #include "mlir/IR/IRMapping.h"
21 #include "mlir/Support/LLVM.h"
22 #include "llvm/ADT/TypeSwitch.h"
23 #include <mlir/Dialect/OpenMP/OpenMPDialect.h>
24 #include <optional>
25 
26 // Return explicit extents. If the base is a fir.box, this won't read it to
27 // return the extents and will instead return an empty vector.
28 llvm::SmallVector<mlir::Value>
29 hlfir::getExplicitExtentsFromShape(mlir::Value shape,
30                                    fir::FirOpBuilder &builder) {
31   llvm::SmallVector<mlir::Value> result;
32   auto *shapeOp = shape.getDefiningOp();
33   if (auto s = mlir::dyn_cast_or_null<fir::ShapeOp>(shapeOp)) {
34     auto e = s.getExtents();
35     result.append(e.begin(), e.end());
36   } else if (auto s = mlir::dyn_cast_or_null<fir::ShapeShiftOp>(shapeOp)) {
37     auto e = s.getExtents();
38     result.append(e.begin(), e.end());
39   } else if (mlir::dyn_cast_or_null<fir::ShiftOp>(shapeOp)) {
40     return {};
41   } else if (auto s = mlir::dyn_cast_or_null<hlfir::ShapeOfOp>(shapeOp)) {
42     hlfir::ExprType expr = mlir::cast<hlfir::ExprType>(s.getExpr().getType());
43     llvm::ArrayRef<int64_t> exprShape = expr.getShape();
44     mlir::Type indexTy = builder.getIndexType();
45     fir::ShapeType shapeTy = mlir::cast<fir::ShapeType>(shape.getType());
46     result.reserve(shapeTy.getRank());
47     for (unsigned i = 0; i < shapeTy.getRank(); ++i) {
48       int64_t extent = exprShape[i];
49       mlir::Value extentVal;
50       if (extent == expr.getUnknownExtent()) {
51         auto op = builder.create<hlfir::GetExtentOp>(shape.getLoc(), shape, i);
52         extentVal = op.getResult();
53       } else {
54         extentVal =
55             builder.createIntegerConstant(shape.getLoc(), indexTy, extent);
56       }
57       result.emplace_back(extentVal);
58     }
59   } else {
60     TODO(shape.getLoc(), "read fir.shape to get extents");
61   }
62   return result;
63 }
64 static llvm::SmallVector<mlir::Value>
65 getExplicitExtents(fir::FortranVariableOpInterface var,
66                    fir::FirOpBuilder &builder) {
67   if (mlir::Value shape = var.getShape())
68     return hlfir::getExplicitExtentsFromShape(var.getShape(), builder);
69   return {};
70 }
71 
72 // Return explicit lower bounds. For pointers and allocatables, this will not
73 // read the lower bounds and instead return an empty vector.
74 static llvm::SmallVector<mlir::Value>
75 getExplicitLboundsFromShape(mlir::Value shape) {
76   llvm::SmallVector<mlir::Value> result;
77   auto *shapeOp = shape.getDefiningOp();
78   if (auto s = mlir::dyn_cast_or_null<fir::ShapeOp>(shapeOp)) {
79     return {};
80   } else if (auto s = mlir::dyn_cast_or_null<fir::ShapeShiftOp>(shapeOp)) {
81     auto e = s.getOrigins();
82     result.append(e.begin(), e.end());
83   } else if (auto s = mlir::dyn_cast_or_null<fir::ShiftOp>(shapeOp)) {
84     auto e = s.getOrigins();
85     result.append(e.begin(), e.end());
86   } else {
87     TODO(shape.getLoc(), "read fir.shape to get lower bounds");
88   }
89   return result;
90 }
91 static llvm::SmallVector<mlir::Value>
92 getExplicitLbounds(fir::FortranVariableOpInterface var) {
93   if (mlir::Value shape = var.getShape())
94     return getExplicitLboundsFromShape(shape);
95   return {};
96 }
97 
98 static void
99 genLboundsAndExtentsFromBox(mlir::Location loc, fir::FirOpBuilder &builder,
100                             hlfir::Entity boxEntity,
101                             llvm::SmallVectorImpl<mlir::Value> &lbounds,
102                             llvm::SmallVectorImpl<mlir::Value> *extents) {
103   assert(mlir::isa<fir::BaseBoxType>(boxEntity.getType()) && "must be a box");
104   mlir::Type idxTy = builder.getIndexType();
105   const int rank = boxEntity.getRank();
106   for (int i = 0; i < rank; ++i) {
107     mlir::Value dim = builder.createIntegerConstant(loc, idxTy, i);
108     auto dimInfo = builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy,
109                                                   boxEntity, dim);
110     lbounds.push_back(dimInfo.getLowerBound());
111     if (extents)
112       extents->push_back(dimInfo.getExtent());
113   }
114 }
115 
116 static llvm::SmallVector<mlir::Value>
117 getNonDefaultLowerBounds(mlir::Location loc, fir::FirOpBuilder &builder,
118                          hlfir::Entity entity) {
119   assert(!entity.isAssumedRank() &&
120          "cannot compute assumed rank bounds statically");
121   if (!entity.mayHaveNonDefaultLowerBounds())
122     return {};
123   if (auto varIface = entity.getIfVariableInterface()) {
124     llvm::SmallVector<mlir::Value> lbounds = getExplicitLbounds(varIface);
125     if (!lbounds.empty())
126       return lbounds;
127   }
128   if (entity.isMutableBox())
129     entity = hlfir::derefPointersAndAllocatables(loc, builder, entity);
130   llvm::SmallVector<mlir::Value> lowerBounds;
131   genLboundsAndExtentsFromBox(loc, builder, entity, lowerBounds,
132                               /*extents=*/nullptr);
133   return lowerBounds;
134 }
135 
136 static llvm::SmallVector<mlir::Value> toSmallVector(mlir::ValueRange range) {
137   llvm::SmallVector<mlir::Value> res;
138   res.append(range.begin(), range.end());
139   return res;
140 }
141 
142 static llvm::SmallVector<mlir::Value> getExplicitTypeParams(hlfir::Entity var) {
143   if (auto varIface = var.getMaybeDereferencedVariableInterface())
144     return toSmallVector(varIface.getExplicitTypeParams());
145   return {};
146 }
147 
148 static mlir::Value tryGettingNonDeferredCharLen(hlfir::Entity var) {
149   if (auto varIface = var.getMaybeDereferencedVariableInterface())
150     if (!varIface.getExplicitTypeParams().empty())
151       return varIface.getExplicitTypeParams()[0];
152   return mlir::Value{};
153 }
154 
155 static mlir::Value genCharacterVariableLength(mlir::Location loc,
156                                               fir::FirOpBuilder &builder,
157                                               hlfir::Entity var) {
158   if (mlir::Value len = tryGettingNonDeferredCharLen(var))
159     return len;
160   auto charType = mlir::cast<fir::CharacterType>(var.getFortranElementType());
161   if (charType.hasConstantLen())
162     return builder.createIntegerConstant(loc, builder.getIndexType(),
163                                          charType.getLen());
164   if (var.isMutableBox())
165     var = hlfir::Entity{builder.create<fir::LoadOp>(loc, var)};
166   mlir::Value len = fir::factory::CharacterExprHelper{builder, loc}.getLength(
167       var.getFirBase());
168   assert(len && "failed to retrieve length");
169   return len;
170 }
171 
172 static fir::CharBoxValue genUnboxChar(mlir::Location loc,
173                                       fir::FirOpBuilder &builder,
174                                       mlir::Value boxChar) {
175   if (auto emboxChar = boxChar.getDefiningOp<fir::EmboxCharOp>())
176     return {emboxChar.getMemref(), emboxChar.getLen()};
177   mlir::Type refType = fir::ReferenceType::get(
178       mlir::cast<fir::BoxCharType>(boxChar.getType()).getEleTy());
179   auto unboxed = builder.create<fir::UnboxCharOp>(
180       loc, refType, builder.getIndexType(), boxChar);
181   mlir::Value addr = unboxed.getResult(0);
182   mlir::Value len = unboxed.getResult(1);
183   if (auto varIface = boxChar.getDefiningOp<fir::FortranVariableOpInterface>())
184     if (mlir::Value explicitlen = varIface.getExplicitCharLen())
185       len = explicitlen;
186   return {addr, len};
187 }
188 
189 mlir::Value hlfir::Entity::getFirBase() const {
190   if (fir::FortranVariableOpInterface variable = getIfVariableInterface()) {
191     if (auto declareOp =
192             mlir::dyn_cast<hlfir::DeclareOp>(variable.getOperation()))
193       return declareOp.getOriginalBase();
194     if (auto associateOp =
195             mlir::dyn_cast<hlfir::AssociateOp>(variable.getOperation()))
196       return associateOp.getFirBase();
197   }
198   return getBase();
199 }
200 
201 static bool isShapeWithLowerBounds(mlir::Value shape) {
202   if (!shape)
203     return false;
204   auto shapeTy = shape.getType();
205   return mlir::isa<fir::ShiftType>(shapeTy) ||
206          mlir::isa<fir::ShapeShiftType>(shapeTy);
207 }
208 
209 bool hlfir::Entity::mayHaveNonDefaultLowerBounds() const {
210   if (!isBoxAddressOrValue() || isScalar())
211     return false;
212   if (isMutableBox())
213     return true;
214   if (auto varIface = getIfVariableInterface())
215     return isShapeWithLowerBounds(varIface.getShape());
216   // Go through chain of fir.box converts.
217   if (auto convert = getDefiningOp<fir::ConvertOp>())
218     return hlfir::Entity{convert.getValue()}.mayHaveNonDefaultLowerBounds();
219   // TODO: Embox and Rebox do not have hlfir variable interface, but are
220   // easy to reason about.
221   return true;
222 }
223 
224 fir::FortranVariableOpInterface
225 hlfir::genDeclare(mlir::Location loc, fir::FirOpBuilder &builder,
226                   const fir::ExtendedValue &exv, llvm::StringRef name,
227                   fir::FortranVariableFlagsAttr flags, mlir::Value dummyScope,
228                   cuf::DataAttributeAttr dataAttr) {
229 
230   mlir::Value base = fir::getBase(exv);
231   assert(fir::conformsWithPassByRef(base.getType()) &&
232          "entity being declared must be in memory");
233   mlir::Value shapeOrShift;
234   llvm::SmallVector<mlir::Value> lenParams;
235   exv.match(
236       [&](const fir::CharBoxValue &box) {
237         lenParams.emplace_back(box.getLen());
238       },
239       [&](const fir::ArrayBoxValue &) {
240         shapeOrShift = builder.createShape(loc, exv);
241       },
242       [&](const fir::CharArrayBoxValue &box) {
243         shapeOrShift = builder.createShape(loc, exv);
244         lenParams.emplace_back(box.getLen());
245       },
246       [&](const fir::BoxValue &box) {
247         if (!box.getLBounds().empty())
248           shapeOrShift = builder.createShape(loc, exv);
249         lenParams.append(box.getExplicitParameters().begin(),
250                          box.getExplicitParameters().end());
251       },
252       [&](const fir::MutableBoxValue &box) {
253         lenParams.append(box.nonDeferredLenParams().begin(),
254                          box.nonDeferredLenParams().end());
255       },
256       [](const auto &) {});
257   auto declareOp = builder.create<hlfir::DeclareOp>(
258       loc, base, name, shapeOrShift, lenParams, dummyScope, flags, dataAttr);
259   return mlir::cast<fir::FortranVariableOpInterface>(declareOp.getOperation());
260 }
261 
262 hlfir::AssociateOp
263 hlfir::genAssociateExpr(mlir::Location loc, fir::FirOpBuilder &builder,
264                         hlfir::Entity value, mlir::Type variableType,
265                         llvm::StringRef name,
266                         std::optional<mlir::NamedAttribute> attr) {
267   assert(value.isValue() && "must not be a variable");
268   mlir::Value shape{};
269   if (value.isArray())
270     shape = genShape(loc, builder, value);
271 
272   mlir::Value source = value;
273   // Lowered scalar expression values for numerical and logical may have a
274   // different type than what is required for the type in memory (logical
275   // expressions are typically manipulated as i1, but needs to be stored
276   // according to the fir.logical<kind> so that the storage size is correct).
277   // Character length mismatches are ignored (it is ok for one to be dynamic
278   // and the other static).
279   mlir::Type varEleTy = getFortranElementType(variableType);
280   mlir::Type valueEleTy = getFortranElementType(value.getType());
281   if (varEleTy != valueEleTy && !(mlir::isa<fir::CharacterType>(valueEleTy) &&
282                                   mlir::isa<fir::CharacterType>(varEleTy))) {
283     assert(value.isScalar() && fir::isa_trivial(value.getType()));
284     source = builder.createConvert(loc, fir::unwrapPassByRefType(variableType),
285                                    value);
286   }
287   llvm::SmallVector<mlir::Value> lenParams;
288   genLengthParameters(loc, builder, value, lenParams);
289   if (attr) {
290     assert(name.empty() && "It attribute is provided, no-name is expected");
291     return builder.create<hlfir::AssociateOp>(loc, source, shape, lenParams,
292                                               fir::FortranVariableFlagsAttr{},
293                                               llvm::ArrayRef{*attr});
294   }
295   return builder.create<hlfir::AssociateOp>(loc, source, name, shape, lenParams,
296                                             fir::FortranVariableFlagsAttr{});
297 }
298 
299 mlir::Value hlfir::genVariableRawAddress(mlir::Location loc,
300                                          fir::FirOpBuilder &builder,
301                                          hlfir::Entity var) {
302   assert(var.isVariable() && "only address of variables can be taken");
303   mlir::Value baseAddr = var.getFirBase();
304   if (var.isMutableBox())
305     baseAddr = builder.create<fir::LoadOp>(loc, baseAddr);
306   // Get raw address.
307   if (mlir::isa<fir::BoxCharType>(var.getType()))
308     baseAddr = genUnboxChar(loc, builder, var.getBase()).getAddr();
309   if (mlir::isa<fir::BaseBoxType>(baseAddr.getType()))
310     baseAddr = builder.create<fir::BoxAddrOp>(loc, baseAddr);
311   return baseAddr;
312 }
313 
314 mlir::Value hlfir::genVariableBoxChar(mlir::Location loc,
315                                       fir::FirOpBuilder &builder,
316                                       hlfir::Entity var) {
317   assert(var.isVariable() && "only address of variables can be taken");
318   if (mlir::isa<fir::BoxCharType>(var.getType()))
319     return var;
320   mlir::Value addr = genVariableRawAddress(loc, builder, var);
321   llvm::SmallVector<mlir::Value> lengths;
322   genLengthParameters(loc, builder, var, lengths);
323   assert(lengths.size() == 1);
324   auto charType = mlir::cast<fir::CharacterType>(var.getFortranElementType());
325   auto boxCharType =
326       fir::BoxCharType::get(builder.getContext(), charType.getFKind());
327   auto scalarAddr =
328       builder.createConvert(loc, fir::ReferenceType::get(charType), addr);
329   return builder.create<fir::EmboxCharOp>(loc, boxCharType, scalarAddr,
330                                           lengths[0]);
331 }
332 
333 hlfir::Entity hlfir::genVariableBox(mlir::Location loc,
334                                     fir::FirOpBuilder &builder,
335                                     hlfir::Entity var) {
336   assert(var.isVariable() && "must be a variable");
337   var = hlfir::derefPointersAndAllocatables(loc, builder, var);
338   if (mlir::isa<fir::BaseBoxType>(var.getType()))
339     return var;
340   // Note: if the var is not a fir.box/fir.class at that point, it has default
341   // lower bounds and is not polymorphic.
342   mlir::Value shape =
343       var.isArray() ? hlfir::genShape(loc, builder, var) : mlir::Value{};
344   llvm::SmallVector<mlir::Value> typeParams;
345   auto maybeCharType =
346       mlir::dyn_cast<fir::CharacterType>(var.getFortranElementType());
347   if (!maybeCharType || maybeCharType.hasDynamicLen())
348     hlfir::genLengthParameters(loc, builder, var, typeParams);
349   mlir::Value addr = var.getBase();
350   if (mlir::isa<fir::BoxCharType>(var.getType()))
351     addr = genVariableRawAddress(loc, builder, var);
352   mlir::Type boxType = fir::BoxType::get(var.getElementOrSequenceType());
353   auto embox =
354       builder.create<fir::EmboxOp>(loc, boxType, addr, shape,
355                                    /*slice=*/mlir::Value{}, typeParams);
356   return hlfir::Entity{embox.getResult()};
357 }
358 
359 hlfir::Entity hlfir::loadTrivialScalar(mlir::Location loc,
360                                        fir::FirOpBuilder &builder,
361                                        Entity entity) {
362   entity = derefPointersAndAllocatables(loc, builder, entity);
363   if (entity.isVariable() && entity.isScalar() &&
364       fir::isa_trivial(entity.getFortranElementType())) {
365     return Entity{builder.create<fir::LoadOp>(loc, entity)};
366   }
367   return entity;
368 }
369 
370 hlfir::Entity hlfir::getElementAt(mlir::Location loc,
371                                   fir::FirOpBuilder &builder, Entity entity,
372                                   mlir::ValueRange oneBasedIndices) {
373   if (entity.isScalar())
374     return entity;
375   llvm::SmallVector<mlir::Value> lenParams;
376   genLengthParameters(loc, builder, entity, lenParams);
377   if (mlir::isa<hlfir::ExprType>(entity.getType()))
378     return hlfir::Entity{builder.create<hlfir::ApplyOp>(
379         loc, entity, oneBasedIndices, lenParams)};
380   // Build hlfir.designate. The lower bounds may need to be added to
381   // the oneBasedIndices since hlfir.designate expect indices
382   // based on the array operand lower bounds.
383   mlir::Type resultType = hlfir::getVariableElementType(entity);
384   hlfir::DesignateOp designate;
385   llvm::SmallVector<mlir::Value> lbounds =
386       getNonDefaultLowerBounds(loc, builder, entity);
387   if (!lbounds.empty()) {
388     llvm::SmallVector<mlir::Value> indices;
389     mlir::Type idxTy = builder.getIndexType();
390     mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
391     for (auto [oneBased, lb] : llvm::zip(oneBasedIndices, lbounds)) {
392       auto lbIdx = builder.createConvert(loc, idxTy, lb);
393       auto oneBasedIdx = builder.createConvert(loc, idxTy, oneBased);
394       auto shift = builder.create<mlir::arith::SubIOp>(loc, lbIdx, one);
395       mlir::Value index =
396           builder.create<mlir::arith::AddIOp>(loc, oneBasedIdx, shift);
397       indices.push_back(index);
398     }
399     designate = builder.create<hlfir::DesignateOp>(loc, resultType, entity,
400                                                    indices, lenParams);
401   } else {
402     designate = builder.create<hlfir::DesignateOp>(loc, resultType, entity,
403                                                    oneBasedIndices, lenParams);
404   }
405   return mlir::cast<fir::FortranVariableOpInterface>(designate.getOperation());
406 }
407 
408 static mlir::Value genUBound(mlir::Location loc, fir::FirOpBuilder &builder,
409                              mlir::Value lb, mlir::Value extent,
410                              mlir::Value one) {
411   if (auto constantLb = fir::getIntIfConstant(lb))
412     if (*constantLb == 1)
413       return extent;
414   extent = builder.createConvert(loc, one.getType(), extent);
415   lb = builder.createConvert(loc, one.getType(), lb);
416   auto add = builder.create<mlir::arith::AddIOp>(loc, lb, extent);
417   return builder.create<mlir::arith::SubIOp>(loc, add, one);
418 }
419 
420 llvm::SmallVector<std::pair<mlir::Value, mlir::Value>>
421 hlfir::genBounds(mlir::Location loc, fir::FirOpBuilder &builder,
422                  Entity entity) {
423   if (mlir::isa<hlfir::ExprType>(entity.getType()))
424     TODO(loc, "bounds of expressions in hlfir");
425   auto [exv, cleanup] = translateToExtendedValue(loc, builder, entity);
426   assert(!cleanup && "translation of entity should not yield cleanup");
427   if (const auto *mutableBox = exv.getBoxOf<fir::MutableBoxValue>())
428     exv = fir::factory::genMutableBoxRead(builder, loc, *mutableBox);
429   mlir::Type idxTy = builder.getIndexType();
430   mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
431   llvm::SmallVector<std::pair<mlir::Value, mlir::Value>> result;
432   for (unsigned dim = 0; dim < exv.rank(); ++dim) {
433     mlir::Value extent = fir::factory::readExtent(builder, loc, exv, dim);
434     mlir::Value lb = fir::factory::readLowerBound(builder, loc, exv, dim, one);
435     mlir::Value ub = genUBound(loc, builder, lb, extent, one);
436     result.push_back({lb, ub});
437   }
438   return result;
439 }
440 
441 llvm::SmallVector<std::pair<mlir::Value, mlir::Value>>
442 hlfir::genBounds(mlir::Location loc, fir::FirOpBuilder &builder,
443                  mlir::Value shape) {
444   assert((mlir::isa<fir::ShapeShiftType>(shape.getType()) ||
445           mlir::isa<fir::ShapeType>(shape.getType())) &&
446          "shape must contain extents");
447   auto extents = hlfir::getExplicitExtentsFromShape(shape, builder);
448   auto lowers = getExplicitLboundsFromShape(shape);
449   assert(lowers.empty() || lowers.size() == extents.size());
450   mlir::Type idxTy = builder.getIndexType();
451   mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
452   llvm::SmallVector<std::pair<mlir::Value, mlir::Value>> result;
453   for (auto extent : llvm::enumerate(extents)) {
454     mlir::Value lb = lowers.empty() ? one : lowers[extent.index()];
455     mlir::Value ub = lowers.empty()
456                          ? extent.value()
457                          : genUBound(loc, builder, lb, extent.value(), one);
458     result.push_back({lb, ub});
459   }
460   return result;
461 }
462 
463 llvm::SmallVector<mlir::Value> hlfir::genLowerbounds(mlir::Location loc,
464                                                      fir::FirOpBuilder &builder,
465                                                      mlir::Value shape,
466                                                      unsigned rank) {
467   llvm::SmallVector<mlir::Value> lbounds;
468   if (shape)
469     lbounds = getExplicitLboundsFromShape(shape);
470   if (!lbounds.empty())
471     return lbounds;
472   mlir::Value one =
473       builder.createIntegerConstant(loc, builder.getIndexType(), 1);
474   return llvm::SmallVector<mlir::Value>(rank, one);
475 }
476 
477 static hlfir::Entity followShapeInducingSource(hlfir::Entity entity) {
478   while (true) {
479     if (auto reassoc = entity.getDefiningOp<hlfir::NoReassocOp>()) {
480       entity = hlfir::Entity{reassoc.getVal()};
481       continue;
482     }
483     if (auto asExpr = entity.getDefiningOp<hlfir::AsExprOp>()) {
484       entity = hlfir::Entity{asExpr.getVar()};
485       continue;
486     }
487     break;
488   }
489   return entity;
490 }
491 
492 static mlir::Value computeVariableExtent(mlir::Location loc,
493                                          fir::FirOpBuilder &builder,
494                                          hlfir::Entity variable,
495                                          fir::SequenceType seqTy,
496                                          unsigned dim) {
497   mlir::Type idxTy = builder.getIndexType();
498   if (seqTy.getShape().size() > dim) {
499     fir::SequenceType::Extent typeExtent = seqTy.getShape()[dim];
500     if (typeExtent != fir::SequenceType::getUnknownExtent())
501       return builder.createIntegerConstant(loc, idxTy, typeExtent);
502   }
503   assert(mlir::isa<fir::BaseBoxType>(variable.getType()) &&
504          "array variable with dynamic extent must be boxed");
505   mlir::Value dimVal = builder.createIntegerConstant(loc, idxTy, dim);
506   auto dimInfo = builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy,
507                                                 variable, dimVal);
508   return dimInfo.getExtent();
509 }
510 llvm::SmallVector<mlir::Value> getVariableExtents(mlir::Location loc,
511                                                   fir::FirOpBuilder &builder,
512                                                   hlfir::Entity variable) {
513   llvm::SmallVector<mlir::Value> extents;
514   if (fir::FortranVariableOpInterface varIface =
515           variable.getIfVariableInterface()) {
516     extents = getExplicitExtents(varIface, builder);
517     if (!extents.empty())
518       return extents;
519   }
520 
521   if (variable.isMutableBox())
522     variable = hlfir::derefPointersAndAllocatables(loc, builder, variable);
523   // Use the type shape information, and/or the fir.box/fir.class shape
524   // information if any extents are not static.
525   fir::SequenceType seqTy = mlir::cast<fir::SequenceType>(
526       hlfir::getFortranElementOrSequenceType(variable.getType()));
527   unsigned rank = seqTy.getShape().size();
528   for (unsigned dim = 0; dim < rank; ++dim)
529     extents.push_back(
530         computeVariableExtent(loc, builder, variable, seqTy, dim));
531   return extents;
532 }
533 
534 static mlir::Value tryRetrievingShapeOrShift(hlfir::Entity entity) {
535   if (mlir::isa<hlfir::ExprType>(entity.getType())) {
536     if (auto elemental = entity.getDefiningOp<hlfir::ElementalOp>())
537       return elemental.getShape();
538     if (auto evalInMem = entity.getDefiningOp<hlfir::EvaluateInMemoryOp>())
539       return evalInMem.getShape();
540     return mlir::Value{};
541   }
542   if (auto varIface = entity.getIfVariableInterface())
543     return varIface.getShape();
544   return {};
545 }
546 
547 mlir::Value hlfir::genShape(mlir::Location loc, fir::FirOpBuilder &builder,
548                             hlfir::Entity entity) {
549   assert(entity.isArray() && "entity must be an array");
550   entity = followShapeInducingSource(entity);
551   assert(entity && "what?");
552   if (auto shape = tryRetrievingShapeOrShift(entity)) {
553     if (mlir::isa<fir::ShapeType>(shape.getType()))
554       return shape;
555     if (mlir::isa<fir::ShapeShiftType>(shape.getType()))
556       if (auto s = shape.getDefiningOp<fir::ShapeShiftOp>())
557         return builder.create<fir::ShapeOp>(loc, s.getExtents());
558   }
559   if (mlir::isa<hlfir::ExprType>(entity.getType()))
560     return builder.create<hlfir::ShapeOfOp>(loc, entity.getBase());
561   // There is no shape lying around for this entity. Retrieve the extents and
562   // build a new fir.shape.
563   return builder.create<fir::ShapeOp>(loc,
564                                       getVariableExtents(loc, builder, entity));
565 }
566 
567 llvm::SmallVector<mlir::Value>
568 hlfir::getIndexExtents(mlir::Location loc, fir::FirOpBuilder &builder,
569                        mlir::Value shape) {
570   llvm::SmallVector<mlir::Value> extents =
571       hlfir::getExplicitExtentsFromShape(shape, builder);
572   mlir::Type indexType = builder.getIndexType();
573   for (auto &extent : extents)
574     extent = builder.createConvert(loc, indexType, extent);
575   return extents;
576 }
577 
578 mlir::Value hlfir::genExtent(mlir::Location loc, fir::FirOpBuilder &builder,
579                              hlfir::Entity entity, unsigned dim) {
580   entity = followShapeInducingSource(entity);
581   if (auto shape = tryRetrievingShapeOrShift(entity)) {
582     auto extents = hlfir::getExplicitExtentsFromShape(shape, builder);
583     if (!extents.empty()) {
584       assert(extents.size() > dim && "bad inquiry");
585       return extents[dim];
586     }
587   }
588   if (entity.isVariable()) {
589     if (entity.isMutableBox())
590       entity = hlfir::derefPointersAndAllocatables(loc, builder, entity);
591     // Use the type shape information, and/or the fir.box/fir.class shape
592     // information if any extents are not static.
593     fir::SequenceType seqTy = mlir::cast<fir::SequenceType>(
594         hlfir::getFortranElementOrSequenceType(entity.getType()));
595     return computeVariableExtent(loc, builder, entity, seqTy, dim);
596   }
597   TODO(loc, "get extent from HLFIR expr without producer holding the shape");
598 }
599 
600 mlir::Value hlfir::genLBound(mlir::Location loc, fir::FirOpBuilder &builder,
601                              hlfir::Entity entity, unsigned dim) {
602   if (!entity.mayHaveNonDefaultLowerBounds())
603     return builder.createIntegerConstant(loc, builder.getIndexType(), 1);
604   if (auto shape = tryRetrievingShapeOrShift(entity)) {
605     auto lbounds = getExplicitLboundsFromShape(shape);
606     if (!lbounds.empty()) {
607       assert(lbounds.size() > dim && "bad inquiry");
608       return lbounds[dim];
609     }
610   }
611   if (entity.isMutableBox())
612     entity = hlfir::derefPointersAndAllocatables(loc, builder, entity);
613   assert(mlir::isa<fir::BaseBoxType>(entity.getType()) && "must be a box");
614   mlir::Type idxTy = builder.getIndexType();
615   mlir::Value dimVal = builder.createIntegerConstant(loc, idxTy, dim);
616   auto dimInfo =
617       builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, entity, dimVal);
618   return dimInfo.getLowerBound();
619 }
620 
621 void hlfir::genLengthParameters(mlir::Location loc, fir::FirOpBuilder &builder,
622                                 Entity entity,
623                                 llvm::SmallVectorImpl<mlir::Value> &result) {
624   if (!entity.hasLengthParameters())
625     return;
626   if (mlir::isa<hlfir::ExprType>(entity.getType())) {
627     mlir::Value expr = entity;
628     if (auto reassoc = expr.getDefiningOp<hlfir::NoReassocOp>())
629       expr = reassoc.getVal();
630     // Going through fir::ExtendedValue would create a temp,
631     // which is not desired for an inquiry.
632     // TODO: make this an interface when adding further character producing ops.
633     if (auto concat = expr.getDefiningOp<hlfir::ConcatOp>()) {
634       result.push_back(concat.getLength());
635       return;
636     } else if (auto concat = expr.getDefiningOp<hlfir::SetLengthOp>()) {
637       result.push_back(concat.getLength());
638       return;
639     } else if (auto asExpr = expr.getDefiningOp<hlfir::AsExprOp>()) {
640       hlfir::genLengthParameters(loc, builder, hlfir::Entity{asExpr.getVar()},
641                                  result);
642       return;
643     } else if (auto elemental = expr.getDefiningOp<hlfir::ElementalOp>()) {
644       result.append(elemental.getTypeparams().begin(),
645                     elemental.getTypeparams().end());
646       return;
647     } else if (auto evalInMem =
648                    expr.getDefiningOp<hlfir::EvaluateInMemoryOp>()) {
649       result.append(evalInMem.getTypeparams().begin(),
650                     evalInMem.getTypeparams().end());
651       return;
652     } else if (auto apply = expr.getDefiningOp<hlfir::ApplyOp>()) {
653       result.append(apply.getTypeparams().begin(), apply.getTypeparams().end());
654       return;
655     }
656     if (entity.isCharacter()) {
657       result.push_back(builder.create<hlfir::GetLengthOp>(loc, expr));
658       return;
659     }
660     TODO(loc, "inquire PDTs length parameters of hlfir.expr");
661   }
662 
663   if (entity.isCharacter()) {
664     result.push_back(genCharacterVariableLength(loc, builder, entity));
665     return;
666   }
667   TODO(loc, "inquire PDTs length parameters in HLFIR");
668 }
669 
670 mlir::Value hlfir::genCharLength(mlir::Location loc, fir::FirOpBuilder &builder,
671                                  hlfir::Entity entity) {
672   llvm::SmallVector<mlir::Value, 1> lenParams;
673   genLengthParameters(loc, builder, entity, lenParams);
674   assert(lenParams.size() == 1 && "characters must have one length parameters");
675   return lenParams[0];
676 }
677 
678 mlir::Value hlfir::genRank(mlir::Location loc, fir::FirOpBuilder &builder,
679                            hlfir::Entity entity, mlir::Type resultType) {
680   if (!entity.isAssumedRank())
681     return builder.createIntegerConstant(loc, resultType, entity.getRank());
682   assert(entity.isBoxAddressOrValue() &&
683          "assumed-ranks are box addresses or values");
684   return builder.create<fir::BoxRankOp>(loc, resultType, entity);
685 }
686 
687 // Return a "shape" that can be used in fir.embox/fir.rebox with \p exv base.
688 static mlir::Value asEmboxShape(mlir::Location loc, fir::FirOpBuilder &builder,
689                                 const fir::ExtendedValue &exv,
690                                 mlir::Value shape) {
691   if (!shape)
692     return shape;
693   // fir.rebox does not need and does not accept extents (fir.shape or
694   // fir.shape_shift) since this information is already in the input fir.box,
695   // it only accepts fir.shift because local lower bounds may not be reflected
696   // in the fir.box.
697   if (mlir::isa<fir::BaseBoxType>(fir::getBase(exv).getType()) &&
698       !mlir::isa<fir::ShiftType>(shape.getType()))
699     return builder.createShape(loc, exv);
700   return shape;
701 }
702 
703 std::pair<mlir::Value, mlir::Value> hlfir::genVariableFirBaseShapeAndParams(
704     mlir::Location loc, fir::FirOpBuilder &builder, Entity entity,
705     llvm::SmallVectorImpl<mlir::Value> &typeParams) {
706   auto [exv, cleanup] = translateToExtendedValue(loc, builder, entity);
707   assert(!cleanup && "variable to Exv should not produce cleanup");
708   if (entity.hasLengthParameters()) {
709     auto params = fir::getTypeParams(exv);
710     typeParams.append(params.begin(), params.end());
711   }
712   if (entity.isScalar())
713     return {fir::getBase(exv), mlir::Value{}};
714   if (auto variableInterface = entity.getIfVariableInterface())
715     return {fir::getBase(exv),
716             asEmboxShape(loc, builder, exv, variableInterface.getShape())};
717   return {fir::getBase(exv), builder.createShape(loc, exv)};
718 }
719 
720 hlfir::Entity hlfir::derefPointersAndAllocatables(mlir::Location loc,
721                                                   fir::FirOpBuilder &builder,
722                                                   Entity entity) {
723   if (entity.isMutableBox()) {
724     hlfir::Entity boxLoad{builder.create<fir::LoadOp>(loc, entity)};
725     if (entity.isScalar()) {
726       if (!entity.isPolymorphic() && !entity.hasLengthParameters())
727         return hlfir::Entity{builder.create<fir::BoxAddrOp>(loc, boxLoad)};
728       mlir::Type elementType = boxLoad.getFortranElementType();
729       if (auto charType = mlir::dyn_cast<fir::CharacterType>(elementType)) {
730         mlir::Value base = builder.create<fir::BoxAddrOp>(loc, boxLoad);
731         if (charType.hasConstantLen())
732           return hlfir::Entity{base};
733         mlir::Value len = genCharacterVariableLength(loc, builder, entity);
734         auto boxCharType =
735             fir::BoxCharType::get(builder.getContext(), charType.getFKind());
736         return hlfir::Entity{
737             builder.create<fir::EmboxCharOp>(loc, boxCharType, base, len)
738                 .getResult()};
739       }
740     }
741     // Otherwise, the entity is either an array, a polymorphic entity, or a
742     // derived type with length parameters. All these entities require a fir.box
743     // or fir.class to hold bounds, dynamic type or length parameter
744     // information. Keep them boxed.
745     return boxLoad;
746   } else if (entity.isProcedurePointer()) {
747     return hlfir::Entity{builder.create<fir::LoadOp>(loc, entity)};
748   }
749   return entity;
750 }
751 
752 mlir::Type hlfir::getVariableElementType(hlfir::Entity variable) {
753   assert(variable.isVariable() && "entity must be a variable");
754   if (variable.isScalar())
755     return variable.getType();
756   mlir::Type eleTy = variable.getFortranElementType();
757   if (variable.isPolymorphic())
758     return fir::ClassType::get(eleTy);
759   if (auto charType = mlir::dyn_cast<fir::CharacterType>(eleTy)) {
760     if (charType.hasDynamicLen())
761       return fir::BoxCharType::get(charType.getContext(), charType.getFKind());
762   } else if (fir::isRecordWithTypeParameters(eleTy)) {
763     return fir::BoxType::get(eleTy);
764   }
765   return fir::ReferenceType::get(eleTy);
766 }
767 
768 mlir::Type hlfir::getEntityElementType(hlfir::Entity entity) {
769   if (entity.isVariable())
770     return getVariableElementType(entity);
771   if (entity.isScalar())
772     return entity.getType();
773   auto exprType = mlir::dyn_cast<hlfir::ExprType>(entity.getType());
774   assert(exprType && "array value must be an hlfir.expr");
775   return exprType.getElementExprType();
776 }
777 
778 static hlfir::ExprType getArrayExprType(mlir::Type elementType,
779                                         mlir::Value shape, bool isPolymorphic) {
780   unsigned rank = mlir::cast<fir::ShapeType>(shape.getType()).getRank();
781   hlfir::ExprType::Shape typeShape(rank, hlfir::ExprType::getUnknownExtent());
782   if (auto shapeOp = shape.getDefiningOp<fir::ShapeOp>())
783     for (auto extent : llvm::enumerate(shapeOp.getExtents()))
784       if (auto cstExtent = fir::getIntIfConstant(extent.value()))
785         typeShape[extent.index()] = *cstExtent;
786   return hlfir::ExprType::get(elementType.getContext(), typeShape, elementType,
787                               isPolymorphic);
788 }
789 
790 hlfir::ElementalOp hlfir::genElementalOp(
791     mlir::Location loc, fir::FirOpBuilder &builder, mlir::Type elementType,
792     mlir::Value shape, mlir::ValueRange typeParams,
793     const ElementalKernelGenerator &genKernel, bool isUnordered,
794     mlir::Value polymorphicMold, mlir::Type exprType) {
795   if (!exprType)
796     exprType = getArrayExprType(elementType, shape, !!polymorphicMold);
797   auto elementalOp = builder.create<hlfir::ElementalOp>(
798       loc, exprType, shape, polymorphicMold, typeParams, isUnordered);
799   auto insertPt = builder.saveInsertionPoint();
800   builder.setInsertionPointToStart(elementalOp.getBody());
801   mlir::Value elementResult = genKernel(loc, builder, elementalOp.getIndices());
802   // Numerical and logical scalars may be lowered to another type than the
803   // Fortran expression type (e.g i1 instead of fir.logical). Array expression
804   // values are typed according to their Fortran type. Insert a cast if needed
805   // here.
806   if (fir::isa_trivial(elementResult.getType()))
807     elementResult = builder.createConvert(loc, elementType, elementResult);
808   builder.create<hlfir::YieldElementOp>(loc, elementResult);
809   builder.restoreInsertionPoint(insertPt);
810   return elementalOp;
811 }
812 
813 // TODO: we do not actually need to clone the YieldElementOp,
814 // because returning its getElementValue() operand should be enough
815 // for all callers of this function.
816 hlfir::YieldElementOp
817 hlfir::inlineElementalOp(mlir::Location loc, fir::FirOpBuilder &builder,
818                          hlfir::ElementalOp elemental,
819                          mlir::ValueRange oneBasedIndices) {
820   // hlfir.elemental region is a SizedRegion<1>.
821   assert(elemental.getRegion().hasOneBlock() &&
822          "expect elemental region to have one block");
823   mlir::IRMapping mapper;
824   mapper.map(elemental.getIndices(), oneBasedIndices);
825   mlir::Operation *newOp;
826   for (auto &op : elemental.getRegion().back().getOperations())
827     newOp = builder.clone(op, mapper);
828   auto yield = mlir::dyn_cast_or_null<hlfir::YieldElementOp>(newOp);
829   assert(yield && "last ElementalOp operation must be am hlfir.yield_element");
830   return yield;
831 }
832 
833 mlir::Value hlfir::inlineElementalOp(
834     mlir::Location loc, fir::FirOpBuilder &builder,
835     hlfir::ElementalOpInterface elemental, mlir::ValueRange oneBasedIndices,
836     mlir::IRMapping &mapper,
837     const std::function<bool(hlfir::ElementalOp)> &mustRecursivelyInline) {
838   mlir::Region &region = elemental.getElementalRegion();
839   // hlfir.elemental region is a SizedRegion<1>.
840   assert(region.hasOneBlock() && "elemental region must have one block");
841   mapper.map(elemental.getIndices(), oneBasedIndices);
842   for (auto &op : region.front().without_terminator()) {
843     if (auto apply = mlir::dyn_cast<hlfir::ApplyOp>(op))
844       if (auto appliedElemental =
845               apply.getExpr().getDefiningOp<hlfir::ElementalOp>())
846         if (mustRecursivelyInline(appliedElemental)) {
847           llvm::SmallVector<mlir::Value> clonedApplyIndices;
848           for (auto indice : apply.getIndices())
849             clonedApplyIndices.push_back(mapper.lookupOrDefault(indice));
850           hlfir::ElementalOpInterface elementalIface =
851               mlir::cast<hlfir::ElementalOpInterface>(
852                   appliedElemental.getOperation());
853           mlir::Value inlined = inlineElementalOp(loc, builder, elementalIface,
854                                                   clonedApplyIndices, mapper,
855                                                   mustRecursivelyInline);
856           mapper.map(apply.getResult(), inlined);
857           continue;
858         }
859     (void)builder.clone(op, mapper);
860   }
861   return mapper.lookupOrDefault(elemental.getElementEntity());
862 }
863 
864 hlfir::LoopNest hlfir::genLoopNest(mlir::Location loc,
865                                    fir::FirOpBuilder &builder,
866                                    mlir::ValueRange extents, bool isUnordered,
867                                    bool emitWorkshareLoop) {
868   emitWorkshareLoop = emitWorkshareLoop && isUnordered;
869   hlfir::LoopNest loopNest;
870   assert(!extents.empty() && "must have at least one extent");
871   mlir::OpBuilder::InsertionGuard guard(builder);
872   loopNest.oneBasedIndices.assign(extents.size(), mlir::Value{});
873   // Build loop nest from column to row.
874   auto one = builder.create<mlir::arith::ConstantIndexOp>(loc, 1);
875   mlir::Type indexType = builder.getIndexType();
876   if (emitWorkshareLoop) {
877     auto wslw = builder.create<mlir::omp::WorkshareLoopWrapperOp>(loc);
878     loopNest.outerOp = wslw;
879     builder.createBlock(&wslw.getRegion());
880     mlir::omp::LoopNestOperands lnops;
881     lnops.loopInclusive = builder.getUnitAttr();
882     for (auto extent : llvm::reverse(extents)) {
883       lnops.loopLowerBounds.push_back(one);
884       lnops.loopUpperBounds.push_back(extent);
885       lnops.loopSteps.push_back(one);
886     }
887     auto lnOp = builder.create<mlir::omp::LoopNestOp>(loc, lnops);
888     mlir::Block *block = builder.createBlock(&lnOp.getRegion());
889     for (auto extent : llvm::reverse(extents))
890       block->addArgument(extent.getType(), extent.getLoc());
891     loopNest.body = block;
892     builder.create<mlir::omp::YieldOp>(loc);
893     for (unsigned dim = 0; dim < extents.size(); dim++)
894       loopNest.oneBasedIndices[extents.size() - dim - 1] =
895           lnOp.getRegion().front().getArgument(dim);
896   } else {
897     unsigned dim = extents.size() - 1;
898     for (auto extent : llvm::reverse(extents)) {
899       auto ub = builder.createConvert(loc, indexType, extent);
900       auto doLoop =
901           builder.create<fir::DoLoopOp>(loc, one, ub, one, isUnordered);
902       loopNest.body = doLoop.getBody();
903       builder.setInsertionPointToStart(loopNest.body);
904       // Reverse the indices so they are in column-major order.
905       loopNest.oneBasedIndices[dim--] = doLoop.getInductionVar();
906       if (!loopNest.outerOp)
907         loopNest.outerOp = doLoop;
908     }
909   }
910   return loopNest;
911 }
912 
913 llvm::SmallVector<mlir::Value> hlfir::genLoopNestWithReductions(
914     mlir::Location loc, fir::FirOpBuilder &builder, mlir::ValueRange extents,
915     mlir::ValueRange reductionInits, const ReductionLoopBodyGenerator &genBody,
916     bool isUnordered) {
917   assert(!extents.empty() && "must have at least one extent");
918   // Build loop nest from column to row.
919   auto one = builder.create<mlir::arith::ConstantIndexOp>(loc, 1);
920   mlir::Type indexType = builder.getIndexType();
921   unsigned dim = extents.size() - 1;
922   fir::DoLoopOp outerLoop = nullptr;
923   fir::DoLoopOp parentLoop = nullptr;
924   llvm::SmallVector<mlir::Value> oneBasedIndices;
925   oneBasedIndices.resize(dim + 1);
926   for (auto extent : llvm::reverse(extents)) {
927     auto ub = builder.createConvert(loc, indexType, extent);
928 
929     // The outermost loop takes reductionInits as the initial
930     // values of its iter-args.
931     // A child loop takes its iter-args from the region iter-args
932     // of its parent loop.
933     fir::DoLoopOp doLoop;
934     if (!parentLoop) {
935       doLoop = builder.create<fir::DoLoopOp>(loc, one, ub, one, isUnordered,
936                                              /*finalCountValue=*/false,
937                                              reductionInits);
938     } else {
939       doLoop = builder.create<fir::DoLoopOp>(loc, one, ub, one, isUnordered,
940                                              /*finalCountValue=*/false,
941                                              parentLoop.getRegionIterArgs());
942       if (!reductionInits.empty()) {
943         // Return the results of the child loop from its parent loop.
944         builder.create<fir::ResultOp>(loc, doLoop.getResults());
945       }
946     }
947 
948     builder.setInsertionPointToStart(doLoop.getBody());
949     // Reverse the indices so they are in column-major order.
950     oneBasedIndices[dim--] = doLoop.getInductionVar();
951     if (!outerLoop)
952       outerLoop = doLoop;
953     parentLoop = doLoop;
954   }
955 
956   llvm::SmallVector<mlir::Value> reductionValues;
957   reductionValues =
958       genBody(loc, builder, oneBasedIndices, parentLoop.getRegionIterArgs());
959   builder.setInsertionPointToEnd(parentLoop.getBody());
960   if (!reductionValues.empty())
961     builder.create<fir::ResultOp>(loc, reductionValues);
962   builder.setInsertionPointAfter(outerLoop);
963   return outerLoop->getResults();
964 }
965 
966 static fir::ExtendedValue translateVariableToExtendedValue(
967     mlir::Location loc, fir::FirOpBuilder &builder, hlfir::Entity variable,
968     bool forceHlfirBase = false, bool contiguousHint = false) {
969   assert(variable.isVariable() && "must be a variable");
970   // When going towards FIR, use the original base value to avoid
971   // introducing descriptors at runtime when they are not required.
972   // This is not done for assumed-rank since the fir::ExtendedValue cannot
973   // held the related lower bounds in an vector. The lower bounds of the
974   // descriptor must always be used instead.
975 
976   mlir::Value base = (forceHlfirBase || variable.isAssumedRank())
977                          ? variable.getBase()
978                          : variable.getFirBase();
979   if (variable.isMutableBox())
980     return fir::MutableBoxValue(base, getExplicitTypeParams(variable),
981                                 fir::MutableProperties{});
982 
983   if (mlir::isa<fir::BaseBoxType>(base.getType())) {
984     const bool contiguous = variable.isSimplyContiguous() || contiguousHint;
985     const bool isAssumedRank = variable.isAssumedRank();
986     if (!contiguous || variable.isPolymorphic() ||
987         variable.isDerivedWithLengthParameters() || variable.isOptional() ||
988         isAssumedRank) {
989       llvm::SmallVector<mlir::Value> nonDefaultLbounds;
990       if (!isAssumedRank)
991         nonDefaultLbounds = getNonDefaultLowerBounds(loc, builder, variable);
992       return fir::BoxValue(base, nonDefaultLbounds,
993                            getExplicitTypeParams(variable));
994     }
995     // Otherwise, the variable can be represented in a fir::ExtendedValue
996     // without the overhead of a fir.box.
997     base = genVariableRawAddress(loc, builder, variable);
998   }
999 
1000   if (variable.isScalar()) {
1001     if (variable.isCharacter()) {
1002       if (mlir::isa<fir::BoxCharType>(base.getType()))
1003         return genUnboxChar(loc, builder, base);
1004       mlir::Value len = genCharacterVariableLength(loc, builder, variable);
1005       return fir::CharBoxValue{base, len};
1006     }
1007     return base;
1008   }
1009   llvm::SmallVector<mlir::Value> extents;
1010   llvm::SmallVector<mlir::Value> nonDefaultLbounds;
1011   if (mlir::isa<fir::BaseBoxType>(variable.getType()) &&
1012       !variable.getIfVariableInterface() &&
1013       variable.mayHaveNonDefaultLowerBounds()) {
1014     // This special case avoids generating two sets of identical
1015     // fir.box_dim to get both the lower bounds and extents.
1016     genLboundsAndExtentsFromBox(loc, builder, variable, nonDefaultLbounds,
1017                                 &extents);
1018   } else {
1019     extents = getVariableExtents(loc, builder, variable);
1020     nonDefaultLbounds = getNonDefaultLowerBounds(loc, builder, variable);
1021   }
1022   if (variable.isCharacter())
1023     return fir::CharArrayBoxValue{
1024         base, genCharacterVariableLength(loc, builder, variable), extents,
1025         nonDefaultLbounds};
1026   return fir::ArrayBoxValue{base, extents, nonDefaultLbounds};
1027 }
1028 
1029 fir::ExtendedValue
1030 hlfir::translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder,
1031                                 fir::FortranVariableOpInterface var,
1032                                 bool forceHlfirBase) {
1033   return translateVariableToExtendedValue(loc, builder, var, forceHlfirBase);
1034 }
1035 
1036 std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>>
1037 hlfir::translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder,
1038                                 hlfir::Entity entity, bool contiguousHint) {
1039   if (entity.isVariable())
1040     return {translateVariableToExtendedValue(loc, builder, entity, false,
1041                                              contiguousHint),
1042             std::nullopt};
1043 
1044   if (entity.isProcedure()) {
1045     if (fir::isCharacterProcedureTuple(entity.getType())) {
1046       auto [boxProc, len] = fir::factory::extractCharacterProcedureTuple(
1047           builder, loc, entity, /*openBoxProc=*/false);
1048       return {fir::CharBoxValue{boxProc, len}, std::nullopt};
1049     }
1050     return {static_cast<mlir::Value>(entity), std::nullopt};
1051   }
1052 
1053   if (mlir::isa<hlfir::ExprType>(entity.getType())) {
1054     mlir::NamedAttribute byRefAttr = fir::getAdaptToByRefAttr(builder);
1055     hlfir::AssociateOp associate = hlfir::genAssociateExpr(
1056         loc, builder, entity, entity.getType(), "", byRefAttr);
1057     auto *bldr = &builder;
1058     hlfir::CleanupFunction cleanup = [bldr, loc, associate]() -> void {
1059       bldr->create<hlfir::EndAssociateOp>(loc, associate);
1060     };
1061     hlfir::Entity temp{associate.getBase()};
1062     return {translateToExtendedValue(loc, builder, temp).first, cleanup};
1063   }
1064   return {{static_cast<mlir::Value>(entity)}, {}};
1065 }
1066 
1067 std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>>
1068 hlfir::convertToValue(mlir::Location loc, fir::FirOpBuilder &builder,
1069                       hlfir::Entity entity) {
1070   // Load scalar references to integer, logical, real, or complex value
1071   // to an mlir value, dereference allocatable and pointers, and get rid
1072   // of fir.box that are not needed or create a copy into contiguous memory.
1073   auto derefedAndLoadedEntity = loadTrivialScalar(loc, builder, entity);
1074   return translateToExtendedValue(loc, builder, derefedAndLoadedEntity);
1075 }
1076 
1077 static fir::ExtendedValue placeTrivialInMemory(mlir::Location loc,
1078                                                fir::FirOpBuilder &builder,
1079                                                mlir::Value val,
1080                                                mlir::Type targetType) {
1081   auto temp = builder.createTemporary(loc, targetType);
1082   if (targetType != val.getType())
1083     builder.createStoreWithConvert(loc, val, temp);
1084   else
1085     builder.create<fir::StoreOp>(loc, val, temp);
1086   return temp;
1087 }
1088 
1089 std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>>
1090 hlfir::convertToBox(mlir::Location loc, fir::FirOpBuilder &builder,
1091                     hlfir::Entity entity, mlir::Type targetType) {
1092   // fir::factory::createBoxValue is not meant to deal with procedures.
1093   // Dereference procedure pointers here.
1094   if (entity.isProcedurePointer())
1095     entity = hlfir::derefPointersAndAllocatables(loc, builder, entity);
1096 
1097   auto [exv, cleanup] = translateToExtendedValue(loc, builder, entity);
1098   // Procedure entities should not go through createBoxValue that embox
1099   // object entities. Return the fir.boxproc directly.
1100   if (entity.isProcedure())
1101     return {exv, cleanup};
1102   mlir::Value base = fir::getBase(exv);
1103   if (fir::isa_trivial(base.getType()))
1104     exv = placeTrivialInMemory(loc, builder, base, targetType);
1105   fir::BoxValue box = fir::factory::createBoxValue(builder, loc, exv);
1106   return {box, cleanup};
1107 }
1108 
1109 std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>>
1110 hlfir::convertToAddress(mlir::Location loc, fir::FirOpBuilder &builder,
1111                         hlfir::Entity entity, mlir::Type targetType) {
1112   hlfir::Entity derefedEntity =
1113       hlfir::derefPointersAndAllocatables(loc, builder, entity);
1114   auto [exv, cleanup] =
1115       hlfir::translateToExtendedValue(loc, builder, derefedEntity);
1116   mlir::Value base = fir::getBase(exv);
1117   if (fir::isa_trivial(base.getType()))
1118     exv = placeTrivialInMemory(loc, builder, base, targetType);
1119   return {exv, cleanup};
1120 }
1121 
1122 /// Clone:
1123 /// ```
1124 /// hlfir.elemental_addr %shape : !fir.shape<1> {
1125 ///   ^bb0(%i : index)
1126 ///    .....
1127 ///    %hlfir.yield %scalarAddress : fir.ref<T>
1128 /// }
1129 /// ```
1130 //
1131 /// into
1132 ///
1133 /// ```
1134 /// %expr = hlfir.elemental %shape : (!fir.shape<1>) -> hlfir.expr<?xT> {
1135 ///   ^bb0(%i : index)
1136 ///    .....
1137 ///    %value = fir.load %scalarAddress : fir.ref<T>
1138 ///    %hlfir.yield_element %value : T
1139 ///  }
1140 /// ```
1141 hlfir::ElementalOp
1142 hlfir::cloneToElementalOp(mlir::Location loc, fir::FirOpBuilder &builder,
1143                           hlfir::ElementalAddrOp elementalAddrOp) {
1144   hlfir::Entity scalarAddress =
1145       hlfir::Entity{mlir::cast<hlfir::YieldOp>(
1146                         elementalAddrOp.getBody().back().getTerminator())
1147                         .getEntity()};
1148   llvm::SmallVector<mlir::Value, 1> typeParams;
1149   hlfir::genLengthParameters(loc, builder, scalarAddress, typeParams);
1150 
1151   builder.setInsertionPointAfter(elementalAddrOp);
1152   auto genKernel = [&](mlir::Location l, fir::FirOpBuilder &b,
1153                        mlir::ValueRange oneBasedIndices) -> hlfir::Entity {
1154     mlir::IRMapping mapper;
1155     mapper.map(elementalAddrOp.getIndices(), oneBasedIndices);
1156     mlir::Operation *newOp = nullptr;
1157     for (auto &op : elementalAddrOp.getBody().back().getOperations())
1158       newOp = b.clone(op, mapper);
1159     auto newYielOp = mlir::dyn_cast_or_null<hlfir::YieldOp>(newOp);
1160     assert(newYielOp && "hlfir.elemental_addr is ill formed");
1161     hlfir::Entity newAddr{newYielOp.getEntity()};
1162     newYielOp->erase();
1163     return hlfir::loadTrivialScalar(l, b, newAddr);
1164   };
1165   mlir::Type elementType = scalarAddress.getFortranElementType();
1166   return hlfir::genElementalOp(
1167       loc, builder, elementType, elementalAddrOp.getShape(), typeParams,
1168       genKernel, !elementalAddrOp.isOrdered(), elementalAddrOp.getMold());
1169 }
1170 
1171 bool hlfir::elementalOpMustProduceTemp(hlfir::ElementalOp elemental) {
1172   for (mlir::Operation *useOp : elemental->getUsers())
1173     if (auto destroy = mlir::dyn_cast<hlfir::DestroyOp>(useOp))
1174       if (destroy.mustFinalizeExpr())
1175         return true;
1176 
1177   return false;
1178 }
1179 
1180 std::pair<hlfir::Entity, mlir::Value>
1181 hlfir::createTempFromMold(mlir::Location loc, fir::FirOpBuilder &builder,
1182                           hlfir::Entity mold) {
1183   llvm::SmallVector<mlir::Value> lenParams;
1184   hlfir::genLengthParameters(loc, builder, mold, lenParams);
1185   llvm::StringRef tmpName{".tmp"};
1186   mlir::Value alloc;
1187   mlir::Value isHeapAlloc;
1188   mlir::Value shape{};
1189   fir::FortranVariableFlagsAttr declAttrs;
1190 
1191   if (mold.isPolymorphic()) {
1192     // Create unallocated polymorphic temporary using the dynamic type
1193     // of the mold. The static type of the temporary matches
1194     // the static type of the mold, but then the dynamic type
1195     // of the mold is applied to the temporary's descriptor.
1196 
1197     if (mold.isArray())
1198       hlfir::genShape(loc, builder, mold);
1199 
1200     // Create polymorphic allocatable box on the stack.
1201     mlir::Type boxHeapType = fir::HeapType::get(fir::unwrapRefType(
1202         mlir::cast<fir::BaseBoxType>(mold.getType()).getEleTy()));
1203     // The box must be initialized, because AllocatableApplyMold
1204     // may read its contents (e.g. for checking whether it is allocated).
1205     alloc = fir::factory::genNullBoxStorage(builder, loc,
1206                                             fir::ClassType::get(boxHeapType));
1207     // The temporary is unallocated even after AllocatableApplyMold below.
1208     // If the temporary is used as assignment LHS it will be automatically
1209     // allocated on the heap, as long as we use Assign family
1210     // runtime functions. So set MustFree to true.
1211     isHeapAlloc = builder.createBool(loc, true);
1212     declAttrs = fir::FortranVariableFlagsAttr::get(
1213         builder.getContext(), fir::FortranVariableFlagsEnum::allocatable);
1214   } else if (mold.isArray()) {
1215     mlir::Type sequenceType =
1216         hlfir::getFortranElementOrSequenceType(mold.getType());
1217     shape = hlfir::genShape(loc, builder, mold);
1218     auto extents = hlfir::getIndexExtents(loc, builder, shape);
1219     alloc = builder.createHeapTemporary(loc, sequenceType, tmpName, extents,
1220                                         lenParams);
1221     isHeapAlloc = builder.createBool(loc, true);
1222   } else {
1223     alloc = builder.createTemporary(loc, mold.getFortranElementType(), tmpName,
1224                                     /*shape=*/std::nullopt, lenParams);
1225     isHeapAlloc = builder.createBool(loc, false);
1226   }
1227   auto declareOp =
1228       builder.create<hlfir::DeclareOp>(loc, alloc, tmpName, shape, lenParams,
1229                                        /*dummy_scope=*/nullptr, declAttrs);
1230   if (mold.isPolymorphic()) {
1231     int rank = mold.getRank();
1232     // TODO: should probably read rank from the mold.
1233     if (rank < 0)
1234       TODO(loc, "create temporary for assumed rank polymorphic");
1235     fir::runtime::genAllocatableApplyMold(builder, loc, alloc,
1236                                           mold.getFirBase(), rank);
1237   }
1238 
1239   return {hlfir::Entity{declareOp.getBase()}, isHeapAlloc};
1240 }
1241 
1242 hlfir::Entity hlfir::createStackTempFromMold(mlir::Location loc,
1243                                              fir::FirOpBuilder &builder,
1244                                              hlfir::Entity mold) {
1245   llvm::SmallVector<mlir::Value> lenParams;
1246   hlfir::genLengthParameters(loc, builder, mold, lenParams);
1247   llvm::StringRef tmpName{".tmp"};
1248   mlir::Value alloc;
1249   mlir::Value shape{};
1250   fir::FortranVariableFlagsAttr declAttrs;
1251 
1252   if (mold.isPolymorphic()) {
1253     // genAllocatableApplyMold does heap allocation
1254     TODO(loc, "createStackTempFromMold for polymorphic type");
1255   } else if (mold.isArray()) {
1256     mlir::Type sequenceType =
1257         hlfir::getFortranElementOrSequenceType(mold.getType());
1258     shape = hlfir::genShape(loc, builder, mold);
1259     auto extents = hlfir::getIndexExtents(loc, builder, shape);
1260     alloc =
1261         builder.createTemporary(loc, sequenceType, tmpName, extents, lenParams);
1262   } else {
1263     alloc = builder.createTemporary(loc, mold.getFortranElementType(), tmpName,
1264                                     /*shape=*/std::nullopt, lenParams);
1265   }
1266   auto declareOp =
1267       builder.create<hlfir::DeclareOp>(loc, alloc, tmpName, shape, lenParams,
1268                                        /*dummy_scope=*/nullptr, declAttrs);
1269   return hlfir::Entity{declareOp.getBase()};
1270 }
1271 
1272 hlfir::EntityWithAttributes
1273 hlfir::convertCharacterKind(mlir::Location loc, fir::FirOpBuilder &builder,
1274                             hlfir::Entity scalarChar, int toKind) {
1275   auto src = hlfir::convertToAddress(loc, builder, scalarChar,
1276                                      scalarChar.getFortranElementType());
1277   assert(src.first.getCharBox() && "must be scalar character");
1278   fir::CharBoxValue res = fir::factory::convertCharacterKind(
1279       builder, loc, *src.first.getCharBox(), toKind);
1280   if (src.second.has_value())
1281     src.second.value()();
1282 
1283   return hlfir::EntityWithAttributes{builder.create<hlfir::DeclareOp>(
1284       loc, res.getAddr(), ".temp.kindconvert", /*shape=*/nullptr,
1285       /*typeparams=*/mlir::ValueRange{res.getLen()},
1286       /*dummy_scope=*/nullptr, fir::FortranVariableFlagsAttr{})};
1287 }
1288 
1289 std::pair<hlfir::Entity, std::optional<hlfir::CleanupFunction>>
1290 hlfir::genTypeAndKindConvert(mlir::Location loc, fir::FirOpBuilder &builder,
1291                              hlfir::Entity source, mlir::Type toType,
1292                              bool preserveLowerBounds) {
1293   mlir::Type fromType = source.getFortranElementType();
1294   toType = hlfir::getFortranElementType(toType);
1295   if (!toType || fromType == toType ||
1296       !(fir::isa_trivial(toType) || mlir::isa<fir::CharacterType>(toType)))
1297     return {source, std::nullopt};
1298 
1299   std::optional<int> toKindCharConvert;
1300   if (auto toCharTy = mlir::dyn_cast<fir::CharacterType>(toType)) {
1301     if (auto fromCharTy = mlir::dyn_cast<fir::CharacterType>(fromType))
1302       if (toCharTy.getFKind() != fromCharTy.getFKind()) {
1303         toKindCharConvert = toCharTy.getFKind();
1304         // Preserve source length (padding/truncation will occur in assignment
1305         // if needed).
1306         toType = fir::CharacterType::get(
1307             fromType.getContext(), toCharTy.getFKind(), fromCharTy.getLen());
1308       }
1309     // Do not convert in case of character length mismatch only, hlfir.assign
1310     // deals with it.
1311     if (!toKindCharConvert)
1312       return {source, std::nullopt};
1313   }
1314 
1315   if (source.getRank() == 0) {
1316     mlir::Value cast = toKindCharConvert
1317                            ? mlir::Value{hlfir::convertCharacterKind(
1318                                  loc, builder, source, *toKindCharConvert)}
1319                            : builder.convertWithSemantics(loc, toType, source);
1320     return {hlfir::Entity{cast}, std::nullopt};
1321   }
1322 
1323   mlir::Value shape = hlfir::genShape(loc, builder, source);
1324   auto genKernel = [source, toType, toKindCharConvert](
1325                        mlir::Location loc, fir::FirOpBuilder &builder,
1326                        mlir::ValueRange oneBasedIndices) -> hlfir::Entity {
1327     auto elementPtr =
1328         hlfir::getElementAt(loc, builder, source, oneBasedIndices);
1329     auto val = hlfir::loadTrivialScalar(loc, builder, elementPtr);
1330     if (toKindCharConvert)
1331       return hlfir::convertCharacterKind(loc, builder, val, *toKindCharConvert);
1332     return hlfir::EntityWithAttributes{
1333         builder.convertWithSemantics(loc, toType, val)};
1334   };
1335   llvm::SmallVector<mlir::Value, 1> lenParams;
1336   hlfir::genLengthParameters(loc, builder, source, lenParams);
1337   mlir::Value convertedRhs =
1338       hlfir::genElementalOp(loc, builder, toType, shape, lenParams, genKernel,
1339                             /*isUnordered=*/true);
1340 
1341   if (preserveLowerBounds && source.mayHaveNonDefaultLowerBounds()) {
1342     hlfir::AssociateOp associate =
1343         genAssociateExpr(loc, builder, hlfir::Entity{convertedRhs},
1344                          convertedRhs.getType(), ".tmp.keeplbounds");
1345     fir::ShapeOp shapeOp = associate.getShape().getDefiningOp<fir::ShapeOp>();
1346     assert(shapeOp && "associate shape must be a fir.shape");
1347     const unsigned rank = shapeOp.getExtents().size();
1348     llvm::SmallVector<mlir::Value> lbAndExtents;
1349     for (unsigned dim = 0; dim < rank; ++dim) {
1350       lbAndExtents.push_back(hlfir::genLBound(loc, builder, source, dim));
1351       lbAndExtents.push_back(shapeOp.getExtents()[dim]);
1352     }
1353     auto shapeShiftType = fir::ShapeShiftType::get(builder.getContext(), rank);
1354     mlir::Value shapeShift =
1355         builder.create<fir::ShapeShiftOp>(loc, shapeShiftType, lbAndExtents);
1356     auto declareOp = builder.create<hlfir::DeclareOp>(
1357         loc, associate.getFirBase(), *associate.getUniqName(), shapeShift,
1358         associate.getTypeparams(), /*dummy_scope=*/nullptr,
1359         /*flags=*/fir::FortranVariableFlagsAttr{});
1360     hlfir::Entity castWithLbounds =
1361         mlir::cast<fir::FortranVariableOpInterface>(declareOp.getOperation());
1362     fir::FirOpBuilder *bldr = &builder;
1363     auto cleanup = [loc, bldr, convertedRhs, associate]() {
1364       bldr->create<hlfir::EndAssociateOp>(loc, associate);
1365       bldr->create<hlfir::DestroyOp>(loc, convertedRhs);
1366     };
1367     return {castWithLbounds, cleanup};
1368   }
1369 
1370   fir::FirOpBuilder *bldr = &builder;
1371   auto cleanup = [loc, bldr, convertedRhs]() {
1372     bldr->create<hlfir::DestroyOp>(loc, convertedRhs);
1373   };
1374   return {hlfir::Entity{convertedRhs}, cleanup};
1375 }
1376 
1377 std::pair<hlfir::Entity, bool> hlfir::computeEvaluateOpInNewTemp(
1378     mlir::Location loc, fir::FirOpBuilder &builder,
1379     hlfir::EvaluateInMemoryOp evalInMem, mlir::Value shape,
1380     mlir::ValueRange typeParams) {
1381   llvm::StringRef tmpName{".tmp.expr_result"};
1382   llvm::SmallVector<mlir::Value> extents =
1383       hlfir::getIndexExtents(loc, builder, shape);
1384   mlir::Type baseType =
1385       hlfir::getFortranElementOrSequenceType(evalInMem.getType());
1386   bool heapAllocated = fir::hasDynamicSize(baseType);
1387   // Note: temporaries are stack allocated here when possible (do not require
1388   // stack save/restore) because flang has always stack allocated function
1389   // results.
1390   mlir::Value temp = heapAllocated
1391                          ? builder.createHeapTemporary(loc, baseType, tmpName,
1392                                                        extents, typeParams)
1393                          : builder.createTemporary(loc, baseType, tmpName,
1394                                                    extents, typeParams);
1395   mlir::Value innerMemory = evalInMem.getMemory();
1396   temp = builder.createConvert(loc, innerMemory.getType(), temp);
1397   auto declareOp = builder.create<hlfir::DeclareOp>(
1398       loc, temp, tmpName, shape, typeParams,
1399       /*dummy_scope=*/nullptr, fir::FortranVariableFlagsAttr{});
1400   computeEvaluateOpIn(loc, builder, evalInMem, declareOp.getOriginalBase());
1401   return {hlfir::Entity{declareOp.getBase()}, /*heapAllocated=*/heapAllocated};
1402 }
1403 
1404 void hlfir::computeEvaluateOpIn(mlir::Location loc, fir::FirOpBuilder &builder,
1405                                 hlfir::EvaluateInMemoryOp evalInMem,
1406                                 mlir::Value storage) {
1407   mlir::Value innerMemory = evalInMem.getMemory();
1408   mlir::Value storageCast =
1409       builder.createConvert(loc, innerMemory.getType(), storage);
1410   mlir::IRMapping mapper;
1411   mapper.map(innerMemory, storageCast);
1412   for (auto &op : evalInMem.getBody().front().without_terminator())
1413     builder.clone(op, mapper);
1414   return;
1415 }
1416 
1417 hlfir::Entity hlfir::loadElementAt(mlir::Location loc,
1418                                    fir::FirOpBuilder &builder,
1419                                    hlfir::Entity entity,
1420                                    mlir::ValueRange oneBasedIndices) {
1421   return loadTrivialScalar(loc, builder,
1422                            getElementAt(loc, builder, entity, oneBasedIndices));
1423 }
1424 
1425 llvm::SmallVector<mlir::Value, Fortran::common::maxRank>
1426 hlfir::genExtentsVector(mlir::Location loc, fir::FirOpBuilder &builder,
1427                         hlfir::Entity entity) {
1428   entity = hlfir::derefPointersAndAllocatables(loc, builder, entity);
1429   mlir::Value shape = hlfir::genShape(loc, builder, entity);
1430   llvm::SmallVector<mlir::Value, Fortran::common::maxRank> extents =
1431       hlfir::getExplicitExtentsFromShape(shape, builder);
1432   if (shape.getUses().empty())
1433     shape.getDefiningOp()->erase();
1434   return extents;
1435 }
1436