1 //===-- ConvertExpr.cpp ---------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "flang/Lower/ConvertExpr.h"
14 #include "flang/Common/default-kinds.h"
15 #include "flang/Common/unwrap.h"
16 #include "flang/Evaluate/fold.h"
17 #include "flang/Evaluate/real.h"
18 #include "flang/Evaluate/traverse.h"
19 #include "flang/Lower/Allocatable.h"
20 #include "flang/Lower/Bridge.h"
21 #include "flang/Lower/BuiltinModules.h"
22 #include "flang/Lower/CallInterface.h"
23 #include "flang/Lower/Coarray.h"
24 #include "flang/Lower/ComponentPath.h"
25 #include "flang/Lower/ConvertType.h"
26 #include "flang/Lower/ConvertVariable.h"
27 #include "flang/Lower/CustomIntrinsicCall.h"
28 #include "flang/Lower/DumpEvaluateExpr.h"
29 #include "flang/Lower/IntrinsicCall.h"
30 #include "flang/Lower/Mangler.h"
31 #include "flang/Lower/Runtime.h"
32 #include "flang/Lower/Support/Utils.h"
33 #include "flang/Lower/Todo.h"
34 #include "flang/Optimizer/Builder/Character.h"
35 #include "flang/Optimizer/Builder/Complex.h"
36 #include "flang/Optimizer/Builder/Factory.h"
37 #include "flang/Optimizer/Builder/Runtime/Character.h"
38 #include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
39 #include "flang/Optimizer/Builder/Runtime/Ragged.h"
40 #include "flang/Optimizer/Dialect/FIRAttr.h"
41 #include "flang/Optimizer/Dialect/FIRDialect.h"
42 #include "flang/Optimizer/Dialect/FIROpsSupport.h"
43 #include "flang/Optimizer/Support/FatalError.h"
44 #include "flang/Semantics/expression.h"
45 #include "flang/Semantics/symbol.h"
46 #include "flang/Semantics/tools.h"
47 #include "flang/Semantics/type.h"
48 #include "mlir/Dialect/Func/IR/FuncOps.h"
49 #include "llvm/Support/CommandLine.h"
50 #include "llvm/Support/Debug.h"
51 #include "llvm/Support/ErrorHandling.h"
52 #include "llvm/Support/raw_ostream.h"
53 #include <algorithm>
54 
55 #define DEBUG_TYPE "flang-lower-expr"
56 
57 //===----------------------------------------------------------------------===//
58 // The composition and structure of Fortran::evaluate::Expr is defined in
59 // the various header files in include/flang/Evaluate. You are referred
60 // there for more information on these data structures. Generally speaking,
61 // these data structures are a strongly typed family of abstract data types
62 // that, composed as trees, describe the syntax of Fortran expressions.
63 //
64 // This part of the bridge can traverse these tree structures and lower them
65 // to the correct FIR representation in SSA form.
66 //===----------------------------------------------------------------------===//
67 
68 static llvm::cl::opt<bool> generateArrayCoordinate(
69     "gen-array-coor",
70     llvm::cl::desc("in lowering create ArrayCoorOp instead of CoordinateOp"),
71     llvm::cl::init(false));
72 
73 // The default attempts to balance a modest allocation size with expected user
74 // input to minimize bounds checks and reallocations during dynamic array
75 // construction. Some user codes may have very large array constructors for
76 // which the default can be increased.
77 static llvm::cl::opt<unsigned> clInitialBufferSize(
78     "array-constructor-initial-buffer-size",
79     llvm::cl::desc(
80         "set the incremental array construction buffer size (default=32)"),
81     llvm::cl::init(32u));
82 
83 /// The various semantics of a program constituent (or a part thereof) as it may
84 /// appear in an expression.
85 ///
86 /// Given the following Fortran declarations.
87 /// ```fortran
88 ///   REAL :: v1, v2, v3
89 ///   REAL, POINTER :: vp1
90 ///   REAL :: a1(c), a2(c)
91 ///   REAL ELEMENTAL FUNCTION f1(arg) ! array -> array
92 ///   FUNCTION f2(arg)                ! array -> array
93 ///   vp1 => v3       ! 1
94 ///   v1 = v2 * vp1   ! 2
95 ///   a1 = a1 + a2    ! 3
96 ///   a1 = f1(a2)     ! 4
97 ///   a1 = f2(a2)     ! 5
98 /// ```
99 ///
100 /// In line 1, `vp1` is a BoxAddr to copy a box value into. The box value is
101 /// constructed from the DataAddr of `v3`.
102 /// In line 2, `v1` is a DataAddr to copy a value into. The value is constructed
103 /// from the DataValue of `v2` and `vp1`. DataValue is implicitly a double
104 /// dereference in the `vp1` case.
105 /// In line 3, `a1` and `a2` on the rhs are RefTransparent. The `a1` on the lhs
106 /// is CopyInCopyOut as `a1` is replaced elementally by the additions.
107 /// In line 4, `a2` can be RefTransparent, ByValueArg, RefOpaque, or BoxAddr if
108 /// `arg` is declared as C-like pass-by-value, VALUE, INTENT(?), or ALLOCATABLE/
109 /// POINTER, respectively. `a1` on the lhs is CopyInCopyOut.
110 ///  In line 5, `a2` may be DataAddr or BoxAddr assuming f2 is transformational.
111 ///  `a1` on the lhs is again CopyInCopyOut.
112 enum class ConstituentSemantics {
113   // Scalar data reference semantics.
114   //
115   // For these let `v` be the location in memory of a variable with value `x`
116   DataValue, // refers to the value `x`
117   DataAddr,  // refers to the address `v`
118   BoxValue,  // refers to a box value containing `v`
119   BoxAddr,   // refers to the address of a box value containing `v`
120 
121   // Array data reference semantics.
122   //
123   // For these let `a` be the location in memory of a sequence of value `[xs]`.
124   // Let `x_i` be the `i`-th value in the sequence `[xs]`.
125 
126   // Referentially transparent. Refers to the array's value, `[xs]`.
127   RefTransparent,
128   // Refers to an ephemeral address `tmp` containing value `x_i` (15.5.2.3.p7
129   // note 2). (Passing a copy by reference to simulate pass-by-value.)
130   ByValueArg,
131   // Refers to the merge of array value `[xs]` with another array value `[ys]`.
132   // This merged array value will be written into memory location `a`.
133   CopyInCopyOut,
134   // Similar to CopyInCopyOut but `a` may be a transient projection (rather than
135   // a whole array).
136   ProjectedCopyInCopyOut,
137   // Similar to ProjectedCopyInCopyOut, except the merge value is not assigned
138   // automatically by the framework. Instead, and address for `[xs]` is made
139   // accessible so that custom assignments to `[xs]` can be implemented.
140   CustomCopyInCopyOut,
141   // Referentially opaque. Refers to the address of `x_i`.
142   RefOpaque
143 };
144 
145 /// Convert parser's INTEGER relational operators to MLIR.  TODO: using
146 /// unordered, but we may want to cons ordered in certain situation.
147 static mlir::arith::CmpIPredicate
148 translateRelational(Fortran::common::RelationalOperator rop) {
149   switch (rop) {
150   case Fortran::common::RelationalOperator::LT:
151     return mlir::arith::CmpIPredicate::slt;
152   case Fortran::common::RelationalOperator::LE:
153     return mlir::arith::CmpIPredicate::sle;
154   case Fortran::common::RelationalOperator::EQ:
155     return mlir::arith::CmpIPredicate::eq;
156   case Fortran::common::RelationalOperator::NE:
157     return mlir::arith::CmpIPredicate::ne;
158   case Fortran::common::RelationalOperator::GT:
159     return mlir::arith::CmpIPredicate::sgt;
160   case Fortran::common::RelationalOperator::GE:
161     return mlir::arith::CmpIPredicate::sge;
162   }
163   llvm_unreachable("unhandled INTEGER relational operator");
164 }
165 
166 /// Convert parser's REAL relational operators to MLIR.
167 /// The choice of order (O prefix) vs unorder (U prefix) follows Fortran 2018
168 /// requirements in the IEEE context (table 17.1 of F2018). This choice is
169 /// also applied in other contexts because it is easier and in line with
170 /// other Fortran compilers.
171 /// FIXME: The signaling/quiet aspect of the table 17.1 requirement is not
172 /// fully enforced. FIR and LLVM `fcmp` instructions do not give any guarantee
173 /// whether the comparison will signal or not in case of quiet NaN argument.
174 static mlir::arith::CmpFPredicate
175 translateFloatRelational(Fortran::common::RelationalOperator rop) {
176   switch (rop) {
177   case Fortran::common::RelationalOperator::LT:
178     return mlir::arith::CmpFPredicate::OLT;
179   case Fortran::common::RelationalOperator::LE:
180     return mlir::arith::CmpFPredicate::OLE;
181   case Fortran::common::RelationalOperator::EQ:
182     return mlir::arith::CmpFPredicate::OEQ;
183   case Fortran::common::RelationalOperator::NE:
184     return mlir::arith::CmpFPredicate::UNE;
185   case Fortran::common::RelationalOperator::GT:
186     return mlir::arith::CmpFPredicate::OGT;
187   case Fortran::common::RelationalOperator::GE:
188     return mlir::arith::CmpFPredicate::OGE;
189   }
190   llvm_unreachable("unhandled REAL relational operator");
191 }
192 
193 static mlir::Value genActualIsPresentTest(fir::FirOpBuilder &builder,
194                                           mlir::Location loc,
195                                           fir::ExtendedValue actual) {
196   if (const auto *ptrOrAlloc = actual.getBoxOf<fir::MutableBoxValue>())
197     return fir::factory::genIsAllocatedOrAssociatedTest(builder, loc,
198                                                         *ptrOrAlloc);
199   // Optional case (not that optional allocatable/pointer cannot be absent
200   // when passed to CMPLX as per 15.5.2.12 point 3 (7) and (8)). It is
201   // therefore possible to catch them in the `then` case above.
202   return builder.create<fir::IsPresentOp>(loc, builder.getI1Type(),
203                                           fir::getBase(actual));
204 }
205 
206 /// Convert the array_load, `load`, to an extended value. If `path` is not
207 /// empty, then traverse through the components designated. The base value is
208 /// `newBase`. This does not accept an array_load with a slice operand.
209 static fir::ExtendedValue
210 arrayLoadExtValue(fir::FirOpBuilder &builder, mlir::Location loc,
211                   fir::ArrayLoadOp load, llvm::ArrayRef<mlir::Value> path,
212                   mlir::Value newBase, mlir::Value newLen = {}) {
213   // Recover the extended value from the load.
214   assert(!load.getSlice() && "slice is not allowed");
215   mlir::Type arrTy = load.getType();
216   if (!path.empty()) {
217     mlir::Type ty = fir::applyPathToType(arrTy, path);
218     if (!ty)
219       fir::emitFatalError(loc, "path does not apply to type");
220     if (!ty.isa<fir::SequenceType>()) {
221       if (fir::isa_char(ty)) {
222         mlir::Value len = newLen;
223         if (!len)
224           len = fir::factory::CharacterExprHelper{builder, loc}.getLength(
225               load.getMemref());
226         if (!len) {
227           assert(load.getTypeparams().size() == 1 &&
228                  "length must be in array_load");
229           len = load.getTypeparams()[0];
230         }
231         return fir::CharBoxValue{newBase, len};
232       }
233       return newBase;
234     }
235     arrTy = ty.cast<fir::SequenceType>();
236   }
237 
238   // Use the shape op, if there is one.
239   mlir::Value shapeVal = load.getShape();
240   if (shapeVal) {
241     if (!mlir::isa<fir::ShiftOp>(shapeVal.getDefiningOp())) {
242       mlir::Type eleTy = fir::unwrapSequenceType(arrTy);
243       std::vector<mlir::Value> extents = fir::factory::getExtents(shapeVal);
244       std::vector<mlir::Value> origins = fir::factory::getOrigins(shapeVal);
245       if (fir::isa_char(eleTy)) {
246         mlir::Value len = newLen;
247         if (!len)
248           len = fir::factory::CharacterExprHelper{builder, loc}.getLength(
249               load.getMemref());
250         if (!len) {
251           assert(load.getTypeparams().size() == 1 &&
252                  "length must be in array_load");
253           len = load.getTypeparams()[0];
254         }
255         return fir::CharArrayBoxValue(newBase, len, extents, origins);
256       }
257       return fir::ArrayBoxValue(newBase, extents, origins);
258     }
259     if (!fir::isa_box_type(load.getMemref().getType()))
260       fir::emitFatalError(loc, "shift op is invalid in this context");
261   }
262 
263   // There is no shape or the array is in a box. Extents and lower bounds must
264   // be read at runtime.
265   if (path.empty() && !shapeVal) {
266     fir::ExtendedValue exv =
267         fir::factory::readBoxValue(builder, loc, load.getMemref());
268     return fir::substBase(exv, newBase);
269   }
270   TODO(loc, "component is boxed, retreive its type parameters");
271 }
272 
273 /// Place \p exv in memory if it is not already a memory reference. If
274 /// \p forceValueType is provided, the value is first casted to the provided
275 /// type before being stored (this is mainly intended for logicals whose value
276 /// may be `i1` but needed to be stored as Fortran logicals).
277 static fir::ExtendedValue
278 placeScalarValueInMemory(fir::FirOpBuilder &builder, mlir::Location loc,
279                          const fir::ExtendedValue &exv,
280                          mlir::Type storageType) {
281   mlir::Value valBase = fir::getBase(exv);
282   if (fir::conformsWithPassByRef(valBase.getType()))
283     return exv;
284 
285   assert(!fir::hasDynamicSize(storageType) &&
286          "only expect statically sized scalars to be by value");
287 
288   // Since `a` is not itself a valid referent, determine its value and
289   // create a temporary location at the beginning of the function for
290   // referencing.
291   mlir::Value val = builder.createConvert(loc, storageType, valBase);
292   mlir::Value temp = builder.createTemporary(
293       loc, storageType,
294       llvm::ArrayRef<mlir::NamedAttribute>{
295           Fortran::lower::getAdaptToByRefAttr(builder)});
296   builder.create<fir::StoreOp>(loc, val, temp);
297   return fir::substBase(exv, temp);
298 }
299 
300 // Copy a copy of scalar \p exv in a new temporary.
301 static fir::ExtendedValue
302 createInMemoryScalarCopy(fir::FirOpBuilder &builder, mlir::Location loc,
303                          const fir::ExtendedValue &exv) {
304   assert(exv.rank() == 0 && "input to scalar memory copy must be a scalar");
305   if (exv.getCharBox() != nullptr)
306     return fir::factory::CharacterExprHelper{builder, loc}.createTempFrom(exv);
307   if (fir::isDerivedWithLengthParameters(exv))
308     TODO(loc, "copy derived type with length parameters");
309   mlir::Type type = fir::unwrapPassByRefType(fir::getBase(exv).getType());
310   fir::ExtendedValue temp = builder.createTemporary(loc, type);
311   fir::factory::genScalarAssignment(builder, loc, temp, exv);
312   return temp;
313 }
314 
315 // An expression with non-zero rank is an array expression.
316 template <typename A>
317 static bool isArray(const A &x) {
318   return x.Rank() != 0;
319 }
320 
321 /// Is this a variable wrapped in parentheses?
322 template <typename A>
323 static bool isParenthesizedVariable(const A &) {
324   return false;
325 }
326 template <typename T>
327 static bool isParenthesizedVariable(const Fortran::evaluate::Expr<T> &expr) {
328   using ExprVariant = decltype(Fortran::evaluate::Expr<T>::u);
329   using Parentheses = Fortran::evaluate::Parentheses<T>;
330   if constexpr (Fortran::common::HasMember<Parentheses, ExprVariant>) {
331     if (const auto *parentheses = std::get_if<Parentheses>(&expr.u))
332       return Fortran::evaluate::IsVariable(parentheses->left());
333     return false;
334   } else {
335     return std::visit([&](const auto &x) { return isParenthesizedVariable(x); },
336                       expr.u);
337   }
338 }
339 
340 /// Does \p expr only refer to symbols that are mapped to IR values in \p symMap
341 /// ?
342 static bool allSymbolsInExprPresentInMap(const Fortran::lower::SomeExpr &expr,
343                                          Fortran::lower::SymMap &symMap) {
344   for (const auto &sym : Fortran::evaluate::CollectSymbols(expr))
345     if (!symMap.lookupSymbol(sym))
346       return false;
347   return true;
348 }
349 
350 /// Generate a load of a value from an address. Beware that this will lose
351 /// any dynamic type information for polymorphic entities (note that unlimited
352 /// polymorphic cannot be loaded and must not be provided here).
353 static fir::ExtendedValue genLoad(fir::FirOpBuilder &builder,
354                                   mlir::Location loc,
355                                   const fir::ExtendedValue &addr) {
356   return addr.match(
357       [](const fir::CharBoxValue &box) -> fir::ExtendedValue { return box; },
358       [&](const fir::UnboxedValue &v) -> fir::ExtendedValue {
359         if (fir::unwrapRefType(fir::getBase(v).getType())
360                 .isa<fir::RecordType>())
361           return v;
362         return builder.create<fir::LoadOp>(loc, fir::getBase(v));
363       },
364       [&](const fir::MutableBoxValue &box) -> fir::ExtendedValue {
365         return genLoad(builder, loc,
366                        fir::factory::genMutableBoxRead(builder, loc, box));
367       },
368       [&](const fir::BoxValue &box) -> fir::ExtendedValue {
369         if (box.isUnlimitedPolymorphic())
370           fir::emitFatalError(
371               loc,
372               "lowering attempting to load an unlimited polymorphic entity");
373         return genLoad(builder, loc,
374                        fir::factory::readBoxValue(builder, loc, box));
375       },
376       [&](const auto &) -> fir::ExtendedValue {
377         fir::emitFatalError(
378             loc, "attempting to load whole array or procedure address");
379       });
380 }
381 
382 /// Create an optional dummy argument value from entity \p exv that may be
383 /// absent. This can only be called with numerical or logical scalar \p exv.
384 /// If \p exv is considered absent according to 15.5.2.12 point 1., the returned
385 /// value is zero (or false), otherwise it is the value of \p exv.
386 static fir::ExtendedValue genOptionalValue(fir::FirOpBuilder &builder,
387                                            mlir::Location loc,
388                                            const fir::ExtendedValue &exv,
389                                            mlir::Value isPresent) {
390   mlir::Type eleType = fir::getBaseTypeOf(exv);
391   assert(exv.rank() == 0 && fir::isa_trivial(eleType) &&
392          "must be a numerical or logical scalar");
393   return builder
394       .genIfOp(loc, {eleType}, isPresent,
395                /*withElseRegion=*/true)
396       .genThen([&]() {
397         mlir::Value val = fir::getBase(genLoad(builder, loc, exv));
398         builder.create<fir::ResultOp>(loc, val);
399       })
400       .genElse([&]() {
401         mlir::Value zero = fir::factory::createZeroValue(builder, loc, eleType);
402         builder.create<fir::ResultOp>(loc, zero);
403       })
404       .getResults()[0];
405 }
406 
407 /// Create an optional dummy argument address from entity \p exv that may be
408 /// absent. If \p exv is considered absent according to 15.5.2.12 point 1., the
409 /// returned value is a null pointer, otherwise it is the address of \p exv.
410 static fir::ExtendedValue genOptionalAddr(fir::FirOpBuilder &builder,
411                                           mlir::Location loc,
412                                           const fir::ExtendedValue &exv,
413                                           mlir::Value isPresent) {
414   // If it is an exv pointer/allocatable, then it cannot be absent
415   // because it is passed to a non-pointer/non-allocatable.
416   if (const auto *box = exv.getBoxOf<fir::MutableBoxValue>())
417     return fir::factory::genMutableBoxRead(builder, loc, *box);
418   // If this is not a POINTER or ALLOCATABLE, then it is already an OPTIONAL
419   // address and can be passed directly.
420   return exv;
421 }
422 
423 /// Create an optional dummy argument address from entity \p exv that may be
424 /// absent. If \p exv is considered absent according to 15.5.2.12 point 1., the
425 /// returned value is an absent fir.box, otherwise it is a fir.box describing \p
426 /// exv.
427 static fir::ExtendedValue genOptionalBox(fir::FirOpBuilder &builder,
428                                          mlir::Location loc,
429                                          const fir::ExtendedValue &exv,
430                                          mlir::Value isPresent) {
431   // Non allocatable/pointer optional box -> simply forward
432   if (exv.getBoxOf<fir::BoxValue>())
433     return exv;
434 
435   fir::ExtendedValue newExv = exv;
436   // Optional allocatable/pointer -> Cannot be absent, but need to translate
437   // unallocated/diassociated into absent fir.box.
438   if (const auto *box = exv.getBoxOf<fir::MutableBoxValue>())
439     newExv = fir::factory::genMutableBoxRead(builder, loc, *box);
440 
441   // createBox will not do create any invalid memory dereferences if exv is
442   // absent. The created fir.box will not be usable, but the SelectOp below
443   // ensures it won't be.
444   mlir::Value box = builder.createBox(loc, newExv);
445   mlir::Type boxType = box.getType();
446   auto absent = builder.create<fir::AbsentOp>(loc, boxType);
447   auto boxOrAbsent = builder.create<mlir::arith::SelectOp>(
448       loc, boxType, isPresent, box, absent);
449   return fir::BoxValue(boxOrAbsent);
450 }
451 
452 /// Is this a call to an elemental procedure with at least one array argument?
453 static bool
454 isElementalProcWithArrayArgs(const Fortran::evaluate::ProcedureRef &procRef) {
455   if (procRef.IsElemental())
456     for (const std::optional<Fortran::evaluate::ActualArgument> &arg :
457          procRef.arguments())
458       if (arg && arg->Rank() != 0)
459         return true;
460   return false;
461 }
462 template <typename T>
463 static bool isElementalProcWithArrayArgs(const Fortran::evaluate::Expr<T> &) {
464   return false;
465 }
466 template <>
467 bool isElementalProcWithArrayArgs(const Fortran::lower::SomeExpr &x) {
468   if (const auto *procRef = std::get_if<Fortran::evaluate::ProcedureRef>(&x.u))
469     return isElementalProcWithArrayArgs(*procRef);
470   return false;
471 }
472 
473 /// Some auxiliary data for processing initialization in ScalarExprLowering
474 /// below. This is currently used for generating dense attributed global
475 /// arrays.
476 struct InitializerData {
477   explicit InitializerData(bool getRawVals = false) : genRawVals{getRawVals} {}
478   llvm::SmallVector<mlir::Attribute> rawVals; // initialization raw values
479   mlir::Type rawType; // Type of elements processed for rawVals vector.
480   bool genRawVals;    // generate the rawVals vector if set.
481 };
482 
483 /// If \p arg is the address of a function with a denoted host-association tuple
484 /// argument, then return the host-associations tuple value of the current
485 /// procedure. Otherwise, return nullptr.
486 static mlir::Value
487 argumentHostAssocs(Fortran::lower::AbstractConverter &converter,
488                    mlir::Value arg) {
489   if (auto addr = mlir::dyn_cast_or_null<fir::AddrOfOp>(arg.getDefiningOp())) {
490     auto &builder = converter.getFirOpBuilder();
491     if (auto funcOp = builder.getNamedFunction(addr.getSymbol()))
492       if (fir::anyFuncArgsHaveAttr(funcOp, fir::getHostAssocAttrName()))
493         return converter.hostAssocTupleValue();
494   }
495   return {};
496 }
497 
498 /// \p argTy must be a tuple (pair) of boxproc and integral types. Convert the
499 /// \p funcAddr argument to a boxproc value, with the host-association as
500 /// required. Call the factory function to finish creating the tuple value.
501 static mlir::Value
502 createBoxProcCharTuple(Fortran::lower::AbstractConverter &converter,
503                        mlir::Type argTy, mlir::Value funcAddr,
504                        mlir::Value charLen) {
505   auto boxTy =
506       argTy.cast<mlir::TupleType>().getType(0).cast<fir::BoxProcType>();
507   mlir::Location loc = converter.getCurrentLocation();
508   auto &builder = converter.getFirOpBuilder();
509   auto boxProc = [&]() -> mlir::Value {
510     if (auto host = argumentHostAssocs(converter, funcAddr))
511       return builder.create<fir::EmboxProcOp>(
512           loc, boxTy, llvm::ArrayRef<mlir::Value>{funcAddr, host});
513     return builder.create<fir::EmboxProcOp>(loc, boxTy, funcAddr);
514   }();
515   return fir::factory::createCharacterProcedureTuple(builder, loc, argTy,
516                                                      boxProc, charLen);
517 }
518 
519 // Helper to get the ultimate first symbol. This works around the fact that
520 // symbol resolution in the front end doesn't always resolve a symbol to its
521 // ultimate symbol but may leave placeholder indirections for use and host
522 // associations.
523 template <typename A>
524 const Fortran::semantics::Symbol &getFirstSym(const A &obj) {
525   return obj.GetFirstSymbol().GetUltimate();
526 }
527 
528 // Helper to get the ultimate last symbol.
529 template <typename A>
530 const Fortran::semantics::Symbol &getLastSym(const A &obj) {
531   return obj.GetLastSymbol().GetUltimate();
532 }
533 
534 namespace {
535 
536 /// Lowering of Fortran::evaluate::Expr<T> expressions
537 class ScalarExprLowering {
538 public:
539   using ExtValue = fir::ExtendedValue;
540 
541   explicit ScalarExprLowering(mlir::Location loc,
542                               Fortran::lower::AbstractConverter &converter,
543                               Fortran::lower::SymMap &symMap,
544                               Fortran::lower::StatementContext &stmtCtx,
545                               InitializerData *initializer = nullptr)
546       : location{loc}, converter{converter},
547         builder{converter.getFirOpBuilder()}, stmtCtx{stmtCtx}, symMap{symMap},
548         inInitializer{initializer} {}
549 
550   ExtValue genExtAddr(const Fortran::lower::SomeExpr &expr) {
551     return gen(expr);
552   }
553 
554   /// Lower `expr` to be passed as a fir.box argument. Do not create a temp
555   /// for the expr if it is a variable that can be described as a fir.box.
556   ExtValue genBoxArg(const Fortran::lower::SomeExpr &expr) {
557     bool saveUseBoxArg = useBoxArg;
558     useBoxArg = true;
559     ExtValue result = gen(expr);
560     useBoxArg = saveUseBoxArg;
561     return result;
562   }
563 
564   ExtValue genExtValue(const Fortran::lower::SomeExpr &expr) {
565     return genval(expr);
566   }
567 
568   /// Lower an expression that is a pointer or an allocatable to a
569   /// MutableBoxValue.
570   fir::MutableBoxValue
571   genMutableBoxValue(const Fortran::lower::SomeExpr &expr) {
572     // Pointers and allocatables can only be:
573     //    - a simple designator "x"
574     //    - a component designator "a%b(i,j)%x"
575     //    - a function reference "foo()"
576     //    - result of NULL() or NULL(MOLD) intrinsic.
577     //    NULL() requires some context to be lowered, so it is not handled
578     //    here and must be lowered according to the context where it appears.
579     ExtValue exv = std::visit(
580         [&](const auto &x) { return genMutableBoxValueImpl(x); }, expr.u);
581     const fir::MutableBoxValue *mutableBox =
582         exv.getBoxOf<fir::MutableBoxValue>();
583     if (!mutableBox)
584       fir::emitFatalError(getLoc(), "expr was not lowered to MutableBoxValue");
585     return *mutableBox;
586   }
587 
588   template <typename T>
589   ExtValue genMutableBoxValueImpl(const T &) {
590     // NULL() case should not be handled here.
591     fir::emitFatalError(getLoc(), "NULL() must be lowered in its context");
592   }
593 
594   /// A `NULL()` in a position where a mutable box is expected has the same
595   /// semantics as an absent optional box value.
596   ExtValue genMutableBoxValueImpl(const Fortran::evaluate::NullPointer &) {
597     mlir::Location loc = getLoc();
598     auto nullConst = builder.createNullConstant(loc);
599     auto noneTy = mlir::NoneType::get(builder.getContext());
600     auto polyRefTy = fir::LLVMPointerType::get(noneTy);
601     // MutableBoxValue will dereference the box, so create a bogus temporary for
602     // the `nullptr`. The LLVM optimizer will garbage collect the temp.
603     auto temp =
604         builder.createTemporary(loc, polyRefTy, /*shape=*/mlir::ValueRange{});
605     auto nullPtr = builder.createConvert(loc, polyRefTy, nullConst);
606     builder.create<fir::StoreOp>(loc, nullPtr, temp);
607     auto nullBoxTy = builder.getRefType(fir::BoxType::get(noneTy));
608     return fir::MutableBoxValue(builder.createConvert(loc, nullBoxTy, temp),
609                                 /*lenParameters=*/mlir::ValueRange{},
610                                 /*mutableProperties=*/{});
611   }
612 
613   template <typename T>
614   ExtValue
615   genMutableBoxValueImpl(const Fortran::evaluate::FunctionRef<T> &funRef) {
616     return genRawProcedureRef(funRef, converter.genType(toEvExpr(funRef)));
617   }
618 
619   template <typename T>
620   ExtValue
621   genMutableBoxValueImpl(const Fortran::evaluate::Designator<T> &designator) {
622     return std::visit(
623         Fortran::common::visitors{
624             [&](const Fortran::evaluate::SymbolRef &sym) -> ExtValue {
625               return symMap.lookupSymbol(*sym).toExtendedValue();
626             },
627             [&](const Fortran::evaluate::Component &comp) -> ExtValue {
628               return genComponent(comp);
629             },
630             [&](const auto &) -> ExtValue {
631               fir::emitFatalError(getLoc(),
632                                   "not an allocatable or pointer designator");
633             }},
634         designator.u);
635   }
636 
637   template <typename T>
638   ExtValue genMutableBoxValueImpl(const Fortran::evaluate::Expr<T> &expr) {
639     return std::visit([&](const auto &x) { return genMutableBoxValueImpl(x); },
640                       expr.u);
641   }
642 
643   mlir::Location getLoc() { return location; }
644 
645   template <typename A>
646   mlir::Value genunbox(const A &expr) {
647     ExtValue e = genval(expr);
648     if (const fir::UnboxedValue *r = e.getUnboxed())
649       return *r;
650     fir::emitFatalError(getLoc(), "unboxed expression expected");
651   }
652 
653   /// Generate an integral constant of `value`
654   template <int KIND>
655   mlir::Value genIntegerConstant(mlir::MLIRContext *context,
656                                  std::int64_t value) {
657     mlir::Type type =
658         converter.genType(Fortran::common::TypeCategory::Integer, KIND);
659     return builder.createIntegerConstant(getLoc(), type, value);
660   }
661 
662   /// Generate a logical/boolean constant of `value`
663   mlir::Value genBoolConstant(bool value) {
664     return builder.createBool(getLoc(), value);
665   }
666 
667   /// Generate a real constant with a value `value`.
668   template <int KIND>
669   mlir::Value genRealConstant(mlir::MLIRContext *context,
670                               const llvm::APFloat &value) {
671     mlir::Type fltTy = Fortran::lower::convertReal(context, KIND);
672     return builder.createRealConstant(getLoc(), fltTy, value);
673   }
674 
675   mlir::Type getSomeKindInteger() { return builder.getIndexType(); }
676 
677   mlir::FuncOp getFunction(llvm::StringRef name, mlir::FunctionType funTy) {
678     if (mlir::FuncOp func = builder.getNamedFunction(name))
679       return func;
680     return builder.createFunction(getLoc(), name, funTy);
681   }
682 
683   template <typename OpTy>
684   mlir::Value createCompareOp(mlir::arith::CmpIPredicate pred,
685                               const ExtValue &left, const ExtValue &right) {
686     if (const fir::UnboxedValue *lhs = left.getUnboxed())
687       if (const fir::UnboxedValue *rhs = right.getUnboxed())
688         return builder.create<OpTy>(getLoc(), pred, *lhs, *rhs);
689     fir::emitFatalError(getLoc(), "array compare should be handled in genarr");
690   }
691   template <typename OpTy, typename A>
692   mlir::Value createCompareOp(const A &ex, mlir::arith::CmpIPredicate pred) {
693     ExtValue left = genval(ex.left());
694     return createCompareOp<OpTy>(pred, left, genval(ex.right()));
695   }
696 
697   template <typename OpTy>
698   mlir::Value createFltCmpOp(mlir::arith::CmpFPredicate pred,
699                              const ExtValue &left, const ExtValue &right) {
700     if (const fir::UnboxedValue *lhs = left.getUnboxed())
701       if (const fir::UnboxedValue *rhs = right.getUnboxed())
702         return builder.create<OpTy>(getLoc(), pred, *lhs, *rhs);
703     fir::emitFatalError(getLoc(), "array compare should be handled in genarr");
704   }
705   template <typename OpTy, typename A>
706   mlir::Value createFltCmpOp(const A &ex, mlir::arith::CmpFPredicate pred) {
707     ExtValue left = genval(ex.left());
708     return createFltCmpOp<OpTy>(pred, left, genval(ex.right()));
709   }
710 
711   /// Create a call to the runtime to compare two CHARACTER values.
712   /// Precondition: This assumes that the two values have `fir.boxchar` type.
713   mlir::Value createCharCompare(mlir::arith::CmpIPredicate pred,
714                                 const ExtValue &left, const ExtValue &right) {
715     return fir::runtime::genCharCompare(builder, getLoc(), pred, left, right);
716   }
717 
718   template <typename A>
719   mlir::Value createCharCompare(const A &ex, mlir::arith::CmpIPredicate pred) {
720     ExtValue left = genval(ex.left());
721     return createCharCompare(pred, left, genval(ex.right()));
722   }
723 
724   /// Returns a reference to a symbol or its box/boxChar descriptor if it has
725   /// one.
726   ExtValue gen(Fortran::semantics::SymbolRef sym) {
727     if (Fortran::lower::SymbolBox val = symMap.lookupSymbol(sym))
728       return val.match(
729           [&](const Fortran::lower::SymbolBox::PointerOrAllocatable &boxAddr) {
730             return fir::factory::genMutableBoxRead(builder, getLoc(), boxAddr);
731           },
732           [&val](auto &) { return val.toExtendedValue(); });
733     LLVM_DEBUG(llvm::dbgs()
734                << "unknown symbol: " << sym << "\nmap: " << symMap << '\n');
735     fir::emitFatalError(getLoc(), "symbol is not mapped to any IR value");
736   }
737 
738   ExtValue genLoad(const ExtValue &exv) {
739     return ::genLoad(builder, getLoc(), exv);
740   }
741 
742   ExtValue genval(Fortran::semantics::SymbolRef sym) {
743     mlir::Location loc = getLoc();
744     ExtValue var = gen(sym);
745     if (const fir::UnboxedValue *s = var.getUnboxed())
746       if (fir::isReferenceLike(s->getType())) {
747         // A function with multiple entry points returning different types
748         // tags all result variables with one of the largest types to allow
749         // them to share the same storage.  A reference to a result variable
750         // of one of the other types requires conversion to the actual type.
751         fir::UnboxedValue addr = *s;
752         if (Fortran::semantics::IsFunctionResult(sym)) {
753           mlir::Type resultType = converter.genType(*sym);
754           if (addr.getType() != resultType)
755             addr = builder.createConvert(loc, builder.getRefType(resultType),
756                                          addr);
757         }
758         return genLoad(addr);
759       }
760     return var;
761   }
762 
763   ExtValue genval(const Fortran::evaluate::BOZLiteralConstant &) {
764     TODO(getLoc(), "BOZ");
765   }
766 
767   /// Return indirection to function designated in ProcedureDesignator.
768   /// The type of the function indirection is not guaranteed to match the one
769   /// of the ProcedureDesignator due to Fortran implicit typing rules.
770   ExtValue genval(const Fortran::evaluate::ProcedureDesignator &proc) {
771     mlir::Location loc = getLoc();
772     if (const Fortran::evaluate::SpecificIntrinsic *intrinsic =
773             proc.GetSpecificIntrinsic()) {
774       mlir::FunctionType signature =
775           Fortran::lower::translateSignature(proc, converter);
776       // Intrinsic lowering is based on the generic name, so retrieve it here in
777       // case it is different from the specific name. The type of the specific
778       // intrinsic is retained in the signature.
779       std::string genericName =
780           converter.getFoldingContext().intrinsics().GetGenericIntrinsicName(
781               intrinsic->name);
782       mlir::SymbolRefAttr symbolRefAttr =
783           Fortran::lower::getUnrestrictedIntrinsicSymbolRefAttr(
784               builder, loc, genericName, signature);
785       mlir::Value funcPtr =
786           builder.create<fir::AddrOfOp>(loc, signature, symbolRefAttr);
787       return funcPtr;
788     }
789     const Fortran::semantics::Symbol *symbol = proc.GetSymbol();
790     assert(symbol && "expected symbol in ProcedureDesignator");
791     mlir::Value funcPtr;
792     mlir::Value funcPtrResultLength;
793     if (Fortran::semantics::IsDummy(*symbol)) {
794       Fortran::lower::SymbolBox val = symMap.lookupSymbol(*symbol);
795       assert(val && "Dummy procedure not in symbol map");
796       funcPtr = val.getAddr();
797       if (fir::isCharacterProcedureTuple(funcPtr.getType(),
798                                          /*acceptRawFunc=*/false))
799         std::tie(funcPtr, funcPtrResultLength) =
800             fir::factory::extractCharacterProcedureTuple(builder, loc, funcPtr);
801     } else {
802       std::string name = converter.mangleName(*symbol);
803       mlir::FuncOp func =
804           Fortran::lower::getOrDeclareFunction(name, proc, converter);
805       funcPtr = builder.create<fir::AddrOfOp>(loc, func.getFunctionType(),
806                                               builder.getSymbolRefAttr(name));
807     }
808     if (Fortran::lower::mustPassLengthWithDummyProcedure(proc, converter)) {
809       // The result length, if available here, must be propagated along the
810       // procedure address so that call sites where the result length is assumed
811       // can retrieve the length.
812       Fortran::evaluate::DynamicType resultType = proc.GetType().value();
813       if (const auto &lengthExpr = resultType.GetCharLength()) {
814         // The length expression may refer to dummy argument symbols that are
815         // meaningless without any actual arguments. Leave the length as
816         // unknown in that case, it be resolved on the call site
817         // with the actual arguments.
818         if (allSymbolsInExprPresentInMap(toEvExpr(*lengthExpr), symMap)) {
819           mlir::Value rawLen = fir::getBase(genval(*lengthExpr));
820           // F2018 7.4.4.2 point 5.
821           funcPtrResultLength =
822               Fortran::lower::genMaxWithZero(builder, getLoc(), rawLen);
823         }
824       }
825       if (!funcPtrResultLength)
826         funcPtrResultLength = builder.createIntegerConstant(
827             loc, builder.getCharacterLengthType(), -1);
828       return fir::CharBoxValue{funcPtr, funcPtrResultLength};
829     }
830     return funcPtr;
831   }
832   ExtValue genval(const Fortran::evaluate::NullPointer &) {
833     return builder.createNullConstant(getLoc());
834   }
835 
836   static bool
837   isDerivedTypeWithLengthParameters(const Fortran::semantics::Symbol &sym) {
838     if (const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType())
839       if (const Fortran::semantics::DerivedTypeSpec *derived =
840               declTy->AsDerived())
841         return Fortran::semantics::CountLenParameters(*derived) > 0;
842     return false;
843   }
844 
845   static bool isBuiltinCPtr(const Fortran::semantics::Symbol &sym) {
846     if (const Fortran::semantics::DeclTypeSpec *declType = sym.GetType())
847       if (const Fortran::semantics::DerivedTypeSpec *derived =
848               declType->AsDerived())
849         return Fortran::semantics::IsIsoCType(derived);
850     return false;
851   }
852 
853   /// Lower structure constructor without a temporary. This can be used in
854   /// fir::GloablOp, and assumes that the structure component is a constant.
855   ExtValue genStructComponentInInitializer(
856       const Fortran::evaluate::StructureConstructor &ctor) {
857     mlir::Location loc = getLoc();
858     mlir::Type ty = translateSomeExprToFIRType(converter, toEvExpr(ctor));
859     auto recTy = ty.cast<fir::RecordType>();
860     auto fieldTy = fir::FieldType::get(ty.getContext());
861     mlir::Value res = builder.create<fir::UndefOp>(loc, recTy);
862 
863     for (const auto &[sym, expr] : ctor.values()) {
864       // Parent components need more work because they do not appear in the
865       // fir.rec type.
866       if (sym->test(Fortran::semantics::Symbol::Flag::ParentComp))
867         TODO(loc, "parent component in structure constructor");
868 
869       llvm::StringRef name = toStringRef(sym->name());
870       mlir::Type componentTy = recTy.getType(name);
871       // FIXME: type parameters must come from the derived-type-spec
872       auto field = builder.create<fir::FieldIndexOp>(
873           loc, fieldTy, name, ty,
874           /*typeParams=*/mlir::ValueRange{} /*TODO*/);
875 
876       if (Fortran::semantics::IsAllocatable(sym))
877         TODO(loc, "allocatable component in structure constructor");
878 
879       if (Fortran::semantics::IsPointer(sym)) {
880         mlir::Value initialTarget = Fortran::lower::genInitialDataTarget(
881             converter, loc, componentTy, expr.value());
882         res = builder.create<fir::InsertValueOp>(
883             loc, recTy, res, initialTarget,
884             builder.getArrayAttr(field.getAttributes()));
885         continue;
886       }
887 
888       if (isDerivedTypeWithLengthParameters(sym))
889         TODO(loc, "component with length parameters in structure constructor");
890 
891       if (isBuiltinCPtr(sym)) {
892         // Builtin c_ptr and c_funptr have special handling because initial
893         // value are handled for them as an extension.
894         mlir::Value addr = fir::getBase(Fortran::lower::genExtAddrInInitializer(
895             converter, loc, expr.value()));
896         if (addr.getType() == componentTy) {
897           // Do nothing. The Ev::Expr was returned as a value that can be
898           // inserted directly to the component without an intermediary.
899         } else {
900           // The Ev::Expr returned is an initializer that is a pointer (e.g.,
901           // null) that must be inserted into an intermediate cptr record
902           // value's address field, which ought to be an intptr_t on the target.
903           assert((fir::isa_ref_type(addr.getType()) ||
904                   addr.getType().isa<mlir::FunctionType>()) &&
905                  "expect reference type for address field");
906           assert(fir::isa_derived(componentTy) &&
907                  "expect C_PTR, C_FUNPTR to be a record");
908           auto cPtrRecTy = componentTy.cast<fir::RecordType>();
909           llvm::StringRef addrFieldName =
910               Fortran::lower::builtin::cptrFieldName;
911           mlir::Type addrFieldTy = cPtrRecTy.getType(addrFieldName);
912           auto addrField = builder.create<fir::FieldIndexOp>(
913               loc, fieldTy, addrFieldName, componentTy,
914               /*typeParams=*/mlir::ValueRange{});
915           mlir::Value castAddr = builder.createConvert(loc, addrFieldTy, addr);
916           auto undef = builder.create<fir::UndefOp>(loc, componentTy);
917           addr = builder.create<fir::InsertValueOp>(
918               loc, componentTy, undef, castAddr,
919               builder.getArrayAttr(addrField.getAttributes()));
920         }
921         res = builder.create<fir::InsertValueOp>(
922             loc, recTy, res, addr, builder.getArrayAttr(field.getAttributes()));
923         continue;
924       }
925 
926       mlir::Value val = fir::getBase(genval(expr.value()));
927       assert(!fir::isa_ref_type(val.getType()) && "expecting a constant value");
928       mlir::Value castVal = builder.createConvert(loc, componentTy, val);
929       res = builder.create<fir::InsertValueOp>(
930           loc, recTy, res, castVal,
931           builder.getArrayAttr(field.getAttributes()));
932     }
933     return res;
934   }
935 
936   /// A structure constructor is lowered two ways. In an initializer context,
937   /// the entire structure must be constant, so the aggregate value is
938   /// constructed inline. This allows it to be the body of a GlobalOp.
939   /// Otherwise, the structure constructor is in an expression. In that case, a
940   /// temporary object is constructed in the stack frame of the procedure.
941   ExtValue genval(const Fortran::evaluate::StructureConstructor &ctor) {
942     if (inInitializer)
943       return genStructComponentInInitializer(ctor);
944     mlir::Location loc = getLoc();
945     mlir::Type ty = translateSomeExprToFIRType(converter, toEvExpr(ctor));
946     auto recTy = ty.cast<fir::RecordType>();
947     auto fieldTy = fir::FieldType::get(ty.getContext());
948     mlir::Value res = builder.createTemporary(loc, recTy);
949 
950     for (const auto &value : ctor.values()) {
951       const Fortran::semantics::Symbol &sym = *value.first;
952       const Fortran::lower::SomeExpr &expr = value.second.value();
953       // Parent components need more work because they do not appear in the
954       // fir.rec type.
955       if (sym.test(Fortran::semantics::Symbol::Flag::ParentComp))
956         TODO(loc, "parent component in structure constructor");
957 
958       if (isDerivedTypeWithLengthParameters(sym))
959         TODO(loc, "component with length parameters in structure constructor");
960 
961       llvm::StringRef name = toStringRef(sym.name());
962       // FIXME: type parameters must come from the derived-type-spec
963       mlir::Value field = builder.create<fir::FieldIndexOp>(
964           loc, fieldTy, name, ty,
965           /*typeParams=*/mlir::ValueRange{} /*TODO*/);
966       mlir::Type coorTy = builder.getRefType(recTy.getType(name));
967       auto coor = builder.create<fir::CoordinateOp>(loc, coorTy,
968                                                     fir::getBase(res), field);
969       ExtValue to = fir::factory::componentToExtendedValue(builder, loc, coor);
970       to.match(
971           [&](const fir::UnboxedValue &toPtr) {
972             ExtValue value = genval(expr);
973             fir::factory::genScalarAssignment(builder, loc, to, value);
974           },
975           [&](const fir::CharBoxValue &) {
976             ExtValue value = genval(expr);
977             fir::factory::genScalarAssignment(builder, loc, to, value);
978           },
979           [&](const fir::ArrayBoxValue &) {
980             Fortran::lower::createSomeArrayAssignment(converter, to, expr,
981                                                       symMap, stmtCtx);
982           },
983           [&](const fir::CharArrayBoxValue &) {
984             Fortran::lower::createSomeArrayAssignment(converter, to, expr,
985                                                       symMap, stmtCtx);
986           },
987           [&](const fir::BoxValue &toBox) {
988             fir::emitFatalError(loc, "derived type components must not be "
989                                      "represented by fir::BoxValue");
990           },
991           [&](const fir::MutableBoxValue &toBox) {
992             if (toBox.isPointer()) {
993               Fortran::lower::associateMutableBox(
994                   converter, loc, toBox, expr, /*lbounds=*/llvm::None, stmtCtx);
995               return;
996             }
997             // For allocatable components, a deep copy is needed.
998             TODO(loc, "allocatable components in derived type assignment");
999           },
1000           [&](const fir::ProcBoxValue &toBox) {
1001             TODO(loc, "procedure pointer component in derived type assignment");
1002           });
1003     }
1004     return res;
1005   }
1006 
1007   /// Lowering of an <i>ac-do-variable</i>, which is not a Symbol.
1008   ExtValue genval(const Fortran::evaluate::ImpliedDoIndex &var) {
1009     return converter.impliedDoBinding(toStringRef(var.name));
1010   }
1011 
1012   ExtValue genval(const Fortran::evaluate::DescriptorInquiry &desc) {
1013     ExtValue exv = desc.base().IsSymbol() ? gen(getLastSym(desc.base()))
1014                                           : gen(desc.base().GetComponent());
1015     mlir::IndexType idxTy = builder.getIndexType();
1016     mlir::Location loc = getLoc();
1017     auto castResult = [&](mlir::Value v) {
1018       using ResTy = Fortran::evaluate::DescriptorInquiry::Result;
1019       return builder.createConvert(
1020           loc, converter.genType(ResTy::category, ResTy::kind), v);
1021     };
1022     switch (desc.field()) {
1023     case Fortran::evaluate::DescriptorInquiry::Field::Len:
1024       return castResult(fir::factory::readCharLen(builder, loc, exv));
1025     case Fortran::evaluate::DescriptorInquiry::Field::LowerBound:
1026       return castResult(fir::factory::readLowerBound(
1027           builder, loc, exv, desc.dimension(),
1028           builder.createIntegerConstant(loc, idxTy, 1)));
1029     case Fortran::evaluate::DescriptorInquiry::Field::Extent:
1030       return castResult(
1031           fir::factory::readExtent(builder, loc, exv, desc.dimension()));
1032     case Fortran::evaluate::DescriptorInquiry::Field::Rank:
1033       TODO(loc, "rank inquiry on assumed rank");
1034     case Fortran::evaluate::DescriptorInquiry::Field::Stride:
1035       // So far the front end does not generate this inquiry.
1036       TODO(loc, "Stride inquiry");
1037     }
1038     llvm_unreachable("unknown descriptor inquiry");
1039   }
1040 
1041   ExtValue genval(const Fortran::evaluate::TypeParamInquiry &) {
1042     TODO(getLoc(), "type parameter inquiry");
1043   }
1044 
1045   mlir::Value extractComplexPart(mlir::Value cplx, bool isImagPart) {
1046     return fir::factory::Complex{builder, getLoc()}.extractComplexPart(
1047         cplx, isImagPart);
1048   }
1049 
1050   template <int KIND>
1051   ExtValue genval(const Fortran::evaluate::ComplexComponent<KIND> &part) {
1052     return extractComplexPart(genunbox(part.left()), part.isImaginaryPart);
1053   }
1054 
1055   template <int KIND>
1056   ExtValue genval(const Fortran::evaluate::Negate<Fortran::evaluate::Type<
1057                       Fortran::common::TypeCategory::Integer, KIND>> &op) {
1058     mlir::Value input = genunbox(op.left());
1059     // Like LLVM, integer negation is the binary op "0 - value"
1060     mlir::Value zero = genIntegerConstant<KIND>(builder.getContext(), 0);
1061     return builder.create<mlir::arith::SubIOp>(getLoc(), zero, input);
1062   }
1063   template <int KIND>
1064   ExtValue genval(const Fortran::evaluate::Negate<Fortran::evaluate::Type<
1065                       Fortran::common::TypeCategory::Real, KIND>> &op) {
1066     return builder.create<mlir::arith::NegFOp>(getLoc(), genunbox(op.left()));
1067   }
1068   template <int KIND>
1069   ExtValue genval(const Fortran::evaluate::Negate<Fortran::evaluate::Type<
1070                       Fortran::common::TypeCategory::Complex, KIND>> &op) {
1071     return builder.create<fir::NegcOp>(getLoc(), genunbox(op.left()));
1072   }
1073 
1074   template <typename OpTy>
1075   mlir::Value createBinaryOp(const ExtValue &left, const ExtValue &right) {
1076     assert(fir::isUnboxedValue(left) && fir::isUnboxedValue(right));
1077     mlir::Value lhs = fir::getBase(left);
1078     mlir::Value rhs = fir::getBase(right);
1079     assert(lhs.getType() == rhs.getType() && "types must be the same");
1080     return builder.create<OpTy>(getLoc(), lhs, rhs);
1081   }
1082 
1083   template <typename OpTy, typename A>
1084   mlir::Value createBinaryOp(const A &ex) {
1085     ExtValue left = genval(ex.left());
1086     return createBinaryOp<OpTy>(left, genval(ex.right()));
1087   }
1088 
1089 #undef GENBIN
1090 #define GENBIN(GenBinEvOp, GenBinTyCat, GenBinFirOp)                           \
1091   template <int KIND>                                                          \
1092   ExtValue genval(const Fortran::evaluate::GenBinEvOp<Fortran::evaluate::Type< \
1093                       Fortran::common::TypeCategory::GenBinTyCat, KIND>> &x) { \
1094     return createBinaryOp<GenBinFirOp>(x);                                     \
1095   }
1096 
1097   GENBIN(Add, Integer, mlir::arith::AddIOp)
1098   GENBIN(Add, Real, mlir::arith::AddFOp)
1099   GENBIN(Add, Complex, fir::AddcOp)
1100   GENBIN(Subtract, Integer, mlir::arith::SubIOp)
1101   GENBIN(Subtract, Real, mlir::arith::SubFOp)
1102   GENBIN(Subtract, Complex, fir::SubcOp)
1103   GENBIN(Multiply, Integer, mlir::arith::MulIOp)
1104   GENBIN(Multiply, Real, mlir::arith::MulFOp)
1105   GENBIN(Multiply, Complex, fir::MulcOp)
1106   GENBIN(Divide, Integer, mlir::arith::DivSIOp)
1107   GENBIN(Divide, Real, mlir::arith::DivFOp)
1108   GENBIN(Divide, Complex, fir::DivcOp)
1109 
1110   template <Fortran::common::TypeCategory TC, int KIND>
1111   ExtValue genval(
1112       const Fortran::evaluate::Power<Fortran::evaluate::Type<TC, KIND>> &op) {
1113     mlir::Type ty = converter.genType(TC, KIND);
1114     mlir::Value lhs = genunbox(op.left());
1115     mlir::Value rhs = genunbox(op.right());
1116     return Fortran::lower::genPow(builder, getLoc(), ty, lhs, rhs);
1117   }
1118 
1119   template <Fortran::common::TypeCategory TC, int KIND>
1120   ExtValue genval(
1121       const Fortran::evaluate::RealToIntPower<Fortran::evaluate::Type<TC, KIND>>
1122           &op) {
1123     mlir::Type ty = converter.genType(TC, KIND);
1124     mlir::Value lhs = genunbox(op.left());
1125     mlir::Value rhs = genunbox(op.right());
1126     return Fortran::lower::genPow(builder, getLoc(), ty, lhs, rhs);
1127   }
1128 
1129   template <int KIND>
1130   ExtValue genval(const Fortran::evaluate::ComplexConstructor<KIND> &op) {
1131     mlir::Value realPartValue = genunbox(op.left());
1132     return fir::factory::Complex{builder, getLoc()}.createComplex(
1133         KIND, realPartValue, genunbox(op.right()));
1134   }
1135 
1136   template <int KIND>
1137   ExtValue genval(const Fortran::evaluate::Concat<KIND> &op) {
1138     ExtValue lhs = genval(op.left());
1139     ExtValue rhs = genval(op.right());
1140     const fir::CharBoxValue *lhsChar = lhs.getCharBox();
1141     const fir::CharBoxValue *rhsChar = rhs.getCharBox();
1142     if (lhsChar && rhsChar)
1143       return fir::factory::CharacterExprHelper{builder, getLoc()}
1144           .createConcatenate(*lhsChar, *rhsChar);
1145     TODO(getLoc(), "character array concatenate");
1146   }
1147 
1148   /// MIN and MAX operations
1149   template <Fortran::common::TypeCategory TC, int KIND>
1150   ExtValue
1151   genval(const Fortran::evaluate::Extremum<Fortran::evaluate::Type<TC, KIND>>
1152              &op) {
1153     mlir::Value lhs = genunbox(op.left());
1154     mlir::Value rhs = genunbox(op.right());
1155     switch (op.ordering) {
1156     case Fortran::evaluate::Ordering::Greater:
1157       return Fortran::lower::genMax(builder, getLoc(),
1158                                     llvm::ArrayRef<mlir::Value>{lhs, rhs});
1159     case Fortran::evaluate::Ordering::Less:
1160       return Fortran::lower::genMin(builder, getLoc(),
1161                                     llvm::ArrayRef<mlir::Value>{lhs, rhs});
1162     case Fortran::evaluate::Ordering::Equal:
1163       llvm_unreachable("Equal is not a valid ordering in this context");
1164     }
1165     llvm_unreachable("unknown ordering");
1166   }
1167 
1168   // Change the dynamic length information without actually changing the
1169   // underlying character storage.
1170   fir::ExtendedValue
1171   replaceScalarCharacterLength(const fir::ExtendedValue &scalarChar,
1172                                mlir::Value newLenValue) {
1173     mlir::Location loc = getLoc();
1174     const fir::CharBoxValue *charBox = scalarChar.getCharBox();
1175     if (!charBox)
1176       fir::emitFatalError(loc, "expected scalar character");
1177     mlir::Value charAddr = charBox->getAddr();
1178     auto charType =
1179         fir::unwrapPassByRefType(charAddr.getType()).cast<fir::CharacterType>();
1180     if (charType.hasConstantLen()) {
1181       // Erase previous constant length from the base type.
1182       fir::CharacterType::LenType newLen = fir::CharacterType::unknownLen();
1183       mlir::Type newCharTy = fir::CharacterType::get(
1184           builder.getContext(), charType.getFKind(), newLen);
1185       mlir::Type newType = fir::ReferenceType::get(newCharTy);
1186       charAddr = builder.createConvert(loc, newType, charAddr);
1187       return fir::CharBoxValue{charAddr, newLenValue};
1188     }
1189     return fir::CharBoxValue{charAddr, newLenValue};
1190   }
1191 
1192   template <int KIND>
1193   ExtValue genval(const Fortran::evaluate::SetLength<KIND> &x) {
1194     mlir::Value newLenValue = genunbox(x.right());
1195     fir::ExtendedValue lhs = gen(x.left());
1196     return replaceScalarCharacterLength(lhs, newLenValue);
1197   }
1198 
1199   template <int KIND>
1200   ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
1201                       Fortran::common::TypeCategory::Integer, KIND>> &op) {
1202     return createCompareOp<mlir::arith::CmpIOp>(op,
1203                                                 translateRelational(op.opr));
1204   }
1205   template <int KIND>
1206   ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
1207                       Fortran::common::TypeCategory::Real, KIND>> &op) {
1208     return createFltCmpOp<mlir::arith::CmpFOp>(
1209         op, translateFloatRelational(op.opr));
1210   }
1211   template <int KIND>
1212   ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
1213                       Fortran::common::TypeCategory::Complex, KIND>> &op) {
1214     return createFltCmpOp<fir::CmpcOp>(op, translateFloatRelational(op.opr));
1215   }
1216   template <int KIND>
1217   ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
1218                       Fortran::common::TypeCategory::Character, KIND>> &op) {
1219     return createCharCompare(op, translateRelational(op.opr));
1220   }
1221 
1222   ExtValue
1223   genval(const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &op) {
1224     return std::visit([&](const auto &x) { return genval(x); }, op.u);
1225   }
1226 
1227   template <Fortran::common::TypeCategory TC1, int KIND,
1228             Fortran::common::TypeCategory TC2>
1229   ExtValue
1230   genval(const Fortran::evaluate::Convert<Fortran::evaluate::Type<TC1, KIND>,
1231                                           TC2> &convert) {
1232     mlir::Type ty = converter.genType(TC1, KIND);
1233     auto fromExpr = genval(convert.left());
1234     auto loc = getLoc();
1235     return fromExpr.match(
1236         [&](const fir::CharBoxValue &boxchar) -> ExtValue {
1237           if constexpr (TC1 == Fortran::common::TypeCategory::Character &&
1238                         TC2 == TC1) {
1239             // Use char_convert. Each code point is translated from a
1240             // narrower/wider encoding to the target encoding. For example, 'A'
1241             // may be translated from 0x41 : i8 to 0x0041 : i16. The symbol
1242             // for euro (0x20AC : i16) may be translated from a wide character
1243             // to "0xE2 0x82 0xAC" : UTF-8.
1244             mlir::Value bufferSize = boxchar.getLen();
1245             auto kindMap = builder.getKindMap();
1246             auto fromBits = kindMap.getCharacterBitsize(
1247                 fir::unwrapRefType(boxchar.getAddr().getType())
1248                     .cast<fir::CharacterType>()
1249                     .getFKind());
1250             auto toBits = kindMap.getCharacterBitsize(
1251                 ty.cast<fir::CharacterType>().getFKind());
1252             if (toBits < fromBits) {
1253               // Scale by relative ratio to give a buffer of the same length.
1254               auto ratio = builder.createIntegerConstant(
1255                   loc, bufferSize.getType(), fromBits / toBits);
1256               bufferSize =
1257                   builder.create<mlir::arith::MulIOp>(loc, bufferSize, ratio);
1258             }
1259             auto dest = builder.create<fir::AllocaOp>(
1260                 loc, ty, mlir::ValueRange{bufferSize});
1261             builder.create<fir::CharConvertOp>(loc, boxchar.getAddr(),
1262                                                boxchar.getLen(), dest);
1263             return fir::CharBoxValue{dest, boxchar.getLen()};
1264           } else {
1265             fir::emitFatalError(
1266                 loc, "unsupported evaluate::Convert between CHARACTER type "
1267                      "category and non-CHARACTER category");
1268           }
1269         },
1270         [&](const fir::UnboxedValue &value) -> ExtValue {
1271           return builder.convertWithSemantics(loc, ty, value);
1272         },
1273         [&](auto &) -> ExtValue {
1274           fir::emitFatalError(loc, "unsupported evaluate::Convert");
1275         });
1276   }
1277 
1278   template <typename A>
1279   ExtValue genval(const Fortran::evaluate::Parentheses<A> &op) {
1280     ExtValue input = genval(op.left());
1281     mlir::Value base = fir::getBase(input);
1282     mlir::Value newBase =
1283         builder.create<fir::NoReassocOp>(getLoc(), base.getType(), base);
1284     return fir::substBase(input, newBase);
1285   }
1286 
1287   template <int KIND>
1288   ExtValue genval(const Fortran::evaluate::Not<KIND> &op) {
1289     mlir::Value logical = genunbox(op.left());
1290     mlir::Value one = genBoolConstant(true);
1291     mlir::Value val =
1292         builder.createConvert(getLoc(), builder.getI1Type(), logical);
1293     return builder.create<mlir::arith::XOrIOp>(getLoc(), val, one);
1294   }
1295 
1296   template <int KIND>
1297   ExtValue genval(const Fortran::evaluate::LogicalOperation<KIND> &op) {
1298     mlir::IntegerType i1Type = builder.getI1Type();
1299     mlir::Value slhs = genunbox(op.left());
1300     mlir::Value srhs = genunbox(op.right());
1301     mlir::Value lhs = builder.createConvert(getLoc(), i1Type, slhs);
1302     mlir::Value rhs = builder.createConvert(getLoc(), i1Type, srhs);
1303     switch (op.logicalOperator) {
1304     case Fortran::evaluate::LogicalOperator::And:
1305       return createBinaryOp<mlir::arith::AndIOp>(lhs, rhs);
1306     case Fortran::evaluate::LogicalOperator::Or:
1307       return createBinaryOp<mlir::arith::OrIOp>(lhs, rhs);
1308     case Fortran::evaluate::LogicalOperator::Eqv:
1309       return createCompareOp<mlir::arith::CmpIOp>(
1310           mlir::arith::CmpIPredicate::eq, lhs, rhs);
1311     case Fortran::evaluate::LogicalOperator::Neqv:
1312       return createCompareOp<mlir::arith::CmpIOp>(
1313           mlir::arith::CmpIPredicate::ne, lhs, rhs);
1314     case Fortran::evaluate::LogicalOperator::Not:
1315       // lib/evaluate expression for .NOT. is Fortran::evaluate::Not<KIND>.
1316       llvm_unreachable(".NOT. is not a binary operator");
1317     }
1318     llvm_unreachable("unhandled logical operation");
1319   }
1320 
1321   /// Convert a scalar literal constant to IR.
1322   template <Fortran::common::TypeCategory TC, int KIND>
1323   ExtValue genScalarLit(
1324       const Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>>
1325           &value) {
1326     if constexpr (TC == Fortran::common::TypeCategory::Integer) {
1327       return genIntegerConstant<KIND>(builder.getContext(), value.ToInt64());
1328     } else if constexpr (TC == Fortran::common::TypeCategory::Logical) {
1329       return genBoolConstant(value.IsTrue());
1330     } else if constexpr (TC == Fortran::common::TypeCategory::Real) {
1331       std::string str = value.DumpHexadecimal();
1332       if constexpr (KIND == 2) {
1333         llvm::APFloat floatVal{llvm::APFloatBase::IEEEhalf(), str};
1334         return genRealConstant<KIND>(builder.getContext(), floatVal);
1335       } else if constexpr (KIND == 3) {
1336         llvm::APFloat floatVal{llvm::APFloatBase::BFloat(), str};
1337         return genRealConstant<KIND>(builder.getContext(), floatVal);
1338       } else if constexpr (KIND == 4) {
1339         llvm::APFloat floatVal{llvm::APFloatBase::IEEEsingle(), str};
1340         return genRealConstant<KIND>(builder.getContext(), floatVal);
1341       } else if constexpr (KIND == 10) {
1342         llvm::APFloat floatVal{llvm::APFloatBase::x87DoubleExtended(), str};
1343         return genRealConstant<KIND>(builder.getContext(), floatVal);
1344       } else if constexpr (KIND == 16) {
1345         llvm::APFloat floatVal{llvm::APFloatBase::IEEEquad(), str};
1346         return genRealConstant<KIND>(builder.getContext(), floatVal);
1347       } else {
1348         // convert everything else to double
1349         llvm::APFloat floatVal{llvm::APFloatBase::IEEEdouble(), str};
1350         return genRealConstant<KIND>(builder.getContext(), floatVal);
1351       }
1352     } else if constexpr (TC == Fortran::common::TypeCategory::Complex) {
1353       using TR =
1354           Fortran::evaluate::Type<Fortran::common::TypeCategory::Real, KIND>;
1355       Fortran::evaluate::ComplexConstructor<KIND> ctor(
1356           Fortran::evaluate::Expr<TR>{
1357               Fortran::evaluate::Constant<TR>{value.REAL()}},
1358           Fortran::evaluate::Expr<TR>{
1359               Fortran::evaluate::Constant<TR>{value.AIMAG()}});
1360       return genunbox(ctor);
1361     } else /*constexpr*/ {
1362       llvm_unreachable("unhandled constant");
1363     }
1364   }
1365 
1366   /// Generate a raw literal value and store it in the rawVals vector.
1367   template <Fortran::common::TypeCategory TC, int KIND>
1368   void
1369   genRawLit(const Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>>
1370                 &value) {
1371     mlir::Attribute val;
1372     assert(inInitializer != nullptr);
1373     if constexpr (TC == Fortran::common::TypeCategory::Integer) {
1374       inInitializer->rawType = converter.genType(TC, KIND);
1375       val = builder.getIntegerAttr(inInitializer->rawType, value.ToInt64());
1376     } else if constexpr (TC == Fortran::common::TypeCategory::Logical) {
1377       inInitializer->rawType =
1378           converter.genType(Fortran::common::TypeCategory::Integer, KIND);
1379       val = builder.getIntegerAttr(inInitializer->rawType, value.IsTrue());
1380     } else if constexpr (TC == Fortran::common::TypeCategory::Real) {
1381       std::string str = value.DumpHexadecimal();
1382       inInitializer->rawType = converter.genType(TC, KIND);
1383       llvm::APFloat floatVal{builder.getKindMap().getFloatSemantics(KIND), str};
1384       val = builder.getFloatAttr(inInitializer->rawType, floatVal);
1385     } else if constexpr (TC == Fortran::common::TypeCategory::Complex) {
1386       std::string strReal = value.REAL().DumpHexadecimal();
1387       std::string strImg = value.AIMAG().DumpHexadecimal();
1388       inInitializer->rawType = converter.genType(TC, KIND);
1389       llvm::APFloat realVal{builder.getKindMap().getFloatSemantics(KIND),
1390                             strReal};
1391       val = builder.getFloatAttr(inInitializer->rawType, realVal);
1392       inInitializer->rawVals.push_back(val);
1393       llvm::APFloat imgVal{builder.getKindMap().getFloatSemantics(KIND),
1394                            strImg};
1395       val = builder.getFloatAttr(inInitializer->rawType, imgVal);
1396     }
1397     inInitializer->rawVals.push_back(val);
1398   }
1399 
1400   /// Convert a scalar literal CHARACTER to IR.
1401   template <int KIND>
1402   ExtValue
1403   genScalarLit(const Fortran::evaluate::Scalar<Fortran::evaluate::Type<
1404                    Fortran::common::TypeCategory::Character, KIND>> &value,
1405                int64_t len) {
1406     using ET = typename std::decay_t<decltype(value)>::value_type;
1407     if constexpr (KIND == 1) {
1408       assert(value.size() == static_cast<std::uint64_t>(len));
1409       // Outline character constant in ro data if it is not in an initializer.
1410       if (!inInitializer)
1411         return fir::factory::createStringLiteral(builder, getLoc(), value);
1412       // When in an initializer context, construct the literal op itself and do
1413       // not construct another constant object in rodata.
1414       fir::StringLitOp stringLit = builder.createStringLitOp(getLoc(), value);
1415       mlir::Value lenp = builder.createIntegerConstant(
1416           getLoc(), builder.getCharacterLengthType(), len);
1417       return fir::CharBoxValue{stringLit.getResult(), lenp};
1418     }
1419     fir::CharacterType type =
1420         fir::CharacterType::get(builder.getContext(), KIND, len);
1421     auto consLit = [&]() -> fir::StringLitOp {
1422       mlir::MLIRContext *context = builder.getContext();
1423       std::int64_t size = static_cast<std::int64_t>(value.size());
1424       mlir::ShapedType shape = mlir::RankedTensorType::get(
1425           llvm::ArrayRef<std::int64_t>{size},
1426           mlir::IntegerType::get(builder.getContext(), sizeof(ET) * 8));
1427       auto denseAttr = mlir::DenseElementsAttr::get(
1428           shape, llvm::ArrayRef<ET>{value.data(), value.size()});
1429       auto denseTag = mlir::StringAttr::get(context, fir::StringLitOp::xlist());
1430       mlir::NamedAttribute dataAttr(denseTag, denseAttr);
1431       auto sizeTag = mlir::StringAttr::get(context, fir::StringLitOp::size());
1432       mlir::NamedAttribute sizeAttr(sizeTag, builder.getI64IntegerAttr(len));
1433       llvm::SmallVector<mlir::NamedAttribute> attrs = {dataAttr, sizeAttr};
1434       return builder.create<fir::StringLitOp>(
1435           getLoc(), llvm::ArrayRef<mlir::Type>{type}, llvm::None, attrs);
1436     };
1437 
1438     mlir::Value lenp = builder.createIntegerConstant(
1439         getLoc(), builder.getCharacterLengthType(), len);
1440     // When in an initializer context, construct the literal op itself and do
1441     // not construct another constant object in rodata.
1442     if (inInitializer)
1443       return fir::CharBoxValue{consLit().getResult(), lenp};
1444 
1445     // Otherwise, the string is in a plain old expression so "outline" the value
1446     // by hashconsing it to a constant literal object.
1447 
1448     std::string globalName =
1449         fir::factory::uniqueCGIdent("cl", (const char *)value.c_str());
1450     fir::GlobalOp global = builder.getNamedGlobal(globalName);
1451     if (!global)
1452       global = builder.createGlobalConstant(
1453           getLoc(), type, globalName,
1454           [&](fir::FirOpBuilder &builder) {
1455             fir::StringLitOp str = consLit();
1456             builder.create<fir::HasValueOp>(getLoc(), str);
1457           },
1458           builder.createLinkOnceLinkage());
1459     auto addr = builder.create<fir::AddrOfOp>(getLoc(), global.resultType(),
1460                                               global.getSymbol());
1461     return fir::CharBoxValue{addr, lenp};
1462   }
1463 
1464   template <Fortran::common::TypeCategory TC, int KIND>
1465   ExtValue genArrayLit(
1466       const Fortran::evaluate::Constant<Fortran::evaluate::Type<TC, KIND>>
1467           &con) {
1468     mlir::Location loc = getLoc();
1469     mlir::IndexType idxTy = builder.getIndexType();
1470     Fortran::evaluate::ConstantSubscript size =
1471         Fortran::evaluate::GetSize(con.shape());
1472     fir::SequenceType::Shape shape(con.shape().begin(), con.shape().end());
1473     mlir::Type eleTy;
1474     if constexpr (TC == Fortran::common::TypeCategory::Character)
1475       eleTy = converter.genType(TC, KIND, {con.LEN()});
1476     else
1477       eleTy = converter.genType(TC, KIND);
1478     auto arrayTy = fir::SequenceType::get(shape, eleTy);
1479     mlir::Value array;
1480     llvm::SmallVector<mlir::Value> lbounds;
1481     llvm::SmallVector<mlir::Value> extents;
1482     if (!inInitializer || !inInitializer->genRawVals) {
1483       array = builder.create<fir::UndefOp>(loc, arrayTy);
1484       for (auto [lb, extent] : llvm::zip(con.lbounds(), shape)) {
1485         lbounds.push_back(builder.createIntegerConstant(loc, idxTy, lb - 1));
1486         extents.push_back(builder.createIntegerConstant(loc, idxTy, extent));
1487       }
1488     }
1489     if (size == 0) {
1490       if constexpr (TC == Fortran::common::TypeCategory::Character) {
1491         mlir::Value len = builder.createIntegerConstant(loc, idxTy, con.LEN());
1492         return fir::CharArrayBoxValue{array, len, extents, lbounds};
1493       } else {
1494         return fir::ArrayBoxValue{array, extents, lbounds};
1495       }
1496     }
1497     Fortran::evaluate::ConstantSubscripts subscripts = con.lbounds();
1498     auto createIdx = [&]() {
1499       llvm::SmallVector<mlir::Attribute> idx;
1500       for (size_t i = 0; i < subscripts.size(); ++i)
1501         idx.push_back(
1502             builder.getIntegerAttr(idxTy, subscripts[i] - con.lbounds()[i]));
1503       return idx;
1504     };
1505     if constexpr (TC == Fortran::common::TypeCategory::Character) {
1506       assert(array && "array must not be nullptr");
1507       do {
1508         mlir::Value elementVal =
1509             fir::getBase(genScalarLit<KIND>(con.At(subscripts), con.LEN()));
1510         array = builder.create<fir::InsertValueOp>(
1511             loc, arrayTy, array, elementVal, builder.getArrayAttr(createIdx()));
1512       } while (con.IncrementSubscripts(subscripts));
1513       mlir::Value len = builder.createIntegerConstant(loc, idxTy, con.LEN());
1514       return fir::CharArrayBoxValue{array, len, extents, lbounds};
1515     } else {
1516       llvm::SmallVector<mlir::Attribute> rangeStartIdx;
1517       uint64_t rangeSize = 0;
1518       do {
1519         if (inInitializer && inInitializer->genRawVals) {
1520           genRawLit<TC, KIND>(con.At(subscripts));
1521           continue;
1522         }
1523         auto getElementVal = [&]() {
1524           return builder.createConvert(
1525               loc, eleTy,
1526               fir::getBase(genScalarLit<TC, KIND>(con.At(subscripts))));
1527         };
1528         Fortran::evaluate::ConstantSubscripts nextSubscripts = subscripts;
1529         bool nextIsSame = con.IncrementSubscripts(nextSubscripts) &&
1530                           con.At(subscripts) == con.At(nextSubscripts);
1531         if (!rangeSize && !nextIsSame) { // single (non-range) value
1532           array = builder.create<fir::InsertValueOp>(
1533               loc, arrayTy, array, getElementVal(),
1534               builder.getArrayAttr(createIdx()));
1535         } else if (!rangeSize) { // start a range
1536           rangeStartIdx = createIdx();
1537           rangeSize = 1;
1538         } else if (nextIsSame) { // expand a range
1539           ++rangeSize;
1540         } else { // end a range
1541           llvm::SmallVector<int64_t> rangeBounds;
1542           llvm::SmallVector<mlir::Attribute> idx = createIdx();
1543           for (size_t i = 0; i < idx.size(); ++i) {
1544             rangeBounds.push_back(rangeStartIdx[i]
1545                                       .cast<mlir::IntegerAttr>()
1546                                       .getValue()
1547                                       .getSExtValue());
1548             rangeBounds.push_back(
1549                 idx[i].cast<mlir::IntegerAttr>().getValue().getSExtValue());
1550           }
1551           array = builder.create<fir::InsertOnRangeOp>(
1552               loc, arrayTy, array, getElementVal(),
1553               builder.getIndexVectorAttr(rangeBounds));
1554           rangeSize = 0;
1555         }
1556       } while (con.IncrementSubscripts(subscripts));
1557       return fir::ArrayBoxValue{array, extents, lbounds};
1558     }
1559   }
1560 
1561   fir::ExtendedValue genArrayLit(
1562       const Fortran::evaluate::Constant<Fortran::evaluate::SomeDerived> &con) {
1563     mlir::Location loc = getLoc();
1564     mlir::IndexType idxTy = builder.getIndexType();
1565     Fortran::evaluate::ConstantSubscript size =
1566         Fortran::evaluate::GetSize(con.shape());
1567     fir::SequenceType::Shape shape(con.shape().begin(), con.shape().end());
1568     mlir::Type eleTy = converter.genType(con.GetType().GetDerivedTypeSpec());
1569     auto arrayTy = fir::SequenceType::get(shape, eleTy);
1570     mlir::Value array = builder.create<fir::UndefOp>(loc, arrayTy);
1571     llvm::SmallVector<mlir::Value> lbounds;
1572     llvm::SmallVector<mlir::Value> extents;
1573     for (auto [lb, extent] : llvm::zip(con.lbounds(), con.shape())) {
1574       lbounds.push_back(builder.createIntegerConstant(loc, idxTy, lb - 1));
1575       extents.push_back(builder.createIntegerConstant(loc, idxTy, extent));
1576     }
1577     if (size == 0)
1578       return fir::ArrayBoxValue{array, extents, lbounds};
1579     Fortran::evaluate::ConstantSubscripts subscripts = con.lbounds();
1580     do {
1581       mlir::Value derivedVal = fir::getBase(genval(con.At(subscripts)));
1582       llvm::SmallVector<mlir::Attribute> idx;
1583       for (auto [dim, lb] : llvm::zip(subscripts, con.lbounds()))
1584         idx.push_back(builder.getIntegerAttr(idxTy, dim - lb));
1585       array = builder.create<fir::InsertValueOp>(
1586           loc, arrayTy, array, derivedVal, builder.getArrayAttr(idx));
1587     } while (con.IncrementSubscripts(subscripts));
1588     return fir::ArrayBoxValue{array, extents, lbounds};
1589   }
1590 
1591   template <Fortran::common::TypeCategory TC, int KIND>
1592   ExtValue
1593   genval(const Fortran::evaluate::Constant<Fortran::evaluate::Type<TC, KIND>>
1594              &con) {
1595     if (con.Rank() > 0)
1596       return genArrayLit(con);
1597     std::optional<Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>>>
1598         opt = con.GetScalarValue();
1599     assert(opt.has_value() && "constant has no value");
1600     if constexpr (TC == Fortran::common::TypeCategory::Character) {
1601       return genScalarLit<KIND>(opt.value(), con.LEN());
1602     } else {
1603       return genScalarLit<TC, KIND>(opt.value());
1604     }
1605   }
1606   fir::ExtendedValue genval(
1607       const Fortran::evaluate::Constant<Fortran::evaluate::SomeDerived> &con) {
1608     if (con.Rank() > 0)
1609       return genArrayLit(con);
1610     if (auto ctor = con.GetScalarValue())
1611       return genval(ctor.value());
1612     fir::emitFatalError(getLoc(),
1613                         "constant of derived type has no constructor");
1614   }
1615 
1616   template <typename A>
1617   ExtValue genval(const Fortran::evaluate::ArrayConstructor<A> &) {
1618     fir::emitFatalError(getLoc(),
1619                         "array constructor: lowering should not reach here");
1620   }
1621 
1622   ExtValue gen(const Fortran::evaluate::ComplexPart &x) {
1623     mlir::Location loc = getLoc();
1624     auto idxTy = builder.getI32Type();
1625     ExtValue exv = gen(x.complex());
1626     mlir::Value base = fir::getBase(exv);
1627     fir::factory::Complex helper{builder, loc};
1628     mlir::Type eleTy =
1629         helper.getComplexPartType(fir::dyn_cast_ptrEleTy(base.getType()));
1630     mlir::Value offset = builder.createIntegerConstant(
1631         loc, idxTy,
1632         x.part() == Fortran::evaluate::ComplexPart::Part::RE ? 0 : 1);
1633     mlir::Value result = builder.create<fir::CoordinateOp>(
1634         loc, builder.getRefType(eleTy), base, mlir::ValueRange{offset});
1635     return {result};
1636   }
1637   ExtValue genval(const Fortran::evaluate::ComplexPart &x) {
1638     return genLoad(gen(x));
1639   }
1640 
1641   /// Reference to a substring.
1642   ExtValue gen(const Fortran::evaluate::Substring &s) {
1643     // Get base string
1644     auto baseString = std::visit(
1645         Fortran::common::visitors{
1646             [&](const Fortran::evaluate::DataRef &x) { return gen(x); },
1647             [&](const Fortran::evaluate::StaticDataObject::Pointer &p)
1648                 -> ExtValue {
1649               if (std::optional<std::string> str = p->AsString())
1650                 return fir::factory::createStringLiteral(builder, getLoc(),
1651                                                          *str);
1652               // TODO: convert StaticDataObject to Constant<T> and use normal
1653               // constant path. Beware that StaticDataObject data() takes into
1654               // account build machine endianness.
1655               TODO(getLoc(),
1656                    "StaticDataObject::Pointer substring with kind > 1");
1657             },
1658         },
1659         s.parent());
1660     llvm::SmallVector<mlir::Value> bounds;
1661     mlir::Value lower = genunbox(s.lower());
1662     bounds.push_back(lower);
1663     if (Fortran::evaluate::MaybeExtentExpr upperBound = s.upper()) {
1664       mlir::Value upper = genunbox(*upperBound);
1665       bounds.push_back(upper);
1666     }
1667     fir::factory::CharacterExprHelper charHelper{builder, getLoc()};
1668     return baseString.match(
1669         [&](const fir::CharBoxValue &x) -> ExtValue {
1670           return charHelper.createSubstring(x, bounds);
1671         },
1672         [&](const fir::CharArrayBoxValue &) -> ExtValue {
1673           fir::emitFatalError(
1674               getLoc(),
1675               "array substring should be handled in array expression");
1676         },
1677         [&](const auto &) -> ExtValue {
1678           fir::emitFatalError(getLoc(), "substring base is not a CharBox");
1679         });
1680   }
1681 
1682   /// The value of a substring.
1683   ExtValue genval(const Fortran::evaluate::Substring &ss) {
1684     // FIXME: why is the value of a substring being lowered the same as the
1685     // address of a substring?
1686     return gen(ss);
1687   }
1688 
1689   ExtValue genval(const Fortran::evaluate::Subscript &subs) {
1690     if (auto *s = std::get_if<Fortran::evaluate::IndirectSubscriptIntegerExpr>(
1691             &subs.u)) {
1692       if (s->value().Rank() > 0)
1693         fir::emitFatalError(getLoc(), "vector subscript is not scalar");
1694       return {genval(s->value())};
1695     }
1696     fir::emitFatalError(getLoc(), "subscript triple notation is not scalar");
1697   }
1698   ExtValue genSubscript(const Fortran::evaluate::Subscript &subs) {
1699     return genval(subs);
1700   }
1701 
1702   ExtValue gen(const Fortran::evaluate::DataRef &dref) {
1703     return std::visit([&](const auto &x) { return gen(x); }, dref.u);
1704   }
1705   ExtValue genval(const Fortran::evaluate::DataRef &dref) {
1706     return std::visit([&](const auto &x) { return genval(x); }, dref.u);
1707   }
1708 
1709   // Helper function to turn the Component structure into a list of nested
1710   // components, ordered from largest/leftmost to smallest/rightmost:
1711   //  - where only the smallest/rightmost item may be allocatable or a pointer
1712   //    (nested allocatable/pointer components require nested coordinate_of ops)
1713   //  - that does not contain any parent components
1714   //    (the front end places parent components directly in the object)
1715   // Return the object used as the base coordinate for the component chain.
1716   static Fortran::evaluate::DataRef const *
1717   reverseComponents(const Fortran::evaluate::Component &cmpt,
1718                     std::list<const Fortran::evaluate::Component *> &list) {
1719     if (!getLastSym(cmpt).test(Fortran::semantics::Symbol::Flag::ParentComp))
1720       list.push_front(&cmpt);
1721     return std::visit(
1722         Fortran::common::visitors{
1723             [&](const Fortran::evaluate::Component &x) {
1724               if (Fortran::semantics::IsAllocatableOrPointer(getLastSym(x)))
1725                 return &cmpt.base();
1726               return reverseComponents(x, list);
1727             },
1728             [&](auto &) { return &cmpt.base(); },
1729         },
1730         cmpt.base().u);
1731   }
1732 
1733   // Return the coordinate of the component reference
1734   ExtValue genComponent(const Fortran::evaluate::Component &cmpt) {
1735     std::list<const Fortran::evaluate::Component *> list;
1736     const Fortran::evaluate::DataRef *base = reverseComponents(cmpt, list);
1737     llvm::SmallVector<mlir::Value> coorArgs;
1738     ExtValue obj = gen(*base);
1739     mlir::Type ty = fir::dyn_cast_ptrOrBoxEleTy(fir::getBase(obj).getType());
1740     mlir::Location loc = getLoc();
1741     auto fldTy = fir::FieldType::get(&converter.getMLIRContext());
1742     // FIXME: need to thread the LEN type parameters here.
1743     for (const Fortran::evaluate::Component *field : list) {
1744       auto recTy = ty.cast<fir::RecordType>();
1745       const Fortran::semantics::Symbol &sym = getLastSym(*field);
1746       llvm::StringRef name = toStringRef(sym.name());
1747       coorArgs.push_back(builder.create<fir::FieldIndexOp>(
1748           loc, fldTy, name, recTy, fir::getTypeParams(obj)));
1749       ty = recTy.getType(name);
1750     }
1751     ty = builder.getRefType(ty);
1752     return fir::factory::componentToExtendedValue(
1753         builder, loc,
1754         builder.create<fir::CoordinateOp>(loc, ty, fir::getBase(obj),
1755                                           coorArgs));
1756   }
1757 
1758   ExtValue gen(const Fortran::evaluate::Component &cmpt) {
1759     // Components may be pointer or allocatable. In the gen() path, the mutable
1760     // aspect is lost to simplify handling on the client side. To retain the
1761     // mutable aspect, genMutableBoxValue should be used.
1762     return genComponent(cmpt).match(
1763         [&](const fir::MutableBoxValue &mutableBox) {
1764           return fir::factory::genMutableBoxRead(builder, getLoc(), mutableBox);
1765         },
1766         [](auto &box) -> ExtValue { return box; });
1767   }
1768 
1769   ExtValue genval(const Fortran::evaluate::Component &cmpt) {
1770     return genLoad(gen(cmpt));
1771   }
1772 
1773   // Determine the result type after removing `dims` dimensions from the array
1774   // type `arrTy`
1775   mlir::Type genSubType(mlir::Type arrTy, unsigned dims) {
1776     mlir::Type unwrapTy = fir::dyn_cast_ptrOrBoxEleTy(arrTy);
1777     assert(unwrapTy && "must be a pointer or box type");
1778     auto seqTy = unwrapTy.cast<fir::SequenceType>();
1779     llvm::ArrayRef<int64_t> shape = seqTy.getShape();
1780     assert(shape.size() > 0 && "removing columns for sequence sans shape");
1781     assert(dims <= shape.size() && "removing more columns than exist");
1782     fir::SequenceType::Shape newBnds;
1783     // follow Fortran semantics and remove columns (from right)
1784     std::size_t e = shape.size() - dims;
1785     for (decltype(e) i = 0; i < e; ++i)
1786       newBnds.push_back(shape[i]);
1787     if (!newBnds.empty())
1788       return fir::SequenceType::get(newBnds, seqTy.getEleTy());
1789     return seqTy.getEleTy();
1790   }
1791 
1792   // Generate the code for a Bound value.
1793   ExtValue genval(const Fortran::semantics::Bound &bound) {
1794     if (bound.isExplicit()) {
1795       Fortran::semantics::MaybeSubscriptIntExpr sub = bound.GetExplicit();
1796       if (sub.has_value())
1797         return genval(*sub);
1798       return genIntegerConstant<8>(builder.getContext(), 1);
1799     }
1800     TODO(getLoc(), "non explicit semantics::Bound lowering");
1801   }
1802 
1803   static bool isSlice(const Fortran::evaluate::ArrayRef &aref) {
1804     for (const Fortran::evaluate::Subscript &sub : aref.subscript())
1805       if (std::holds_alternative<Fortran::evaluate::Triplet>(sub.u))
1806         return true;
1807     return false;
1808   }
1809 
1810   /// Lower an ArrayRef to a fir.coordinate_of given its lowered base.
1811   ExtValue genCoordinateOp(const ExtValue &array,
1812                            const Fortran::evaluate::ArrayRef &aref) {
1813     mlir::Location loc = getLoc();
1814     // References to array of rank > 1 with non constant shape that are not
1815     // fir.box must be collapsed into an offset computation in lowering already.
1816     // The same is needed with dynamic length character arrays of all ranks.
1817     mlir::Type baseType =
1818         fir::dyn_cast_ptrOrBoxEleTy(fir::getBase(array).getType());
1819     if ((array.rank() > 1 && fir::hasDynamicSize(baseType)) ||
1820         fir::characterWithDynamicLen(fir::unwrapSequenceType(baseType)))
1821       if (!array.getBoxOf<fir::BoxValue>())
1822         return genOffsetAndCoordinateOp(array, aref);
1823     // Generate a fir.coordinate_of with zero based array indexes.
1824     llvm::SmallVector<mlir::Value> args;
1825     for (const auto &subsc : llvm::enumerate(aref.subscript())) {
1826       ExtValue subVal = genSubscript(subsc.value());
1827       assert(fir::isUnboxedValue(subVal) && "subscript must be simple scalar");
1828       mlir::Value val = fir::getBase(subVal);
1829       mlir::Type ty = val.getType();
1830       mlir::Value lb = getLBound(array, subsc.index(), ty);
1831       args.push_back(builder.create<mlir::arith::SubIOp>(loc, ty, val, lb));
1832     }
1833 
1834     mlir::Value base = fir::getBase(array);
1835     auto seqTy =
1836         fir::dyn_cast_ptrOrBoxEleTy(base.getType()).cast<fir::SequenceType>();
1837     assert(args.size() == seqTy.getDimension());
1838     mlir::Type ty = builder.getRefType(seqTy.getEleTy());
1839     auto addr = builder.create<fir::CoordinateOp>(loc, ty, base, args);
1840     return fir::factory::arrayElementToExtendedValue(builder, loc, array, addr);
1841   }
1842 
1843   /// Lower an ArrayRef to a fir.coordinate_of using an element offset instead
1844   /// of array indexes.
1845   /// This generates offset computation from the indexes and length parameters,
1846   /// and use the offset to access the element with a fir.coordinate_of. This
1847   /// must only be used if it is not possible to generate a normal
1848   /// fir.coordinate_of using array indexes (i.e. when the shape information is
1849   /// unavailable in the IR).
1850   ExtValue genOffsetAndCoordinateOp(const ExtValue &array,
1851                                     const Fortran::evaluate::ArrayRef &aref) {
1852     mlir::Location loc = getLoc();
1853     mlir::Value addr = fir::getBase(array);
1854     mlir::Type arrTy = fir::dyn_cast_ptrEleTy(addr.getType());
1855     auto eleTy = arrTy.cast<fir::SequenceType>().getEleTy();
1856     mlir::Type seqTy = builder.getRefType(builder.getVarLenSeqTy(eleTy));
1857     mlir::Type refTy = builder.getRefType(eleTy);
1858     mlir::Value base = builder.createConvert(loc, seqTy, addr);
1859     mlir::IndexType idxTy = builder.getIndexType();
1860     mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
1861     mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
1862     auto getLB = [&](const auto &arr, unsigned dim) -> mlir::Value {
1863       return arr.getLBounds().empty() ? one : arr.getLBounds()[dim];
1864     };
1865     auto genFullDim = [&](const auto &arr, mlir::Value delta) -> mlir::Value {
1866       mlir::Value total = zero;
1867       assert(arr.getExtents().size() == aref.subscript().size());
1868       delta = builder.createConvert(loc, idxTy, delta);
1869       unsigned dim = 0;
1870       for (auto [ext, sub] : llvm::zip(arr.getExtents(), aref.subscript())) {
1871         ExtValue subVal = genSubscript(sub);
1872         assert(fir::isUnboxedValue(subVal));
1873         mlir::Value val =
1874             builder.createConvert(loc, idxTy, fir::getBase(subVal));
1875         mlir::Value lb = builder.createConvert(loc, idxTy, getLB(arr, dim));
1876         mlir::Value diff = builder.create<mlir::arith::SubIOp>(loc, val, lb);
1877         mlir::Value prod =
1878             builder.create<mlir::arith::MulIOp>(loc, delta, diff);
1879         total = builder.create<mlir::arith::AddIOp>(loc, prod, total);
1880         if (ext)
1881           delta = builder.create<mlir::arith::MulIOp>(loc, delta, ext);
1882         ++dim;
1883       }
1884       mlir::Type origRefTy = refTy;
1885       if (fir::factory::CharacterExprHelper::isCharacterScalar(refTy)) {
1886         fir::CharacterType chTy =
1887             fir::factory::CharacterExprHelper::getCharacterType(refTy);
1888         if (fir::characterWithDynamicLen(chTy)) {
1889           mlir::MLIRContext *ctx = builder.getContext();
1890           fir::KindTy kind =
1891               fir::factory::CharacterExprHelper::getCharacterKind(chTy);
1892           fir::CharacterType singleTy =
1893               fir::CharacterType::getSingleton(ctx, kind);
1894           refTy = builder.getRefType(singleTy);
1895           mlir::Type seqRefTy =
1896               builder.getRefType(builder.getVarLenSeqTy(singleTy));
1897           base = builder.createConvert(loc, seqRefTy, base);
1898         }
1899       }
1900       auto coor = builder.create<fir::CoordinateOp>(
1901           loc, refTy, base, llvm::ArrayRef<mlir::Value>{total});
1902       // Convert to expected, original type after address arithmetic.
1903       return builder.createConvert(loc, origRefTy, coor);
1904     };
1905     return array.match(
1906         [&](const fir::ArrayBoxValue &arr) -> ExtValue {
1907           // FIXME: this check can be removed when slicing is implemented
1908           if (isSlice(aref))
1909             fir::emitFatalError(
1910                 getLoc(),
1911                 "slice should be handled in array expression context");
1912           return genFullDim(arr, one);
1913         },
1914         [&](const fir::CharArrayBoxValue &arr) -> ExtValue {
1915           mlir::Value delta = arr.getLen();
1916           // If the length is known in the type, fir.coordinate_of will
1917           // already take the length into account.
1918           if (fir::factory::CharacterExprHelper::hasConstantLengthInType(arr))
1919             delta = one;
1920           return fir::CharBoxValue(genFullDim(arr, delta), arr.getLen());
1921         },
1922         [&](const fir::BoxValue &arr) -> ExtValue {
1923           // CoordinateOp for BoxValue is not generated here. The dimensions
1924           // must be kept in the fir.coordinate_op so that potential fir.box
1925           // strides can be applied by codegen.
1926           fir::emitFatalError(
1927               loc, "internal: BoxValue in dim-collapsed fir.coordinate_of");
1928         },
1929         [&](const auto &) -> ExtValue {
1930           fir::emitFatalError(loc, "internal: array lowering failed");
1931         });
1932   }
1933 
1934   /// Lower an ArrayRef to a fir.array_coor.
1935   ExtValue genArrayCoorOp(const ExtValue &exv,
1936                           const Fortran::evaluate::ArrayRef &aref) {
1937     mlir::Location loc = getLoc();
1938     mlir::Value addr = fir::getBase(exv);
1939     mlir::Type arrTy = fir::dyn_cast_ptrOrBoxEleTy(addr.getType());
1940     mlir::Type eleTy = arrTy.cast<fir::SequenceType>().getEleTy();
1941     mlir::Type refTy = builder.getRefType(eleTy);
1942     mlir::IndexType idxTy = builder.getIndexType();
1943     llvm::SmallVector<mlir::Value> arrayCoorArgs;
1944     // The ArrayRef is expected to be scalar here, arrays are handled in array
1945     // expression lowering. So no vector subscript or triplet is expected here.
1946     for (const auto &sub : aref.subscript()) {
1947       ExtValue subVal = genSubscript(sub);
1948       assert(fir::isUnboxedValue(subVal));
1949       arrayCoorArgs.push_back(
1950           builder.createConvert(loc, idxTy, fir::getBase(subVal)));
1951     }
1952     mlir::Value shape = builder.createShape(loc, exv);
1953     mlir::Value elementAddr = builder.create<fir::ArrayCoorOp>(
1954         loc, refTy, addr, shape, /*slice=*/mlir::Value{}, arrayCoorArgs,
1955         fir::getTypeParams(exv));
1956     return fir::factory::arrayElementToExtendedValue(builder, loc, exv,
1957                                                      elementAddr);
1958   }
1959 
1960   /// Return the coordinate of the array reference.
1961   ExtValue gen(const Fortran::evaluate::ArrayRef &aref) {
1962     ExtValue base = aref.base().IsSymbol() ? gen(getFirstSym(aref.base()))
1963                                            : gen(aref.base().GetComponent());
1964     // Check for command-line override to use array_coor op.
1965     if (generateArrayCoordinate)
1966       return genArrayCoorOp(base, aref);
1967     // Otherwise, use coordinate_of op.
1968     return genCoordinateOp(base, aref);
1969   }
1970 
1971   /// Return lower bounds of \p box in dimension \p dim. The returned value
1972   /// has type \ty.
1973   mlir::Value getLBound(const ExtValue &box, unsigned dim, mlir::Type ty) {
1974     assert(box.rank() > 0 && "must be an array");
1975     mlir::Location loc = getLoc();
1976     mlir::Value one = builder.createIntegerConstant(loc, ty, 1);
1977     mlir::Value lb = fir::factory::readLowerBound(builder, loc, box, dim, one);
1978     return builder.createConvert(loc, ty, lb);
1979   }
1980 
1981   ExtValue genval(const Fortran::evaluate::ArrayRef &aref) {
1982     return genLoad(gen(aref));
1983   }
1984 
1985   ExtValue gen(const Fortran::evaluate::CoarrayRef &coref) {
1986     return Fortran::lower::CoarrayExprHelper{converter, getLoc(), symMap}
1987         .genAddr(coref);
1988   }
1989 
1990   ExtValue genval(const Fortran::evaluate::CoarrayRef &coref) {
1991     return Fortran::lower::CoarrayExprHelper{converter, getLoc(), symMap}
1992         .genValue(coref);
1993   }
1994 
1995   template <typename A>
1996   ExtValue gen(const Fortran::evaluate::Designator<A> &des) {
1997     return std::visit([&](const auto &x) { return gen(x); }, des.u);
1998   }
1999   template <typename A>
2000   ExtValue genval(const Fortran::evaluate::Designator<A> &des) {
2001     return std::visit([&](const auto &x) { return genval(x); }, des.u);
2002   }
2003 
2004   mlir::Type genType(const Fortran::evaluate::DynamicType &dt) {
2005     if (dt.category() != Fortran::common::TypeCategory::Derived)
2006       return converter.genType(dt.category(), dt.kind());
2007     return converter.genType(dt.GetDerivedTypeSpec());
2008   }
2009 
2010   /// Lower a function reference
2011   template <typename A>
2012   ExtValue genFunctionRef(const Fortran::evaluate::FunctionRef<A> &funcRef) {
2013     if (!funcRef.GetType().has_value())
2014       fir::emitFatalError(getLoc(), "a function must have a type");
2015     mlir::Type resTy = genType(*funcRef.GetType());
2016     return genProcedureRef(funcRef, {resTy});
2017   }
2018 
2019   /// Lower function call `funcRef` and return a reference to the resultant
2020   /// value. This is required for lowering expressions such as `f1(f2(v))`.
2021   template <typename A>
2022   ExtValue gen(const Fortran::evaluate::FunctionRef<A> &funcRef) {
2023     ExtValue retVal = genFunctionRef(funcRef);
2024     mlir::Type resultType = converter.genType(toEvExpr(funcRef));
2025     return placeScalarValueInMemory(builder, getLoc(), retVal, resultType);
2026   }
2027 
2028   /// Helper to lower intrinsic arguments for inquiry intrinsic.
2029   ExtValue
2030   lowerIntrinsicArgumentAsInquired(const Fortran::lower::SomeExpr &expr) {
2031     if (Fortran::evaluate::IsAllocatableOrPointerObject(
2032             expr, converter.getFoldingContext()))
2033       return genMutableBoxValue(expr);
2034     /// Do not create temps for array sections whose properties only need to be
2035     /// inquired: create a descriptor that will be inquired.
2036     if (Fortran::evaluate::IsVariable(expr) && isArray(expr) &&
2037         !Fortran::evaluate::UnwrapWholeSymbolOrComponentDataRef(expr))
2038       return lowerIntrinsicArgumentAsBox(expr);
2039     return gen(expr);
2040   }
2041 
2042   /// Helper to lower intrinsic arguments to a fir::BoxValue.
2043   /// It preserves all the non default lower bounds/non deferred length
2044   /// parameter information.
2045   ExtValue lowerIntrinsicArgumentAsBox(const Fortran::lower::SomeExpr &expr) {
2046     mlir::Location loc = getLoc();
2047     ExtValue exv = genBoxArg(expr);
2048     mlir::Value box = builder.createBox(loc, exv);
2049     return fir::BoxValue(
2050         box, fir::factory::getNonDefaultLowerBounds(builder, loc, exv),
2051         fir::factory::getNonDeferredLengthParams(exv));
2052   }
2053 
2054   /// Generate a call to an intrinsic function.
2055   ExtValue
2056   genIntrinsicRef(const Fortran::evaluate::ProcedureRef &procRef,
2057                   const Fortran::evaluate::SpecificIntrinsic &intrinsic,
2058                   llvm::Optional<mlir::Type> resultType) {
2059     llvm::SmallVector<ExtValue> operands;
2060 
2061     llvm::StringRef name = intrinsic.name;
2062     mlir::Location loc = getLoc();
2063     if (Fortran::lower::intrinsicRequiresCustomOptionalHandling(
2064             procRef, intrinsic, converter)) {
2065       using ExvAndPresence = std::pair<ExtValue, llvm::Optional<mlir::Value>>;
2066       llvm::SmallVector<ExvAndPresence, 4> operands;
2067       auto prepareOptionalArg = [&](const Fortran::lower::SomeExpr &expr) {
2068         ExtValue optionalArg = lowerIntrinsicArgumentAsInquired(expr);
2069         mlir::Value isPresent =
2070             genActualIsPresentTest(builder, loc, optionalArg);
2071         operands.emplace_back(optionalArg, isPresent);
2072       };
2073       auto prepareOtherArg = [&](const Fortran::lower::SomeExpr &expr) {
2074         operands.emplace_back(genval(expr), llvm::None);
2075       };
2076       Fortran::lower::prepareCustomIntrinsicArgument(
2077           procRef, intrinsic, resultType, prepareOptionalArg, prepareOtherArg,
2078           converter);
2079 
2080       auto getArgument = [&](std::size_t i) -> ExtValue {
2081         if (fir::conformsWithPassByRef(
2082                 fir::getBase(operands[i].first).getType()))
2083           return genLoad(operands[i].first);
2084         return operands[i].first;
2085       };
2086       auto isPresent = [&](std::size_t i) -> llvm::Optional<mlir::Value> {
2087         return operands[i].second;
2088       };
2089       return Fortran::lower::lowerCustomIntrinsic(
2090           builder, loc, name, resultType, isPresent, getArgument,
2091           operands.size(), stmtCtx);
2092     }
2093 
2094     const Fortran::lower::IntrinsicArgumentLoweringRules *argLowering =
2095         Fortran::lower::getIntrinsicArgumentLowering(name);
2096     for (const auto &[arg, dummy] :
2097          llvm::zip(procRef.arguments(),
2098                    intrinsic.characteristics.value().dummyArguments)) {
2099       auto *expr = Fortran::evaluate::UnwrapExpr<Fortran::lower::SomeExpr>(arg);
2100       if (!expr) {
2101         // Absent optional.
2102         operands.emplace_back(Fortran::lower::getAbsentIntrinsicArgument());
2103         continue;
2104       }
2105       if (!argLowering) {
2106         // No argument lowering instruction, lower by value.
2107         operands.emplace_back(genval(*expr));
2108         continue;
2109       }
2110       // Ad-hoc argument lowering handling.
2111       Fortran::lower::ArgLoweringRule argRules =
2112           Fortran::lower::lowerIntrinsicArgumentAs(loc, *argLowering,
2113                                                    dummy.name);
2114       if (argRules.handleDynamicOptional &&
2115           Fortran::evaluate::MayBePassedAsAbsentOptional(
2116               *expr, converter.getFoldingContext())) {
2117         ExtValue optional = lowerIntrinsicArgumentAsInquired(*expr);
2118         mlir::Value isPresent = genActualIsPresentTest(builder, loc, optional);
2119         switch (argRules.lowerAs) {
2120         case Fortran::lower::LowerIntrinsicArgAs::Value:
2121           operands.emplace_back(
2122               genOptionalValue(builder, loc, optional, isPresent));
2123           continue;
2124         case Fortran::lower::LowerIntrinsicArgAs::Addr:
2125           operands.emplace_back(
2126               genOptionalAddr(builder, loc, optional, isPresent));
2127           continue;
2128         case Fortran::lower::LowerIntrinsicArgAs::Box:
2129           operands.emplace_back(
2130               genOptionalBox(builder, loc, optional, isPresent));
2131           continue;
2132         case Fortran::lower::LowerIntrinsicArgAs::Inquired:
2133           operands.emplace_back(optional);
2134           continue;
2135         }
2136         llvm_unreachable("bad switch");
2137       }
2138       switch (argRules.lowerAs) {
2139       case Fortran::lower::LowerIntrinsicArgAs::Value:
2140         operands.emplace_back(genval(*expr));
2141         continue;
2142       case Fortran::lower::LowerIntrinsicArgAs::Addr:
2143         operands.emplace_back(gen(*expr));
2144         continue;
2145       case Fortran::lower::LowerIntrinsicArgAs::Box:
2146         operands.emplace_back(lowerIntrinsicArgumentAsBox(*expr));
2147         continue;
2148       case Fortran::lower::LowerIntrinsicArgAs::Inquired:
2149         operands.emplace_back(lowerIntrinsicArgumentAsInquired(*expr));
2150         continue;
2151       }
2152       llvm_unreachable("bad switch");
2153     }
2154     // Let the intrinsic library lower the intrinsic procedure call
2155     return Fortran::lower::genIntrinsicCall(builder, getLoc(), name, resultType,
2156                                             operands, stmtCtx);
2157   }
2158 
2159   template <typename A>
2160   bool isCharacterType(const A &exp) {
2161     if (auto type = exp.GetType())
2162       return type->category() == Fortran::common::TypeCategory::Character;
2163     return false;
2164   }
2165 
2166   /// helper to detect statement functions
2167   static bool
2168   isStatementFunctionCall(const Fortran::evaluate::ProcedureRef &procRef) {
2169     if (const Fortran::semantics::Symbol *symbol = procRef.proc().GetSymbol())
2170       if (const auto *details =
2171               symbol->detailsIf<Fortran::semantics::SubprogramDetails>())
2172         return details->stmtFunction().has_value();
2173     return false;
2174   }
2175   /// Generate Statement function calls
2176   ExtValue genStmtFunctionRef(const Fortran::evaluate::ProcedureRef &procRef) {
2177     const Fortran::semantics::Symbol *symbol = procRef.proc().GetSymbol();
2178     assert(symbol && "expected symbol in ProcedureRef of statement functions");
2179     const auto &details = symbol->get<Fortran::semantics::SubprogramDetails>();
2180 
2181     // Statement functions have their own scope, we just need to associate
2182     // the dummy symbols to argument expressions. They are no
2183     // optional/alternate return arguments. Statement functions cannot be
2184     // recursive (directly or indirectly) so it is safe to add dummy symbols to
2185     // the local map here.
2186     symMap.pushScope();
2187     for (auto [arg, bind] :
2188          llvm::zip(details.dummyArgs(), procRef.arguments())) {
2189       assert(arg && "alternate return in statement function");
2190       assert(bind && "optional argument in statement function");
2191       const auto *expr = bind->UnwrapExpr();
2192       // TODO: assumed type in statement function, that surprisingly seems
2193       // allowed, probably because nobody thought of restricting this usage.
2194       // gfortran/ifort compiles this.
2195       assert(expr && "assumed type used as statement function argument");
2196       // As per Fortran 2018 C1580, statement function arguments can only be
2197       // scalars, so just pass the box with the address. The only care is to
2198       // to use the dummy character explicit length if any instead of the
2199       // actual argument length (that can be bigger).
2200       if (const Fortran::semantics::DeclTypeSpec *type = arg->GetType())
2201         if (type->category() == Fortran::semantics::DeclTypeSpec::Character)
2202           if (const Fortran::semantics::MaybeIntExpr &lenExpr =
2203                   type->characterTypeSpec().length().GetExplicit()) {
2204             mlir::Value len = fir::getBase(genval(*lenExpr));
2205             // F2018 7.4.4.2 point 5.
2206             len = Fortran::lower::genMaxWithZero(builder, getLoc(), len);
2207             symMap.addSymbol(*arg,
2208                              replaceScalarCharacterLength(gen(*expr), len));
2209             continue;
2210           }
2211       symMap.addSymbol(*arg, gen(*expr));
2212     }
2213 
2214     // Explicitly map statement function host associated symbols to their
2215     // parent scope lowered symbol box.
2216     for (const Fortran::semantics::SymbolRef &sym :
2217          Fortran::evaluate::CollectSymbols(*details.stmtFunction()))
2218       if (const auto *details =
2219               sym->detailsIf<Fortran::semantics::HostAssocDetails>())
2220         if (!symMap.lookupSymbol(*sym))
2221           symMap.addSymbol(*sym, gen(details->symbol()));
2222 
2223     ExtValue result = genval(details.stmtFunction().value());
2224     LLVM_DEBUG(llvm::dbgs() << "stmt-function: " << result << '\n');
2225     symMap.popScope();
2226     return result;
2227   }
2228 
2229   /// Helper to package a Value and its properties into an ExtendedValue.
2230   static ExtValue toExtendedValue(mlir::Location loc, mlir::Value base,
2231                                   llvm::ArrayRef<mlir::Value> extents,
2232                                   llvm::ArrayRef<mlir::Value> lengths) {
2233     mlir::Type type = base.getType();
2234     if (type.isa<fir::BoxType>())
2235       return fir::BoxValue(base, /*lbounds=*/{}, lengths, extents);
2236     type = fir::unwrapRefType(type);
2237     if (type.isa<fir::BoxType>())
2238       return fir::MutableBoxValue(base, lengths, /*mutableProperties*/ {});
2239     if (auto seqTy = type.dyn_cast<fir::SequenceType>()) {
2240       if (seqTy.getDimension() != extents.size())
2241         fir::emitFatalError(loc, "incorrect number of extents for array");
2242       if (seqTy.getEleTy().isa<fir::CharacterType>()) {
2243         if (lengths.empty())
2244           fir::emitFatalError(loc, "missing length for character");
2245         assert(lengths.size() == 1);
2246         return fir::CharArrayBoxValue(base, lengths[0], extents);
2247       }
2248       return fir::ArrayBoxValue(base, extents);
2249     }
2250     if (type.isa<fir::CharacterType>()) {
2251       if (lengths.empty())
2252         fir::emitFatalError(loc, "missing length for character");
2253       assert(lengths.size() == 1);
2254       return fir::CharBoxValue(base, lengths[0]);
2255     }
2256     return base;
2257   }
2258 
2259   // Find the argument that corresponds to the host associations.
2260   // Verify some assumptions about how the signature was built here.
2261   [[maybe_unused]] static unsigned findHostAssocTuplePos(mlir::FuncOp fn) {
2262     // Scan the argument list from last to first as the host associations are
2263     // appended for now.
2264     for (unsigned i = fn.getNumArguments(); i > 0; --i)
2265       if (fn.getArgAttr(i - 1, fir::getHostAssocAttrName())) {
2266         // Host assoc tuple must be last argument (for now).
2267         assert(i == fn.getNumArguments() && "tuple must be last");
2268         return i - 1;
2269       }
2270     llvm_unreachable("anyFuncArgsHaveAttr failed");
2271   }
2272 
2273   /// Create a contiguous temporary array with the same shape,
2274   /// length parameters and type as mold. It is up to the caller to deallocate
2275   /// the temporary.
2276   ExtValue genArrayTempFromMold(const ExtValue &mold,
2277                                 llvm::StringRef tempName) {
2278     mlir::Type type = fir::dyn_cast_ptrOrBoxEleTy(fir::getBase(mold).getType());
2279     assert(type && "expected descriptor or memory type");
2280     mlir::Location loc = getLoc();
2281     llvm::SmallVector<mlir::Value> extents =
2282         fir::factory::getExtents(builder, loc, mold);
2283     llvm::SmallVector<mlir::Value> allocMemTypeParams =
2284         fir::getTypeParams(mold);
2285     mlir::Value charLen;
2286     mlir::Type elementType = fir::unwrapSequenceType(type);
2287     if (auto charType = elementType.dyn_cast<fir::CharacterType>()) {
2288       charLen = allocMemTypeParams.empty()
2289                     ? fir::factory::readCharLen(builder, loc, mold)
2290                     : allocMemTypeParams[0];
2291       if (charType.hasDynamicLen() && allocMemTypeParams.empty())
2292         allocMemTypeParams.push_back(charLen);
2293     } else if (fir::hasDynamicSize(elementType)) {
2294       TODO(loc, "Creating temporary for derived type with length parameters");
2295     }
2296 
2297     mlir::Value temp = builder.create<fir::AllocMemOp>(
2298         loc, type, tempName, allocMemTypeParams, extents);
2299     if (fir::unwrapSequenceType(type).isa<fir::CharacterType>())
2300       return fir::CharArrayBoxValue{temp, charLen, extents};
2301     return fir::ArrayBoxValue{temp, extents};
2302   }
2303 
2304   /// Copy \p source array into \p dest array. Both arrays must be
2305   /// conforming, but neither array must be contiguous.
2306   void genArrayCopy(ExtValue dest, ExtValue source) {
2307     return createSomeArrayAssignment(converter, dest, source, symMap, stmtCtx);
2308   }
2309 
2310   /// Lower a non-elemental procedure reference and read allocatable and pointer
2311   /// results into normal values.
2312   ExtValue genProcedureRef(const Fortran::evaluate::ProcedureRef &procRef,
2313                            llvm::Optional<mlir::Type> resultType) {
2314     ExtValue res = genRawProcedureRef(procRef, resultType);
2315     // In most contexts, pointers and allocatable do not appear as allocatable
2316     // or pointer variable on the caller side (see 8.5.3 note 1 for
2317     // allocatables). The few context where this can happen must call
2318     // genRawProcedureRef directly.
2319     if (const auto *box = res.getBoxOf<fir::MutableBoxValue>())
2320       return fir::factory::genMutableBoxRead(builder, getLoc(), *box);
2321     return res;
2322   }
2323 
2324   /// Given a call site for which the arguments were already lowered, generate
2325   /// the call and return the result. This function deals with explicit result
2326   /// allocation and lowering if needed. It also deals with passing the host
2327   /// link to internal procedures.
2328   ExtValue genCallOpAndResult(Fortran::lower::CallerInterface &caller,
2329                               mlir::FunctionType callSiteType,
2330                               llvm::Optional<mlir::Type> resultType) {
2331     mlir::Location loc = getLoc();
2332     using PassBy = Fortran::lower::CallerInterface::PassEntityBy;
2333     // Handle cases where caller must allocate the result or a fir.box for it.
2334     bool mustPopSymMap = false;
2335     if (caller.mustMapInterfaceSymbols()) {
2336       symMap.pushScope();
2337       mustPopSymMap = true;
2338       Fortran::lower::mapCallInterfaceSymbols(converter, caller, symMap);
2339     }
2340     // If this is an indirect call, retrieve the function address. Also retrieve
2341     // the result length if this is a character function (note that this length
2342     // will be used only if there is no explicit length in the local interface).
2343     mlir::Value funcPointer;
2344     mlir::Value charFuncPointerLength;
2345     if (const Fortran::semantics::Symbol *sym =
2346             caller.getIfIndirectCallSymbol()) {
2347       funcPointer = symMap.lookupSymbol(*sym).getAddr();
2348       if (!funcPointer)
2349         fir::emitFatalError(loc, "failed to find indirect call symbol address");
2350       if (fir::isCharacterProcedureTuple(funcPointer.getType(),
2351                                          /*acceptRawFunc=*/false))
2352         std::tie(funcPointer, charFuncPointerLength) =
2353             fir::factory::extractCharacterProcedureTuple(builder, loc,
2354                                                          funcPointer);
2355     }
2356 
2357     mlir::IndexType idxTy = builder.getIndexType();
2358     auto lowerSpecExpr = [&](const auto &expr) -> mlir::Value {
2359       return builder.createConvert(
2360           loc, idxTy, fir::getBase(converter.genExprValue(expr, stmtCtx)));
2361     };
2362     llvm::SmallVector<mlir::Value> resultLengths;
2363     auto allocatedResult = [&]() -> llvm::Optional<ExtValue> {
2364       llvm::SmallVector<mlir::Value> extents;
2365       llvm::SmallVector<mlir::Value> lengths;
2366       if (!caller.callerAllocateResult())
2367         return {};
2368       mlir::Type type = caller.getResultStorageType();
2369       if (type.isa<fir::SequenceType>())
2370         caller.walkResultExtents([&](const Fortran::lower::SomeExpr &e) {
2371           extents.emplace_back(lowerSpecExpr(e));
2372         });
2373       caller.walkResultLengths([&](const Fortran::lower::SomeExpr &e) {
2374         lengths.emplace_back(lowerSpecExpr(e));
2375       });
2376 
2377       // Result length parameters should not be provided to box storage
2378       // allocation and save_results, but they are still useful information to
2379       // keep in the ExtendedValue if non-deferred.
2380       if (!type.isa<fir::BoxType>()) {
2381         if (fir::isa_char(fir::unwrapSequenceType(type)) && lengths.empty()) {
2382           // Calling an assumed length function. This is only possible if this
2383           // is a call to a character dummy procedure.
2384           if (!charFuncPointerLength)
2385             fir::emitFatalError(loc, "failed to retrieve character function "
2386                                      "length while calling it");
2387           lengths.push_back(charFuncPointerLength);
2388         }
2389         resultLengths = lengths;
2390       }
2391 
2392       if (!extents.empty() || !lengths.empty()) {
2393         auto *bldr = &converter.getFirOpBuilder();
2394         auto stackSaveFn = fir::factory::getLlvmStackSave(builder);
2395         auto stackSaveSymbol = bldr->getSymbolRefAttr(stackSaveFn.getName());
2396         mlir::Value sp =
2397             bldr->create<fir::CallOp>(
2398                     loc, stackSaveFn.getFunctionType().getResults(),
2399                     stackSaveSymbol, mlir::ValueRange{})
2400                 .getResult(0);
2401         stmtCtx.attachCleanup([bldr, loc, sp]() {
2402           auto stackRestoreFn = fir::factory::getLlvmStackRestore(*bldr);
2403           auto stackRestoreSymbol =
2404               bldr->getSymbolRefAttr(stackRestoreFn.getName());
2405           bldr->create<fir::CallOp>(
2406               loc, stackRestoreFn.getFunctionType().getResults(),
2407               stackRestoreSymbol, mlir::ValueRange{sp});
2408         });
2409       }
2410       mlir::Value temp =
2411           builder.createTemporary(loc, type, ".result", extents, resultLengths);
2412       return toExtendedValue(loc, temp, extents, lengths);
2413     }();
2414 
2415     if (mustPopSymMap)
2416       symMap.popScope();
2417 
2418     // Place allocated result or prepare the fir.save_result arguments.
2419     mlir::Value arrayResultShape;
2420     if (allocatedResult) {
2421       if (std::optional<Fortran::lower::CallInterface<
2422               Fortran::lower::CallerInterface>::PassedEntity>
2423               resultArg = caller.getPassedResult()) {
2424         if (resultArg->passBy == PassBy::AddressAndLength)
2425           caller.placeAddressAndLengthInput(*resultArg,
2426                                             fir::getBase(*allocatedResult),
2427                                             fir::getLen(*allocatedResult));
2428         else if (resultArg->passBy == PassBy::BaseAddress)
2429           caller.placeInput(*resultArg, fir::getBase(*allocatedResult));
2430         else
2431           fir::emitFatalError(
2432               loc, "only expect character scalar result to be passed by ref");
2433       } else {
2434         assert(caller.mustSaveResult());
2435         arrayResultShape = allocatedResult->match(
2436             [&](const fir::CharArrayBoxValue &) {
2437               return builder.createShape(loc, *allocatedResult);
2438             },
2439             [&](const fir::ArrayBoxValue &) {
2440               return builder.createShape(loc, *allocatedResult);
2441             },
2442             [&](const auto &) { return mlir::Value{}; });
2443       }
2444     }
2445 
2446     // In older Fortran, procedure argument types are inferred. This may lead
2447     // different view of what the function signature is in different locations.
2448     // Casts are inserted as needed below to accommodate this.
2449 
2450     // The mlir::FuncOp type prevails, unless it has a different number of
2451     // arguments which can happen in legal program if it was passed as a dummy
2452     // procedure argument earlier with no further type information.
2453     mlir::SymbolRefAttr funcSymbolAttr;
2454     bool addHostAssociations = false;
2455     if (!funcPointer) {
2456       mlir::FunctionType funcOpType = caller.getFuncOp().getFunctionType();
2457       mlir::SymbolRefAttr symbolAttr =
2458           builder.getSymbolRefAttr(caller.getMangledName());
2459       if (callSiteType.getNumResults() == funcOpType.getNumResults() &&
2460           callSiteType.getNumInputs() + 1 == funcOpType.getNumInputs() &&
2461           fir::anyFuncArgsHaveAttr(caller.getFuncOp(),
2462                                    fir::getHostAssocAttrName())) {
2463         // The number of arguments is off by one, and we're lowering a function
2464         // with host associations. Modify call to include host associations
2465         // argument by appending the value at the end of the operands.
2466         assert(funcOpType.getInput(findHostAssocTuplePos(caller.getFuncOp())) ==
2467                converter.hostAssocTupleValue().getType());
2468         addHostAssociations = true;
2469       }
2470       if (!addHostAssociations &&
2471           (callSiteType.getNumResults() != funcOpType.getNumResults() ||
2472            callSiteType.getNumInputs() != funcOpType.getNumInputs())) {
2473         // Deal with argument number mismatch by making a function pointer so
2474         // that function type cast can be inserted. Do not emit a warning here
2475         // because this can happen in legal program if the function is not
2476         // defined here and it was first passed as an argument without any more
2477         // information.
2478         funcPointer =
2479             builder.create<fir::AddrOfOp>(loc, funcOpType, symbolAttr);
2480       } else if (callSiteType.getResults() != funcOpType.getResults()) {
2481         // Implicit interface result type mismatch are not standard Fortran, but
2482         // some compilers are not complaining about it.  The front end is not
2483         // protecting lowering from this currently. Support this with a
2484         // discouraging warning.
2485         LLVM_DEBUG(mlir::emitWarning(
2486             loc, "a return type mismatch is not standard compliant and may "
2487                  "lead to undefined behavior."));
2488         // Cast the actual function to the current caller implicit type because
2489         // that is the behavior we would get if we could not see the definition.
2490         funcPointer =
2491             builder.create<fir::AddrOfOp>(loc, funcOpType, symbolAttr);
2492       } else {
2493         funcSymbolAttr = symbolAttr;
2494       }
2495     }
2496 
2497     mlir::FunctionType funcType =
2498         funcPointer ? callSiteType : caller.getFuncOp().getFunctionType();
2499     llvm::SmallVector<mlir::Value> operands;
2500     // First operand of indirect call is the function pointer. Cast it to
2501     // required function type for the call to handle procedures that have a
2502     // compatible interface in Fortran, but that have different signatures in
2503     // FIR.
2504     if (funcPointer) {
2505       operands.push_back(
2506           funcPointer.getType().isa<fir::BoxProcType>()
2507               ? builder.create<fir::BoxAddrOp>(loc, funcType, funcPointer)
2508               : builder.createConvert(loc, funcType, funcPointer));
2509     }
2510 
2511     // Deal with potential mismatches in arguments types. Passing an array to a
2512     // scalar argument should for instance be tolerated here.
2513     bool callingImplicitInterface = caller.canBeCalledViaImplicitInterface();
2514     for (auto [fst, snd] :
2515          llvm::zip(caller.getInputs(), funcType.getInputs())) {
2516       // When passing arguments to a procedure that can be called an implicit
2517       // interface, allow character actual arguments to be passed to dummy
2518       // arguments of any type and vice versa
2519       mlir::Value cast;
2520       auto *context = builder.getContext();
2521       if (snd.isa<fir::BoxProcType>() &&
2522           fst.getType().isa<mlir::FunctionType>()) {
2523         auto funcTy = mlir::FunctionType::get(context, llvm::None, llvm::None);
2524         auto boxProcTy = builder.getBoxProcType(funcTy);
2525         if (mlir::Value host = argumentHostAssocs(converter, fst)) {
2526           cast = builder.create<fir::EmboxProcOp>(
2527               loc, boxProcTy, llvm::ArrayRef<mlir::Value>{fst, host});
2528         } else {
2529           cast = builder.create<fir::EmboxProcOp>(loc, boxProcTy, fst);
2530         }
2531       } else {
2532         cast = builder.convertWithSemantics(loc, snd, fst,
2533                                             callingImplicitInterface);
2534       }
2535       operands.push_back(cast);
2536     }
2537 
2538     // Add host associations as necessary.
2539     if (addHostAssociations)
2540       operands.push_back(converter.hostAssocTupleValue());
2541 
2542     auto call = builder.create<fir::CallOp>(loc, funcType.getResults(),
2543                                             funcSymbolAttr, operands);
2544 
2545     if (caller.mustSaveResult())
2546       builder.create<fir::SaveResultOp>(
2547           loc, call.getResult(0), fir::getBase(allocatedResult.getValue()),
2548           arrayResultShape, resultLengths);
2549 
2550     if (allocatedResult) {
2551       allocatedResult->match(
2552           [&](const fir::MutableBoxValue &box) {
2553             if (box.isAllocatable()) {
2554               // 9.7.3.2 point 4. Finalize allocatables.
2555               fir::FirOpBuilder *bldr = &converter.getFirOpBuilder();
2556               stmtCtx.attachCleanup([bldr, loc, box]() {
2557                 fir::factory::genFinalization(*bldr, loc, box);
2558               });
2559             }
2560           },
2561           [](const auto &) {});
2562       return *allocatedResult;
2563     }
2564 
2565     if (!resultType.hasValue())
2566       return mlir::Value{}; // subroutine call
2567     // For now, Fortran return values are implemented with a single MLIR
2568     // function return value.
2569     assert(call.getNumResults() == 1 &&
2570            "Expected exactly one result in FUNCTION call");
2571     return call.getResult(0);
2572   }
2573 
2574   /// Like genExtAddr, but ensure the address returned is a temporary even if \p
2575   /// expr is variable inside parentheses.
2576   ExtValue genTempExtAddr(const Fortran::lower::SomeExpr &expr) {
2577     // In general, genExtAddr might not create a temp for variable inside
2578     // parentheses to avoid creating array temporary in sub-expressions. It only
2579     // ensures the sub-expression is not re-associated with other parts of the
2580     // expression. In the call semantics, there is a difference between expr and
2581     // variable (see R1524). For expressions, a variable storage must not be
2582     // argument associated since it could be modified inside the call, or the
2583     // variable could also be modified by other means during the call.
2584     if (!isParenthesizedVariable(expr))
2585       return genExtAddr(expr);
2586     if (expr.Rank() > 0)
2587       return asArray(expr);
2588     mlir::Location loc = getLoc();
2589     return genExtValue(expr).match(
2590         [&](const fir::CharBoxValue &boxChar) -> ExtValue {
2591           return fir::factory::CharacterExprHelper{builder, loc}.createTempFrom(
2592               boxChar);
2593         },
2594         [&](const fir::UnboxedValue &v) -> ExtValue {
2595           mlir::Type type = v.getType();
2596           mlir::Value value = v;
2597           if (fir::isa_ref_type(type))
2598             value = builder.create<fir::LoadOp>(loc, value);
2599           mlir::Value temp = builder.createTemporary(loc, value.getType());
2600           builder.create<fir::StoreOp>(loc, value, temp);
2601           return temp;
2602         },
2603         [&](const fir::BoxValue &x) -> ExtValue {
2604           // Derived type scalar that may be polymorphic.
2605           assert(!x.hasRank() && x.isDerived());
2606           if (x.isDerivedWithLengthParameters())
2607             fir::emitFatalError(
2608                 loc, "making temps for derived type with length parameters");
2609           // TODO: polymorphic aspects should be kept but for now the temp
2610           // created always has the declared type.
2611           mlir::Value var =
2612               fir::getBase(fir::factory::readBoxValue(builder, loc, x));
2613           auto value = builder.create<fir::LoadOp>(loc, var);
2614           mlir::Value temp = builder.createTemporary(loc, value.getType());
2615           builder.create<fir::StoreOp>(loc, value, temp);
2616           return temp;
2617         },
2618         [&](const auto &) -> ExtValue {
2619           fir::emitFatalError(loc, "expr is not a scalar value");
2620         });
2621   }
2622 
2623   /// Helper structure to track potential copy-in of non contiguous variable
2624   /// argument into a contiguous temp. It is used to deallocate the temp that
2625   /// may have been created as well as to the copy-out from the temp to the
2626   /// variable after the call.
2627   struct CopyOutPair {
2628     ExtValue var;
2629     ExtValue temp;
2630     // Flag to indicate if the argument may have been modified by the
2631     // callee, in which case it must be copied-out to the variable.
2632     bool argMayBeModifiedByCall;
2633     // Optional boolean value that, if present and false, prevents
2634     // the copy-out and temp deallocation.
2635     llvm::Optional<mlir::Value> restrictCopyAndFreeAtRuntime;
2636   };
2637   using CopyOutPairs = llvm::SmallVector<CopyOutPair, 4>;
2638 
2639   /// Helper to read any fir::BoxValue into other fir::ExtendedValue categories
2640   /// not based on fir.box.
2641   /// This will lose any non contiguous stride information and dynamic type and
2642   /// should only be called if \p exv is known to be contiguous or if its base
2643   /// address will be replaced by a contiguous one. If \p exv is not a
2644   /// fir::BoxValue, this is a no-op.
2645   ExtValue readIfBoxValue(const ExtValue &exv) {
2646     if (const auto *box = exv.getBoxOf<fir::BoxValue>())
2647       return fir::factory::readBoxValue(builder, getLoc(), *box);
2648     return exv;
2649   }
2650 
2651   /// Generate a contiguous temp to pass \p actualArg as argument \p arg. The
2652   /// creation of the temp and copy-in can be made conditional at runtime by
2653   /// providing a runtime boolean flag \p restrictCopyAtRuntime (in which case
2654   /// the temp and copy will only be made if the value is true at runtime).
2655   ExtValue genCopyIn(const ExtValue &actualArg,
2656                      const Fortran::lower::CallerInterface::PassedEntity &arg,
2657                      CopyOutPairs &copyOutPairs,
2658                      llvm::Optional<mlir::Value> restrictCopyAtRuntime) {
2659     if (!restrictCopyAtRuntime) {
2660       ExtValue temp = genArrayTempFromMold(actualArg, ".copyinout");
2661       if (arg.mayBeReadByCall())
2662         genArrayCopy(temp, actualArg);
2663       copyOutPairs.emplace_back(CopyOutPair{
2664           actualArg, temp, arg.mayBeModifiedByCall(), restrictCopyAtRuntime});
2665       return temp;
2666     }
2667     // Otherwise, need to be careful to only copy-in if allowed at runtime.
2668     mlir::Location loc = getLoc();
2669     auto addrType = fir::HeapType::get(
2670         fir::unwrapPassByRefType(fir::getBase(actualArg).getType()));
2671     mlir::Value addr =
2672         builder
2673             .genIfOp(loc, {addrType}, *restrictCopyAtRuntime,
2674                      /*withElseRegion=*/true)
2675             .genThen([&]() {
2676               auto temp = genArrayTempFromMold(actualArg, ".copyinout");
2677               if (arg.mayBeReadByCall())
2678                 genArrayCopy(temp, actualArg);
2679               builder.create<fir::ResultOp>(loc, fir::getBase(temp));
2680             })
2681             .genElse([&]() {
2682               auto nullPtr = builder.createNullConstant(loc, addrType);
2683               builder.create<fir::ResultOp>(loc, nullPtr);
2684             })
2685             .getResults()[0];
2686     // Associate the temp address with actualArg lengths and extents.
2687     fir::ExtendedValue temp = fir::substBase(readIfBoxValue(actualArg), addr);
2688     copyOutPairs.emplace_back(CopyOutPair{
2689         actualArg, temp, arg.mayBeModifiedByCall(), restrictCopyAtRuntime});
2690     return temp;
2691   }
2692 
2693   /// Generate copy-out if needed and free the temporary for an argument that
2694   /// has been copied-in into a contiguous temp.
2695   void genCopyOut(const CopyOutPair &copyOutPair) {
2696     mlir::Location loc = getLoc();
2697     if (!copyOutPair.restrictCopyAndFreeAtRuntime) {
2698       if (copyOutPair.argMayBeModifiedByCall)
2699         genArrayCopy(copyOutPair.var, copyOutPair.temp);
2700       builder.create<fir::FreeMemOp>(loc, fir::getBase(copyOutPair.temp));
2701       return;
2702     }
2703     builder.genIfThen(loc, *copyOutPair.restrictCopyAndFreeAtRuntime)
2704         .genThen([&]() {
2705           if (copyOutPair.argMayBeModifiedByCall)
2706             genArrayCopy(copyOutPair.var, copyOutPair.temp);
2707           builder.create<fir::FreeMemOp>(loc, fir::getBase(copyOutPair.temp));
2708         })
2709         .end();
2710   }
2711 
2712   /// Lower a non-elemental procedure reference.
2713   ExtValue genRawProcedureRef(const Fortran::evaluate::ProcedureRef &procRef,
2714                               llvm::Optional<mlir::Type> resultType) {
2715     mlir::Location loc = getLoc();
2716     if (isElementalProcWithArrayArgs(procRef))
2717       fir::emitFatalError(loc, "trying to lower elemental procedure with array "
2718                                "arguments as normal procedure");
2719     if (const Fortran::evaluate::SpecificIntrinsic *intrinsic =
2720             procRef.proc().GetSpecificIntrinsic())
2721       return genIntrinsicRef(procRef, *intrinsic, resultType);
2722 
2723     if (isStatementFunctionCall(procRef))
2724       return genStmtFunctionRef(procRef);
2725 
2726     Fortran::lower::CallerInterface caller(procRef, converter);
2727     using PassBy = Fortran::lower::CallerInterface::PassEntityBy;
2728 
2729     llvm::SmallVector<fir::MutableBoxValue> mutableModifiedByCall;
2730     // List of <var, temp> where temp must be copied into var after the call.
2731     CopyOutPairs copyOutPairs;
2732 
2733     mlir::FunctionType callSiteType = caller.genFunctionType();
2734 
2735     // Lower the actual arguments and map the lowered values to the dummy
2736     // arguments.
2737     for (const Fortran::lower::CallInterface<
2738              Fortran::lower::CallerInterface>::PassedEntity &arg :
2739          caller.getPassedArguments()) {
2740       const auto *actual = arg.entity;
2741       mlir::Type argTy = callSiteType.getInput(arg.firArgument);
2742       if (!actual) {
2743         // Optional dummy argument for which there is no actual argument.
2744         caller.placeInput(arg, builder.create<fir::AbsentOp>(loc, argTy));
2745         continue;
2746       }
2747       const auto *expr = actual->UnwrapExpr();
2748       if (!expr)
2749         TODO(loc, "assumed type actual argument lowering");
2750 
2751       if (arg.passBy == PassBy::Value) {
2752         ExtValue argVal = genval(*expr);
2753         if (!fir::isUnboxedValue(argVal))
2754           fir::emitFatalError(
2755               loc, "internal error: passing non trivial value by value");
2756         caller.placeInput(arg, fir::getBase(argVal));
2757         continue;
2758       }
2759 
2760       if (arg.passBy == PassBy::MutableBox) {
2761         if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
2762                 *expr)) {
2763           // If expr is NULL(), the mutableBox created must be a deallocated
2764           // pointer with the dummy argument characteristics (see table 16.5
2765           // in Fortran 2018 standard).
2766           // No length parameters are set for the created box because any non
2767           // deferred type parameters of the dummy will be evaluated on the
2768           // callee side, and it is illegal to use NULL without a MOLD if any
2769           // dummy length parameters are assumed.
2770           mlir::Type boxTy = fir::dyn_cast_ptrEleTy(argTy);
2771           assert(boxTy && boxTy.isa<fir::BoxType>() &&
2772                  "must be a fir.box type");
2773           mlir::Value boxStorage = builder.createTemporary(loc, boxTy);
2774           mlir::Value nullBox = fir::factory::createUnallocatedBox(
2775               builder, loc, boxTy, /*nonDeferredParams=*/{});
2776           builder.create<fir::StoreOp>(loc, nullBox, boxStorage);
2777           caller.placeInput(arg, boxStorage);
2778           continue;
2779         }
2780         if (fir::isPointerType(argTy) &&
2781             !Fortran::evaluate::IsObjectPointer(
2782                 *expr, converter.getFoldingContext())) {
2783           // Passing a non POINTER actual argument to a POINTER dummy argument.
2784           // Create a pointer of the dummy argument type and assign the actual
2785           // argument to it.
2786           mlir::Value irBox =
2787               builder.createTemporary(loc, fir::unwrapRefType(argTy));
2788           // Non deferred parameters will be evaluated on the callee side.
2789           fir::MutableBoxValue pointer(irBox,
2790                                        /*nonDeferredParams=*/mlir::ValueRange{},
2791                                        /*mutableProperties=*/{});
2792           Fortran::lower::associateMutableBox(converter, loc, pointer, *expr,
2793                                               /*lbounds*/ mlir::ValueRange{},
2794                                               stmtCtx);
2795           caller.placeInput(arg, irBox);
2796           continue;
2797         }
2798         // Passing a POINTER to a POINTER, or an ALLOCATABLE to an ALLOCATABLE.
2799         fir::MutableBoxValue mutableBox = genMutableBoxValue(*expr);
2800         mlir::Value irBox =
2801             fir::factory::getMutableIRBox(builder, loc, mutableBox);
2802         caller.placeInput(arg, irBox);
2803         if (arg.mayBeModifiedByCall())
2804           mutableModifiedByCall.emplace_back(std::move(mutableBox));
2805         continue;
2806       }
2807       const bool actualArgIsVariable = Fortran::evaluate::IsVariable(*expr);
2808       if (arg.passBy == PassBy::BaseAddressValueAttribute) {
2809         mlir::Value temp;
2810         if (isArray(*expr)) {
2811           auto val = genBoxArg(*expr);
2812           if (!actualArgIsVariable)
2813             temp = getBase(val);
2814           else {
2815             ExtValue copy = genArrayTempFromMold(val, ".copy");
2816             genArrayCopy(copy, val);
2817             temp = fir::getBase(copy);
2818           }
2819         } else {
2820           mlir::Value val = fir::getBase(genval(*expr));
2821           temp = builder.createTemporary(
2822               loc, val.getType(),
2823               llvm::ArrayRef<mlir::NamedAttribute>{
2824                   Fortran::lower::getAdaptToByRefAttr(builder)});
2825           builder.create<fir::StoreOp>(loc, val, temp);
2826         }
2827         caller.placeInput(arg, temp);
2828         continue;
2829       }
2830       if (arg.passBy == PassBy::BaseAddress || arg.passBy == PassBy::BoxChar) {
2831         const bool actualIsSimplyContiguous =
2832             !actualArgIsVariable || Fortran::evaluate::IsSimplyContiguous(
2833                                         *expr, converter.getFoldingContext());
2834         auto argAddr = [&]() -> ExtValue {
2835           ExtValue baseAddr;
2836           if (actualArgIsVariable && arg.isOptional()) {
2837             if (Fortran::evaluate::IsAllocatableOrPointerObject(
2838                     *expr, converter.getFoldingContext())) {
2839               // Fortran 2018 15.5.2.12 point 1: If unallocated/disassociated,
2840               // it is as if the argument was absent. The main care here is to
2841               // not do a copy-in/copy-out because the temp address, even though
2842               // pointing to a null size storage, would not be a nullptr and
2843               // therefore the argument would not be considered absent on the
2844               // callee side. Note: if wholeSymbol is optional, it cannot be
2845               // absent as per 15.5.2.12 point 7. and 8. We rely on this to
2846               // un-conditionally read the allocatable/pointer descriptor here.
2847               if (actualIsSimplyContiguous)
2848                 return genBoxArg(*expr);
2849               fir::MutableBoxValue mutableBox = genMutableBoxValue(*expr);
2850               mlir::Value isAssociated =
2851                   fir::factory::genIsAllocatedOrAssociatedTest(builder, loc,
2852                                                                mutableBox);
2853               fir::ExtendedValue actualExv =
2854                   fir::factory::genMutableBoxRead(builder, loc, mutableBox);
2855               return genCopyIn(actualExv, arg, copyOutPairs, isAssociated);
2856             }
2857             if (const Fortran::semantics::Symbol *wholeSymbol =
2858                     Fortran::evaluate::UnwrapWholeSymbolOrComponentDataRef(
2859                         *expr))
2860               if (Fortran::semantics::IsOptional(*wholeSymbol)) {
2861                 ExtValue actualArg = gen(*expr);
2862                 mlir::Value actualArgBase = fir::getBase(actualArg);
2863                 if (!actualArgBase.getType().isa<fir::BoxType>())
2864                   return actualArg;
2865                 // Do not read wholeSymbol descriptor that may be a nullptr in
2866                 // case wholeSymbol is absent.
2867                 // Absent descriptor cannot be read. To avoid any issue in
2868                 // copy-in/copy-out, and when retrieving the address/length
2869                 // create an descriptor pointing to a null address here if the
2870                 // fir.box is absent.
2871                 mlir::Value isPresent = builder.create<fir::IsPresentOp>(
2872                     loc, builder.getI1Type(), actualArgBase);
2873                 mlir::Type boxType = actualArgBase.getType();
2874                 mlir::Value emptyBox = fir::factory::createUnallocatedBox(
2875                     builder, loc, boxType, llvm::None);
2876                 auto safeToReadBox = builder.create<mlir::arith::SelectOp>(
2877                     loc, isPresent, actualArgBase, emptyBox);
2878                 fir::ExtendedValue safeToReadExv =
2879                     fir::substBase(actualArg, safeToReadBox);
2880                 if (actualIsSimplyContiguous)
2881                   return safeToReadExv;
2882                 return genCopyIn(safeToReadExv, arg, copyOutPairs, isPresent);
2883               }
2884             // Fall through: The actual argument can safely be
2885             // copied-in/copied-out without any care if needed.
2886           }
2887           if (actualArgIsVariable && expr->Rank() > 0) {
2888             ExtValue box = genBoxArg(*expr);
2889             if (!actualIsSimplyContiguous)
2890               return genCopyIn(box, arg, copyOutPairs,
2891                                /*restrictCopyAtRuntime=*/llvm::None);
2892             // Contiguous: just use the box we created above!
2893             // This gets "unboxed" below, if needed.
2894             return box;
2895           }
2896           // Actual argument is a non optional/non pointer/non allocatable
2897           // scalar.
2898           if (actualArgIsVariable)
2899             return genExtAddr(*expr);
2900           // Actual argument is not a variable. Make sure a variable address is
2901           // not passed.
2902           return genTempExtAddr(*expr);
2903         }();
2904         // Scalar and contiguous expressions may be lowered to a fir.box,
2905         // either to account for potential polymorphism, or because lowering
2906         // did not account for some contiguity hints.
2907         // Here, polymorphism does not matter (an entity of the declared type
2908         // is passed, not one of the dynamic type), and the expr is known to
2909         // be simply contiguous, so it is safe to unbox it and pass the
2910         // address without making a copy.
2911         argAddr = readIfBoxValue(argAddr);
2912 
2913         if (arg.passBy == PassBy::BaseAddress) {
2914           caller.placeInput(arg, fir::getBase(argAddr));
2915         } else {
2916           assert(arg.passBy == PassBy::BoxChar);
2917           auto helper = fir::factory::CharacterExprHelper{builder, loc};
2918           auto boxChar = argAddr.match(
2919               [&](const fir::CharBoxValue &x) { return helper.createEmbox(x); },
2920               [&](const fir::CharArrayBoxValue &x) {
2921                 return helper.createEmbox(x);
2922               },
2923               [&](const auto &x) -> mlir::Value {
2924                 // Fortran allows an actual argument of a completely different
2925                 // type to be passed to a procedure expecting a CHARACTER in the
2926                 // dummy argument position. When this happens, the data pointer
2927                 // argument is simply assumed to point to CHARACTER data and the
2928                 // LEN argument used is garbage. Simulate this behavior by
2929                 // free-casting the base address to be a !fir.char reference and
2930                 // setting the LEN argument to undefined. What could go wrong?
2931                 auto dataPtr = fir::getBase(x);
2932                 assert(!dataPtr.getType().template isa<fir::BoxType>());
2933                 return builder.convertWithSemantics(
2934                     loc, argTy, dataPtr,
2935                     /*allowCharacterConversion=*/true);
2936               });
2937           caller.placeInput(arg, boxChar);
2938         }
2939       } else if (arg.passBy == PassBy::Box) {
2940         // Before lowering to an address, handle the allocatable/pointer actual
2941         // argument to optional fir.box dummy. It is legal to pass
2942         // unallocated/disassociated entity to an optional. In this case, an
2943         // absent fir.box must be created instead of a fir.box with a null value
2944         // (Fortran 2018 15.5.2.12 point 1).
2945         if (arg.isOptional() && Fortran::evaluate::IsAllocatableOrPointerObject(
2946                                     *expr, converter.getFoldingContext())) {
2947           // Note that passing an absent allocatable to a non-allocatable
2948           // optional dummy argument is illegal (15.5.2.12 point 3 (8)). So
2949           // nothing has to be done to generate an absent argument in this case,
2950           // and it is OK to unconditionally read the mutable box here.
2951           fir::MutableBoxValue mutableBox = genMutableBoxValue(*expr);
2952           mlir::Value isAllocated =
2953               fir::factory::genIsAllocatedOrAssociatedTest(builder, loc,
2954                                                            mutableBox);
2955           auto absent = builder.create<fir::AbsentOp>(loc, argTy);
2956           /// For now, assume it is not OK to pass the allocatable/pointer
2957           /// descriptor to a non pointer/allocatable dummy. That is a strict
2958           /// interpretation of 18.3.6 point 4 that stipulates the descriptor
2959           /// has the dummy attributes in BIND(C) contexts.
2960           mlir::Value box = builder.createBox(
2961               loc, fir::factory::genMutableBoxRead(builder, loc, mutableBox));
2962           // Need the box types to be exactly similar for the selectOp.
2963           mlir::Value convertedBox = builder.createConvert(loc, argTy, box);
2964           caller.placeInput(arg, builder.create<mlir::arith::SelectOp>(
2965                                      loc, isAllocated, convertedBox, absent));
2966         } else {
2967           // Make sure a variable address is only passed if the expression is
2968           // actually a variable.
2969           mlir::Value box =
2970               actualArgIsVariable
2971                   ? builder.createBox(loc, genBoxArg(*expr))
2972                   : builder.createBox(getLoc(), genTempExtAddr(*expr));
2973           caller.placeInput(arg, box);
2974         }
2975       } else if (arg.passBy == PassBy::AddressAndLength) {
2976         ExtValue argRef = genExtAddr(*expr);
2977         caller.placeAddressAndLengthInput(arg, fir::getBase(argRef),
2978                                           fir::getLen(argRef));
2979       } else if (arg.passBy == PassBy::CharProcTuple) {
2980         ExtValue argRef = genExtAddr(*expr);
2981         mlir::Value tuple = createBoxProcCharTuple(
2982             converter, argTy, fir::getBase(argRef), fir::getLen(argRef));
2983         caller.placeInput(arg, tuple);
2984       } else {
2985         TODO(loc, "pass by value in non elemental function call");
2986       }
2987     }
2988 
2989     ExtValue result = genCallOpAndResult(caller, callSiteType, resultType);
2990 
2991     // Sync pointers and allocatables that may have been modified during the
2992     // call.
2993     for (const auto &mutableBox : mutableModifiedByCall)
2994       fir::factory::syncMutableBoxFromIRBox(builder, loc, mutableBox);
2995     // Handle case where result was passed as argument
2996 
2997     // Copy-out temps that were created for non contiguous variable arguments if
2998     // needed.
2999     for (const auto &copyOutPair : copyOutPairs)
3000       genCopyOut(copyOutPair);
3001 
3002     return result;
3003   }
3004 
3005   template <typename A>
3006   ExtValue genval(const Fortran::evaluate::FunctionRef<A> &funcRef) {
3007     ExtValue result = genFunctionRef(funcRef);
3008     if (result.rank() == 0 && fir::isa_ref_type(fir::getBase(result).getType()))
3009       return genLoad(result);
3010     return result;
3011   }
3012 
3013   ExtValue genval(const Fortran::evaluate::ProcedureRef &procRef) {
3014     llvm::Optional<mlir::Type> resTy;
3015     if (procRef.hasAlternateReturns())
3016       resTy = builder.getIndexType();
3017     return genProcedureRef(procRef, resTy);
3018   }
3019 
3020   template <typename A>
3021   bool isScalar(const A &x) {
3022     return x.Rank() == 0;
3023   }
3024 
3025   /// Helper to detect Transformational function reference.
3026   template <typename T>
3027   bool isTransformationalRef(const T &) {
3028     return false;
3029   }
3030   template <typename T>
3031   bool isTransformationalRef(const Fortran::evaluate::FunctionRef<T> &funcRef) {
3032     return !funcRef.IsElemental() && funcRef.Rank();
3033   }
3034   template <typename T>
3035   bool isTransformationalRef(Fortran::evaluate::Expr<T> expr) {
3036     return std::visit([&](const auto &e) { return isTransformationalRef(e); },
3037                       expr.u);
3038   }
3039 
3040   template <typename A>
3041   ExtValue asArray(const A &x) {
3042     return Fortran::lower::createSomeArrayTempValue(converter, toEvExpr(x),
3043                                                     symMap, stmtCtx);
3044   }
3045 
3046   /// Lower an array value as an argument. This argument can be passed as a box
3047   /// value, so it may be possible to avoid making a temporary.
3048   template <typename A>
3049   ExtValue asArrayArg(const Fortran::evaluate::Expr<A> &x) {
3050     return std::visit([&](const auto &e) { return asArrayArg(e, x); }, x.u);
3051   }
3052   template <typename A, typename B>
3053   ExtValue asArrayArg(const Fortran::evaluate::Expr<A> &x, const B &y) {
3054     return std::visit([&](const auto &e) { return asArrayArg(e, y); }, x.u);
3055   }
3056   template <typename A, typename B>
3057   ExtValue asArrayArg(const Fortran::evaluate::Designator<A> &, const B &x) {
3058     // Designator is being passed as an argument to a procedure. Lower the
3059     // expression to a boxed value.
3060     auto someExpr = toEvExpr(x);
3061     return Fortran::lower::createBoxValue(getLoc(), converter, someExpr, symMap,
3062                                           stmtCtx);
3063   }
3064   template <typename A, typename B>
3065   ExtValue asArrayArg(const A &, const B &x) {
3066     // If the expression to pass as an argument is not a designator, then create
3067     // an array temp.
3068     return asArray(x);
3069   }
3070 
3071   template <typename A>
3072   ExtValue gen(const Fortran::evaluate::Expr<A> &x) {
3073     // Whole array symbols or components, and results of transformational
3074     // functions already have a storage and the scalar expression lowering path
3075     // is used to not create a new temporary storage.
3076     if (isScalar(x) ||
3077         Fortran::evaluate::UnwrapWholeSymbolOrComponentDataRef(x) ||
3078         isTransformationalRef(x))
3079       return std::visit([&](const auto &e) { return genref(e); }, x.u);
3080     if (useBoxArg)
3081       return asArrayArg(x);
3082     return asArray(x);
3083   }
3084   template <typename A>
3085   ExtValue genval(const Fortran::evaluate::Expr<A> &x) {
3086     if (isScalar(x) || Fortran::evaluate::UnwrapWholeSymbolDataRef(x) ||
3087         inInitializer)
3088       return std::visit([&](const auto &e) { return genval(e); }, x.u);
3089     return asArray(x);
3090   }
3091 
3092   template <int KIND>
3093   ExtValue genval(const Fortran::evaluate::Expr<Fortran::evaluate::Type<
3094                       Fortran::common::TypeCategory::Logical, KIND>> &exp) {
3095     return std::visit([&](const auto &e) { return genval(e); }, exp.u);
3096   }
3097 
3098   using RefSet =
3099       std::tuple<Fortran::evaluate::ComplexPart, Fortran::evaluate::Substring,
3100                  Fortran::evaluate::DataRef, Fortran::evaluate::Component,
3101                  Fortran::evaluate::ArrayRef, Fortran::evaluate::CoarrayRef,
3102                  Fortran::semantics::SymbolRef>;
3103   template <typename A>
3104   static constexpr bool inRefSet = Fortran::common::HasMember<A, RefSet>;
3105 
3106   template <typename A, typename = std::enable_if_t<inRefSet<A>>>
3107   ExtValue genref(const A &a) {
3108     return gen(a);
3109   }
3110   template <typename A>
3111   ExtValue genref(const A &a) {
3112     if (inInitializer) {
3113       // Initialization expressions can never allocate memory.
3114       return genval(a);
3115     }
3116     mlir::Type storageType = converter.genType(toEvExpr(a));
3117     return placeScalarValueInMemory(builder, getLoc(), genval(a), storageType);
3118   }
3119 
3120   template <typename A, template <typename> typename T,
3121             typename B = std::decay_t<T<A>>,
3122             std::enable_if_t<
3123                 std::is_same_v<B, Fortran::evaluate::Expr<A>> ||
3124                     std::is_same_v<B, Fortran::evaluate::Designator<A>> ||
3125                     std::is_same_v<B, Fortran::evaluate::FunctionRef<A>>,
3126                 bool> = true>
3127   ExtValue genref(const T<A> &x) {
3128     return gen(x);
3129   }
3130 
3131 private:
3132   mlir::Location location;
3133   Fortran::lower::AbstractConverter &converter;
3134   fir::FirOpBuilder &builder;
3135   Fortran::lower::StatementContext &stmtCtx;
3136   Fortran::lower::SymMap &symMap;
3137   InitializerData *inInitializer = nullptr;
3138   bool useBoxArg = false; // expression lowered as argument
3139 };
3140 } // namespace
3141 
3142 // Helper for changing the semantics in a given context. Preserves the current
3143 // semantics which is resumed when the "push" goes out of scope.
3144 #define PushSemantics(PushVal)                                                 \
3145   [[maybe_unused]] auto pushSemanticsLocalVariable##__LINE__ =                 \
3146       Fortran::common::ScopedSet(semant, PushVal);
3147 
3148 static bool isAdjustedArrayElementType(mlir::Type t) {
3149   return fir::isa_char(t) || fir::isa_derived(t) || t.isa<fir::SequenceType>();
3150 }
3151 static bool elementTypeWasAdjusted(mlir::Type t) {
3152   if (auto ty = t.dyn_cast<fir::ReferenceType>())
3153     return isAdjustedArrayElementType(ty.getEleTy());
3154   return false;
3155 }
3156 static mlir::Type adjustedArrayElementType(mlir::Type t) {
3157   return isAdjustedArrayElementType(t) ? fir::ReferenceType::get(t) : t;
3158 }
3159 
3160 /// Helper to generate calls to scalar user defined assignment procedures.
3161 static void genScalarUserDefinedAssignmentCall(fir::FirOpBuilder &builder,
3162                                                mlir::Location loc,
3163                                                mlir::FuncOp func,
3164                                                const fir::ExtendedValue &lhs,
3165                                                const fir::ExtendedValue &rhs) {
3166   auto prepareUserDefinedArg =
3167       [](fir::FirOpBuilder &builder, mlir::Location loc,
3168          const fir::ExtendedValue &value, mlir::Type argType) -> mlir::Value {
3169     if (argType.isa<fir::BoxCharType>()) {
3170       const fir::CharBoxValue *charBox = value.getCharBox();
3171       assert(charBox && "argument type mismatch in elemental user assignment");
3172       return fir::factory::CharacterExprHelper{builder, loc}.createEmbox(
3173           *charBox);
3174     }
3175     if (argType.isa<fir::BoxType>()) {
3176       mlir::Value box = builder.createBox(loc, value);
3177       return builder.createConvert(loc, argType, box);
3178     }
3179     // Simple pass by address.
3180     mlir::Type argBaseType = fir::unwrapRefType(argType);
3181     assert(!fir::hasDynamicSize(argBaseType));
3182     mlir::Value from = fir::getBase(value);
3183     if (argBaseType != fir::unwrapRefType(from.getType())) {
3184       // With logicals, it is possible that from is i1 here.
3185       if (fir::isa_ref_type(from.getType()))
3186         from = builder.create<fir::LoadOp>(loc, from);
3187       from = builder.createConvert(loc, argBaseType, from);
3188     }
3189     if (!fir::isa_ref_type(from.getType())) {
3190       mlir::Value temp = builder.createTemporary(loc, argBaseType);
3191       builder.create<fir::StoreOp>(loc, from, temp);
3192       from = temp;
3193     }
3194     return builder.createConvert(loc, argType, from);
3195   };
3196   assert(func.getNumArguments() == 2);
3197   mlir::Type lhsType = func.getFunctionType().getInput(0);
3198   mlir::Type rhsType = func.getFunctionType().getInput(1);
3199   mlir::Value lhsArg = prepareUserDefinedArg(builder, loc, lhs, lhsType);
3200   mlir::Value rhsArg = prepareUserDefinedArg(builder, loc, rhs, rhsType);
3201   builder.create<fir::CallOp>(loc, func, mlir::ValueRange{lhsArg, rhsArg});
3202 }
3203 
3204 /// Convert the result of a fir.array_modify to an ExtendedValue given the
3205 /// related fir.array_load.
3206 static fir::ExtendedValue arrayModifyToExv(fir::FirOpBuilder &builder,
3207                                            mlir::Location loc,
3208                                            fir::ArrayLoadOp load,
3209                                            mlir::Value elementAddr) {
3210   mlir::Type eleTy = fir::unwrapPassByRefType(elementAddr.getType());
3211   if (fir::isa_char(eleTy)) {
3212     auto len = fir::factory::CharacterExprHelper{builder, loc}.getLength(
3213         load.getMemref());
3214     if (!len) {
3215       assert(load.getTypeparams().size() == 1 &&
3216              "length must be in array_load");
3217       len = load.getTypeparams()[0];
3218     }
3219     return fir::CharBoxValue{elementAddr, len};
3220   }
3221   return elementAddr;
3222 }
3223 
3224 //===----------------------------------------------------------------------===//
3225 //
3226 // Lowering of scalar expressions in an explicit iteration space context.
3227 //
3228 //===----------------------------------------------------------------------===//
3229 
3230 // Shared code for creating a copy of a derived type element. This function is
3231 // called from a continuation.
3232 inline static fir::ArrayAmendOp
3233 createDerivedArrayAmend(mlir::Location loc, fir::ArrayLoadOp destLoad,
3234                         fir::FirOpBuilder &builder, fir::ArrayAccessOp destAcc,
3235                         const fir::ExtendedValue &elementExv, mlir::Type eleTy,
3236                         mlir::Value innerArg) {
3237   if (destLoad.getTypeparams().empty()) {
3238     fir::factory::genRecordAssignment(builder, loc, destAcc, elementExv);
3239   } else {
3240     auto boxTy = fir::BoxType::get(eleTy);
3241     auto toBox = builder.create<fir::EmboxOp>(loc, boxTy, destAcc.getResult(),
3242                                               mlir::Value{}, mlir::Value{},
3243                                               destLoad.getTypeparams());
3244     auto fromBox = builder.create<fir::EmboxOp>(
3245         loc, boxTy, fir::getBase(elementExv), mlir::Value{}, mlir::Value{},
3246         destLoad.getTypeparams());
3247     fir::factory::genRecordAssignment(builder, loc, fir::BoxValue(toBox),
3248                                       fir::BoxValue(fromBox));
3249   }
3250   return builder.create<fir::ArrayAmendOp>(loc, innerArg.getType(), innerArg,
3251                                            destAcc);
3252 }
3253 
3254 inline static fir::ArrayAmendOp
3255 createCharArrayAmend(mlir::Location loc, fir::FirOpBuilder &builder,
3256                      fir::ArrayAccessOp dstOp, mlir::Value &dstLen,
3257                      const fir::ExtendedValue &srcExv, mlir::Value innerArg,
3258                      llvm::ArrayRef<mlir::Value> bounds) {
3259   fir::CharBoxValue dstChar(dstOp, dstLen);
3260   fir::factory::CharacterExprHelper helper{builder, loc};
3261   if (!bounds.empty()) {
3262     dstChar = helper.createSubstring(dstChar, bounds);
3263     fir::factory::genCharacterCopy(fir::getBase(srcExv), fir::getLen(srcExv),
3264                                    dstChar.getAddr(), dstChar.getLen(), builder,
3265                                    loc);
3266     // Update the LEN to the substring's LEN.
3267     dstLen = dstChar.getLen();
3268   }
3269   // For a CHARACTER, we generate the element assignment loops inline.
3270   helper.createAssign(fir::ExtendedValue{dstChar}, srcExv);
3271   // Mark this array element as amended.
3272   mlir::Type ty = innerArg.getType();
3273   auto amend = builder.create<fir::ArrayAmendOp>(loc, ty, innerArg, dstOp);
3274   return amend;
3275 }
3276 
3277 /// Build an ExtendedValue from a fir.array<?x...?xT> without actually setting
3278 /// the actual extents and lengths. This is only to allow their propagation as
3279 /// ExtendedValue without triggering verifier failures when propagating
3280 /// character/arrays as unboxed values. Only the base of the resulting
3281 /// ExtendedValue should be used, it is undefined to use the length or extents
3282 /// of the extended value returned,
3283 inline static fir::ExtendedValue
3284 convertToArrayBoxValue(mlir::Location loc, fir::FirOpBuilder &builder,
3285                        mlir::Value val, mlir::Value len) {
3286   mlir::Type ty = fir::unwrapRefType(val.getType());
3287   mlir::IndexType idxTy = builder.getIndexType();
3288   auto seqTy = ty.cast<fir::SequenceType>();
3289   auto undef = builder.create<fir::UndefOp>(loc, idxTy);
3290   llvm::SmallVector<mlir::Value> extents(seqTy.getDimension(), undef);
3291   if (fir::isa_char(seqTy.getEleTy()))
3292     return fir::CharArrayBoxValue(val, len ? len : undef, extents);
3293   return fir::ArrayBoxValue(val, extents);
3294 }
3295 
3296 //===----------------------------------------------------------------------===//
3297 //
3298 // Lowering of array expressions.
3299 //
3300 //===----------------------------------------------------------------------===//
3301 
3302 namespace {
3303 class ArrayExprLowering {
3304   using ExtValue = fir::ExtendedValue;
3305 
3306   /// Structure to keep track of lowered array operands in the
3307   /// array expression. Useful to later deduce the shape of the
3308   /// array expression.
3309   struct ArrayOperand {
3310     /// Array base (can be a fir.box).
3311     mlir::Value memref;
3312     /// ShapeOp, ShapeShiftOp or ShiftOp
3313     mlir::Value shape;
3314     /// SliceOp
3315     mlir::Value slice;
3316     /// Can this operand be absent ?
3317     bool mayBeAbsent = false;
3318   };
3319 
3320   using ImplicitSubscripts = Fortran::lower::details::ImplicitSubscripts;
3321   using PathComponent = Fortran::lower::PathComponent;
3322 
3323   /// Active iteration space.
3324   using IterationSpace = Fortran::lower::IterationSpace;
3325   using IterSpace = const Fortran::lower::IterationSpace &;
3326 
3327   /// Current continuation. Function that will generate IR for a single
3328   /// iteration of the pending iterative loop structure.
3329   using CC = Fortran::lower::GenerateElementalArrayFunc;
3330 
3331   /// Projection continuation. Function that will project one iteration space
3332   /// into another.
3333   using PC = std::function<IterationSpace(IterSpace)>;
3334   using ArrayBaseTy =
3335       std::variant<std::monostate, const Fortran::evaluate::ArrayRef *,
3336                    const Fortran::evaluate::DataRef *>;
3337   using ComponentPath = Fortran::lower::ComponentPath;
3338 
3339 public:
3340   //===--------------------------------------------------------------------===//
3341   // Regular array assignment
3342   //===--------------------------------------------------------------------===//
3343 
3344   /// Entry point for array assignments. Both the left-hand and right-hand sides
3345   /// can either be ExtendedValue or evaluate::Expr.
3346   template <typename TL, typename TR>
3347   static void lowerArrayAssignment(Fortran::lower::AbstractConverter &converter,
3348                                    Fortran::lower::SymMap &symMap,
3349                                    Fortran::lower::StatementContext &stmtCtx,
3350                                    const TL &lhs, const TR &rhs) {
3351     ArrayExprLowering ael{converter, stmtCtx, symMap,
3352                           ConstituentSemantics::CopyInCopyOut};
3353     ael.lowerArrayAssignment(lhs, rhs);
3354   }
3355 
3356   template <typename TL, typename TR>
3357   void lowerArrayAssignment(const TL &lhs, const TR &rhs) {
3358     mlir::Location loc = getLoc();
3359     /// Here the target subspace is not necessarily contiguous. The ArrayUpdate
3360     /// continuation is implicitly returned in `ccStoreToDest` and the ArrayLoad
3361     /// in `destination`.
3362     PushSemantics(ConstituentSemantics::ProjectedCopyInCopyOut);
3363     ccStoreToDest = genarr(lhs);
3364     determineShapeOfDest(lhs);
3365     semant = ConstituentSemantics::RefTransparent;
3366     ExtValue exv = lowerArrayExpression(rhs);
3367     if (explicitSpaceIsActive()) {
3368       explicitSpace->finalizeContext();
3369       builder.create<fir::ResultOp>(loc, fir::getBase(exv));
3370     } else {
3371       builder.create<fir::ArrayMergeStoreOp>(
3372           loc, destination, fir::getBase(exv), destination.getMemref(),
3373           destination.getSlice(), destination.getTypeparams());
3374     }
3375   }
3376 
3377   //===--------------------------------------------------------------------===//
3378   // WHERE array assignment, FORALL assignment, and FORALL+WHERE array
3379   // assignment
3380   //===--------------------------------------------------------------------===//
3381 
3382   /// Entry point for array assignment when the iteration space is explicitly
3383   /// defined (Fortran's FORALL) with or without masks, and/or the implied
3384   /// iteration space involves masks (Fortran's WHERE). Both contexts (explicit
3385   /// space and implicit space with masks) may be present.
3386   static void lowerAnyMaskedArrayAssignment(
3387       Fortran::lower::AbstractConverter &converter,
3388       Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx,
3389       const Fortran::lower::SomeExpr &lhs, const Fortran::lower::SomeExpr &rhs,
3390       Fortran::lower::ExplicitIterSpace &explicitSpace,
3391       Fortran::lower::ImplicitIterSpace &implicitSpace) {
3392     if (explicitSpace.isActive() && lhs.Rank() == 0) {
3393       // Scalar assignment expression in a FORALL context.
3394       ArrayExprLowering ael(converter, stmtCtx, symMap,
3395                             ConstituentSemantics::RefTransparent,
3396                             &explicitSpace, &implicitSpace);
3397       ael.lowerScalarAssignment(lhs, rhs);
3398       return;
3399     }
3400     // Array assignment expression in a FORALL and/or WHERE context.
3401     ArrayExprLowering ael(converter, stmtCtx, symMap,
3402                           ConstituentSemantics::CopyInCopyOut, &explicitSpace,
3403                           &implicitSpace);
3404     ael.lowerArrayAssignment(lhs, rhs);
3405   }
3406 
3407   //===--------------------------------------------------------------------===//
3408   // Array assignment to allocatable array
3409   //===--------------------------------------------------------------------===//
3410 
3411   /// Entry point for assignment to allocatable array.
3412   static void lowerAllocatableArrayAssignment(
3413       Fortran::lower::AbstractConverter &converter,
3414       Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx,
3415       const Fortran::lower::SomeExpr &lhs, const Fortran::lower::SomeExpr &rhs,
3416       Fortran::lower::ExplicitIterSpace &explicitSpace,
3417       Fortran::lower::ImplicitIterSpace &implicitSpace) {
3418     ArrayExprLowering ael(converter, stmtCtx, symMap,
3419                           ConstituentSemantics::CopyInCopyOut, &explicitSpace,
3420                           &implicitSpace);
3421     ael.lowerAllocatableArrayAssignment(lhs, rhs);
3422   }
3423 
3424   /// Assignment to allocatable array.
3425   ///
3426   /// The semantics are reverse that of a "regular" array assignment. The rhs
3427   /// defines the iteration space of the computation and the lhs is
3428   /// resized/reallocated to fit if necessary.
3429   void lowerAllocatableArrayAssignment(const Fortran::lower::SomeExpr &lhs,
3430                                        const Fortran::lower::SomeExpr &rhs) {
3431     // With assignment to allocatable, we want to lower the rhs first and use
3432     // its shape to determine if we need to reallocate, etc.
3433     mlir::Location loc = getLoc();
3434     // FIXME: If the lhs is in an explicit iteration space, the assignment may
3435     // be to an array of allocatable arrays rather than a single allocatable
3436     // array.
3437     fir::MutableBoxValue mutableBox =
3438         createMutableBox(loc, converter, lhs, symMap);
3439     mlir::Type resultTy = converter.genType(rhs);
3440     if (rhs.Rank() > 0)
3441       determineShapeOfDest(rhs);
3442     auto rhsCC = [&]() {
3443       PushSemantics(ConstituentSemantics::RefTransparent);
3444       return genarr(rhs);
3445     }();
3446 
3447     llvm::SmallVector<mlir::Value> lengthParams;
3448     // Currently no safe way to gather length from rhs (at least for
3449     // character, it cannot be taken from array_loads since it may be
3450     // changed by concatenations).
3451     if ((mutableBox.isCharacter() && !mutableBox.hasNonDeferredLenParams()) ||
3452         mutableBox.isDerivedWithLengthParameters())
3453       TODO(loc, "gather rhs length parameters in assignment to allocatable");
3454 
3455     // The allocatable must take lower bounds from the expr if it is
3456     // reallocated and the right hand side is not a scalar.
3457     const bool takeLboundsIfRealloc = rhs.Rank() > 0;
3458     llvm::SmallVector<mlir::Value> lbounds;
3459     // When the reallocated LHS takes its lower bounds from the RHS,
3460     // they will be non default only if the RHS is a whole array
3461     // variable. Otherwise, lbounds is left empty and default lower bounds
3462     // will be used.
3463     if (takeLboundsIfRealloc &&
3464         Fortran::evaluate::UnwrapWholeSymbolOrComponentDataRef(rhs)) {
3465       assert(arrayOperands.size() == 1 &&
3466              "lbounds can only come from one array");
3467       std::vector<mlir::Value> lbs =
3468           fir::factory::getOrigins(arrayOperands[0].shape);
3469       lbounds.append(lbs.begin(), lbs.end());
3470     }
3471     fir::factory::MutableBoxReallocation realloc =
3472         fir::factory::genReallocIfNeeded(builder, loc, mutableBox, destShape,
3473                                          lengthParams);
3474     // Create ArrayLoad for the mutable box and save it into `destination`.
3475     PushSemantics(ConstituentSemantics::ProjectedCopyInCopyOut);
3476     ccStoreToDest = genarr(realloc.newValue);
3477     // If the rhs is scalar, get shape from the allocatable ArrayLoad.
3478     if (destShape.empty())
3479       destShape = getShape(destination);
3480     // Finish lowering the loop nest.
3481     assert(destination && "destination must have been set");
3482     ExtValue exv = lowerArrayExpression(rhsCC, resultTy);
3483     if (explicitSpaceIsActive()) {
3484       explicitSpace->finalizeContext();
3485       builder.create<fir::ResultOp>(loc, fir::getBase(exv));
3486     } else {
3487       builder.create<fir::ArrayMergeStoreOp>(
3488           loc, destination, fir::getBase(exv), destination.getMemref(),
3489           destination.getSlice(), destination.getTypeparams());
3490     }
3491     fir::factory::finalizeRealloc(builder, loc, mutableBox, lbounds,
3492                                   takeLboundsIfRealloc, realloc);
3493   }
3494 
3495   /// Entry point for when an array expression appears in a context where the
3496   /// result must be boxed. (BoxValue semantics.)
3497   static ExtValue
3498   lowerBoxedArrayExpression(Fortran::lower::AbstractConverter &converter,
3499                             Fortran::lower::SymMap &symMap,
3500                             Fortran::lower::StatementContext &stmtCtx,
3501                             const Fortran::lower::SomeExpr &expr) {
3502     ArrayExprLowering ael{converter, stmtCtx, symMap,
3503                           ConstituentSemantics::BoxValue};
3504     return ael.lowerBoxedArrayExpr(expr);
3505   }
3506 
3507   ExtValue lowerBoxedArrayExpr(const Fortran::lower::SomeExpr &exp) {
3508     return std::visit(
3509         [&](const auto &e) {
3510           auto f = genarr(e);
3511           ExtValue exv = f(IterationSpace{});
3512           if (fir::getBase(exv).getType().template isa<fir::BoxType>())
3513             return exv;
3514           fir::emitFatalError(getLoc(), "array must be emboxed");
3515         },
3516         exp.u);
3517   }
3518 
3519   /// Entry point into lowering an expression with rank. This entry point is for
3520   /// lowering a rhs expression, for example. (RefTransparent semantics.)
3521   static ExtValue
3522   lowerNewArrayExpression(Fortran::lower::AbstractConverter &converter,
3523                           Fortran::lower::SymMap &symMap,
3524                           Fortran::lower::StatementContext &stmtCtx,
3525                           const Fortran::lower::SomeExpr &expr) {
3526     ArrayExprLowering ael{converter, stmtCtx, symMap};
3527     ael.determineShapeOfDest(expr);
3528     ExtValue loopRes = ael.lowerArrayExpression(expr);
3529     fir::ArrayLoadOp dest = ael.destination;
3530     mlir::Value tempRes = dest.getMemref();
3531     fir::FirOpBuilder &builder = converter.getFirOpBuilder();
3532     mlir::Location loc = converter.getCurrentLocation();
3533     builder.create<fir::ArrayMergeStoreOp>(loc, dest, fir::getBase(loopRes),
3534                                            tempRes, dest.getSlice(),
3535                                            dest.getTypeparams());
3536 
3537     auto arrTy =
3538         fir::dyn_cast_ptrEleTy(tempRes.getType()).cast<fir::SequenceType>();
3539     if (auto charTy =
3540             arrTy.getEleTy().template dyn_cast<fir::CharacterType>()) {
3541       if (fir::characterWithDynamicLen(charTy))
3542         TODO(loc, "CHARACTER does not have constant LEN");
3543       mlir::Value len = builder.createIntegerConstant(
3544           loc, builder.getCharacterLengthType(), charTy.getLen());
3545       return fir::CharArrayBoxValue(tempRes, len, dest.getExtents());
3546     }
3547     return fir::ArrayBoxValue(tempRes, dest.getExtents());
3548   }
3549 
3550   static void lowerLazyArrayExpression(
3551       Fortran::lower::AbstractConverter &converter,
3552       Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx,
3553       const Fortran::lower::SomeExpr &expr, mlir::Value raggedHeader) {
3554     ArrayExprLowering ael(converter, stmtCtx, symMap);
3555     ael.lowerLazyArrayExpression(expr, raggedHeader);
3556   }
3557 
3558   /// Lower the expression \p expr into a buffer that is created on demand. The
3559   /// variable containing the pointer to the buffer is \p var and the variable
3560   /// containing the shape of the buffer is \p shapeBuffer.
3561   void lowerLazyArrayExpression(const Fortran::lower::SomeExpr &expr,
3562                                 mlir::Value header) {
3563     mlir::Location loc = getLoc();
3564     mlir::TupleType hdrTy = fir::factory::getRaggedArrayHeaderType(builder);
3565     mlir::IntegerType i32Ty = builder.getIntegerType(32);
3566 
3567     // Once the loop extents have been computed, which may require being inside
3568     // some explicit loops, lazily allocate the expression on the heap. The
3569     // following continuation creates the buffer as needed.
3570     ccPrelude = [=](llvm::ArrayRef<mlir::Value> shape) {
3571       mlir::IntegerType i64Ty = builder.getIntegerType(64);
3572       mlir::Value byteSize = builder.createIntegerConstant(loc, i64Ty, 1);
3573       fir::runtime::genRaggedArrayAllocate(
3574           loc, builder, header, /*asHeaders=*/false, byteSize, shape);
3575     };
3576 
3577     // Create a dummy array_load before the loop. We're storing to a lazy
3578     // temporary, so there will be no conflict and no copy-in. TODO: skip this
3579     // as there isn't any necessity for it.
3580     ccLoadDest = [=](llvm::ArrayRef<mlir::Value> shape) -> fir::ArrayLoadOp {
3581       mlir::Value one = builder.createIntegerConstant(loc, i32Ty, 1);
3582       auto var = builder.create<fir::CoordinateOp>(
3583           loc, builder.getRefType(hdrTy.getType(1)), header, one);
3584       auto load = builder.create<fir::LoadOp>(loc, var);
3585       mlir::Type eleTy =
3586           fir::unwrapSequenceType(fir::unwrapRefType(load.getType()));
3587       auto seqTy = fir::SequenceType::get(eleTy, shape.size());
3588       mlir::Value castTo =
3589           builder.createConvert(loc, fir::HeapType::get(seqTy), load);
3590       mlir::Value shapeOp = builder.genShape(loc, shape);
3591       return builder.create<fir::ArrayLoadOp>(
3592           loc, seqTy, castTo, shapeOp, /*slice=*/mlir::Value{}, llvm::None);
3593     };
3594     // Custom lowering of the element store to deal with the extra indirection
3595     // to the lazy allocated buffer.
3596     ccStoreToDest = [=](IterSpace iters) {
3597       mlir::Value one = builder.createIntegerConstant(loc, i32Ty, 1);
3598       auto var = builder.create<fir::CoordinateOp>(
3599           loc, builder.getRefType(hdrTy.getType(1)), header, one);
3600       auto load = builder.create<fir::LoadOp>(loc, var);
3601       mlir::Type eleTy =
3602           fir::unwrapSequenceType(fir::unwrapRefType(load.getType()));
3603       auto seqTy = fir::SequenceType::get(eleTy, iters.iterVec().size());
3604       auto toTy = fir::HeapType::get(seqTy);
3605       mlir::Value castTo = builder.createConvert(loc, toTy, load);
3606       mlir::Value shape = builder.genShape(loc, genIterationShape());
3607       llvm::SmallVector<mlir::Value> indices = fir::factory::originateIndices(
3608           loc, builder, castTo.getType(), shape, iters.iterVec());
3609       auto eleAddr = builder.create<fir::ArrayCoorOp>(
3610           loc, builder.getRefType(eleTy), castTo, shape,
3611           /*slice=*/mlir::Value{}, indices, destination.getTypeparams());
3612       mlir::Value eleVal =
3613           builder.createConvert(loc, eleTy, iters.getElement());
3614       builder.create<fir::StoreOp>(loc, eleVal, eleAddr);
3615       return iters.innerArgument();
3616     };
3617 
3618     // Lower the array expression now. Clean-up any temps that may have
3619     // been generated when lowering `expr` right after the lowered value
3620     // was stored to the ragged array temporary. The local temps will not
3621     // be needed afterwards.
3622     stmtCtx.pushScope();
3623     [[maybe_unused]] ExtValue loopRes = lowerArrayExpression(expr);
3624     stmtCtx.finalize(/*popScope=*/true);
3625     assert(fir::getBase(loopRes));
3626   }
3627 
3628   static void
3629   lowerElementalUserAssignment(Fortran::lower::AbstractConverter &converter,
3630                                Fortran::lower::SymMap &symMap,
3631                                Fortran::lower::StatementContext &stmtCtx,
3632                                Fortran::lower::ExplicitIterSpace &explicitSpace,
3633                                Fortran::lower::ImplicitIterSpace &implicitSpace,
3634                                const Fortran::evaluate::ProcedureRef &procRef) {
3635     ArrayExprLowering ael(converter, stmtCtx, symMap,
3636                           ConstituentSemantics::CustomCopyInCopyOut,
3637                           &explicitSpace, &implicitSpace);
3638     assert(procRef.arguments().size() == 2);
3639     const auto *lhs = procRef.arguments()[0].value().UnwrapExpr();
3640     const auto *rhs = procRef.arguments()[1].value().UnwrapExpr();
3641     assert(lhs && rhs &&
3642            "user defined assignment arguments must be expressions");
3643     mlir::FuncOp func =
3644         Fortran::lower::CallerInterface(procRef, converter).getFuncOp();
3645     ael.lowerElementalUserAssignment(func, *lhs, *rhs);
3646   }
3647 
3648   void lowerElementalUserAssignment(mlir::FuncOp userAssignment,
3649                                     const Fortran::lower::SomeExpr &lhs,
3650                                     const Fortran::lower::SomeExpr &rhs) {
3651     mlir::Location loc = getLoc();
3652     PushSemantics(ConstituentSemantics::CustomCopyInCopyOut);
3653     auto genArrayModify = genarr(lhs);
3654     ccStoreToDest = [=](IterSpace iters) -> ExtValue {
3655       auto modifiedArray = genArrayModify(iters);
3656       auto arrayModify = mlir::dyn_cast_or_null<fir::ArrayModifyOp>(
3657           fir::getBase(modifiedArray).getDefiningOp());
3658       assert(arrayModify && "must be created by ArrayModifyOp");
3659       fir::ExtendedValue lhs =
3660           arrayModifyToExv(builder, loc, destination, arrayModify.getResult(0));
3661       genScalarUserDefinedAssignmentCall(builder, loc, userAssignment, lhs,
3662                                          iters.elementExv());
3663       return modifiedArray;
3664     };
3665     determineShapeOfDest(lhs);
3666     semant = ConstituentSemantics::RefTransparent;
3667     auto exv = lowerArrayExpression(rhs);
3668     if (explicitSpaceIsActive()) {
3669       explicitSpace->finalizeContext();
3670       builder.create<fir::ResultOp>(loc, fir::getBase(exv));
3671     } else {
3672       builder.create<fir::ArrayMergeStoreOp>(
3673           loc, destination, fir::getBase(exv), destination.getMemref(),
3674           destination.getSlice(), destination.getTypeparams());
3675     }
3676   }
3677 
3678   /// Lower an elemental subroutine call with at least one array argument.
3679   /// An elemental subroutine is an exception and does not have copy-in/copy-out
3680   /// semantics. See 15.8.3.
3681   /// Do NOT use this for user defined assignments.
3682   static void
3683   lowerElementalSubroutine(Fortran::lower::AbstractConverter &converter,
3684                            Fortran::lower::SymMap &symMap,
3685                            Fortran::lower::StatementContext &stmtCtx,
3686                            const Fortran::lower::SomeExpr &call) {
3687     ArrayExprLowering ael(converter, stmtCtx, symMap,
3688                           ConstituentSemantics::RefTransparent);
3689     ael.lowerElementalSubroutine(call);
3690   }
3691 
3692   // TODO: See the comment in genarr(const Fortran::lower::Parentheses<T>&).
3693   // This is skipping generation of copy-in/copy-out code for analysis that is
3694   // required when arguments are in parentheses.
3695   void lowerElementalSubroutine(const Fortran::lower::SomeExpr &call) {
3696     auto f = genarr(call);
3697     llvm::SmallVector<mlir::Value> shape = genIterationShape();
3698     auto [iterSpace, insPt] = genImplicitLoops(shape, /*innerArg=*/{});
3699     f(iterSpace);
3700     finalizeElementCtx();
3701     builder.restoreInsertionPoint(insPt);
3702   }
3703 
3704   template <typename A, typename B>
3705   ExtValue lowerScalarAssignment(const A &lhs, const B &rhs) {
3706     // 1) Lower the rhs expression with array_fetch op(s).
3707     IterationSpace iters;
3708     iters.setElement(genarr(rhs)(iters));
3709     fir::ExtendedValue elementalExv = iters.elementExv();
3710     // 2) Lower the lhs expression to an array_update.
3711     semant = ConstituentSemantics::ProjectedCopyInCopyOut;
3712     auto lexv = genarr(lhs)(iters);
3713     // 3) Finalize the inner context.
3714     explicitSpace->finalizeContext();
3715     // 4) Thread the array value updated forward. Note: the lhs might be
3716     // ill-formed (performing scalar assignment in an array context),
3717     // in which case there is no array to thread.
3718     auto createResult = [&](auto op) {
3719       mlir::Value oldInnerArg = op.getSequence();
3720       std::size_t offset = explicitSpace->argPosition(oldInnerArg);
3721       explicitSpace->setInnerArg(offset, fir::getBase(lexv));
3722       builder.create<fir::ResultOp>(getLoc(), fir::getBase(lexv));
3723     };
3724     if (auto updateOp = mlir::dyn_cast<fir::ArrayUpdateOp>(
3725             fir::getBase(lexv).getDefiningOp()))
3726       createResult(updateOp);
3727     else if (auto amend = mlir::dyn_cast<fir::ArrayAmendOp>(
3728                  fir::getBase(lexv).getDefiningOp()))
3729       createResult(amend);
3730     else if (auto modifyOp = mlir::dyn_cast<fir::ArrayModifyOp>(
3731                  fir::getBase(lexv).getDefiningOp()))
3732       createResult(modifyOp);
3733     return lexv;
3734   }
3735 
3736   static ExtValue lowerScalarUserAssignment(
3737       Fortran::lower::AbstractConverter &converter,
3738       Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx,
3739       Fortran::lower::ExplicitIterSpace &explicitIterSpace,
3740       mlir::FuncOp userAssignmentFunction, const Fortran::lower::SomeExpr &lhs,
3741       const Fortran::lower::SomeExpr &rhs) {
3742     Fortran::lower::ImplicitIterSpace implicit;
3743     ArrayExprLowering ael(converter, stmtCtx, symMap,
3744                           ConstituentSemantics::RefTransparent,
3745                           &explicitIterSpace, &implicit);
3746     return ael.lowerScalarUserAssignment(userAssignmentFunction, lhs, rhs);
3747   }
3748 
3749   ExtValue lowerScalarUserAssignment(mlir::FuncOp userAssignment,
3750                                      const Fortran::lower::SomeExpr &lhs,
3751                                      const Fortran::lower::SomeExpr &rhs) {
3752     mlir::Location loc = getLoc();
3753     if (rhs.Rank() > 0)
3754       TODO(loc, "user-defined elemental assigment from expression with rank");
3755     // 1) Lower the rhs expression with array_fetch op(s).
3756     IterationSpace iters;
3757     iters.setElement(genarr(rhs)(iters));
3758     fir::ExtendedValue elementalExv = iters.elementExv();
3759     // 2) Lower the lhs expression to an array_modify.
3760     semant = ConstituentSemantics::CustomCopyInCopyOut;
3761     auto lexv = genarr(lhs)(iters);
3762     bool isIllFormedLHS = false;
3763     // 3) Insert the call
3764     if (auto modifyOp = mlir::dyn_cast<fir::ArrayModifyOp>(
3765             fir::getBase(lexv).getDefiningOp())) {
3766       mlir::Value oldInnerArg = modifyOp.getSequence();
3767       std::size_t offset = explicitSpace->argPosition(oldInnerArg);
3768       explicitSpace->setInnerArg(offset, fir::getBase(lexv));
3769       fir::ExtendedValue exv = arrayModifyToExv(
3770           builder, loc, explicitSpace->getLhsLoad(0).getValue(),
3771           modifyOp.getResult(0));
3772       genScalarUserDefinedAssignmentCall(builder, loc, userAssignment, exv,
3773                                          elementalExv);
3774     } else {
3775       // LHS is ill formed, it is a scalar with no references to FORALL
3776       // subscripts, so there is actually no array assignment here. The user
3777       // code is probably bad, but still insert user assignment call since it
3778       // was not rejected by semantics (a warning was emitted).
3779       isIllFormedLHS = true;
3780       genScalarUserDefinedAssignmentCall(builder, getLoc(), userAssignment,
3781                                          lexv, elementalExv);
3782     }
3783     // 4) Finalize the inner context.
3784     explicitSpace->finalizeContext();
3785     // 5). Thread the array value updated forward.
3786     if (!isIllFormedLHS)
3787       builder.create<fir::ResultOp>(getLoc(), fir::getBase(lexv));
3788     return lexv;
3789   }
3790 
3791 private:
3792   void determineShapeOfDest(const fir::ExtendedValue &lhs) {
3793     destShape = fir::factory::getExtents(builder, getLoc(), lhs);
3794   }
3795 
3796   void determineShapeOfDest(const Fortran::lower::SomeExpr &lhs) {
3797     if (!destShape.empty())
3798       return;
3799     if (explicitSpaceIsActive() && determineShapeWithSlice(lhs))
3800       return;
3801     mlir::Type idxTy = builder.getIndexType();
3802     mlir::Location loc = getLoc();
3803     if (std::optional<Fortran::evaluate::ConstantSubscripts> constantShape =
3804             Fortran::evaluate::GetConstantExtents(converter.getFoldingContext(),
3805                                                   lhs))
3806       for (Fortran::common::ConstantSubscript extent : *constantShape)
3807         destShape.push_back(builder.createIntegerConstant(loc, idxTy, extent));
3808   }
3809 
3810   bool genShapeFromDataRef(const Fortran::semantics::Symbol &x) {
3811     return false;
3812   }
3813   bool genShapeFromDataRef(const Fortran::evaluate::CoarrayRef &) {
3814     TODO(getLoc(), "coarray ref");
3815     return false;
3816   }
3817   bool genShapeFromDataRef(const Fortran::evaluate::Component &x) {
3818     return x.base().Rank() > 0 ? genShapeFromDataRef(x.base()) : false;
3819   }
3820   bool genShapeFromDataRef(const Fortran::evaluate::ArrayRef &x) {
3821     if (x.Rank() == 0)
3822       return false;
3823     if (x.base().Rank() > 0)
3824       if (genShapeFromDataRef(x.base()))
3825         return true;
3826     // x has rank and x.base did not produce a shape.
3827     ExtValue exv = x.base().IsSymbol() ? asScalarRef(getFirstSym(x.base()))
3828                                        : asScalarRef(x.base().GetComponent());
3829     mlir::Location loc = getLoc();
3830     mlir::IndexType idxTy = builder.getIndexType();
3831     llvm::SmallVector<mlir::Value> definedShape =
3832         fir::factory::getExtents(builder, loc, exv);
3833     mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
3834     for (auto ss : llvm::enumerate(x.subscript())) {
3835       std::visit(Fortran::common::visitors{
3836                      [&](const Fortran::evaluate::Triplet &trip) {
3837                        // For a subscript of triple notation, we compute the
3838                        // range of this dimension of the iteration space.
3839                        auto lo = [&]() {
3840                          if (auto optLo = trip.lower())
3841                            return fir::getBase(asScalar(*optLo));
3842                          return getLBound(exv, ss.index(), one);
3843                        }();
3844                        auto hi = [&]() {
3845                          if (auto optHi = trip.upper())
3846                            return fir::getBase(asScalar(*optHi));
3847                          return getUBound(exv, ss.index(), one);
3848                        }();
3849                        auto step = builder.createConvert(
3850                            loc, idxTy, fir::getBase(asScalar(trip.stride())));
3851                        auto extent = builder.genExtentFromTriplet(loc, lo, hi,
3852                                                                   step, idxTy);
3853                        destShape.push_back(extent);
3854                      },
3855                      [&](auto) {}},
3856                  ss.value().u);
3857     }
3858     return true;
3859   }
3860   bool genShapeFromDataRef(const Fortran::evaluate::NamedEntity &x) {
3861     if (x.IsSymbol())
3862       return genShapeFromDataRef(getFirstSym(x));
3863     return genShapeFromDataRef(x.GetComponent());
3864   }
3865   bool genShapeFromDataRef(const Fortran::evaluate::DataRef &x) {
3866     return std::visit([&](const auto &v) { return genShapeFromDataRef(v); },
3867                       x.u);
3868   }
3869 
3870   /// When in an explicit space, the ranked component must be evaluated to
3871   /// determine the actual number of iterations when slicing triples are
3872   /// present. Lower these expressions here.
3873   bool determineShapeWithSlice(const Fortran::lower::SomeExpr &lhs) {
3874     LLVM_DEBUG(Fortran::lower::DumpEvaluateExpr::dump(
3875         llvm::dbgs() << "determine shape of:\n", lhs));
3876     // FIXME: We may not want to use ExtractDataRef here since it doesn't deal
3877     // with substrings, etc.
3878     std::optional<Fortran::evaluate::DataRef> dref =
3879         Fortran::evaluate::ExtractDataRef(lhs);
3880     return dref.has_value() ? genShapeFromDataRef(*dref) : false;
3881   }
3882 
3883   /// CHARACTER and derived type elements are treated as memory references. The
3884   /// numeric types are treated as values.
3885   static mlir::Type adjustedArraySubtype(mlir::Type ty,
3886                                          mlir::ValueRange indices) {
3887     mlir::Type pathTy = fir::applyPathToType(ty, indices);
3888     assert(pathTy && "indices failed to apply to type");
3889     return adjustedArrayElementType(pathTy);
3890   }
3891 
3892   ExtValue lowerArrayExpression(const Fortran::lower::SomeExpr &exp) {
3893     mlir::Type resTy = converter.genType(exp);
3894     return std::visit(
3895         [&](const auto &e) { return lowerArrayExpression(genarr(e), resTy); },
3896         exp.u);
3897   }
3898   ExtValue lowerArrayExpression(const ExtValue &exv) {
3899     assert(!explicitSpace);
3900     mlir::Type resTy = fir::unwrapPassByRefType(fir::getBase(exv).getType());
3901     return lowerArrayExpression(genarr(exv), resTy);
3902   }
3903 
3904   void populateBounds(llvm::SmallVectorImpl<mlir::Value> &bounds,
3905                       const Fortran::evaluate::Substring *substring) {
3906     if (!substring)
3907       return;
3908     bounds.push_back(fir::getBase(asScalar(substring->lower())));
3909     if (auto upper = substring->upper())
3910       bounds.push_back(fir::getBase(asScalar(*upper)));
3911   }
3912 
3913   /// Default store to destination implementation.
3914   /// This implements the default case, which is to assign the value in
3915   /// `iters.element` into the destination array, `iters.innerArgument`. Handles
3916   /// by value and by reference assignment.
3917   CC defaultStoreToDestination(const Fortran::evaluate::Substring *substring) {
3918     return [=](IterSpace iterSpace) -> ExtValue {
3919       mlir::Location loc = getLoc();
3920       mlir::Value innerArg = iterSpace.innerArgument();
3921       fir::ExtendedValue exv = iterSpace.elementExv();
3922       mlir::Type arrTy = innerArg.getType();
3923       mlir::Type eleTy = fir::applyPathToType(arrTy, iterSpace.iterVec());
3924       if (isAdjustedArrayElementType(eleTy)) {
3925         // The elemental update is in the memref domain. Under this semantics,
3926         // we must always copy the computed new element from its location in
3927         // memory into the destination array.
3928         mlir::Type resRefTy = builder.getRefType(eleTy);
3929         // Get a reference to the array element to be amended.
3930         auto arrayOp = builder.create<fir::ArrayAccessOp>(
3931             loc, resRefTy, innerArg, iterSpace.iterVec(),
3932             destination.getTypeparams());
3933         if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) {
3934           llvm::SmallVector<mlir::Value> substringBounds;
3935           populateBounds(substringBounds, substring);
3936           mlir::Value dstLen = fir::factory::genLenOfCharacter(
3937               builder, loc, destination, iterSpace.iterVec(), substringBounds);
3938           fir::ArrayAmendOp amend = createCharArrayAmend(
3939               loc, builder, arrayOp, dstLen, exv, innerArg, substringBounds);
3940           return abstractArrayExtValue(amend, dstLen);
3941         }
3942         if (fir::isa_derived(eleTy)) {
3943           fir::ArrayAmendOp amend = createDerivedArrayAmend(
3944               loc, destination, builder, arrayOp, exv, eleTy, innerArg);
3945           return abstractArrayExtValue(amend /*FIXME: typeparams?*/);
3946         }
3947         assert(eleTy.isa<fir::SequenceType>() && "must be an array");
3948         TODO(loc, "array (as element) assignment");
3949       }
3950       // By value semantics. The element is being assigned by value.
3951       mlir::Value ele = builder.createConvert(loc, eleTy, fir::getBase(exv));
3952       auto update = builder.create<fir::ArrayUpdateOp>(
3953           loc, arrTy, innerArg, ele, iterSpace.iterVec(),
3954           destination.getTypeparams());
3955       return abstractArrayExtValue(update);
3956     };
3957   }
3958 
3959   /// For an elemental array expression.
3960   ///   1. Lower the scalars and array loads.
3961   ///   2. Create the iteration space.
3962   ///   3. Create the element-by-element computation in the loop.
3963   ///   4. Return the resulting array value.
3964   /// If no destination was set in the array context, a temporary of
3965   /// \p resultTy will be created to hold the evaluated expression.
3966   /// Otherwise, \p resultTy is ignored and the expression is evaluated
3967   /// in the destination. \p f is a continuation built from an
3968   /// evaluate::Expr or an ExtendedValue.
3969   ExtValue lowerArrayExpression(CC f, mlir::Type resultTy) {
3970     mlir::Location loc = getLoc();
3971     auto [iterSpace, insPt] = genIterSpace(resultTy);
3972     auto exv = f(iterSpace);
3973     iterSpace.setElement(std::move(exv));
3974     auto lambda = ccStoreToDest.hasValue()
3975                       ? ccStoreToDest.getValue()
3976                       : defaultStoreToDestination(/*substring=*/nullptr);
3977     mlir::Value updVal = fir::getBase(lambda(iterSpace));
3978     finalizeElementCtx();
3979     builder.create<fir::ResultOp>(loc, updVal);
3980     builder.restoreInsertionPoint(insPt);
3981     return abstractArrayExtValue(iterSpace.outerResult());
3982   }
3983 
3984   /// Compute the shape of a slice.
3985   llvm::SmallVector<mlir::Value> computeSliceShape(mlir::Value slice) {
3986     llvm::SmallVector<mlir::Value> slicedShape;
3987     auto slOp = mlir::cast<fir::SliceOp>(slice.getDefiningOp());
3988     mlir::Operation::operand_range triples = slOp.getTriples();
3989     mlir::IndexType idxTy = builder.getIndexType();
3990     mlir::Location loc = getLoc();
3991     for (unsigned i = 0, end = triples.size(); i < end; i += 3) {
3992       if (!mlir::isa_and_nonnull<fir::UndefOp>(
3993               triples[i + 1].getDefiningOp())) {
3994         // (..., lb:ub:step, ...) case:  extent = max((ub-lb+step)/step, 0)
3995         // See Fortran 2018 9.5.3.3.2 section for more details.
3996         mlir::Value res = builder.genExtentFromTriplet(
3997             loc, triples[i], triples[i + 1], triples[i + 2], idxTy);
3998         slicedShape.emplace_back(res);
3999       } else {
4000         // do nothing. `..., i, ...` case, so dimension is dropped.
4001       }
4002     }
4003     return slicedShape;
4004   }
4005 
4006   /// Get the shape from an ArrayOperand. The shape of the array is adjusted if
4007   /// the array was sliced.
4008   llvm::SmallVector<mlir::Value> getShape(ArrayOperand array) {
4009     if (array.slice)
4010       return computeSliceShape(array.slice);
4011     if (array.memref.getType().isa<fir::BoxType>())
4012       return fir::factory::readExtents(builder, getLoc(),
4013                                        fir::BoxValue{array.memref});
4014     std::vector<mlir::Value, std::allocator<mlir::Value>> extents =
4015         fir::factory::getExtents(array.shape);
4016     return {extents.begin(), extents.end()};
4017   }
4018 
4019   /// Get the shape from an ArrayLoad.
4020   llvm::SmallVector<mlir::Value> getShape(fir::ArrayLoadOp arrayLoad) {
4021     return getShape(ArrayOperand{arrayLoad.getMemref(), arrayLoad.getShape(),
4022                                  arrayLoad.getSlice()});
4023   }
4024 
4025   /// Returns the first array operand that may not be absent. If all
4026   /// array operands may be absent, return the first one.
4027   const ArrayOperand &getInducingShapeArrayOperand() const {
4028     assert(!arrayOperands.empty());
4029     for (const ArrayOperand &op : arrayOperands)
4030       if (!op.mayBeAbsent)
4031         return op;
4032     // If all arrays operand appears in optional position, then none of them
4033     // is allowed to be absent as per 15.5.2.12 point 3. (6). Just pick the
4034     // first operands.
4035     // TODO: There is an opportunity to add a runtime check here that
4036     // this array is present as required.
4037     return arrayOperands[0];
4038   }
4039 
4040   /// Generate the shape of the iteration space over the array expression. The
4041   /// iteration space may be implicit, explicit, or both. If it is implied it is
4042   /// based on the destination and operand array loads, or an optional
4043   /// Fortran::evaluate::Shape from the front end. If the shape is explicit,
4044   /// this returns any implicit shape component, if it exists.
4045   llvm::SmallVector<mlir::Value> genIterationShape() {
4046     // Use the precomputed destination shape.
4047     if (!destShape.empty())
4048       return destShape;
4049     // Otherwise, use the destination's shape.
4050     if (destination)
4051       return getShape(destination);
4052     // Otherwise, use the first ArrayLoad operand shape.
4053     if (!arrayOperands.empty())
4054       return getShape(getInducingShapeArrayOperand());
4055     fir::emitFatalError(getLoc(),
4056                         "failed to compute the array expression shape");
4057   }
4058 
4059   bool explicitSpaceIsActive() const {
4060     return explicitSpace && explicitSpace->isActive();
4061   }
4062 
4063   bool implicitSpaceHasMasks() const {
4064     return implicitSpace && !implicitSpace->empty();
4065   }
4066 
4067   CC genMaskAccess(mlir::Value tmp, mlir::Value shape) {
4068     mlir::Location loc = getLoc();
4069     return [=, builder = &converter.getFirOpBuilder()](IterSpace iters) {
4070       mlir::Type arrTy = fir::dyn_cast_ptrOrBoxEleTy(tmp.getType());
4071       auto eleTy = arrTy.cast<fir::SequenceType>().getEleTy();
4072       mlir::Type eleRefTy = builder->getRefType(eleTy);
4073       mlir::IntegerType i1Ty = builder->getI1Type();
4074       // Adjust indices for any shift of the origin of the array.
4075       llvm::SmallVector<mlir::Value> indices = fir::factory::originateIndices(
4076           loc, *builder, tmp.getType(), shape, iters.iterVec());
4077       auto addr = builder->create<fir::ArrayCoorOp>(
4078           loc, eleRefTy, tmp, shape, /*slice=*/mlir::Value{}, indices,
4079           /*typeParams=*/llvm::None);
4080       auto load = builder->create<fir::LoadOp>(loc, addr);
4081       return builder->createConvert(loc, i1Ty, load);
4082     };
4083   }
4084 
4085   /// Construct the incremental instantiations of the ragged array structure.
4086   /// Rebind the lazy buffer variable, etc. as we go.
4087   template <bool withAllocation = false>
4088   mlir::Value prepareRaggedArrays(Fortran::lower::FrontEndExpr expr) {
4089     assert(explicitSpaceIsActive());
4090     mlir::Location loc = getLoc();
4091     mlir::TupleType raggedTy = fir::factory::getRaggedArrayHeaderType(builder);
4092     llvm::SmallVector<llvm::SmallVector<fir::DoLoopOp>> loopStack =
4093         explicitSpace->getLoopStack();
4094     const std::size_t depth = loopStack.size();
4095     mlir::IntegerType i64Ty = builder.getIntegerType(64);
4096     [[maybe_unused]] mlir::Value byteSize =
4097         builder.createIntegerConstant(loc, i64Ty, 1);
4098     mlir::Value header = implicitSpace->lookupMaskHeader(expr);
4099     for (std::remove_const_t<decltype(depth)> i = 0; i < depth; ++i) {
4100       auto insPt = builder.saveInsertionPoint();
4101       if (i < depth - 1)
4102         builder.setInsertionPoint(loopStack[i + 1][0]);
4103 
4104       // Compute and gather the extents.
4105       llvm::SmallVector<mlir::Value> extents;
4106       for (auto doLoop : loopStack[i])
4107         extents.push_back(builder.genExtentFromTriplet(
4108             loc, doLoop.getLowerBound(), doLoop.getUpperBound(),
4109             doLoop.getStep(), i64Ty));
4110       if constexpr (withAllocation) {
4111         fir::runtime::genRaggedArrayAllocate(
4112             loc, builder, header, /*asHeader=*/true, byteSize, extents);
4113       }
4114 
4115       // Compute the dynamic position into the header.
4116       llvm::SmallVector<mlir::Value> offsets;
4117       for (auto doLoop : loopStack[i]) {
4118         auto m = builder.create<mlir::arith::SubIOp>(
4119             loc, doLoop.getInductionVar(), doLoop.getLowerBound());
4120         auto n = builder.create<mlir::arith::DivSIOp>(loc, m, doLoop.getStep());
4121         mlir::Value one = builder.createIntegerConstant(loc, n.getType(), 1);
4122         offsets.push_back(builder.create<mlir::arith::AddIOp>(loc, n, one));
4123       }
4124       mlir::IntegerType i32Ty = builder.getIntegerType(32);
4125       mlir::Value uno = builder.createIntegerConstant(loc, i32Ty, 1);
4126       mlir::Type coorTy = builder.getRefType(raggedTy.getType(1));
4127       auto hdOff = builder.create<fir::CoordinateOp>(loc, coorTy, header, uno);
4128       auto toTy = fir::SequenceType::get(raggedTy, offsets.size());
4129       mlir::Type toRefTy = builder.getRefType(toTy);
4130       auto ldHdr = builder.create<fir::LoadOp>(loc, hdOff);
4131       mlir::Value hdArr = builder.createConvert(loc, toRefTy, ldHdr);
4132       auto shapeOp = builder.genShape(loc, extents);
4133       header = builder.create<fir::ArrayCoorOp>(
4134           loc, builder.getRefType(raggedTy), hdArr, shapeOp,
4135           /*slice=*/mlir::Value{}, offsets,
4136           /*typeparams=*/mlir::ValueRange{});
4137       auto hdrVar = builder.create<fir::CoordinateOp>(loc, coorTy, header, uno);
4138       auto inVar = builder.create<fir::LoadOp>(loc, hdrVar);
4139       mlir::Value two = builder.createIntegerConstant(loc, i32Ty, 2);
4140       mlir::Type coorTy2 = builder.getRefType(raggedTy.getType(2));
4141       auto hdrSh = builder.create<fir::CoordinateOp>(loc, coorTy2, header, two);
4142       auto shapePtr = builder.create<fir::LoadOp>(loc, hdrSh);
4143       // Replace the binding.
4144       implicitSpace->rebind(expr, genMaskAccess(inVar, shapePtr));
4145       if (i < depth - 1)
4146         builder.restoreInsertionPoint(insPt);
4147     }
4148     return header;
4149   }
4150 
4151   /// Lower mask expressions with implied iteration spaces from the variants of
4152   /// WHERE syntax. Since it is legal for mask expressions to have side-effects
4153   /// and modify values that will be used for the lhs, rhs, or both of
4154   /// subsequent assignments, the mask must be evaluated before the assignment
4155   /// is processed.
4156   /// Mask expressions are array expressions too.
4157   void genMasks() {
4158     // Lower the mask expressions, if any.
4159     if (implicitSpaceHasMasks()) {
4160       mlir::Location loc = getLoc();
4161       // Mask expressions are array expressions too.
4162       for (const auto *e : implicitSpace->getExprs())
4163         if (e && !implicitSpace->isLowered(e)) {
4164           if (mlir::Value var = implicitSpace->lookupMaskVariable(e)) {
4165             // Allocate the mask buffer lazily.
4166             assert(explicitSpaceIsActive());
4167             mlir::Value header =
4168                 prepareRaggedArrays</*withAllocations=*/true>(e);
4169             Fortran::lower::createLazyArrayTempValue(converter, *e, header,
4170                                                      symMap, stmtCtx);
4171             // Close the explicit loops.
4172             builder.create<fir::ResultOp>(loc, explicitSpace->getInnerArgs());
4173             builder.setInsertionPointAfter(explicitSpace->getOuterLoop());
4174             // Open a new copy of the explicit loop nest.
4175             explicitSpace->genLoopNest();
4176             continue;
4177           }
4178           fir::ExtendedValue tmp = Fortran::lower::createSomeArrayTempValue(
4179               converter, *e, symMap, stmtCtx);
4180           mlir::Value shape = builder.createShape(loc, tmp);
4181           implicitSpace->bind(e, genMaskAccess(fir::getBase(tmp), shape));
4182         }
4183 
4184       // Set buffer from the header.
4185       for (const auto *e : implicitSpace->getExprs()) {
4186         if (!e)
4187           continue;
4188         if (implicitSpace->lookupMaskVariable(e)) {
4189           // Index into the ragged buffer to retrieve cached results.
4190           const int rank = e->Rank();
4191           assert(destShape.empty() ||
4192                  static_cast<std::size_t>(rank) == destShape.size());
4193           mlir::Value header = prepareRaggedArrays(e);
4194           mlir::TupleType raggedTy =
4195               fir::factory::getRaggedArrayHeaderType(builder);
4196           mlir::IntegerType i32Ty = builder.getIntegerType(32);
4197           mlir::Value one = builder.createIntegerConstant(loc, i32Ty, 1);
4198           auto coor1 = builder.create<fir::CoordinateOp>(
4199               loc, builder.getRefType(raggedTy.getType(1)), header, one);
4200           auto db = builder.create<fir::LoadOp>(loc, coor1);
4201           mlir::Type eleTy =
4202               fir::unwrapSequenceType(fir::unwrapRefType(db.getType()));
4203           mlir::Type buffTy =
4204               builder.getRefType(fir::SequenceType::get(eleTy, rank));
4205           // Address of ragged buffer data.
4206           mlir::Value buff = builder.createConvert(loc, buffTy, db);
4207 
4208           mlir::Value two = builder.createIntegerConstant(loc, i32Ty, 2);
4209           auto coor2 = builder.create<fir::CoordinateOp>(
4210               loc, builder.getRefType(raggedTy.getType(2)), header, two);
4211           auto shBuff = builder.create<fir::LoadOp>(loc, coor2);
4212           mlir::IntegerType i64Ty = builder.getIntegerType(64);
4213           mlir::IndexType idxTy = builder.getIndexType();
4214           llvm::SmallVector<mlir::Value> extents;
4215           for (std::remove_const_t<decltype(rank)> i = 0; i < rank; ++i) {
4216             mlir::Value off = builder.createIntegerConstant(loc, i32Ty, i);
4217             auto coor = builder.create<fir::CoordinateOp>(
4218                 loc, builder.getRefType(i64Ty), shBuff, off);
4219             auto ldExt = builder.create<fir::LoadOp>(loc, coor);
4220             extents.push_back(builder.createConvert(loc, idxTy, ldExt));
4221           }
4222           if (destShape.empty())
4223             destShape = extents;
4224           // Construct shape of buffer.
4225           mlir::Value shapeOp = builder.genShape(loc, extents);
4226 
4227           // Replace binding with the local result.
4228           implicitSpace->rebind(e, genMaskAccess(buff, shapeOp));
4229         }
4230       }
4231     }
4232   }
4233 
4234   // FIXME: should take multiple inner arguments.
4235   std::pair<IterationSpace, mlir::OpBuilder::InsertPoint>
4236   genImplicitLoops(mlir::ValueRange shape, mlir::Value innerArg) {
4237     mlir::Location loc = getLoc();
4238     mlir::IndexType idxTy = builder.getIndexType();
4239     mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
4240     mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
4241     llvm::SmallVector<mlir::Value> loopUppers;
4242 
4243     // Convert any implied shape to closed interval form. The fir.do_loop will
4244     // run from 0 to `extent - 1` inclusive.
4245     for (auto extent : shape)
4246       loopUppers.push_back(
4247           builder.create<mlir::arith::SubIOp>(loc, extent, one));
4248 
4249     // Iteration space is created with outermost columns, innermost rows
4250     llvm::SmallVector<fir::DoLoopOp> loops;
4251 
4252     const std::size_t loopDepth = loopUppers.size();
4253     llvm::SmallVector<mlir::Value> ivars;
4254 
4255     for (auto i : llvm::enumerate(llvm::reverse(loopUppers))) {
4256       if (i.index() > 0) {
4257         assert(!loops.empty());
4258         builder.setInsertionPointToStart(loops.back().getBody());
4259       }
4260       fir::DoLoopOp loop;
4261       if (innerArg) {
4262         loop = builder.create<fir::DoLoopOp>(
4263             loc, zero, i.value(), one, isUnordered(),
4264             /*finalCount=*/false, mlir::ValueRange{innerArg});
4265         innerArg = loop.getRegionIterArgs().front();
4266         if (explicitSpaceIsActive())
4267           explicitSpace->setInnerArg(0, innerArg);
4268       } else {
4269         loop = builder.create<fir::DoLoopOp>(loc, zero, i.value(), one,
4270                                              isUnordered(),
4271                                              /*finalCount=*/false);
4272       }
4273       ivars.push_back(loop.getInductionVar());
4274       loops.push_back(loop);
4275     }
4276 
4277     if (innerArg)
4278       for (std::remove_const_t<decltype(loopDepth)> i = 0; i + 1 < loopDepth;
4279            ++i) {
4280         builder.setInsertionPointToEnd(loops[i].getBody());
4281         builder.create<fir::ResultOp>(loc, loops[i + 1].getResult(0));
4282       }
4283 
4284     // Move insertion point to the start of the innermost loop in the nest.
4285     builder.setInsertionPointToStart(loops.back().getBody());
4286     // Set `afterLoopNest` to just after the entire loop nest.
4287     auto currPt = builder.saveInsertionPoint();
4288     builder.setInsertionPointAfter(loops[0]);
4289     auto afterLoopNest = builder.saveInsertionPoint();
4290     builder.restoreInsertionPoint(currPt);
4291 
4292     // Put the implicit loop variables in row to column order to match FIR's
4293     // Ops. (The loops were constructed from outermost column to innermost
4294     // row.)
4295     mlir::Value outerRes = loops[0].getResult(0);
4296     return {IterationSpace(innerArg, outerRes, llvm::reverse(ivars)),
4297             afterLoopNest};
4298   }
4299 
4300   /// Build the iteration space into which the array expression will be
4301   /// lowered. The resultType is used to create a temporary, if needed.
4302   std::pair<IterationSpace, mlir::OpBuilder::InsertPoint>
4303   genIterSpace(mlir::Type resultType) {
4304     mlir::Location loc = getLoc();
4305     llvm::SmallVector<mlir::Value> shape = genIterationShape();
4306     if (!destination) {
4307       // Allocate storage for the result if it is not already provided.
4308       destination = createAndLoadSomeArrayTemp(resultType, shape);
4309     }
4310 
4311     // Generate the lazy mask allocation, if one was given.
4312     if (ccPrelude.hasValue())
4313       ccPrelude.getValue()(shape);
4314 
4315     // Now handle the implicit loops.
4316     mlir::Value inner = explicitSpaceIsActive()
4317                             ? explicitSpace->getInnerArgs().front()
4318                             : destination.getResult();
4319     auto [iters, afterLoopNest] = genImplicitLoops(shape, inner);
4320     mlir::Value innerArg = iters.innerArgument();
4321 
4322     // Generate the mask conditional structure, if there are masks. Unlike the
4323     // explicit masks, which are interleaved, these mask expression appear in
4324     // the innermost loop.
4325     if (implicitSpaceHasMasks()) {
4326       // Recover the cached condition from the mask buffer.
4327       auto genCond = [&](Fortran::lower::FrontEndExpr e, IterSpace iters) {
4328         return implicitSpace->getBoundClosure(e)(iters);
4329       };
4330 
4331       // Handle the negated conditions in topological order of the WHERE
4332       // clauses. See 10.2.3.2p4 as to why this control structure is produced.
4333       for (llvm::SmallVector<Fortran::lower::FrontEndExpr> maskExprs :
4334            implicitSpace->getMasks()) {
4335         const std::size_t size = maskExprs.size() - 1;
4336         auto genFalseBlock = [&](const auto *e, auto &&cond) {
4337           auto ifOp = builder.create<fir::IfOp>(
4338               loc, mlir::TypeRange{innerArg.getType()}, fir::getBase(cond),
4339               /*withElseRegion=*/true);
4340           builder.create<fir::ResultOp>(loc, ifOp.getResult(0));
4341           builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
4342           builder.create<fir::ResultOp>(loc, innerArg);
4343           builder.setInsertionPointToStart(&ifOp.getElseRegion().front());
4344         };
4345         auto genTrueBlock = [&](const auto *e, auto &&cond) {
4346           auto ifOp = builder.create<fir::IfOp>(
4347               loc, mlir::TypeRange{innerArg.getType()}, fir::getBase(cond),
4348               /*withElseRegion=*/true);
4349           builder.create<fir::ResultOp>(loc, ifOp.getResult(0));
4350           builder.setInsertionPointToStart(&ifOp.getElseRegion().front());
4351           builder.create<fir::ResultOp>(loc, innerArg);
4352           builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
4353         };
4354         for (std::remove_const_t<decltype(size)> i = 0; i < size; ++i)
4355           if (const auto *e = maskExprs[i])
4356             genFalseBlock(e, genCond(e, iters));
4357 
4358         // The last condition is either non-negated or unconditionally negated.
4359         if (const auto *e = maskExprs[size])
4360           genTrueBlock(e, genCond(e, iters));
4361       }
4362     }
4363 
4364     // We're ready to lower the body (an assignment statement) for this context
4365     // of loop nests at this point.
4366     return {iters, afterLoopNest};
4367   }
4368 
4369   fir::ArrayLoadOp
4370   createAndLoadSomeArrayTemp(mlir::Type type,
4371                              llvm::ArrayRef<mlir::Value> shape) {
4372     if (ccLoadDest.hasValue())
4373       return ccLoadDest.getValue()(shape);
4374     auto seqTy = type.dyn_cast<fir::SequenceType>();
4375     assert(seqTy && "must be an array");
4376     mlir::Location loc = getLoc();
4377     // TODO: Need to thread the length parameters here. For character, they may
4378     // differ from the operands length (e.g concatenation). So the array loads
4379     // type parameters are not enough.
4380     if (auto charTy = seqTy.getEleTy().dyn_cast<fir::CharacterType>())
4381       if (charTy.hasDynamicLen())
4382         TODO(loc, "character array expression temp with dynamic length");
4383     if (auto recTy = seqTy.getEleTy().dyn_cast<fir::RecordType>())
4384       if (recTy.getNumLenParams() > 0)
4385         TODO(loc, "derived type array expression temp with length parameters");
4386     mlir::Value temp = seqTy.hasConstantShape()
4387                            ? builder.create<fir::AllocMemOp>(loc, type)
4388                            : builder.create<fir::AllocMemOp>(
4389                                  loc, type, ".array.expr", llvm::None, shape);
4390     fir::FirOpBuilder *bldr = &converter.getFirOpBuilder();
4391     stmtCtx.attachCleanup(
4392         [bldr, loc, temp]() { bldr->create<fir::FreeMemOp>(loc, temp); });
4393     mlir::Value shapeOp = genShapeOp(shape);
4394     return builder.create<fir::ArrayLoadOp>(loc, seqTy, temp, shapeOp,
4395                                             /*slice=*/mlir::Value{},
4396                                             llvm::None);
4397   }
4398 
4399   static fir::ShapeOp genShapeOp(mlir::Location loc, fir::FirOpBuilder &builder,
4400                                  llvm::ArrayRef<mlir::Value> shape) {
4401     mlir::IndexType idxTy = builder.getIndexType();
4402     llvm::SmallVector<mlir::Value> idxShape;
4403     for (auto s : shape)
4404       idxShape.push_back(builder.createConvert(loc, idxTy, s));
4405     auto shapeTy = fir::ShapeType::get(builder.getContext(), idxShape.size());
4406     return builder.create<fir::ShapeOp>(loc, shapeTy, idxShape);
4407   }
4408 
4409   fir::ShapeOp genShapeOp(llvm::ArrayRef<mlir::Value> shape) {
4410     return genShapeOp(getLoc(), builder, shape);
4411   }
4412 
4413   //===--------------------------------------------------------------------===//
4414   // Expression traversal and lowering.
4415   //===--------------------------------------------------------------------===//
4416 
4417   /// Lower the expression, \p x, in a scalar context.
4418   template <typename A>
4419   ExtValue asScalar(const A &x) {
4420     return ScalarExprLowering{getLoc(), converter, symMap, stmtCtx}.genval(x);
4421   }
4422 
4423   /// Lower the expression, \p x, in a scalar context. If this is an explicit
4424   /// space, the expression may be scalar and refer to an array. We want to
4425   /// raise the array access to array operations in FIR to analyze potential
4426   /// conflicts even when the result is a scalar element.
4427   template <typename A>
4428   ExtValue asScalarArray(const A &x) {
4429     return explicitSpaceIsActive() ? genarr(x)(IterationSpace{}) : asScalar(x);
4430   }
4431 
4432   /// Lower the expression in a scalar context to a memory reference.
4433   template <typename A>
4434   ExtValue asScalarRef(const A &x) {
4435     return ScalarExprLowering{getLoc(), converter, symMap, stmtCtx}.gen(x);
4436   }
4437 
4438   /// Lower an expression without dereferencing any indirection that may be
4439   /// a nullptr (because this is an absent optional or unallocated/disassociated
4440   /// descriptor). The returned expression cannot be addressed directly, it is
4441   /// meant to inquire about its status before addressing the related entity.
4442   template <typename A>
4443   ExtValue asInquired(const A &x) {
4444     return ScalarExprLowering{getLoc(), converter, symMap, stmtCtx}
4445         .lowerIntrinsicArgumentAsInquired(x);
4446   }
4447 
4448   /// Some temporaries are allocated on an element-by-element basis during the
4449   /// array expression evaluation. Collect the cleanups here so the resources
4450   /// can be freed before the next loop iteration, avoiding memory leaks. etc.
4451   Fortran::lower::StatementContext &getElementCtx() {
4452     if (!elementCtx) {
4453       stmtCtx.pushScope();
4454       elementCtx = true;
4455     }
4456     return stmtCtx;
4457   }
4458 
4459   /// If there were temporaries created for this element evaluation, finalize
4460   /// and deallocate the resources now. This should be done just prior the the
4461   /// fir::ResultOp at the end of the innermost loop.
4462   void finalizeElementCtx() {
4463     if (elementCtx) {
4464       stmtCtx.finalize(/*popScope=*/true);
4465       elementCtx = false;
4466     }
4467   }
4468 
4469   /// Lower an elemental function array argument. This ensures array
4470   /// sub-expressions that are not variables and must be passed by address
4471   /// are lowered by value and placed in memory.
4472   template <typename A>
4473   CC genElementalArgument(const A &x) {
4474     // Ensure the returned element is in memory if this is what was requested.
4475     if ((semant == ConstituentSemantics::RefOpaque ||
4476          semant == ConstituentSemantics::DataAddr ||
4477          semant == ConstituentSemantics::ByValueArg)) {
4478       if (!Fortran::evaluate::IsVariable(x)) {
4479         PushSemantics(ConstituentSemantics::DataValue);
4480         CC cc = genarr(x);
4481         mlir::Location loc = getLoc();
4482         if (isParenthesizedVariable(x)) {
4483           // Parenthesised variables are lowered to a reference to the variable
4484           // storage. When passing it as an argument, a copy must be passed.
4485           return [=](IterSpace iters) -> ExtValue {
4486             return createInMemoryScalarCopy(builder, loc, cc(iters));
4487           };
4488         }
4489         mlir::Type storageType =
4490             fir::unwrapSequenceType(converter.genType(toEvExpr(x)));
4491         return [=](IterSpace iters) -> ExtValue {
4492           return placeScalarValueInMemory(builder, loc, cc(iters), storageType);
4493         };
4494       }
4495     }
4496     return genarr(x);
4497   }
4498 
4499   // A procedure reference to a Fortran elemental intrinsic procedure.
4500   CC genElementalIntrinsicProcRef(
4501       const Fortran::evaluate::ProcedureRef &procRef,
4502       llvm::Optional<mlir::Type> retTy,
4503       const Fortran::evaluate::SpecificIntrinsic &intrinsic) {
4504     llvm::SmallVector<CC> operands;
4505     llvm::StringRef name = intrinsic.name;
4506     const Fortran::lower::IntrinsicArgumentLoweringRules *argLowering =
4507         Fortran::lower::getIntrinsicArgumentLowering(name);
4508     mlir::Location loc = getLoc();
4509     if (Fortran::lower::intrinsicRequiresCustomOptionalHandling(
4510             procRef, intrinsic, converter)) {
4511       using CcPairT = std::pair<CC, llvm::Optional<mlir::Value>>;
4512       llvm::SmallVector<CcPairT> operands;
4513       auto prepareOptionalArg = [&](const Fortran::lower::SomeExpr &expr) {
4514         if (expr.Rank() == 0) {
4515           ExtValue optionalArg = this->asInquired(expr);
4516           mlir::Value isPresent =
4517               genActualIsPresentTest(builder, loc, optionalArg);
4518           operands.emplace_back(
4519               [=](IterSpace iters) -> ExtValue {
4520                 return genLoad(builder, loc, optionalArg);
4521               },
4522               isPresent);
4523         } else {
4524           auto [cc, isPresent, _] = this->genOptionalArrayFetch(expr);
4525           operands.emplace_back(cc, isPresent);
4526         }
4527       };
4528       auto prepareOtherArg = [&](const Fortran::lower::SomeExpr &expr) {
4529         PushSemantics(ConstituentSemantics::RefTransparent);
4530         operands.emplace_back(genElementalArgument(expr), llvm::None);
4531       };
4532       Fortran::lower::prepareCustomIntrinsicArgument(
4533           procRef, intrinsic, retTy, prepareOptionalArg, prepareOtherArg,
4534           converter);
4535 
4536       fir::FirOpBuilder *bldr = &converter.getFirOpBuilder();
4537       llvm::StringRef name = intrinsic.name;
4538       return [=](IterSpace iters) -> ExtValue {
4539         auto getArgument = [&](std::size_t i) -> ExtValue {
4540           return operands[i].first(iters);
4541         };
4542         auto isPresent = [&](std::size_t i) -> llvm::Optional<mlir::Value> {
4543           return operands[i].second;
4544         };
4545         return Fortran::lower::lowerCustomIntrinsic(
4546             *bldr, loc, name, retTy, isPresent, getArgument, operands.size(),
4547             getElementCtx());
4548       };
4549     }
4550     /// Otherwise, pre-lower arguments and use intrinsic lowering utility.
4551     for (const auto &[arg, dummy] :
4552          llvm::zip(procRef.arguments(),
4553                    intrinsic.characteristics.value().dummyArguments)) {
4554       const auto *expr =
4555           Fortran::evaluate::UnwrapExpr<Fortran::lower::SomeExpr>(arg);
4556       if (!expr) {
4557         // Absent optional.
4558         operands.emplace_back([=](IterSpace) { return mlir::Value{}; });
4559       } else if (!argLowering) {
4560         // No argument lowering instruction, lower by value.
4561         PushSemantics(ConstituentSemantics::RefTransparent);
4562         operands.emplace_back(genElementalArgument(*expr));
4563       } else {
4564         // Ad-hoc argument lowering handling.
4565         Fortran::lower::ArgLoweringRule argRules =
4566             Fortran::lower::lowerIntrinsicArgumentAs(getLoc(), *argLowering,
4567                                                      dummy.name);
4568         if (argRules.handleDynamicOptional &&
4569             Fortran::evaluate::MayBePassedAsAbsentOptional(
4570                 *expr, converter.getFoldingContext())) {
4571           // Currently, there is not elemental intrinsic that requires lowering
4572           // a potentially absent argument to something else than a value (apart
4573           // from character MAX/MIN that are handled elsewhere.)
4574           if (argRules.lowerAs != Fortran::lower::LowerIntrinsicArgAs::Value)
4575             TODO(loc, "lowering non trivial optional elemental intrinsic array "
4576                       "argument");
4577           PushSemantics(ConstituentSemantics::RefTransparent);
4578           operands.emplace_back(genarrForwardOptionalArgumentToCall(*expr));
4579           continue;
4580         }
4581         switch (argRules.lowerAs) {
4582         case Fortran::lower::LowerIntrinsicArgAs::Value: {
4583           PushSemantics(ConstituentSemantics::RefTransparent);
4584           operands.emplace_back(genElementalArgument(*expr));
4585         } break;
4586         case Fortran::lower::LowerIntrinsicArgAs::Addr: {
4587           // Note: assume does not have Fortran VALUE attribute semantics.
4588           PushSemantics(ConstituentSemantics::RefOpaque);
4589           operands.emplace_back(genElementalArgument(*expr));
4590         } break;
4591         case Fortran::lower::LowerIntrinsicArgAs::Box: {
4592           PushSemantics(ConstituentSemantics::RefOpaque);
4593           auto lambda = genElementalArgument(*expr);
4594           operands.emplace_back([=](IterSpace iters) {
4595             return builder.createBox(loc, lambda(iters));
4596           });
4597         } break;
4598         case Fortran::lower::LowerIntrinsicArgAs::Inquired:
4599           TODO(loc, "intrinsic function with inquired argument");
4600           break;
4601         }
4602       }
4603     }
4604 
4605     // Let the intrinsic library lower the intrinsic procedure call
4606     return [=](IterSpace iters) {
4607       llvm::SmallVector<ExtValue> args;
4608       for (const auto &cc : operands)
4609         args.push_back(cc(iters));
4610       return Fortran::lower::genIntrinsicCall(builder, loc, name, retTy, args,
4611                                               getElementCtx());
4612     };
4613   }
4614 
4615   /// Lower a procedure reference to a user-defined elemental procedure.
4616   CC genElementalUserDefinedProcRef(
4617       const Fortran::evaluate::ProcedureRef &procRef,
4618       llvm::Optional<mlir::Type> retTy) {
4619     using PassBy = Fortran::lower::CallerInterface::PassEntityBy;
4620 
4621     // 10.1.4 p5. Impure elemental procedures must be called in element order.
4622     if (const Fortran::semantics::Symbol *procSym = procRef.proc().GetSymbol())
4623       if (!Fortran::semantics::IsPureProcedure(*procSym))
4624         setUnordered(false);
4625 
4626     Fortran::lower::CallerInterface caller(procRef, converter);
4627     llvm::SmallVector<CC> operands;
4628     operands.reserve(caller.getPassedArguments().size());
4629     mlir::Location loc = getLoc();
4630     mlir::FunctionType callSiteType = caller.genFunctionType();
4631     for (const Fortran::lower::CallInterface<
4632              Fortran::lower::CallerInterface>::PassedEntity &arg :
4633          caller.getPassedArguments()) {
4634       // 15.8.3 p1. Elemental procedure with intent(out)/intent(inout)
4635       // arguments must be called in element order.
4636       if (arg.mayBeModifiedByCall())
4637         setUnordered(false);
4638       const auto *actual = arg.entity;
4639       mlir::Type argTy = callSiteType.getInput(arg.firArgument);
4640       if (!actual) {
4641         // Optional dummy argument for which there is no actual argument.
4642         auto absent = builder.create<fir::AbsentOp>(loc, argTy);
4643         operands.emplace_back([=](IterSpace) { return absent; });
4644         continue;
4645       }
4646       const auto *expr = actual->UnwrapExpr();
4647       if (!expr)
4648         TODO(loc, "assumed type actual argument lowering");
4649 
4650       LLVM_DEBUG(expr->AsFortran(llvm::dbgs()
4651                                  << "argument: " << arg.firArgument << " = [")
4652                  << "]\n");
4653       if (arg.isOptional() && Fortran::evaluate::MayBePassedAsAbsentOptional(
4654                                   *expr, converter.getFoldingContext()))
4655         TODO(loc,
4656              "passing dynamically optional argument to elemental procedures");
4657       switch (arg.passBy) {
4658       case PassBy::Value: {
4659         // True pass-by-value semantics.
4660         PushSemantics(ConstituentSemantics::RefTransparent);
4661         operands.emplace_back(genElementalArgument(*expr));
4662       } break;
4663       case PassBy::BaseAddressValueAttribute: {
4664         // VALUE attribute or pass-by-reference to a copy semantics. (byval*)
4665         if (isArray(*expr)) {
4666           PushSemantics(ConstituentSemantics::ByValueArg);
4667           operands.emplace_back(genElementalArgument(*expr));
4668         } else {
4669           // Store scalar value in a temp to fulfill VALUE attribute.
4670           mlir::Value val = fir::getBase(asScalar(*expr));
4671           mlir::Value temp = builder.createTemporary(
4672               loc, val.getType(),
4673               llvm::ArrayRef<mlir::NamedAttribute>{
4674                   Fortran::lower::getAdaptToByRefAttr(builder)});
4675           builder.create<fir::StoreOp>(loc, val, temp);
4676           operands.emplace_back(
4677               [=](IterSpace iters) -> ExtValue { return temp; });
4678         }
4679       } break;
4680       case PassBy::BaseAddress: {
4681         if (isArray(*expr)) {
4682           PushSemantics(ConstituentSemantics::RefOpaque);
4683           operands.emplace_back(genElementalArgument(*expr));
4684         } else {
4685           ExtValue exv = asScalarRef(*expr);
4686           operands.emplace_back([=](IterSpace iters) { return exv; });
4687         }
4688       } break;
4689       case PassBy::CharBoxValueAttribute: {
4690         if (isArray(*expr)) {
4691           PushSemantics(ConstituentSemantics::DataValue);
4692           auto lambda = genElementalArgument(*expr);
4693           operands.emplace_back([=](IterSpace iters) {
4694             return fir::factory::CharacterExprHelper{builder, loc}
4695                 .createTempFrom(lambda(iters));
4696           });
4697         } else {
4698           fir::factory::CharacterExprHelper helper(builder, loc);
4699           fir::CharBoxValue argVal = helper.createTempFrom(asScalarRef(*expr));
4700           operands.emplace_back(
4701               [=](IterSpace iters) -> ExtValue { return argVal; });
4702         }
4703       } break;
4704       case PassBy::BoxChar: {
4705         PushSemantics(ConstituentSemantics::RefOpaque);
4706         operands.emplace_back(genElementalArgument(*expr));
4707       } break;
4708       case PassBy::AddressAndLength:
4709         // PassBy::AddressAndLength is only used for character results. Results
4710         // are not handled here.
4711         fir::emitFatalError(
4712             loc, "unexpected PassBy::AddressAndLength in elemental call");
4713         break;
4714       case PassBy::CharProcTuple: {
4715         ExtValue argRef = asScalarRef(*expr);
4716         mlir::Value tuple = createBoxProcCharTuple(
4717             converter, argTy, fir::getBase(argRef), fir::getLen(argRef));
4718         operands.emplace_back(
4719             [=](IterSpace iters) -> ExtValue { return tuple; });
4720       } break;
4721       case PassBy::Box:
4722       case PassBy::MutableBox:
4723         // See C15100 and C15101
4724         fir::emitFatalError(loc, "cannot be POINTER, ALLOCATABLE");
4725       }
4726     }
4727 
4728     if (caller.getIfIndirectCallSymbol())
4729       fir::emitFatalError(loc, "cannot be indirect call");
4730 
4731     // The lambda is mutable so that `caller` copy can be modified inside it.
4732     return
4733         [=, caller = std::move(caller)](IterSpace iters) mutable -> ExtValue {
4734           for (const auto &[cc, argIface] :
4735                llvm::zip(operands, caller.getPassedArguments())) {
4736             auto exv = cc(iters);
4737             auto arg = exv.match(
4738                 [&](const fir::CharBoxValue &cb) -> mlir::Value {
4739                   return fir::factory::CharacterExprHelper{builder, loc}
4740                       .createEmbox(cb);
4741                 },
4742                 [&](const auto &) { return fir::getBase(exv); });
4743             caller.placeInput(argIface, arg);
4744           }
4745           return ScalarExprLowering{loc, converter, symMap, getElementCtx()}
4746               .genCallOpAndResult(caller, callSiteType, retTy);
4747         };
4748   }
4749 
4750   /// Generate a procedure reference. This code is shared for both functions and
4751   /// subroutines, the difference being reflected by `retTy`.
4752   CC genProcRef(const Fortran::evaluate::ProcedureRef &procRef,
4753                 llvm::Optional<mlir::Type> retTy) {
4754     mlir::Location loc = getLoc();
4755     if (procRef.IsElemental()) {
4756       if (const Fortran::evaluate::SpecificIntrinsic *intrin =
4757               procRef.proc().GetSpecificIntrinsic()) {
4758         // All elemental intrinsic functions are pure and cannot modify their
4759         // arguments. The only elemental subroutine, MVBITS has an Intent(inout)
4760         // argument. So for this last one, loops must be in element order
4761         // according to 15.8.3 p1.
4762         if (!retTy)
4763           setUnordered(false);
4764 
4765         // Elemental intrinsic call.
4766         // The intrinsic procedure is called once per element of the array.
4767         return genElementalIntrinsicProcRef(procRef, retTy, *intrin);
4768       }
4769       if (ScalarExprLowering::isStatementFunctionCall(procRef))
4770         fir::emitFatalError(loc, "statement function cannot be elemental");
4771 
4772       // Elemental call.
4773       // The procedure is called once per element of the array argument(s).
4774       return genElementalUserDefinedProcRef(procRef, retTy);
4775     }
4776 
4777     // Transformational call.
4778     // The procedure is called once and produces a value of rank > 0.
4779     if (const Fortran::evaluate::SpecificIntrinsic *intrinsic =
4780             procRef.proc().GetSpecificIntrinsic()) {
4781       if (explicitSpaceIsActive() && procRef.Rank() == 0) {
4782         // Elide any implicit loop iters.
4783         return [=, &procRef](IterSpace) {
4784           return ScalarExprLowering{loc, converter, symMap, stmtCtx}
4785               .genIntrinsicRef(procRef, *intrinsic, retTy);
4786         };
4787       }
4788       return genarr(
4789           ScalarExprLowering{loc, converter, symMap, stmtCtx}.genIntrinsicRef(
4790               procRef, *intrinsic, retTy));
4791     }
4792 
4793     if (explicitSpaceIsActive() && procRef.Rank() == 0) {
4794       // Elide any implicit loop iters.
4795       return [=, &procRef](IterSpace) {
4796         return ScalarExprLowering{loc, converter, symMap, stmtCtx}
4797             .genProcedureRef(procRef, retTy);
4798       };
4799     }
4800     // In the default case, the call can be hoisted out of the loop nest. Apply
4801     // the iterations to the result, which may be an array value.
4802     return genarr(
4803         ScalarExprLowering{loc, converter, symMap, stmtCtx}.genProcedureRef(
4804             procRef, retTy));
4805   }
4806 
4807   CC genarr(const Fortran::evaluate::ProcedureDesignator &) {
4808     TODO(getLoc(), "procedure designator");
4809   }
4810   CC genarr(const Fortran::evaluate::ProcedureRef &x) {
4811     if (x.hasAlternateReturns())
4812       fir::emitFatalError(getLoc(),
4813                           "array procedure reference with alt-return");
4814     return genProcRef(x, llvm::None);
4815   }
4816   template <typename A>
4817   CC genScalarAndForwardValue(const A &x) {
4818     ExtValue result = asScalar(x);
4819     return [=](IterSpace) { return result; };
4820   }
4821   template <typename A, typename = std::enable_if_t<Fortran::common::HasMember<
4822                             A, Fortran::evaluate::TypelessExpression>>>
4823   CC genarr(const A &x) {
4824     return genScalarAndForwardValue(x);
4825   }
4826 
4827   template <typename A>
4828   CC genarr(const Fortran::evaluate::Expr<A> &x) {
4829     LLVM_DEBUG(Fortran::lower::DumpEvaluateExpr::dump(llvm::dbgs(), x));
4830     if (isArray(x) || explicitSpaceIsActive() ||
4831         isElementalProcWithArrayArgs(x))
4832       return std::visit([&](const auto &e) { return genarr(e); }, x.u);
4833     return genScalarAndForwardValue(x);
4834   }
4835 
4836   // Converting a value of memory bound type requires creating a temp and
4837   // copying the value.
4838   static ExtValue convertAdjustedType(fir::FirOpBuilder &builder,
4839                                       mlir::Location loc, mlir::Type toType,
4840                                       const ExtValue &exv) {
4841     return exv.match(
4842         [&](const fir::CharBoxValue &cb) -> ExtValue {
4843           mlir::Value len = cb.getLen();
4844           auto mem =
4845               builder.create<fir::AllocaOp>(loc, toType, mlir::ValueRange{len});
4846           fir::CharBoxValue result(mem, len);
4847           fir::factory::CharacterExprHelper{builder, loc}.createAssign(
4848               ExtValue{result}, exv);
4849           return result;
4850         },
4851         [&](const auto &) -> ExtValue {
4852           fir::emitFatalError(loc, "convert on adjusted extended value");
4853         });
4854   }
4855   template <Fortran::common::TypeCategory TC1, int KIND,
4856             Fortran::common::TypeCategory TC2>
4857   CC genarr(const Fortran::evaluate::Convert<Fortran::evaluate::Type<TC1, KIND>,
4858                                              TC2> &x) {
4859     mlir::Location loc = getLoc();
4860     auto lambda = genarr(x.left());
4861     mlir::Type ty = converter.genType(TC1, KIND);
4862     return [=](IterSpace iters) -> ExtValue {
4863       auto exv = lambda(iters);
4864       mlir::Value val = fir::getBase(exv);
4865       auto valTy = val.getType();
4866       if (elementTypeWasAdjusted(valTy) &&
4867           !(fir::isa_ref_type(valTy) && fir::isa_integer(ty)))
4868         return convertAdjustedType(builder, loc, ty, exv);
4869       return builder.createConvert(loc, ty, val);
4870     };
4871   }
4872 
4873   template <int KIND>
4874   CC genarr(const Fortran::evaluate::ComplexComponent<KIND> &x) {
4875     mlir::Location loc = getLoc();
4876     auto lambda = genarr(x.left());
4877     bool isImagPart = x.isImaginaryPart;
4878     return [=](IterSpace iters) -> ExtValue {
4879       mlir::Value lhs = fir::getBase(lambda(iters));
4880       return fir::factory::Complex{builder, loc}.extractComplexPart(lhs,
4881                                                                     isImagPart);
4882     };
4883   }
4884 
4885   template <typename T>
4886   CC genarr(const Fortran::evaluate::Parentheses<T> &x) {
4887     mlir::Location loc = getLoc();
4888     if (isReferentiallyOpaque()) {
4889       // Context is a call argument in, for example, an elemental procedure
4890       // call. TODO: all array arguments should use array_load, array_access,
4891       // array_amend, and INTENT(OUT), INTENT(INOUT) arguments should have
4892       // array_merge_store ops.
4893       TODO(loc, "parentheses on argument in elemental call");
4894     }
4895     auto f = genarr(x.left());
4896     return [=](IterSpace iters) -> ExtValue {
4897       auto val = f(iters);
4898       mlir::Value base = fir::getBase(val);
4899       auto newBase =
4900           builder.create<fir::NoReassocOp>(loc, base.getType(), base);
4901       return fir::substBase(val, newBase);
4902     };
4903   }
4904   template <int KIND>
4905   CC genarr(const Fortran::evaluate::Negate<Fortran::evaluate::Type<
4906                 Fortran::common::TypeCategory::Integer, KIND>> &x) {
4907     mlir::Location loc = getLoc();
4908     auto f = genarr(x.left());
4909     return [=](IterSpace iters) -> ExtValue {
4910       mlir::Value val = fir::getBase(f(iters));
4911       mlir::Type ty =
4912           converter.genType(Fortran::common::TypeCategory::Integer, KIND);
4913       mlir::Value zero = builder.createIntegerConstant(loc, ty, 0);
4914       return builder.create<mlir::arith::SubIOp>(loc, zero, val);
4915     };
4916   }
4917   template <int KIND>
4918   CC genarr(const Fortran::evaluate::Negate<Fortran::evaluate::Type<
4919                 Fortran::common::TypeCategory::Real, KIND>> &x) {
4920     mlir::Location loc = getLoc();
4921     auto f = genarr(x.left());
4922     return [=](IterSpace iters) -> ExtValue {
4923       return builder.create<mlir::arith::NegFOp>(loc, fir::getBase(f(iters)));
4924     };
4925   }
4926   template <int KIND>
4927   CC genarr(const Fortran::evaluate::Negate<Fortran::evaluate::Type<
4928                 Fortran::common::TypeCategory::Complex, KIND>> &x) {
4929     mlir::Location loc = getLoc();
4930     auto f = genarr(x.left());
4931     return [=](IterSpace iters) -> ExtValue {
4932       return builder.create<fir::NegcOp>(loc, fir::getBase(f(iters)));
4933     };
4934   }
4935 
4936   //===--------------------------------------------------------------------===//
4937   // Binary elemental ops
4938   //===--------------------------------------------------------------------===//
4939 
4940   template <typename OP, typename A>
4941   CC createBinaryOp(const A &evEx) {
4942     mlir::Location loc = getLoc();
4943     auto lambda = genarr(evEx.left());
4944     auto rf = genarr(evEx.right());
4945     return [=](IterSpace iters) -> ExtValue {
4946       mlir::Value left = fir::getBase(lambda(iters));
4947       mlir::Value right = fir::getBase(rf(iters));
4948       return builder.create<OP>(loc, left, right);
4949     };
4950   }
4951 
4952 #undef GENBIN
4953 #define GENBIN(GenBinEvOp, GenBinTyCat, GenBinFirOp)                           \
4954   template <int KIND>                                                          \
4955   CC genarr(const Fortran::evaluate::GenBinEvOp<Fortran::evaluate::Type<       \
4956                 Fortran::common::TypeCategory::GenBinTyCat, KIND>> &x) {       \
4957     return createBinaryOp<GenBinFirOp>(x);                                     \
4958   }
4959 
4960   GENBIN(Add, Integer, mlir::arith::AddIOp)
4961   GENBIN(Add, Real, mlir::arith::AddFOp)
4962   GENBIN(Add, Complex, fir::AddcOp)
4963   GENBIN(Subtract, Integer, mlir::arith::SubIOp)
4964   GENBIN(Subtract, Real, mlir::arith::SubFOp)
4965   GENBIN(Subtract, Complex, fir::SubcOp)
4966   GENBIN(Multiply, Integer, mlir::arith::MulIOp)
4967   GENBIN(Multiply, Real, mlir::arith::MulFOp)
4968   GENBIN(Multiply, Complex, fir::MulcOp)
4969   GENBIN(Divide, Integer, mlir::arith::DivSIOp)
4970   GENBIN(Divide, Real, mlir::arith::DivFOp)
4971   GENBIN(Divide, Complex, fir::DivcOp)
4972 
4973   template <Fortran::common::TypeCategory TC, int KIND>
4974   CC genarr(
4975       const Fortran::evaluate::Power<Fortran::evaluate::Type<TC, KIND>> &x) {
4976     mlir::Location loc = getLoc();
4977     mlir::Type ty = converter.genType(TC, KIND);
4978     auto lf = genarr(x.left());
4979     auto rf = genarr(x.right());
4980     return [=](IterSpace iters) -> ExtValue {
4981       mlir::Value lhs = fir::getBase(lf(iters));
4982       mlir::Value rhs = fir::getBase(rf(iters));
4983       return Fortran::lower::genPow(builder, loc, ty, lhs, rhs);
4984     };
4985   }
4986   template <Fortran::common::TypeCategory TC, int KIND>
4987   CC genarr(
4988       const Fortran::evaluate::Extremum<Fortran::evaluate::Type<TC, KIND>> &x) {
4989     mlir::Location loc = getLoc();
4990     auto lf = genarr(x.left());
4991     auto rf = genarr(x.right());
4992     switch (x.ordering) {
4993     case Fortran::evaluate::Ordering::Greater:
4994       return [=](IterSpace iters) -> ExtValue {
4995         mlir::Value lhs = fir::getBase(lf(iters));
4996         mlir::Value rhs = fir::getBase(rf(iters));
4997         return Fortran::lower::genMax(builder, loc,
4998                                       llvm::ArrayRef<mlir::Value>{lhs, rhs});
4999       };
5000     case Fortran::evaluate::Ordering::Less:
5001       return [=](IterSpace iters) -> ExtValue {
5002         mlir::Value lhs = fir::getBase(lf(iters));
5003         mlir::Value rhs = fir::getBase(rf(iters));
5004         return Fortran::lower::genMin(builder, loc,
5005                                       llvm::ArrayRef<mlir::Value>{lhs, rhs});
5006       };
5007     case Fortran::evaluate::Ordering::Equal:
5008       llvm_unreachable("Equal is not a valid ordering in this context");
5009     }
5010     llvm_unreachable("unknown ordering");
5011   }
5012   template <Fortran::common::TypeCategory TC, int KIND>
5013   CC genarr(
5014       const Fortran::evaluate::RealToIntPower<Fortran::evaluate::Type<TC, KIND>>
5015           &x) {
5016     mlir::Location loc = getLoc();
5017     auto ty = converter.genType(TC, KIND);
5018     auto lf = genarr(x.left());
5019     auto rf = genarr(x.right());
5020     return [=](IterSpace iters) {
5021       mlir::Value lhs = fir::getBase(lf(iters));
5022       mlir::Value rhs = fir::getBase(rf(iters));
5023       return Fortran::lower::genPow(builder, loc, ty, lhs, rhs);
5024     };
5025   }
5026   template <int KIND>
5027   CC genarr(const Fortran::evaluate::ComplexConstructor<KIND> &x) {
5028     mlir::Location loc = getLoc();
5029     auto lf = genarr(x.left());
5030     auto rf = genarr(x.right());
5031     return [=](IterSpace iters) -> ExtValue {
5032       mlir::Value lhs = fir::getBase(lf(iters));
5033       mlir::Value rhs = fir::getBase(rf(iters));
5034       return fir::factory::Complex{builder, loc}.createComplex(KIND, lhs, rhs);
5035     };
5036   }
5037 
5038   /// Fortran's concatenation operator `//`.
5039   template <int KIND>
5040   CC genarr(const Fortran::evaluate::Concat<KIND> &x) {
5041     mlir::Location loc = getLoc();
5042     auto lf = genarr(x.left());
5043     auto rf = genarr(x.right());
5044     return [=](IterSpace iters) -> ExtValue {
5045       auto lhs = lf(iters);
5046       auto rhs = rf(iters);
5047       const fir::CharBoxValue *lchr = lhs.getCharBox();
5048       const fir::CharBoxValue *rchr = rhs.getCharBox();
5049       if (lchr && rchr) {
5050         return fir::factory::CharacterExprHelper{builder, loc}
5051             .createConcatenate(*lchr, *rchr);
5052       }
5053       TODO(loc, "concat on unexpected extended values");
5054       return mlir::Value{};
5055     };
5056   }
5057 
5058   template <int KIND>
5059   CC genarr(const Fortran::evaluate::SetLength<KIND> &x) {
5060     auto lf = genarr(x.left());
5061     mlir::Value rhs = fir::getBase(asScalar(x.right()));
5062     return [=](IterSpace iters) -> ExtValue {
5063       mlir::Value lhs = fir::getBase(lf(iters));
5064       return fir::CharBoxValue{lhs, rhs};
5065     };
5066   }
5067 
5068   template <typename A>
5069   CC genarr(const Fortran::evaluate::Constant<A> &x) {
5070     if (/*explicitSpaceIsActive() &&*/ x.Rank() == 0)
5071       return genScalarAndForwardValue(x);
5072     mlir::Location loc = getLoc();
5073     mlir::IndexType idxTy = builder.getIndexType();
5074     mlir::Type arrTy = converter.genType(toEvExpr(x));
5075     std::string globalName = Fortran::lower::mangle::mangleArrayLiteral(x);
5076     fir::GlobalOp global = builder.getNamedGlobal(globalName);
5077     if (!global) {
5078       mlir::Type symTy = arrTy;
5079       mlir::Type eleTy = symTy.cast<fir::SequenceType>().getEleTy();
5080       // If we have a rank-1 array of integer, real, or logical, then we can
5081       // create a global array with the dense attribute.
5082       //
5083       // The mlir tensor type can only handle integer, real, or logical. It
5084       // does not currently support nested structures which is required for
5085       // complex.
5086       //
5087       // Also, we currently handle just rank-1 since tensor type assumes
5088       // row major array ordering. We will need to reorder the dimensions
5089       // in the tensor type to support Fortran's column major array ordering.
5090       // How to create this tensor type is to be determined.
5091       if (x.Rank() == 1 &&
5092           eleTy.isa<fir::LogicalType, mlir::IntegerType, mlir::FloatType>())
5093         global = Fortran::lower::createDenseGlobal(
5094             loc, arrTy, globalName, builder.createInternalLinkage(), true,
5095             toEvExpr(x), converter);
5096       // Note: If call to createDenseGlobal() returns 0, then call
5097       // createGlobalConstant() below.
5098       if (!global)
5099         global = builder.createGlobalConstant(
5100             loc, arrTy, globalName,
5101             [&](fir::FirOpBuilder &builder) {
5102               Fortran::lower::StatementContext stmtCtx(
5103                   /*cleanupProhibited=*/true);
5104               fir::ExtendedValue result =
5105                   Fortran::lower::createSomeInitializerExpression(
5106                       loc, converter, toEvExpr(x), symMap, stmtCtx);
5107               mlir::Value castTo =
5108                   builder.createConvert(loc, arrTy, fir::getBase(result));
5109               builder.create<fir::HasValueOp>(loc, castTo);
5110             },
5111             builder.createInternalLinkage());
5112     }
5113     auto addr = builder.create<fir::AddrOfOp>(getLoc(), global.resultType(),
5114                                               global.getSymbol());
5115     auto seqTy = global.getType().cast<fir::SequenceType>();
5116     llvm::SmallVector<mlir::Value> extents;
5117     for (auto extent : seqTy.getShape())
5118       extents.push_back(builder.createIntegerConstant(loc, idxTy, extent));
5119     if (auto charTy = seqTy.getEleTy().dyn_cast<fir::CharacterType>()) {
5120       mlir::Value len = builder.createIntegerConstant(loc, builder.getI64Type(),
5121                                                       charTy.getLen());
5122       return genarr(fir::CharArrayBoxValue{addr, len, extents});
5123     }
5124     return genarr(fir::ArrayBoxValue{addr, extents});
5125   }
5126 
5127   //===--------------------------------------------------------------------===//
5128   // A vector subscript expression may be wrapped with a cast to INTEGER*8.
5129   // Get rid of it here so the vector can be loaded. Add it back when
5130   // generating the elemental evaluation (inside the loop nest).
5131 
5132   static Fortran::lower::SomeExpr
5133   ignoreEvConvert(const Fortran::evaluate::Expr<Fortran::evaluate::Type<
5134                       Fortran::common::TypeCategory::Integer, 8>> &x) {
5135     return std::visit([&](const auto &v) { return ignoreEvConvert(v); }, x.u);
5136   }
5137   template <Fortran::common::TypeCategory FROM>
5138   static Fortran::lower::SomeExpr ignoreEvConvert(
5139       const Fortran::evaluate::Convert<
5140           Fortran::evaluate::Type<Fortran::common::TypeCategory::Integer, 8>,
5141           FROM> &x) {
5142     return toEvExpr(x.left());
5143   }
5144   template <typename A>
5145   static Fortran::lower::SomeExpr ignoreEvConvert(const A &x) {
5146     return toEvExpr(x);
5147   }
5148 
5149   //===--------------------------------------------------------------------===//
5150   // Get the `Se::Symbol*` for the subscript expression, `x`. This symbol can
5151   // be used to determine the lbound, ubound of the vector.
5152 
5153   template <typename A>
5154   static const Fortran::semantics::Symbol *
5155   extractSubscriptSymbol(const Fortran::evaluate::Expr<A> &x) {
5156     return std::visit([&](const auto &v) { return extractSubscriptSymbol(v); },
5157                       x.u);
5158   }
5159   template <typename A>
5160   static const Fortran::semantics::Symbol *
5161   extractSubscriptSymbol(const Fortran::evaluate::Designator<A> &x) {
5162     return Fortran::evaluate::UnwrapWholeSymbolDataRef(x);
5163   }
5164   template <typename A>
5165   static const Fortran::semantics::Symbol *extractSubscriptSymbol(const A &x) {
5166     return nullptr;
5167   }
5168 
5169   //===--------------------------------------------------------------------===//
5170 
5171   /// Get the declared lower bound value of the array `x` in dimension `dim`.
5172   /// The argument `one` must be an ssa-value for the constant 1.
5173   mlir::Value getLBound(const ExtValue &x, unsigned dim, mlir::Value one) {
5174     return fir::factory::readLowerBound(builder, getLoc(), x, dim, one);
5175   }
5176 
5177   /// Get the declared upper bound value of the array `x` in dimension `dim`.
5178   /// The argument `one` must be an ssa-value for the constant 1.
5179   mlir::Value getUBound(const ExtValue &x, unsigned dim, mlir::Value one) {
5180     mlir::Location loc = getLoc();
5181     mlir::Value lb = getLBound(x, dim, one);
5182     mlir::Value extent = fir::factory::readExtent(builder, loc, x, dim);
5183     auto add = builder.create<mlir::arith::AddIOp>(loc, lb, extent);
5184     return builder.create<mlir::arith::SubIOp>(loc, add, one);
5185   }
5186 
5187   /// Return the extent of the boxed array `x` in dimesion `dim`.
5188   mlir::Value getExtent(const ExtValue &x, unsigned dim) {
5189     return fir::factory::readExtent(builder, getLoc(), x, dim);
5190   }
5191 
5192   template <typename A>
5193   ExtValue genArrayBase(const A &base) {
5194     ScalarExprLowering sel{getLoc(), converter, symMap, stmtCtx};
5195     return base.IsSymbol() ? sel.gen(getFirstSym(base))
5196                            : sel.gen(base.GetComponent());
5197   }
5198 
5199   template <typename A>
5200   bool hasEvArrayRef(const A &x) {
5201     struct HasEvArrayRefHelper
5202         : public Fortran::evaluate::AnyTraverse<HasEvArrayRefHelper> {
5203       HasEvArrayRefHelper()
5204           : Fortran::evaluate::AnyTraverse<HasEvArrayRefHelper>(*this) {}
5205       using Fortran::evaluate::AnyTraverse<HasEvArrayRefHelper>::operator();
5206       bool operator()(const Fortran::evaluate::ArrayRef &) const {
5207         return true;
5208       }
5209     } helper;
5210     return helper(x);
5211   }
5212 
5213   CC genVectorSubscriptArrayFetch(const Fortran::lower::SomeExpr &expr,
5214                                   std::size_t dim) {
5215     PushSemantics(ConstituentSemantics::RefTransparent);
5216     auto saved = Fortran::common::ScopedSet(explicitSpace, nullptr);
5217     llvm::SmallVector<mlir::Value> savedDestShape = destShape;
5218     destShape.clear();
5219     auto result = genarr(expr);
5220     if (destShape.empty())
5221       TODO(getLoc(), "expected vector to have an extent");
5222     assert(destShape.size() == 1 && "vector has rank > 1");
5223     if (destShape[0] != savedDestShape[dim]) {
5224       // Not the same, so choose the smaller value.
5225       mlir::Location loc = getLoc();
5226       auto cmp = builder.create<mlir::arith::CmpIOp>(
5227           loc, mlir::arith::CmpIPredicate::sgt, destShape[0],
5228           savedDestShape[dim]);
5229       auto sel = builder.create<mlir::arith::SelectOp>(
5230           loc, cmp, savedDestShape[dim], destShape[0]);
5231       savedDestShape[dim] = sel;
5232       destShape = savedDestShape;
5233     }
5234     return result;
5235   }
5236 
5237   /// Generate an access by vector subscript using the index in the iteration
5238   /// vector at `dim`.
5239   mlir::Value genAccessByVector(mlir::Location loc, CC genArrFetch,
5240                                 IterSpace iters, std::size_t dim) {
5241     IterationSpace vecIters(iters,
5242                             llvm::ArrayRef<mlir::Value>{iters.iterValue(dim)});
5243     fir::ExtendedValue fetch = genArrFetch(vecIters);
5244     mlir::IndexType idxTy = builder.getIndexType();
5245     return builder.createConvert(loc, idxTy, fir::getBase(fetch));
5246   }
5247 
5248   /// When we have an array reference, the expressions specified in each
5249   /// dimension may be slice operations (e.g. `i:j:k`), vectors, or simple
5250   /// (loop-invarianet) scalar expressions. This returns the base entity, the
5251   /// resulting type, and a continuation to adjust the default iteration space.
5252   void genSliceIndices(ComponentPath &cmptData, const ExtValue &arrayExv,
5253                        const Fortran::evaluate::ArrayRef &x, bool atBase) {
5254     mlir::Location loc = getLoc();
5255     mlir::IndexType idxTy = builder.getIndexType();
5256     mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
5257     llvm::SmallVector<mlir::Value> &trips = cmptData.trips;
5258     LLVM_DEBUG(llvm::dbgs() << "array: " << arrayExv << '\n');
5259     auto &pc = cmptData.pc;
5260     const bool useTripsForSlice = !explicitSpaceIsActive();
5261     const bool createDestShape = destShape.empty();
5262     bool useSlice = false;
5263     std::size_t shapeIndex = 0;
5264     for (auto sub : llvm::enumerate(x.subscript())) {
5265       const std::size_t subsIndex = sub.index();
5266       std::visit(
5267           Fortran::common::visitors{
5268               [&](const Fortran::evaluate::Triplet &t) {
5269                 mlir::Value lowerBound;
5270                 if (auto optLo = t.lower())
5271                   lowerBound = fir::getBase(asScalar(*optLo));
5272                 else
5273                   lowerBound = getLBound(arrayExv, subsIndex, one);
5274                 lowerBound = builder.createConvert(loc, idxTy, lowerBound);
5275                 mlir::Value stride = fir::getBase(asScalar(t.stride()));
5276                 stride = builder.createConvert(loc, idxTy, stride);
5277                 if (useTripsForSlice || createDestShape) {
5278                   // Generate a slice operation for the triplet. The first and
5279                   // second position of the triplet may be omitted, and the
5280                   // declared lbound and/or ubound expression values,
5281                   // respectively, should be used instead.
5282                   trips.push_back(lowerBound);
5283                   mlir::Value upperBound;
5284                   if (auto optUp = t.upper())
5285                     upperBound = fir::getBase(asScalar(*optUp));
5286                   else
5287                     upperBound = getUBound(arrayExv, subsIndex, one);
5288                   upperBound = builder.createConvert(loc, idxTy, upperBound);
5289                   trips.push_back(upperBound);
5290                   trips.push_back(stride);
5291                   if (createDestShape) {
5292                     auto extent = builder.genExtentFromTriplet(
5293                         loc, lowerBound, upperBound, stride, idxTy);
5294                     destShape.push_back(extent);
5295                   }
5296                   useSlice = true;
5297                 }
5298                 if (!useTripsForSlice) {
5299                   auto currentPC = pc;
5300                   pc = [=](IterSpace iters) {
5301                     IterationSpace newIters = currentPC(iters);
5302                     mlir::Value impliedIter = newIters.iterValue(subsIndex);
5303                     // FIXME: must use the lower bound of this component.
5304                     auto arrLowerBound =
5305                         atBase ? getLBound(arrayExv, subsIndex, one) : one;
5306                     auto initial = builder.create<mlir::arith::SubIOp>(
5307                         loc, lowerBound, arrLowerBound);
5308                     auto prod = builder.create<mlir::arith::MulIOp>(
5309                         loc, impliedIter, stride);
5310                     auto result =
5311                         builder.create<mlir::arith::AddIOp>(loc, initial, prod);
5312                     newIters.setIndexValue(subsIndex, result);
5313                     return newIters;
5314                   };
5315                 }
5316                 shapeIndex++;
5317               },
5318               [&](const Fortran::evaluate::IndirectSubscriptIntegerExpr &ie) {
5319                 const auto &e = ie.value(); // dereference
5320                 if (isArray(e)) {
5321                   // This is a vector subscript. Use the index values as read
5322                   // from a vector to determine the temporary array value.
5323                   // Note: 9.5.3.3.3(3) specifies undefined behavior for
5324                   // multiple updates to any specific array element through a
5325                   // vector subscript with replicated values.
5326                   assert(!isBoxValue() &&
5327                          "fir.box cannot be created with vector subscripts");
5328                   auto arrExpr = ignoreEvConvert(e);
5329                   if (createDestShape) {
5330                     destShape.push_back(fir::getExtentAtDimension(
5331                         arrayExv, builder, loc, subsIndex));
5332                   }
5333                   auto genArrFetch =
5334                       genVectorSubscriptArrayFetch(arrExpr, shapeIndex);
5335                   auto currentPC = pc;
5336                   pc = [=](IterSpace iters) {
5337                     IterationSpace newIters = currentPC(iters);
5338                     auto val = genAccessByVector(loc, genArrFetch, newIters,
5339                                                  subsIndex);
5340                     // Value read from vector subscript array and normalized
5341                     // using the base array's lower bound value.
5342                     mlir::Value lb = fir::factory::readLowerBound(
5343                         builder, loc, arrayExv, subsIndex, one);
5344                     auto origin = builder.create<mlir::arith::SubIOp>(
5345                         loc, idxTy, val, lb);
5346                     newIters.setIndexValue(subsIndex, origin);
5347                     return newIters;
5348                   };
5349                   if (useTripsForSlice) {
5350                     LLVM_ATTRIBUTE_UNUSED auto vectorSubscriptShape =
5351                         getShape(arrayOperands.back());
5352                     auto undef = builder.create<fir::UndefOp>(loc, idxTy);
5353                     trips.push_back(undef);
5354                     trips.push_back(undef);
5355                     trips.push_back(undef);
5356                   }
5357                   shapeIndex++;
5358                 } else {
5359                   // This is a regular scalar subscript.
5360                   if (useTripsForSlice) {
5361                     // A regular scalar index, which does not yield an array
5362                     // section. Use a degenerate slice operation
5363                     // `(e:undef:undef)` in this dimension as a placeholder.
5364                     // This does not necessarily change the rank of the original
5365                     // array, so the iteration space must also be extended to
5366                     // include this expression in this dimension to adjust to
5367                     // the array's declared rank.
5368                     mlir::Value v = fir::getBase(asScalar(e));
5369                     trips.push_back(v);
5370                     auto undef = builder.create<fir::UndefOp>(loc, idxTy);
5371                     trips.push_back(undef);
5372                     trips.push_back(undef);
5373                     auto currentPC = pc;
5374                     // Cast `e` to index type.
5375                     mlir::Value iv = builder.createConvert(loc, idxTy, v);
5376                     // Normalize `e` by subtracting the declared lbound.
5377                     mlir::Value lb = fir::factory::readLowerBound(
5378                         builder, loc, arrayExv, subsIndex, one);
5379                     mlir::Value ivAdj =
5380                         builder.create<mlir::arith::SubIOp>(loc, idxTy, iv, lb);
5381                     // Add lbound adjusted value of `e` to the iteration vector
5382                     // (except when creating a box because the iteration vector
5383                     // is empty).
5384                     if (!isBoxValue())
5385                       pc = [=](IterSpace iters) {
5386                         IterationSpace newIters = currentPC(iters);
5387                         newIters.insertIndexValue(subsIndex, ivAdj);
5388                         return newIters;
5389                       };
5390                   } else {
5391                     auto currentPC = pc;
5392                     mlir::Value newValue = fir::getBase(asScalarArray(e));
5393                     mlir::Value result =
5394                         builder.createConvert(loc, idxTy, newValue);
5395                     mlir::Value lb = fir::factory::readLowerBound(
5396                         builder, loc, arrayExv, subsIndex, one);
5397                     result = builder.create<mlir::arith::SubIOp>(loc, idxTy,
5398                                                                  result, lb);
5399                     pc = [=](IterSpace iters) {
5400                       IterationSpace newIters = currentPC(iters);
5401                       newIters.insertIndexValue(subsIndex, result);
5402                       return newIters;
5403                     };
5404                   }
5405                 }
5406               }},
5407           sub.value().u);
5408     }
5409     if (!useSlice)
5410       trips.clear();
5411   }
5412 
5413   static mlir::Type unwrapBoxEleTy(mlir::Type ty) {
5414     if (auto boxTy = ty.dyn_cast<fir::BoxType>())
5415       return fir::unwrapRefType(boxTy.getEleTy());
5416     return ty;
5417   }
5418 
5419   llvm::SmallVector<mlir::Value> getShape(mlir::Type ty) {
5420     llvm::SmallVector<mlir::Value> result;
5421     ty = unwrapBoxEleTy(ty);
5422     mlir::Location loc = getLoc();
5423     mlir::IndexType idxTy = builder.getIndexType();
5424     for (auto extent : ty.cast<fir::SequenceType>().getShape()) {
5425       auto v = extent == fir::SequenceType::getUnknownExtent()
5426                    ? builder.create<fir::UndefOp>(loc, idxTy).getResult()
5427                    : builder.createIntegerConstant(loc, idxTy, extent);
5428       result.push_back(v);
5429     }
5430     return result;
5431   }
5432 
5433   CC genarr(const Fortran::semantics::SymbolRef &sym,
5434             ComponentPath &components) {
5435     return genarr(sym.get(), components);
5436   }
5437 
5438   ExtValue abstractArrayExtValue(mlir::Value val, mlir::Value len = {}) {
5439     return convertToArrayBoxValue(getLoc(), builder, val, len);
5440   }
5441 
5442   CC genarr(const ExtValue &extMemref) {
5443     ComponentPath dummy(/*isImplicit=*/true);
5444     return genarr(extMemref, dummy);
5445   }
5446 
5447   /// Base case of generating an array reference,
5448   CC genarr(const ExtValue &extMemref, ComponentPath &components) {
5449     mlir::Location loc = getLoc();
5450     mlir::Value memref = fir::getBase(extMemref);
5451     mlir::Type arrTy = fir::dyn_cast_ptrOrBoxEleTy(memref.getType());
5452     assert(arrTy.isa<fir::SequenceType>() && "memory ref must be an array");
5453     mlir::Value shape = builder.createShape(loc, extMemref);
5454     mlir::Value slice;
5455     if (components.isSlice()) {
5456       if (isBoxValue() && components.substring) {
5457         // Append the substring operator to emboxing Op as it will become an
5458         // interior adjustment (add offset, adjust LEN) to the CHARACTER value
5459         // being referenced in the descriptor.
5460         llvm::SmallVector<mlir::Value> substringBounds;
5461         populateBounds(substringBounds, components.substring);
5462         // Convert to (offset, size)
5463         mlir::Type iTy = substringBounds[0].getType();
5464         if (substringBounds.size() != 2) {
5465           fir::CharacterType charTy =
5466               fir::factory::CharacterExprHelper::getCharType(arrTy);
5467           if (charTy.hasConstantLen()) {
5468             mlir::IndexType idxTy = builder.getIndexType();
5469             fir::CharacterType::LenType charLen = charTy.getLen();
5470             mlir::Value lenValue =
5471                 builder.createIntegerConstant(loc, idxTy, charLen);
5472             substringBounds.push_back(lenValue);
5473           } else {
5474             llvm::SmallVector<mlir::Value> typeparams =
5475                 fir::getTypeParams(extMemref);
5476             substringBounds.push_back(typeparams.back());
5477           }
5478         }
5479         // Convert the lower bound to 0-based substring.
5480         mlir::Value one =
5481             builder.createIntegerConstant(loc, substringBounds[0].getType(), 1);
5482         substringBounds[0] =
5483             builder.create<mlir::arith::SubIOp>(loc, substringBounds[0], one);
5484         // Convert the upper bound to a length.
5485         mlir::Value cast = builder.createConvert(loc, iTy, substringBounds[1]);
5486         mlir::Value zero = builder.createIntegerConstant(loc, iTy, 0);
5487         auto size =
5488             builder.create<mlir::arith::SubIOp>(loc, cast, substringBounds[0]);
5489         auto cmp = builder.create<mlir::arith::CmpIOp>(
5490             loc, mlir::arith::CmpIPredicate::sgt, size, zero);
5491         // size = MAX(upper - (lower - 1), 0)
5492         substringBounds[1] =
5493             builder.create<mlir::arith::SelectOp>(loc, cmp, size, zero);
5494         slice = builder.create<fir::SliceOp>(loc, components.trips,
5495                                              components.suffixComponents,
5496                                              substringBounds);
5497       } else {
5498         slice = builder.createSlice(loc, extMemref, components.trips,
5499                                     components.suffixComponents);
5500       }
5501       if (components.hasComponents()) {
5502         auto seqTy = arrTy.cast<fir::SequenceType>();
5503         mlir::Type eleTy =
5504             fir::applyPathToType(seqTy.getEleTy(), components.suffixComponents);
5505         if (!eleTy)
5506           fir::emitFatalError(loc, "slicing path is ill-formed");
5507         if (auto realTy = eleTy.dyn_cast<fir::RealType>())
5508           eleTy = Fortran::lower::convertReal(realTy.getContext(),
5509                                               realTy.getFKind());
5510 
5511         // create the type of the projected array.
5512         arrTy = fir::SequenceType::get(seqTy.getShape(), eleTy);
5513         LLVM_DEBUG(llvm::dbgs()
5514                    << "type of array projection from component slicing: "
5515                    << eleTy << ", " << arrTy << '\n');
5516       }
5517     }
5518     arrayOperands.push_back(ArrayOperand{memref, shape, slice});
5519     if (destShape.empty())
5520       destShape = getShape(arrayOperands.back());
5521     if (isBoxValue()) {
5522       // Semantics are a reference to a boxed array.
5523       // This case just requires that an embox operation be created to box the
5524       // value. The value of the box is forwarded in the continuation.
5525       mlir::Type reduceTy = reduceRank(arrTy, slice);
5526       auto boxTy = fir::BoxType::get(reduceTy);
5527       if (components.substring) {
5528         // Adjust char length to substring size.
5529         fir::CharacterType charTy =
5530             fir::factory::CharacterExprHelper::getCharType(reduceTy);
5531         auto seqTy = reduceTy.cast<fir::SequenceType>();
5532         // TODO: Use a constant for fir.char LEN if we can compute it.
5533         boxTy = fir::BoxType::get(
5534             fir::SequenceType::get(fir::CharacterType::getUnknownLen(
5535                                        builder.getContext(), charTy.getFKind()),
5536                                    seqTy.getDimension()));
5537       }
5538       mlir::Value embox =
5539           memref.getType().isa<fir::BoxType>()
5540               ? builder.create<fir::ReboxOp>(loc, boxTy, memref, shape, slice)
5541                     .getResult()
5542               : builder
5543                     .create<fir::EmboxOp>(loc, boxTy, memref, shape, slice,
5544                                           fir::getTypeParams(extMemref))
5545                     .getResult();
5546       return [=](IterSpace) -> ExtValue { return fir::BoxValue(embox); };
5547     }
5548     auto eleTy = arrTy.cast<fir::SequenceType>().getEleTy();
5549     if (isReferentiallyOpaque()) {
5550       // Semantics are an opaque reference to an array.
5551       // This case forwards a continuation that will generate the address
5552       // arithmetic to the array element. This does not have copy-in/copy-out
5553       // semantics. No attempt to copy the array value will be made during the
5554       // interpretation of the Fortran statement.
5555       mlir::Type refEleTy = builder.getRefType(eleTy);
5556       return [=](IterSpace iters) -> ExtValue {
5557         // ArrayCoorOp does not expect zero based indices.
5558         llvm::SmallVector<mlir::Value> indices = fir::factory::originateIndices(
5559             loc, builder, memref.getType(), shape, iters.iterVec());
5560         mlir::Value coor = builder.create<fir::ArrayCoorOp>(
5561             loc, refEleTy, memref, shape, slice, indices,
5562             fir::getTypeParams(extMemref));
5563         if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) {
5564           llvm::SmallVector<mlir::Value> substringBounds;
5565           populateBounds(substringBounds, components.substring);
5566           if (!substringBounds.empty()) {
5567             mlir::Value dstLen = fir::factory::genLenOfCharacter(
5568                 builder, loc, arrTy.cast<fir::SequenceType>(), memref,
5569                 fir::getTypeParams(extMemref), iters.iterVec(),
5570                 substringBounds);
5571             fir::CharBoxValue dstChar(coor, dstLen);
5572             return fir::factory::CharacterExprHelper{builder, loc}
5573                 .createSubstring(dstChar, substringBounds);
5574           }
5575         }
5576         return fir::factory::arraySectionElementToExtendedValue(
5577             builder, loc, extMemref, coor, slice);
5578       };
5579     }
5580     auto arrLoad = builder.create<fir::ArrayLoadOp>(
5581         loc, arrTy, memref, shape, slice, fir::getTypeParams(extMemref));
5582     mlir::Value arrLd = arrLoad.getResult();
5583     if (isProjectedCopyInCopyOut()) {
5584       // Semantics are projected copy-in copy-out.
5585       // The backing store of the destination of an array expression may be
5586       // partially modified. These updates are recorded in FIR by forwarding a
5587       // continuation that generates an `array_update` Op. The destination is
5588       // always loaded at the beginning of the statement and merged at the
5589       // end.
5590       destination = arrLoad;
5591       auto lambda = ccStoreToDest.hasValue()
5592                         ? ccStoreToDest.getValue()
5593                         : defaultStoreToDestination(components.substring);
5594       return [=](IterSpace iters) -> ExtValue { return lambda(iters); };
5595     }
5596     if (isCustomCopyInCopyOut()) {
5597       // Create an array_modify to get the LHS element address and indicate
5598       // the assignment, the actual assignment must be implemented in
5599       // ccStoreToDest.
5600       destination = arrLoad;
5601       return [=](IterSpace iters) -> ExtValue {
5602         mlir::Value innerArg = iters.innerArgument();
5603         mlir::Type resTy = innerArg.getType();
5604         mlir::Type eleTy = fir::applyPathToType(resTy, iters.iterVec());
5605         mlir::Type refEleTy =
5606             fir::isa_ref_type(eleTy) ? eleTy : builder.getRefType(eleTy);
5607         auto arrModify = builder.create<fir::ArrayModifyOp>(
5608             loc, mlir::TypeRange{refEleTy, resTy}, innerArg, iters.iterVec(),
5609             destination.getTypeparams());
5610         return abstractArrayExtValue(arrModify.getResult(1));
5611       };
5612     }
5613     if (isCopyInCopyOut()) {
5614       // Semantics are copy-in copy-out.
5615       // The continuation simply forwards the result of the `array_load` Op,
5616       // which is the value of the array as it was when loaded. All data
5617       // references with rank > 0 in an array expression typically have
5618       // copy-in copy-out semantics.
5619       return [=](IterSpace) -> ExtValue { return arrLd; };
5620     }
5621     mlir::Operation::operand_range arrLdTypeParams = arrLoad.getTypeparams();
5622     if (isValueAttribute()) {
5623       // Semantics are value attribute.
5624       // Here the continuation will `array_fetch` a value from an array and
5625       // then store that value in a temporary. One can thus imitate pass by
5626       // value even when the call is pass by reference.
5627       return [=](IterSpace iters) -> ExtValue {
5628         mlir::Value base;
5629         mlir::Type eleTy = fir::applyPathToType(arrTy, iters.iterVec());
5630         if (isAdjustedArrayElementType(eleTy)) {
5631           mlir::Type eleRefTy = builder.getRefType(eleTy);
5632           base = builder.create<fir::ArrayAccessOp>(
5633               loc, eleRefTy, arrLd, iters.iterVec(), arrLdTypeParams);
5634         } else {
5635           base = builder.create<fir::ArrayFetchOp>(
5636               loc, eleTy, arrLd, iters.iterVec(), arrLdTypeParams);
5637         }
5638         mlir::Value temp = builder.createTemporary(
5639             loc, base.getType(),
5640             llvm::ArrayRef<mlir::NamedAttribute>{
5641                 Fortran::lower::getAdaptToByRefAttr(builder)});
5642         builder.create<fir::StoreOp>(loc, base, temp);
5643         return fir::factory::arraySectionElementToExtendedValue(
5644             builder, loc, extMemref, temp, slice);
5645       };
5646     }
5647     // In the default case, the array reference forwards an `array_fetch` or
5648     // `array_access` Op in the continuation.
5649     return [=](IterSpace iters) -> ExtValue {
5650       mlir::Type eleTy = fir::applyPathToType(arrTy, iters.iterVec());
5651       if (isAdjustedArrayElementType(eleTy)) {
5652         mlir::Type eleRefTy = builder.getRefType(eleTy);
5653         mlir::Value arrayOp = builder.create<fir::ArrayAccessOp>(
5654             loc, eleRefTy, arrLd, iters.iterVec(), arrLdTypeParams);
5655         if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) {
5656           llvm::SmallVector<mlir::Value> substringBounds;
5657           populateBounds(substringBounds, components.substring);
5658           if (!substringBounds.empty()) {
5659             mlir::Value dstLen = fir::factory::genLenOfCharacter(
5660                 builder, loc, arrLoad, iters.iterVec(), substringBounds);
5661             fir::CharBoxValue dstChar(arrayOp, dstLen);
5662             return fir::factory::CharacterExprHelper{builder, loc}
5663                 .createSubstring(dstChar, substringBounds);
5664           }
5665         }
5666         return fir::factory::arraySectionElementToExtendedValue(
5667             builder, loc, extMemref, arrayOp, slice);
5668       }
5669       auto arrFetch = builder.create<fir::ArrayFetchOp>(
5670           loc, eleTy, arrLd, iters.iterVec(), arrLdTypeParams);
5671       return fir::factory::arraySectionElementToExtendedValue(
5672           builder, loc, extMemref, arrFetch, slice);
5673     };
5674   }
5675 
5676   /// Given an optional fir.box, returns an fir.box that is the original one if
5677   /// it is present and it otherwise an unallocated box.
5678   /// Absent fir.box are implemented as a null pointer descriptor. Generated
5679   /// code may need to unconditionally read a fir.box that can be absent.
5680   /// This helper allows creating a fir.box that can be read in all cases
5681   /// outside of a fir.if (isPresent) region. However, the usages of the value
5682   /// read from such box should still only be done in a fir.if(isPresent).
5683   static fir::ExtendedValue
5684   absentBoxToUnalllocatedBox(fir::FirOpBuilder &builder, mlir::Location loc,
5685                              const fir::ExtendedValue &exv,
5686                              mlir::Value isPresent) {
5687     mlir::Value box = fir::getBase(exv);
5688     mlir::Type boxType = box.getType();
5689     assert(boxType.isa<fir::BoxType>() && "argument must be a fir.box");
5690     mlir::Value emptyBox =
5691         fir::factory::createUnallocatedBox(builder, loc, boxType, llvm::None);
5692     auto safeToReadBox =
5693         builder.create<mlir::arith::SelectOp>(loc, isPresent, box, emptyBox);
5694     return fir::substBase(exv, safeToReadBox);
5695   }
5696 
5697   std::tuple<CC, mlir::Value, mlir::Type>
5698   genOptionalArrayFetch(const Fortran::lower::SomeExpr &expr) {
5699     assert(expr.Rank() > 0 && "expr must be an array");
5700     mlir::Location loc = getLoc();
5701     ExtValue optionalArg = asInquired(expr);
5702     mlir::Value isPresent = genActualIsPresentTest(builder, loc, optionalArg);
5703     // Generate an array load and access to an array that may be an absent
5704     // optional or an unallocated optional.
5705     mlir::Value base = getBase(optionalArg);
5706     const bool hasOptionalAttr =
5707         fir::valueHasFirAttribute(base, fir::getOptionalAttrName());
5708     mlir::Type baseType = fir::unwrapRefType(base.getType());
5709     const bool isBox = baseType.isa<fir::BoxType>();
5710     const bool isAllocOrPtr = Fortran::evaluate::IsAllocatableOrPointerObject(
5711         expr, converter.getFoldingContext());
5712     mlir::Type arrType = fir::unwrapPassByRefType(baseType);
5713     mlir::Type eleType = fir::unwrapSequenceType(arrType);
5714     ExtValue exv = optionalArg;
5715     if (hasOptionalAttr && isBox && !isAllocOrPtr) {
5716       // Elemental argument cannot be allocatable or pointers (C15100).
5717       // Hence, per 15.5.2.12 3 (8) and (9), the provided Allocatable and
5718       // Pointer optional arrays cannot be absent. The only kind of entities
5719       // that can get here are optional assumed shape and polymorphic entities.
5720       exv = absentBoxToUnalllocatedBox(builder, loc, exv, isPresent);
5721     }
5722     // All the properties can be read from any fir.box but the read values may
5723     // be undefined and should only be used inside a fir.if (canBeRead) region.
5724     if (const auto *mutableBox = exv.getBoxOf<fir::MutableBoxValue>())
5725       exv = fir::factory::genMutableBoxRead(builder, loc, *mutableBox);
5726 
5727     mlir::Value memref = fir::getBase(exv);
5728     mlir::Value shape = builder.createShape(loc, exv);
5729     mlir::Value noSlice;
5730     auto arrLoad = builder.create<fir::ArrayLoadOp>(
5731         loc, arrType, memref, shape, noSlice, fir::getTypeParams(exv));
5732     mlir::Operation::operand_range arrLdTypeParams = arrLoad.getTypeparams();
5733     mlir::Value arrLd = arrLoad.getResult();
5734     // Mark the load to tell later passes it is unsafe to use this array_load
5735     // shape unconditionally.
5736     arrLoad->setAttr(fir::getOptionalAttrName(), builder.getUnitAttr());
5737 
5738     // Place the array as optional on the arrayOperands stack so that its
5739     // shape will only be used as a fallback to induce the implicit loop nest
5740     // (that is if there is no non optional array arguments).
5741     arrayOperands.push_back(
5742         ArrayOperand{memref, shape, noSlice, /*mayBeAbsent=*/true});
5743 
5744     // By value semantics.
5745     auto cc = [=](IterSpace iters) -> ExtValue {
5746       auto arrFetch = builder.create<fir::ArrayFetchOp>(
5747           loc, eleType, arrLd, iters.iterVec(), arrLdTypeParams);
5748       return fir::factory::arraySectionElementToExtendedValue(
5749           builder, loc, exv, arrFetch, noSlice);
5750     };
5751     return {cc, isPresent, eleType};
5752   }
5753 
5754   /// Generate a continuation to pass \p expr to an OPTIONAL argument of an
5755   /// elemental procedure. This is meant to handle the cases where \p expr might
5756   /// be dynamically absent (i.e. when it is a POINTER, an ALLOCATABLE or an
5757   /// OPTIONAL variable). If p\ expr is guaranteed to be present genarr() can
5758   /// directly be called instead.
5759   CC genarrForwardOptionalArgumentToCall(const Fortran::lower::SomeExpr &expr) {
5760     mlir::Location loc = getLoc();
5761     // Only by-value numerical and logical so far.
5762     if (semant != ConstituentSemantics::RefTransparent)
5763       TODO(loc, "optional arguments in user defined elemental procedures");
5764 
5765     // Handle scalar argument case (the if-then-else is generated outside of the
5766     // implicit loop nest).
5767     if (expr.Rank() == 0) {
5768       ExtValue optionalArg = asInquired(expr);
5769       mlir::Value isPresent = genActualIsPresentTest(builder, loc, optionalArg);
5770       mlir::Value elementValue =
5771           fir::getBase(genOptionalValue(builder, loc, optionalArg, isPresent));
5772       return [=](IterSpace iters) -> ExtValue { return elementValue; };
5773     }
5774 
5775     CC cc;
5776     mlir::Value isPresent;
5777     mlir::Type eleType;
5778     std::tie(cc, isPresent, eleType) = genOptionalArrayFetch(expr);
5779     return [=](IterSpace iters) -> ExtValue {
5780       mlir::Value elementValue =
5781           builder
5782               .genIfOp(loc, {eleType}, isPresent,
5783                        /*withElseRegion=*/true)
5784               .genThen([&]() {
5785                 builder.create<fir::ResultOp>(loc, fir::getBase(cc(iters)));
5786               })
5787               .genElse([&]() {
5788                 mlir::Value zero =
5789                     fir::factory::createZeroValue(builder, loc, eleType);
5790                 builder.create<fir::ResultOp>(loc, zero);
5791               })
5792               .getResults()[0];
5793       return elementValue;
5794     };
5795   }
5796 
5797   /// Reduce the rank of a array to be boxed based on the slice's operands.
5798   static mlir::Type reduceRank(mlir::Type arrTy, mlir::Value slice) {
5799     if (slice) {
5800       auto slOp = mlir::dyn_cast<fir::SliceOp>(slice.getDefiningOp());
5801       assert(slOp && "expected slice op");
5802       auto seqTy = arrTy.dyn_cast<fir::SequenceType>();
5803       assert(seqTy && "expected array type");
5804       mlir::Operation::operand_range triples = slOp.getTriples();
5805       fir::SequenceType::Shape shape;
5806       // reduce the rank for each invariant dimension
5807       for (unsigned i = 1, end = triples.size(); i < end; i += 3)
5808         if (!mlir::isa_and_nonnull<fir::UndefOp>(triples[i].getDefiningOp()))
5809           shape.push_back(fir::SequenceType::getUnknownExtent());
5810       return fir::SequenceType::get(shape, seqTy.getEleTy());
5811     }
5812     // not sliced, so no change in rank
5813     return arrTy;
5814   }
5815 
5816   /// Example: <code>array%RE</code>
5817   CC genarr(const Fortran::evaluate::ComplexPart &x,
5818             ComponentPath &components) {
5819     components.reversePath.push_back(&x);
5820     return genarr(x.complex(), components);
5821   }
5822 
5823   template <typename A>
5824   CC genSlicePath(const A &x, ComponentPath &components) {
5825     return genarr(x, components);
5826   }
5827 
5828   CC genarr(const Fortran::evaluate::StaticDataObject::Pointer &,
5829             ComponentPath &components) {
5830     fir::emitFatalError(getLoc(), "substring of static array object");
5831   }
5832 
5833   /// Substrings (see 9.4.1)
5834   CC genarr(const Fortran::evaluate::Substring &x, ComponentPath &components) {
5835     components.substring = &x;
5836     return std::visit([&](const auto &v) { return genarr(v, components); },
5837                       x.parent());
5838   }
5839 
5840   template <typename T>
5841   CC genarr(const Fortran::evaluate::FunctionRef<T> &funRef) {
5842     // Note that it's possible that the function being called returns either an
5843     // array or a scalar.  In the first case, use the element type of the array.
5844     return genProcRef(
5845         funRef, fir::unwrapSequenceType(converter.genType(toEvExpr(funRef))));
5846   }
5847 
5848   //===--------------------------------------------------------------------===//
5849   // Array construction
5850   //===--------------------------------------------------------------------===//
5851 
5852   /// Target agnostic computation of the size of an element in the array.
5853   /// Returns the size in bytes with type `index` or a null Value if the element
5854   /// size is not constant.
5855   mlir::Value computeElementSize(const ExtValue &exv, mlir::Type eleTy,
5856                                  mlir::Type resTy) {
5857     mlir::Location loc = getLoc();
5858     mlir::IndexType idxTy = builder.getIndexType();
5859     mlir::Value multiplier = builder.createIntegerConstant(loc, idxTy, 1);
5860     if (fir::hasDynamicSize(eleTy)) {
5861       if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) {
5862         // Array of char with dynamic length parameter. Downcast to an array
5863         // of singleton char, and scale by the len type parameter from
5864         // `exv`.
5865         exv.match(
5866             [&](const fir::CharBoxValue &cb) { multiplier = cb.getLen(); },
5867             [&](const fir::CharArrayBoxValue &cb) { multiplier = cb.getLen(); },
5868             [&](const fir::BoxValue &box) {
5869               multiplier = fir::factory::CharacterExprHelper(builder, loc)
5870                                .readLengthFromBox(box.getAddr());
5871             },
5872             [&](const fir::MutableBoxValue &box) {
5873               multiplier = fir::factory::CharacterExprHelper(builder, loc)
5874                                .readLengthFromBox(box.getAddr());
5875             },
5876             [&](const auto &) {
5877               fir::emitFatalError(loc,
5878                                   "array constructor element has unknown size");
5879             });
5880         fir::CharacterType newEleTy = fir::CharacterType::getSingleton(
5881             eleTy.getContext(), charTy.getFKind());
5882         if (auto seqTy = resTy.dyn_cast<fir::SequenceType>()) {
5883           assert(eleTy == seqTy.getEleTy());
5884           resTy = fir::SequenceType::get(seqTy.getShape(), newEleTy);
5885         }
5886         eleTy = newEleTy;
5887       } else {
5888         TODO(loc, "dynamic sized type");
5889       }
5890     }
5891     mlir::Type eleRefTy = builder.getRefType(eleTy);
5892     mlir::Type resRefTy = builder.getRefType(resTy);
5893     mlir::Value nullPtr = builder.createNullConstant(loc, resRefTy);
5894     auto offset = builder.create<fir::CoordinateOp>(
5895         loc, eleRefTy, nullPtr, mlir::ValueRange{multiplier});
5896     return builder.createConvert(loc, idxTy, offset);
5897   }
5898 
5899   /// Get the function signature of the LLVM memcpy intrinsic.
5900   mlir::FunctionType memcpyType() {
5901     return fir::factory::getLlvmMemcpy(builder).getFunctionType();
5902   }
5903 
5904   /// Create a call to the LLVM memcpy intrinsic.
5905   void createCallMemcpy(llvm::ArrayRef<mlir::Value> args) {
5906     mlir::Location loc = getLoc();
5907     mlir::FuncOp memcpyFunc = fir::factory::getLlvmMemcpy(builder);
5908     mlir::SymbolRefAttr funcSymAttr =
5909         builder.getSymbolRefAttr(memcpyFunc.getName());
5910     mlir::FunctionType funcTy = memcpyFunc.getFunctionType();
5911     builder.create<fir::CallOp>(loc, funcTy.getResults(), funcSymAttr, args);
5912   }
5913 
5914   // Construct code to check for a buffer overrun and realloc the buffer when
5915   // space is depleted. This is done between each item in the ac-value-list.
5916   mlir::Value growBuffer(mlir::Value mem, mlir::Value needed,
5917                          mlir::Value bufferSize, mlir::Value buffSize,
5918                          mlir::Value eleSz) {
5919     mlir::Location loc = getLoc();
5920     mlir::FuncOp reallocFunc = fir::factory::getRealloc(builder);
5921     auto cond = builder.create<mlir::arith::CmpIOp>(
5922         loc, mlir::arith::CmpIPredicate::sle, bufferSize, needed);
5923     auto ifOp = builder.create<fir::IfOp>(loc, mem.getType(), cond,
5924                                           /*withElseRegion=*/true);
5925     auto insPt = builder.saveInsertionPoint();
5926     builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
5927     // Not enough space, resize the buffer.
5928     mlir::IndexType idxTy = builder.getIndexType();
5929     mlir::Value two = builder.createIntegerConstant(loc, idxTy, 2);
5930     auto newSz = builder.create<mlir::arith::MulIOp>(loc, needed, two);
5931     builder.create<fir::StoreOp>(loc, newSz, buffSize);
5932     mlir::Value byteSz = builder.create<mlir::arith::MulIOp>(loc, newSz, eleSz);
5933     mlir::SymbolRefAttr funcSymAttr =
5934         builder.getSymbolRefAttr(reallocFunc.getName());
5935     mlir::FunctionType funcTy = reallocFunc.getFunctionType();
5936     auto newMem = builder.create<fir::CallOp>(
5937         loc, funcTy.getResults(), funcSymAttr,
5938         llvm::ArrayRef<mlir::Value>{
5939             builder.createConvert(loc, funcTy.getInputs()[0], mem),
5940             builder.createConvert(loc, funcTy.getInputs()[1], byteSz)});
5941     mlir::Value castNewMem =
5942         builder.createConvert(loc, mem.getType(), newMem.getResult(0));
5943     builder.create<fir::ResultOp>(loc, castNewMem);
5944     builder.setInsertionPointToStart(&ifOp.getElseRegion().front());
5945     // Otherwise, just forward the buffer.
5946     builder.create<fir::ResultOp>(loc, mem);
5947     builder.restoreInsertionPoint(insPt);
5948     return ifOp.getResult(0);
5949   }
5950 
5951   /// Copy the next value (or vector of values) into the array being
5952   /// constructed.
5953   mlir::Value copyNextArrayCtorSection(const ExtValue &exv, mlir::Value buffPos,
5954                                        mlir::Value buffSize, mlir::Value mem,
5955                                        mlir::Value eleSz, mlir::Type eleTy,
5956                                        mlir::Type eleRefTy, mlir::Type resTy) {
5957     mlir::Location loc = getLoc();
5958     auto off = builder.create<fir::LoadOp>(loc, buffPos);
5959     auto limit = builder.create<fir::LoadOp>(loc, buffSize);
5960     mlir::IndexType idxTy = builder.getIndexType();
5961     mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
5962 
5963     if (fir::isRecordWithAllocatableMember(eleTy))
5964       TODO(loc, "deep copy on allocatable members");
5965 
5966     if (!eleSz) {
5967       // Compute the element size at runtime.
5968       assert(fir::hasDynamicSize(eleTy));
5969       if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) {
5970         auto charBytes =
5971             builder.getKindMap().getCharacterBitsize(charTy.getFKind()) / 8;
5972         mlir::Value bytes =
5973             builder.createIntegerConstant(loc, idxTy, charBytes);
5974         mlir::Value length = fir::getLen(exv);
5975         if (!length)
5976           fir::emitFatalError(loc, "result is not boxed character");
5977         eleSz = builder.create<mlir::arith::MulIOp>(loc, bytes, length);
5978       } else {
5979         TODO(loc, "PDT size");
5980         // Will call the PDT's size function with the type parameters.
5981       }
5982     }
5983 
5984     // Compute the coordinate using `fir.coordinate_of`, or, if the type has
5985     // dynamic size, generating the pointer arithmetic.
5986     auto computeCoordinate = [&](mlir::Value buff, mlir::Value off) {
5987       mlir::Type refTy = eleRefTy;
5988       if (fir::hasDynamicSize(eleTy)) {
5989         if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) {
5990           // Scale a simple pointer using dynamic length and offset values.
5991           auto chTy = fir::CharacterType::getSingleton(charTy.getContext(),
5992                                                        charTy.getFKind());
5993           refTy = builder.getRefType(chTy);
5994           mlir::Type toTy = builder.getRefType(builder.getVarLenSeqTy(chTy));
5995           buff = builder.createConvert(loc, toTy, buff);
5996           off = builder.create<mlir::arith::MulIOp>(loc, off, eleSz);
5997         } else {
5998           TODO(loc, "PDT offset");
5999         }
6000       }
6001       auto coor = builder.create<fir::CoordinateOp>(loc, refTy, buff,
6002                                                     mlir::ValueRange{off});
6003       return builder.createConvert(loc, eleRefTy, coor);
6004     };
6005 
6006     // Lambda to lower an abstract array box value.
6007     auto doAbstractArray = [&](const auto &v) {
6008       // Compute the array size.
6009       mlir::Value arrSz = one;
6010       for (auto ext : v.getExtents())
6011         arrSz = builder.create<mlir::arith::MulIOp>(loc, arrSz, ext);
6012 
6013       // Grow the buffer as needed.
6014       auto endOff = builder.create<mlir::arith::AddIOp>(loc, off, arrSz);
6015       mem = growBuffer(mem, endOff, limit, buffSize, eleSz);
6016 
6017       // Copy the elements to the buffer.
6018       mlir::Value byteSz =
6019           builder.create<mlir::arith::MulIOp>(loc, arrSz, eleSz);
6020       auto buff = builder.createConvert(loc, fir::HeapType::get(resTy), mem);
6021       mlir::Value buffi = computeCoordinate(buff, off);
6022       llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
6023           builder, loc, memcpyType(), buffi, v.getAddr(), byteSz,
6024           /*volatile=*/builder.createBool(loc, false));
6025       createCallMemcpy(args);
6026 
6027       // Save the incremented buffer position.
6028       builder.create<fir::StoreOp>(loc, endOff, buffPos);
6029     };
6030 
6031     // Copy a trivial scalar value into the buffer.
6032     auto doTrivialScalar = [&](const ExtValue &v, mlir::Value len = {}) {
6033       // Increment the buffer position.
6034       auto plusOne = builder.create<mlir::arith::AddIOp>(loc, off, one);
6035 
6036       // Grow the buffer as needed.
6037       mem = growBuffer(mem, plusOne, limit, buffSize, eleSz);
6038 
6039       // Store the element in the buffer.
6040       mlir::Value buff =
6041           builder.createConvert(loc, fir::HeapType::get(resTy), mem);
6042       auto buffi = builder.create<fir::CoordinateOp>(loc, eleRefTy, buff,
6043                                                      mlir::ValueRange{off});
6044       fir::factory::genScalarAssignment(
6045           builder, loc,
6046           [&]() -> ExtValue {
6047             if (len)
6048               return fir::CharBoxValue(buffi, len);
6049             return buffi;
6050           }(),
6051           v);
6052       builder.create<fir::StoreOp>(loc, plusOne, buffPos);
6053     };
6054 
6055     // Copy the value.
6056     exv.match(
6057         [&](mlir::Value) { doTrivialScalar(exv); },
6058         [&](const fir::CharBoxValue &v) {
6059           auto buffer = v.getBuffer();
6060           if (fir::isa_char(buffer.getType())) {
6061             doTrivialScalar(exv, eleSz);
6062           } else {
6063             // Increment the buffer position.
6064             auto plusOne = builder.create<mlir::arith::AddIOp>(loc, off, one);
6065 
6066             // Grow the buffer as needed.
6067             mem = growBuffer(mem, plusOne, limit, buffSize, eleSz);
6068 
6069             // Store the element in the buffer.
6070             mlir::Value buff =
6071                 builder.createConvert(loc, fir::HeapType::get(resTy), mem);
6072             mlir::Value buffi = computeCoordinate(buff, off);
6073             llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
6074                 builder, loc, memcpyType(), buffi, v.getAddr(), eleSz,
6075                 /*volatile=*/builder.createBool(loc, false));
6076             createCallMemcpy(args);
6077 
6078             builder.create<fir::StoreOp>(loc, plusOne, buffPos);
6079           }
6080         },
6081         [&](const fir::ArrayBoxValue &v) { doAbstractArray(v); },
6082         [&](const fir::CharArrayBoxValue &v) { doAbstractArray(v); },
6083         [&](const auto &) {
6084           TODO(loc, "unhandled array constructor expression");
6085         });
6086     return mem;
6087   }
6088 
6089   // Lower the expr cases in an ac-value-list.
6090   template <typename A>
6091   std::pair<ExtValue, bool>
6092   genArrayCtorInitializer(const Fortran::evaluate::Expr<A> &x, mlir::Type,
6093                           mlir::Value, mlir::Value, mlir::Value,
6094                           Fortran::lower::StatementContext &stmtCtx) {
6095     if (isArray(x))
6096       return {lowerNewArrayExpression(converter, symMap, stmtCtx, toEvExpr(x)),
6097               /*needCopy=*/true};
6098     return {asScalar(x), /*needCopy=*/true};
6099   }
6100 
6101   // Lower an ac-implied-do in an ac-value-list.
6102   template <typename A>
6103   std::pair<ExtValue, bool>
6104   genArrayCtorInitializer(const Fortran::evaluate::ImpliedDo<A> &x,
6105                           mlir::Type resTy, mlir::Value mem,
6106                           mlir::Value buffPos, mlir::Value buffSize,
6107                           Fortran::lower::StatementContext &) {
6108     mlir::Location loc = getLoc();
6109     mlir::IndexType idxTy = builder.getIndexType();
6110     mlir::Value lo =
6111         builder.createConvert(loc, idxTy, fir::getBase(asScalar(x.lower())));
6112     mlir::Value up =
6113         builder.createConvert(loc, idxTy, fir::getBase(asScalar(x.upper())));
6114     mlir::Value step =
6115         builder.createConvert(loc, idxTy, fir::getBase(asScalar(x.stride())));
6116     auto seqTy = resTy.template cast<fir::SequenceType>();
6117     mlir::Type eleTy = fir::unwrapSequenceType(seqTy);
6118     auto loop =
6119         builder.create<fir::DoLoopOp>(loc, lo, up, step, /*unordered=*/false,
6120                                       /*finalCount=*/false, mem);
6121     // create a new binding for x.name(), to ac-do-variable, to the iteration
6122     // value.
6123     symMap.pushImpliedDoBinding(toStringRef(x.name()), loop.getInductionVar());
6124     auto insPt = builder.saveInsertionPoint();
6125     builder.setInsertionPointToStart(loop.getBody());
6126     // Thread mem inside the loop via loop argument.
6127     mem = loop.getRegionIterArgs()[0];
6128 
6129     mlir::Type eleRefTy = builder.getRefType(eleTy);
6130 
6131     // Any temps created in the loop body must be freed inside the loop body.
6132     stmtCtx.pushScope();
6133     llvm::Optional<mlir::Value> charLen;
6134     for (const Fortran::evaluate::ArrayConstructorValue<A> &acv : x.values()) {
6135       auto [exv, copyNeeded] = std::visit(
6136           [&](const auto &v) {
6137             return genArrayCtorInitializer(v, resTy, mem, buffPos, buffSize,
6138                                            stmtCtx);
6139           },
6140           acv.u);
6141       mlir::Value eleSz = computeElementSize(exv, eleTy, resTy);
6142       mem = copyNeeded ? copyNextArrayCtorSection(exv, buffPos, buffSize, mem,
6143                                                   eleSz, eleTy, eleRefTy, resTy)
6144                        : fir::getBase(exv);
6145       if (fir::isa_char(seqTy.getEleTy()) && !charLen.hasValue()) {
6146         charLen = builder.createTemporary(loc, builder.getI64Type());
6147         mlir::Value castLen =
6148             builder.createConvert(loc, builder.getI64Type(), fir::getLen(exv));
6149         builder.create<fir::StoreOp>(loc, castLen, charLen.getValue());
6150       }
6151     }
6152     stmtCtx.finalize(/*popScope=*/true);
6153 
6154     builder.create<fir::ResultOp>(loc, mem);
6155     builder.restoreInsertionPoint(insPt);
6156     mem = loop.getResult(0);
6157     symMap.popImpliedDoBinding();
6158     llvm::SmallVector<mlir::Value> extents = {
6159         builder.create<fir::LoadOp>(loc, buffPos).getResult()};
6160 
6161     // Convert to extended value.
6162     if (fir::isa_char(seqTy.getEleTy())) {
6163       auto len = builder.create<fir::LoadOp>(loc, charLen.getValue());
6164       return {fir::CharArrayBoxValue{mem, len, extents}, /*needCopy=*/false};
6165     }
6166     return {fir::ArrayBoxValue{mem, extents}, /*needCopy=*/false};
6167   }
6168 
6169   // To simplify the handling and interaction between the various cases, array
6170   // constructors are always lowered to the incremental construction code
6171   // pattern, even if the extent of the array value is constant. After the
6172   // MemToReg pass and constant folding, the optimizer should be able to
6173   // determine that all the buffer overrun tests are false when the
6174   // incremental construction wasn't actually required.
6175   template <typename A>
6176   CC genarr(const Fortran::evaluate::ArrayConstructor<A> &x) {
6177     mlir::Location loc = getLoc();
6178     auto evExpr = toEvExpr(x);
6179     mlir::Type resTy = translateSomeExprToFIRType(converter, evExpr);
6180     mlir::IndexType idxTy = builder.getIndexType();
6181     auto seqTy = resTy.template cast<fir::SequenceType>();
6182     mlir::Type eleTy = fir::unwrapSequenceType(resTy);
6183     mlir::Value buffSize = builder.createTemporary(loc, idxTy, ".buff.size");
6184     mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
6185     mlir::Value buffPos = builder.createTemporary(loc, idxTy, ".buff.pos");
6186     builder.create<fir::StoreOp>(loc, zero, buffPos);
6187     // Allocate space for the array to be constructed.
6188     mlir::Value mem;
6189     if (fir::hasDynamicSize(resTy)) {
6190       if (fir::hasDynamicSize(eleTy)) {
6191         // The size of each element may depend on a general expression. Defer
6192         // creating the buffer until after the expression is evaluated.
6193         mem = builder.createNullConstant(loc, builder.getRefType(eleTy));
6194         builder.create<fir::StoreOp>(loc, zero, buffSize);
6195       } else {
6196         mlir::Value initBuffSz =
6197             builder.createIntegerConstant(loc, idxTy, clInitialBufferSize);
6198         mem = builder.create<fir::AllocMemOp>(
6199             loc, eleTy, /*typeparams=*/llvm::None, initBuffSz);
6200         builder.create<fir::StoreOp>(loc, initBuffSz, buffSize);
6201       }
6202     } else {
6203       mem = builder.create<fir::AllocMemOp>(loc, resTy);
6204       int64_t buffSz = 1;
6205       for (auto extent : seqTy.getShape())
6206         buffSz *= extent;
6207       mlir::Value initBuffSz =
6208           builder.createIntegerConstant(loc, idxTy, buffSz);
6209       builder.create<fir::StoreOp>(loc, initBuffSz, buffSize);
6210     }
6211     // Compute size of element
6212     mlir::Type eleRefTy = builder.getRefType(eleTy);
6213 
6214     // Populate the buffer with the elements, growing as necessary.
6215     llvm::Optional<mlir::Value> charLen;
6216     for (const auto &expr : x) {
6217       auto [exv, copyNeeded] = std::visit(
6218           [&](const auto &e) {
6219             return genArrayCtorInitializer(e, resTy, mem, buffPos, buffSize,
6220                                            stmtCtx);
6221           },
6222           expr.u);
6223       mlir::Value eleSz = computeElementSize(exv, eleTy, resTy);
6224       mem = copyNeeded ? copyNextArrayCtorSection(exv, buffPos, buffSize, mem,
6225                                                   eleSz, eleTy, eleRefTy, resTy)
6226                        : fir::getBase(exv);
6227       if (fir::isa_char(seqTy.getEleTy()) && !charLen.hasValue()) {
6228         charLen = builder.createTemporary(loc, builder.getI64Type());
6229         mlir::Value castLen =
6230             builder.createConvert(loc, builder.getI64Type(), fir::getLen(exv));
6231         builder.create<fir::StoreOp>(loc, castLen, charLen.getValue());
6232       }
6233     }
6234     mem = builder.createConvert(loc, fir::HeapType::get(resTy), mem);
6235     llvm::SmallVector<mlir::Value> extents = {
6236         builder.create<fir::LoadOp>(loc, buffPos)};
6237 
6238     // Cleanup the temporary.
6239     fir::FirOpBuilder *bldr = &converter.getFirOpBuilder();
6240     stmtCtx.attachCleanup(
6241         [bldr, loc, mem]() { bldr->create<fir::FreeMemOp>(loc, mem); });
6242 
6243     // Return the continuation.
6244     if (fir::isa_char(seqTy.getEleTy())) {
6245       if (charLen.hasValue()) {
6246         auto len = builder.create<fir::LoadOp>(loc, charLen.getValue());
6247         return genarr(fir::CharArrayBoxValue{mem, len, extents});
6248       }
6249       return genarr(fir::CharArrayBoxValue{mem, zero, extents});
6250     }
6251     return genarr(fir::ArrayBoxValue{mem, extents});
6252   }
6253 
6254   CC genarr(const Fortran::evaluate::ImpliedDoIndex &) {
6255     fir::emitFatalError(getLoc(), "implied do index cannot have rank > 0");
6256   }
6257   CC genarr(const Fortran::evaluate::TypeParamInquiry &x) {
6258     TODO(getLoc(), "array expr type parameter inquiry");
6259     return [](IterSpace iters) -> ExtValue { return mlir::Value{}; };
6260   }
6261   CC genarr(const Fortran::evaluate::DescriptorInquiry &x) {
6262     TODO(getLoc(), "array expr descriptor inquiry");
6263     return [](IterSpace iters) -> ExtValue { return mlir::Value{}; };
6264   }
6265   CC genarr(const Fortran::evaluate::StructureConstructor &x) {
6266     TODO(getLoc(), "structure constructor");
6267     return [](IterSpace iters) -> ExtValue { return mlir::Value{}; };
6268   }
6269 
6270   //===--------------------------------------------------------------------===//
6271   // LOCICAL operators (.NOT., .AND., .EQV., etc.)
6272   //===--------------------------------------------------------------------===//
6273 
6274   template <int KIND>
6275   CC genarr(const Fortran::evaluate::Not<KIND> &x) {
6276     mlir::Location loc = getLoc();
6277     mlir::IntegerType i1Ty = builder.getI1Type();
6278     auto lambda = genarr(x.left());
6279     mlir::Value truth = builder.createBool(loc, true);
6280     return [=](IterSpace iters) -> ExtValue {
6281       mlir::Value logical = fir::getBase(lambda(iters));
6282       mlir::Value val = builder.createConvert(loc, i1Ty, logical);
6283       return builder.create<mlir::arith::XOrIOp>(loc, val, truth);
6284     };
6285   }
6286   template <typename OP, typename A>
6287   CC createBinaryBoolOp(const A &x) {
6288     mlir::Location loc = getLoc();
6289     mlir::IntegerType i1Ty = builder.getI1Type();
6290     auto lf = genarr(x.left());
6291     auto rf = genarr(x.right());
6292     return [=](IterSpace iters) -> ExtValue {
6293       mlir::Value left = fir::getBase(lf(iters));
6294       mlir::Value right = fir::getBase(rf(iters));
6295       mlir::Value lhs = builder.createConvert(loc, i1Ty, left);
6296       mlir::Value rhs = builder.createConvert(loc, i1Ty, right);
6297       return builder.create<OP>(loc, lhs, rhs);
6298     };
6299   }
6300   template <typename OP, typename A>
6301   CC createCompareBoolOp(mlir::arith::CmpIPredicate pred, const A &x) {
6302     mlir::Location loc = getLoc();
6303     mlir::IntegerType i1Ty = builder.getI1Type();
6304     auto lf = genarr(x.left());
6305     auto rf = genarr(x.right());
6306     return [=](IterSpace iters) -> ExtValue {
6307       mlir::Value left = fir::getBase(lf(iters));
6308       mlir::Value right = fir::getBase(rf(iters));
6309       mlir::Value lhs = builder.createConvert(loc, i1Ty, left);
6310       mlir::Value rhs = builder.createConvert(loc, i1Ty, right);
6311       return builder.create<OP>(loc, pred, lhs, rhs);
6312     };
6313   }
6314   template <int KIND>
6315   CC genarr(const Fortran::evaluate::LogicalOperation<KIND> &x) {
6316     switch (x.logicalOperator) {
6317     case Fortran::evaluate::LogicalOperator::And:
6318       return createBinaryBoolOp<mlir::arith::AndIOp>(x);
6319     case Fortran::evaluate::LogicalOperator::Or:
6320       return createBinaryBoolOp<mlir::arith::OrIOp>(x);
6321     case Fortran::evaluate::LogicalOperator::Eqv:
6322       return createCompareBoolOp<mlir::arith::CmpIOp>(
6323           mlir::arith::CmpIPredicate::eq, x);
6324     case Fortran::evaluate::LogicalOperator::Neqv:
6325       return createCompareBoolOp<mlir::arith::CmpIOp>(
6326           mlir::arith::CmpIPredicate::ne, x);
6327     case Fortran::evaluate::LogicalOperator::Not:
6328       llvm_unreachable(".NOT. handled elsewhere");
6329     }
6330     llvm_unreachable("unhandled case");
6331   }
6332 
6333   //===--------------------------------------------------------------------===//
6334   // Relational operators (<, <=, ==, etc.)
6335   //===--------------------------------------------------------------------===//
6336 
6337   template <typename OP, typename PRED, typename A>
6338   CC createCompareOp(PRED pred, const A &x) {
6339     mlir::Location loc = getLoc();
6340     auto lf = genarr(x.left());
6341     auto rf = genarr(x.right());
6342     return [=](IterSpace iters) -> ExtValue {
6343       mlir::Value lhs = fir::getBase(lf(iters));
6344       mlir::Value rhs = fir::getBase(rf(iters));
6345       return builder.create<OP>(loc, pred, lhs, rhs);
6346     };
6347   }
6348   template <typename A>
6349   CC createCompareCharOp(mlir::arith::CmpIPredicate pred, const A &x) {
6350     mlir::Location loc = getLoc();
6351     auto lf = genarr(x.left());
6352     auto rf = genarr(x.right());
6353     return [=](IterSpace iters) -> ExtValue {
6354       auto lhs = lf(iters);
6355       auto rhs = rf(iters);
6356       return fir::runtime::genCharCompare(builder, loc, pred, lhs, rhs);
6357     };
6358   }
6359   template <int KIND>
6360   CC genarr(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
6361                 Fortran::common::TypeCategory::Integer, KIND>> &x) {
6362     return createCompareOp<mlir::arith::CmpIOp>(translateRelational(x.opr), x);
6363   }
6364   template <int KIND>
6365   CC genarr(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
6366                 Fortran::common::TypeCategory::Character, KIND>> &x) {
6367     return createCompareCharOp(translateRelational(x.opr), x);
6368   }
6369   template <int KIND>
6370   CC genarr(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
6371                 Fortran::common::TypeCategory::Real, KIND>> &x) {
6372     return createCompareOp<mlir::arith::CmpFOp>(translateFloatRelational(x.opr),
6373                                                 x);
6374   }
6375   template <int KIND>
6376   CC genarr(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
6377                 Fortran::common::TypeCategory::Complex, KIND>> &x) {
6378     return createCompareOp<fir::CmpcOp>(translateFloatRelational(x.opr), x);
6379   }
6380   CC genarr(
6381       const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &r) {
6382     return std::visit([&](const auto &x) { return genarr(x); }, r.u);
6383   }
6384 
6385   template <typename A>
6386   CC genarr(const Fortran::evaluate::Designator<A> &des) {
6387     ComponentPath components(des.Rank() > 0);
6388     return std::visit([&](const auto &x) { return genarr(x, components); },
6389                       des.u);
6390   }
6391 
6392   /// Is the path component rank > 0?
6393   static bool ranked(const PathComponent &x) {
6394     return std::visit(Fortran::common::visitors{
6395                           [](const ImplicitSubscripts &) { return false; },
6396                           [](const auto *v) { return v->Rank() > 0; }},
6397                       x);
6398   }
6399 
6400   //===-------------------------------------------------------------------===//
6401   // Array data references in an explicit iteration space.
6402   //
6403   // Use the base array that was loaded before the loop nest.
6404   //===-------------------------------------------------------------------===//
6405 
6406   /// Lower the path (`revPath`, in reverse) to be appended to an array_fetch or
6407   /// array_update op. \p ty is the initial type of the array
6408   /// (reference). Returns the type of the element after application of the
6409   /// path in \p components.
6410   ///
6411   /// TODO: This needs to deal with array's with initial bounds other than 1.
6412   /// TODO: Thread type parameters correctly.
6413   mlir::Type lowerPath(const ExtValue &arrayExv, ComponentPath &components) {
6414     mlir::Location loc = getLoc();
6415     mlir::Type ty = fir::getBase(arrayExv).getType();
6416     auto &revPath = components.reversePath;
6417     ty = fir::unwrapPassByRefType(ty);
6418     bool prefix = true;
6419     auto addComponent = [&](mlir::Value v) {
6420       if (prefix)
6421         components.prefixComponents.push_back(v);
6422       else
6423         components.suffixComponents.push_back(v);
6424     };
6425     mlir::IndexType idxTy = builder.getIndexType();
6426     mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
6427     bool atBase = true;
6428     auto saveSemant = semant;
6429     if (isProjectedCopyInCopyOut())
6430       semant = ConstituentSemantics::RefTransparent;
6431     for (const auto &v : llvm::reverse(revPath)) {
6432       std::visit(
6433           Fortran::common::visitors{
6434               [&](const ImplicitSubscripts &) {
6435                 prefix = false;
6436                 ty = fir::unwrapSequenceType(ty);
6437               },
6438               [&](const Fortran::evaluate::ComplexPart *x) {
6439                 assert(!prefix && "complex part must be at end");
6440                 mlir::Value offset = builder.createIntegerConstant(
6441                     loc, builder.getI32Type(),
6442                     x->part() == Fortran::evaluate::ComplexPart::Part::RE ? 0
6443                                                                           : 1);
6444                 components.suffixComponents.push_back(offset);
6445                 ty = fir::applyPathToType(ty, mlir::ValueRange{offset});
6446               },
6447               [&](const Fortran::evaluate::ArrayRef *x) {
6448                 if (Fortran::lower::isRankedArrayAccess(*x)) {
6449                   genSliceIndices(components, arrayExv, *x, atBase);
6450                 } else {
6451                   // Array access where the expressions are scalar and cannot
6452                   // depend upon the implied iteration space.
6453                   unsigned ssIndex = 0u;
6454                   for (const auto &ss : x->subscript()) {
6455                     std::visit(
6456                         Fortran::common::visitors{
6457                             [&](const Fortran::evaluate::
6458                                     IndirectSubscriptIntegerExpr &ie) {
6459                               const auto &e = ie.value();
6460                               if (isArray(e))
6461                                 fir::emitFatalError(
6462                                     loc,
6463                                     "multiple components along single path "
6464                                     "generating array subexpressions");
6465                               // Lower scalar index expression, append it to
6466                               // subs.
6467                               mlir::Value subscriptVal =
6468                                   fir::getBase(asScalarArray(e));
6469                               // arrayExv is the base array. It needs to reflect
6470                               // the current array component instead.
6471                               // FIXME: must use lower bound of this component,
6472                               // not just the constant 1.
6473                               mlir::Value lb =
6474                                   atBase ? fir::factory::readLowerBound(
6475                                                builder, loc, arrayExv, ssIndex,
6476                                                one)
6477                                          : one;
6478                               mlir::Value val = builder.createConvert(
6479                                   loc, idxTy, subscriptVal);
6480                               mlir::Value ivAdj =
6481                                   builder.create<mlir::arith::SubIOp>(
6482                                       loc, idxTy, val, lb);
6483                               addComponent(
6484                                   builder.createConvert(loc, idxTy, ivAdj));
6485                             },
6486                             [&](const auto &) {
6487                               fir::emitFatalError(
6488                                   loc, "multiple components along single path "
6489                                        "generating array subexpressions");
6490                             }},
6491                         ss.u);
6492                     ssIndex++;
6493                   }
6494                 }
6495                 ty = fir::unwrapSequenceType(ty);
6496               },
6497               [&](const Fortran::evaluate::Component *x) {
6498                 auto fieldTy = fir::FieldType::get(builder.getContext());
6499                 llvm::StringRef name = toStringRef(getLastSym(*x).name());
6500                 auto recTy = ty.cast<fir::RecordType>();
6501                 ty = recTy.getType(name);
6502                 auto fld = builder.create<fir::FieldIndexOp>(
6503                     loc, fieldTy, name, recTy, fir::getTypeParams(arrayExv));
6504                 addComponent(fld);
6505               }},
6506           v);
6507       atBase = false;
6508     }
6509     semant = saveSemant;
6510     ty = fir::unwrapSequenceType(ty);
6511     components.applied = true;
6512     return ty;
6513   }
6514 
6515   llvm::SmallVector<mlir::Value> genSubstringBounds(ComponentPath &components) {
6516     llvm::SmallVector<mlir::Value> result;
6517     if (components.substring)
6518       populateBounds(result, components.substring);
6519     return result;
6520   }
6521 
6522   CC applyPathToArrayLoad(fir::ArrayLoadOp load, ComponentPath &components) {
6523     mlir::Location loc = getLoc();
6524     auto revPath = components.reversePath;
6525     fir::ExtendedValue arrayExv =
6526         arrayLoadExtValue(builder, loc, load, {}, load);
6527     mlir::Type eleTy = lowerPath(arrayExv, components);
6528     auto currentPC = components.pc;
6529     auto pc = [=, prefix = components.prefixComponents,
6530                suffix = components.suffixComponents](IterSpace iters) {
6531       IterationSpace newIters = currentPC(iters);
6532       // Add path prefix and suffix.
6533       IterationSpace addIters(newIters, prefix, suffix);
6534       return addIters;
6535     };
6536     components.pc = [=](IterSpace iters) { return iters; };
6537     llvm::SmallVector<mlir::Value> substringBounds =
6538         genSubstringBounds(components);
6539     if (isProjectedCopyInCopyOut()) {
6540       destination = load;
6541       auto lambda = [=, esp = this->explicitSpace](IterSpace iters) mutable {
6542         mlir::Value innerArg = esp->findArgumentOfLoad(load);
6543         if (isAdjustedArrayElementType(eleTy)) {
6544           mlir::Type eleRefTy = builder.getRefType(eleTy);
6545           auto arrayOp = builder.create<fir::ArrayAccessOp>(
6546               loc, eleRefTy, innerArg, iters.iterVec(), load.getTypeparams());
6547           if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) {
6548             mlir::Value dstLen = fir::factory::genLenOfCharacter(
6549                 builder, loc, load, iters.iterVec(), substringBounds);
6550             fir::ArrayAmendOp amend = createCharArrayAmend(
6551                 loc, builder, arrayOp, dstLen, iters.elementExv(), innerArg,
6552                 substringBounds);
6553             return arrayLoadExtValue(builder, loc, load, iters.iterVec(), amend,
6554                                      dstLen);
6555           } else if (fir::isa_derived(eleTy)) {
6556             fir::ArrayAmendOp amend =
6557                 createDerivedArrayAmend(loc, load, builder, arrayOp,
6558                                         iters.elementExv(), eleTy, innerArg);
6559             return arrayLoadExtValue(builder, loc, load, iters.iterVec(),
6560                                      amend);
6561           }
6562           assert(eleTy.isa<fir::SequenceType>());
6563           TODO(loc, "array (as element) assignment");
6564         }
6565         mlir::Value castedElement =
6566             builder.createConvert(loc, eleTy, iters.getElement());
6567         auto update = builder.create<fir::ArrayUpdateOp>(
6568             loc, innerArg.getType(), innerArg, castedElement, iters.iterVec(),
6569             load.getTypeparams());
6570         return arrayLoadExtValue(builder, loc, load, iters.iterVec(), update);
6571       };
6572       return [=](IterSpace iters) mutable { return lambda(pc(iters)); };
6573     }
6574     if (isCustomCopyInCopyOut()) {
6575       // Create an array_modify to get the LHS element address and indicate
6576       // the assignment, and create the call to the user defined assignment.
6577       destination = load;
6578       auto lambda = [=](IterSpace iters) mutable {
6579         mlir::Value innerArg = explicitSpace->findArgumentOfLoad(load);
6580         mlir::Type refEleTy =
6581             fir::isa_ref_type(eleTy) ? eleTy : builder.getRefType(eleTy);
6582         auto arrModify = builder.create<fir::ArrayModifyOp>(
6583             loc, mlir::TypeRange{refEleTy, innerArg.getType()}, innerArg,
6584             iters.iterVec(), load.getTypeparams());
6585         return arrayLoadExtValue(builder, loc, load, iters.iterVec(),
6586                                  arrModify.getResult(1));
6587       };
6588       return [=](IterSpace iters) mutable { return lambda(pc(iters)); };
6589     }
6590     auto lambda = [=, semant = this->semant](IterSpace iters) mutable {
6591       if (semant == ConstituentSemantics::RefOpaque ||
6592           isAdjustedArrayElementType(eleTy)) {
6593         mlir::Type resTy = builder.getRefType(eleTy);
6594         // Use array element reference semantics.
6595         auto access = builder.create<fir::ArrayAccessOp>(
6596             loc, resTy, load, iters.iterVec(), load.getTypeparams());
6597         mlir::Value newBase = access;
6598         if (fir::isa_char(eleTy)) {
6599           mlir::Value dstLen = fir::factory::genLenOfCharacter(
6600               builder, loc, load, iters.iterVec(), substringBounds);
6601           if (!substringBounds.empty()) {
6602             fir::CharBoxValue charDst{access, dstLen};
6603             fir::factory::CharacterExprHelper helper{builder, loc};
6604             charDst = helper.createSubstring(charDst, substringBounds);
6605             newBase = charDst.getAddr();
6606           }
6607           return arrayLoadExtValue(builder, loc, load, iters.iterVec(), newBase,
6608                                    dstLen);
6609         }
6610         return arrayLoadExtValue(builder, loc, load, iters.iterVec(), newBase);
6611       }
6612       auto fetch = builder.create<fir::ArrayFetchOp>(
6613           loc, eleTy, load, iters.iterVec(), load.getTypeparams());
6614       return arrayLoadExtValue(builder, loc, load, iters.iterVec(), fetch);
6615     };
6616     return [=](IterSpace iters) mutable {
6617       auto newIters = pc(iters);
6618       return lambda(newIters);
6619     };
6620   }
6621 
6622   template <typename A>
6623   CC genImplicitArrayAccess(const A &x, ComponentPath &components) {
6624     components.reversePath.push_back(ImplicitSubscripts{});
6625     ExtValue exv = asScalarRef(x);
6626     lowerPath(exv, components);
6627     auto lambda = genarr(exv, components);
6628     return [=](IterSpace iters) { return lambda(components.pc(iters)); };
6629   }
6630   CC genImplicitArrayAccess(const Fortran::evaluate::NamedEntity &x,
6631                             ComponentPath &components) {
6632     if (x.IsSymbol())
6633       return genImplicitArrayAccess(getFirstSym(x), components);
6634     return genImplicitArrayAccess(x.GetComponent(), components);
6635   }
6636 
6637   template <typename A>
6638   CC genAsScalar(const A &x) {
6639     mlir::Location loc = getLoc();
6640     if (isProjectedCopyInCopyOut()) {
6641       return [=, &x, builder = &converter.getFirOpBuilder()](
6642                  IterSpace iters) -> ExtValue {
6643         ExtValue exv = asScalarRef(x);
6644         mlir::Value val = fir::getBase(exv);
6645         mlir::Type eleTy = fir::unwrapRefType(val.getType());
6646         if (isAdjustedArrayElementType(eleTy)) {
6647           if (fir::isa_char(eleTy)) {
6648             fir::factory::CharacterExprHelper{*builder, loc}.createAssign(
6649                 exv, iters.elementExv());
6650           } else if (fir::isa_derived(eleTy)) {
6651             TODO(loc, "assignment of derived type");
6652           } else {
6653             fir::emitFatalError(loc, "array type not expected in scalar");
6654           }
6655         } else {
6656           builder->create<fir::StoreOp>(loc, iters.getElement(), val);
6657         }
6658         return exv;
6659       };
6660     }
6661     return [=, &x](IterSpace) { return asScalar(x); };
6662   }
6663 
6664   CC genarr(const Fortran::semantics::Symbol &x, ComponentPath &components) {
6665     if (explicitSpaceIsActive()) {
6666       if (x.Rank() > 0)
6667         components.reversePath.push_back(ImplicitSubscripts{});
6668       if (fir::ArrayLoadOp load = explicitSpace->findBinding(&x))
6669         return applyPathToArrayLoad(load, components);
6670     } else {
6671       return genImplicitArrayAccess(x, components);
6672     }
6673     if (pathIsEmpty(components))
6674       return genAsScalar(x);
6675     mlir::Location loc = getLoc();
6676     return [=](IterSpace) -> ExtValue {
6677       fir::emitFatalError(loc, "reached symbol with path");
6678     };
6679   }
6680 
6681   /// Lower a component path with or without rank.
6682   /// Example: <code>array%baz%qux%waldo</code>
6683   CC genarr(const Fortran::evaluate::Component &x, ComponentPath &components) {
6684     if (explicitSpaceIsActive()) {
6685       if (x.base().Rank() == 0 && x.Rank() > 0)
6686         components.reversePath.push_back(ImplicitSubscripts{});
6687       if (fir::ArrayLoadOp load = explicitSpace->findBinding(&x))
6688         return applyPathToArrayLoad(load, components);
6689     } else {
6690       if (x.base().Rank() == 0)
6691         return genImplicitArrayAccess(x, components);
6692     }
6693     bool atEnd = pathIsEmpty(components);
6694     if (!getLastSym(x).test(Fortran::semantics::Symbol::Flag::ParentComp))
6695       // Skip parent components; their components are placed directly in the
6696       // object.
6697       components.reversePath.push_back(&x);
6698     auto result = genarr(x.base(), components);
6699     if (components.applied)
6700       return result;
6701     if (atEnd)
6702       return genAsScalar(x);
6703     mlir::Location loc = getLoc();
6704     return [=](IterSpace) -> ExtValue {
6705       fir::emitFatalError(loc, "reached component with path");
6706     };
6707   }
6708 
6709   /// Array reference with subscripts. If this has rank > 0, this is a form
6710   /// of an array section (slice).
6711   ///
6712   /// There are two "slicing" primitives that may be applied on a dimension by
6713   /// dimension basis: (1) triple notation and (2) vector addressing. Since
6714   /// dimensions can be selectively sliced, some dimensions may contain
6715   /// regular scalar expressions and those dimensions do not participate in
6716   /// the array expression evaluation.
6717   CC genarr(const Fortran::evaluate::ArrayRef &x, ComponentPath &components) {
6718     if (explicitSpaceIsActive()) {
6719       if (Fortran::lower::isRankedArrayAccess(x))
6720         components.reversePath.push_back(ImplicitSubscripts{});
6721       if (fir::ArrayLoadOp load = explicitSpace->findBinding(&x)) {
6722         components.reversePath.push_back(&x);
6723         return applyPathToArrayLoad(load, components);
6724       }
6725     } else {
6726       if (Fortran::lower::isRankedArrayAccess(x)) {
6727         components.reversePath.push_back(&x);
6728         return genImplicitArrayAccess(x.base(), components);
6729       }
6730     }
6731     bool atEnd = pathIsEmpty(components);
6732     components.reversePath.push_back(&x);
6733     auto result = genarr(x.base(), components);
6734     if (components.applied)
6735       return result;
6736     mlir::Location loc = getLoc();
6737     if (atEnd) {
6738       if (x.Rank() == 0)
6739         return genAsScalar(x);
6740       fir::emitFatalError(loc, "expected scalar");
6741     }
6742     return [=](IterSpace) -> ExtValue {
6743       fir::emitFatalError(loc, "reached arrayref with path");
6744     };
6745   }
6746 
6747   CC genarr(const Fortran::evaluate::CoarrayRef &x, ComponentPath &components) {
6748     TODO(getLoc(), "coarray reference");
6749   }
6750 
6751   CC genarr(const Fortran::evaluate::NamedEntity &x,
6752             ComponentPath &components) {
6753     return x.IsSymbol() ? genarr(getFirstSym(x), components)
6754                         : genarr(x.GetComponent(), components);
6755   }
6756 
6757   CC genarr(const Fortran::evaluate::DataRef &x, ComponentPath &components) {
6758     return std::visit([&](const auto &v) { return genarr(v, components); },
6759                       x.u);
6760   }
6761 
6762   bool pathIsEmpty(const ComponentPath &components) {
6763     return components.reversePath.empty();
6764   }
6765 
6766   explicit ArrayExprLowering(Fortran::lower::AbstractConverter &converter,
6767                              Fortran::lower::StatementContext &stmtCtx,
6768                              Fortran::lower::SymMap &symMap)
6769       : converter{converter}, builder{converter.getFirOpBuilder()},
6770         stmtCtx{stmtCtx}, symMap{symMap} {}
6771 
6772   explicit ArrayExprLowering(Fortran::lower::AbstractConverter &converter,
6773                              Fortran::lower::StatementContext &stmtCtx,
6774                              Fortran::lower::SymMap &symMap,
6775                              ConstituentSemantics sem)
6776       : converter{converter}, builder{converter.getFirOpBuilder()},
6777         stmtCtx{stmtCtx}, symMap{symMap}, semant{sem} {}
6778 
6779   explicit ArrayExprLowering(Fortran::lower::AbstractConverter &converter,
6780                              Fortran::lower::StatementContext &stmtCtx,
6781                              Fortran::lower::SymMap &symMap,
6782                              ConstituentSemantics sem,
6783                              Fortran::lower::ExplicitIterSpace *expSpace,
6784                              Fortran::lower::ImplicitIterSpace *impSpace)
6785       : converter{converter}, builder{converter.getFirOpBuilder()},
6786         stmtCtx{stmtCtx}, symMap{symMap},
6787         explicitSpace(expSpace->isActive() ? expSpace : nullptr),
6788         implicitSpace(impSpace->empty() ? nullptr : impSpace), semant{sem} {
6789     // Generate any mask expressions, as necessary. This is the compute step
6790     // that creates the effective masks. See 10.2.3.2 in particular.
6791     genMasks();
6792   }
6793 
6794   mlir::Location getLoc() { return converter.getCurrentLocation(); }
6795 
6796   /// Array appears in a lhs context such that it is assigned after the rhs is
6797   /// fully evaluated.
6798   inline bool isCopyInCopyOut() {
6799     return semant == ConstituentSemantics::CopyInCopyOut;
6800   }
6801 
6802   /// Array appears in a lhs (or temp) context such that a projected,
6803   /// discontiguous subspace of the array is assigned after the rhs is fully
6804   /// evaluated. That is, the rhs array value is merged into a section of the
6805   /// lhs array.
6806   inline bool isProjectedCopyInCopyOut() {
6807     return semant == ConstituentSemantics::ProjectedCopyInCopyOut;
6808   }
6809 
6810   // ???: Do we still need this?
6811   inline bool isCustomCopyInCopyOut() {
6812     return semant == ConstituentSemantics::CustomCopyInCopyOut;
6813   }
6814 
6815   /// Array appears in a context where it must be boxed.
6816   inline bool isBoxValue() { return semant == ConstituentSemantics::BoxValue; }
6817 
6818   /// Array appears in a context where differences in the memory reference can
6819   /// be observable in the computational results. For example, an array
6820   /// element is passed to an impure procedure.
6821   inline bool isReferentiallyOpaque() {
6822     return semant == ConstituentSemantics::RefOpaque;
6823   }
6824 
6825   /// Array appears in a context where it is passed as a VALUE argument.
6826   inline bool isValueAttribute() {
6827     return semant == ConstituentSemantics::ByValueArg;
6828   }
6829 
6830   /// Can the loops over the expression be unordered?
6831   inline bool isUnordered() const { return unordered; }
6832 
6833   void setUnordered(bool b) { unordered = b; }
6834 
6835   Fortran::lower::AbstractConverter &converter;
6836   fir::FirOpBuilder &builder;
6837   Fortran::lower::StatementContext &stmtCtx;
6838   bool elementCtx = false;
6839   Fortran::lower::SymMap &symMap;
6840   /// The continuation to generate code to update the destination.
6841   llvm::Optional<CC> ccStoreToDest;
6842   llvm::Optional<std::function<void(llvm::ArrayRef<mlir::Value>)>> ccPrelude;
6843   llvm::Optional<std::function<fir::ArrayLoadOp(llvm::ArrayRef<mlir::Value>)>>
6844       ccLoadDest;
6845   /// The destination is the loaded array into which the results will be
6846   /// merged.
6847   fir::ArrayLoadOp destination;
6848   /// The shape of the destination.
6849   llvm::SmallVector<mlir::Value> destShape;
6850   /// List of arrays in the expression that have been loaded.
6851   llvm::SmallVector<ArrayOperand> arrayOperands;
6852   /// If there is a user-defined iteration space, explicitShape will hold the
6853   /// information from the front end.
6854   Fortran::lower::ExplicitIterSpace *explicitSpace = nullptr;
6855   Fortran::lower::ImplicitIterSpace *implicitSpace = nullptr;
6856   ConstituentSemantics semant = ConstituentSemantics::RefTransparent;
6857   // Can the array expression be evaluated in any order?
6858   // Will be set to false if any of the expression parts prevent this.
6859   bool unordered = true;
6860 };
6861 } // namespace
6862 
6863 fir::ExtendedValue Fortran::lower::createSomeExtendedExpression(
6864     mlir::Location loc, Fortran::lower::AbstractConverter &converter,
6865     const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap,
6866     Fortran::lower::StatementContext &stmtCtx) {
6867   LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "expr: ") << '\n');
6868   return ScalarExprLowering{loc, converter, symMap, stmtCtx}.genval(expr);
6869 }
6870 
6871 fir::GlobalOp Fortran::lower::createDenseGlobal(
6872     mlir::Location loc, mlir::Type symTy, llvm::StringRef globalName,
6873     mlir::StringAttr linkage, bool isConst,
6874     const Fortran::lower::SomeExpr &expr,
6875     Fortran::lower::AbstractConverter &converter) {
6876 
6877   Fortran::lower::StatementContext stmtCtx(/*prohibited=*/true);
6878   Fortran::lower::SymMap emptyMap;
6879   InitializerData initData(/*genRawVals=*/true);
6880   ScalarExprLowering sel(loc, converter, emptyMap, stmtCtx,
6881                          /*initializer=*/&initData);
6882   sel.genval(expr);
6883 
6884   size_t sz = initData.rawVals.size();
6885   llvm::ArrayRef<mlir::Attribute> ar = {initData.rawVals.data(), sz};
6886 
6887   mlir::RankedTensorType tensorTy;
6888   auto &builder = converter.getFirOpBuilder();
6889   mlir::Type iTy = initData.rawType;
6890   if (!iTy)
6891     return 0; // array extent is probably 0 in this case, so just return 0.
6892   tensorTy = mlir::RankedTensorType::get(sz, iTy);
6893   auto init = mlir::DenseElementsAttr::get(tensorTy, ar);
6894   return builder.createGlobal(loc, symTy, globalName, linkage, init, isConst);
6895 }
6896 
6897 fir::ExtendedValue Fortran::lower::createSomeInitializerExpression(
6898     mlir::Location loc, Fortran::lower::AbstractConverter &converter,
6899     const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap,
6900     Fortran::lower::StatementContext &stmtCtx) {
6901   LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "expr: ") << '\n');
6902   InitializerData initData; // needed for initializations
6903   return ScalarExprLowering{loc, converter, symMap, stmtCtx,
6904                             /*initializer=*/&initData}
6905       .genval(expr);
6906 }
6907 
6908 fir::ExtendedValue Fortran::lower::createSomeExtendedAddress(
6909     mlir::Location loc, Fortran::lower::AbstractConverter &converter,
6910     const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap,
6911     Fortran::lower::StatementContext &stmtCtx) {
6912   LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "address: ") << '\n');
6913   return ScalarExprLowering(loc, converter, symMap, stmtCtx).gen(expr);
6914 }
6915 
6916 fir::ExtendedValue Fortran::lower::createInitializerAddress(
6917     mlir::Location loc, Fortran::lower::AbstractConverter &converter,
6918     const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap,
6919     Fortran::lower::StatementContext &stmtCtx) {
6920   LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "address: ") << '\n');
6921   InitializerData init;
6922   return ScalarExprLowering(loc, converter, symMap, stmtCtx, &init).gen(expr);
6923 }
6924 
6925 void Fortran::lower::createSomeArrayAssignment(
6926     Fortran::lower::AbstractConverter &converter,
6927     const Fortran::lower::SomeExpr &lhs, const Fortran::lower::SomeExpr &rhs,
6928     Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx) {
6929   LLVM_DEBUG(lhs.AsFortran(llvm::dbgs() << "onto array: ") << '\n';
6930              rhs.AsFortran(llvm::dbgs() << "assign expression: ") << '\n';);
6931   ArrayExprLowering::lowerArrayAssignment(converter, symMap, stmtCtx, lhs, rhs);
6932 }
6933 
6934 void Fortran::lower::createSomeArrayAssignment(
6935     Fortran::lower::AbstractConverter &converter, const fir::ExtendedValue &lhs,
6936     const Fortran::lower::SomeExpr &rhs, Fortran::lower::SymMap &symMap,
6937     Fortran::lower::StatementContext &stmtCtx) {
6938   LLVM_DEBUG(llvm::dbgs() << "onto array: " << lhs << '\n';
6939              rhs.AsFortran(llvm::dbgs() << "assign expression: ") << '\n';);
6940   ArrayExprLowering::lowerArrayAssignment(converter, symMap, stmtCtx, lhs, rhs);
6941 }
6942 void Fortran::lower::createSomeArrayAssignment(
6943     Fortran::lower::AbstractConverter &converter, const fir::ExtendedValue &lhs,
6944     const fir::ExtendedValue &rhs, Fortran::lower::SymMap &symMap,
6945     Fortran::lower::StatementContext &stmtCtx) {
6946   LLVM_DEBUG(llvm::dbgs() << "onto array: " << lhs << '\n';
6947              llvm::dbgs() << "assign expression: " << rhs << '\n';);
6948   ArrayExprLowering::lowerArrayAssignment(converter, symMap, stmtCtx, lhs, rhs);
6949 }
6950 
6951 void Fortran::lower::createAnyMaskedArrayAssignment(
6952     Fortran::lower::AbstractConverter &converter,
6953     const Fortran::lower::SomeExpr &lhs, const Fortran::lower::SomeExpr &rhs,
6954     Fortran::lower::ExplicitIterSpace &explicitSpace,
6955     Fortran::lower::ImplicitIterSpace &implicitSpace,
6956     Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx) {
6957   LLVM_DEBUG(lhs.AsFortran(llvm::dbgs() << "onto array: ") << '\n';
6958              rhs.AsFortran(llvm::dbgs() << "assign expression: ")
6959              << " given the explicit iteration space:\n"
6960              << explicitSpace << "\n and implied mask conditions:\n"
6961              << implicitSpace << '\n';);
6962   ArrayExprLowering::lowerAnyMaskedArrayAssignment(
6963       converter, symMap, stmtCtx, lhs, rhs, explicitSpace, implicitSpace);
6964 }
6965 
6966 void Fortran::lower::createAllocatableArrayAssignment(
6967     Fortran::lower::AbstractConverter &converter,
6968     const Fortran::lower::SomeExpr &lhs, const Fortran::lower::SomeExpr &rhs,
6969     Fortran::lower::ExplicitIterSpace &explicitSpace,
6970     Fortran::lower::ImplicitIterSpace &implicitSpace,
6971     Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx) {
6972   LLVM_DEBUG(lhs.AsFortran(llvm::dbgs() << "defining array: ") << '\n';
6973              rhs.AsFortran(llvm::dbgs() << "assign expression: ")
6974              << " given the explicit iteration space:\n"
6975              << explicitSpace << "\n and implied mask conditions:\n"
6976              << implicitSpace << '\n';);
6977   ArrayExprLowering::lowerAllocatableArrayAssignment(
6978       converter, symMap, stmtCtx, lhs, rhs, explicitSpace, implicitSpace);
6979 }
6980 
6981 fir::ExtendedValue Fortran::lower::createSomeArrayTempValue(
6982     Fortran::lower::AbstractConverter &converter,
6983     const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap,
6984     Fortran::lower::StatementContext &stmtCtx) {
6985   LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "array value: ") << '\n');
6986   return ArrayExprLowering::lowerNewArrayExpression(converter, symMap, stmtCtx,
6987                                                     expr);
6988 }
6989 
6990 void Fortran::lower::createLazyArrayTempValue(
6991     Fortran::lower::AbstractConverter &converter,
6992     const Fortran::lower::SomeExpr &expr, mlir::Value raggedHeader,
6993     Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx) {
6994   LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "array value: ") << '\n');
6995   ArrayExprLowering::lowerLazyArrayExpression(converter, symMap, stmtCtx, expr,
6996                                               raggedHeader);
6997 }
6998 
6999 fir::ExtendedValue
7000 Fortran::lower::createSomeArrayBox(Fortran::lower::AbstractConverter &converter,
7001                                    const Fortran::lower::SomeExpr &expr,
7002                                    Fortran::lower::SymMap &symMap,
7003                                    Fortran::lower::StatementContext &stmtCtx) {
7004   LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "box designator: ") << '\n');
7005   return ArrayExprLowering::lowerBoxedArrayExpression(converter, symMap,
7006                                                       stmtCtx, expr);
7007 }
7008 
7009 fir::MutableBoxValue Fortran::lower::createMutableBox(
7010     mlir::Location loc, Fortran::lower::AbstractConverter &converter,
7011     const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap) {
7012   // MutableBox lowering StatementContext does not need to be propagated
7013   // to the caller because the result value is a variable, not a temporary
7014   // expression. The StatementContext clean-up can occur before using the
7015   // resulting MutableBoxValue. Variables of all other types are handled in the
7016   // bridge.
7017   Fortran::lower::StatementContext dummyStmtCtx;
7018   return ScalarExprLowering{loc, converter, symMap, dummyStmtCtx}
7019       .genMutableBoxValue(expr);
7020 }
7021 
7022 fir::ExtendedValue Fortran::lower::createBoxValue(
7023     mlir::Location loc, Fortran::lower::AbstractConverter &converter,
7024     const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap,
7025     Fortran::lower::StatementContext &stmtCtx) {
7026   if (expr.Rank() > 0 && Fortran::evaluate::IsVariable(expr) &&
7027       !Fortran::evaluate::HasVectorSubscript(expr))
7028     return Fortran::lower::createSomeArrayBox(converter, expr, symMap, stmtCtx);
7029   fir::ExtendedValue addr = Fortran::lower::createSomeExtendedAddress(
7030       loc, converter, expr, symMap, stmtCtx);
7031   return fir::BoxValue(converter.getFirOpBuilder().createBox(loc, addr));
7032 }
7033 
7034 mlir::Value Fortran::lower::createSubroutineCall(
7035     AbstractConverter &converter, const evaluate::ProcedureRef &call,
7036     ExplicitIterSpace &explicitIterSpace, ImplicitIterSpace &implicitIterSpace,
7037     SymMap &symMap, StatementContext &stmtCtx, bool isUserDefAssignment) {
7038   mlir::Location loc = converter.getCurrentLocation();
7039 
7040   if (isUserDefAssignment) {
7041     assert(call.arguments().size() == 2);
7042     const auto *lhs = call.arguments()[0].value().UnwrapExpr();
7043     const auto *rhs = call.arguments()[1].value().UnwrapExpr();
7044     assert(lhs && rhs &&
7045            "user defined assignment arguments must be expressions");
7046     if (call.IsElemental() && lhs->Rank() > 0) {
7047       // Elemental user defined assignment has special requirements to deal with
7048       // LHS/RHS overlaps. See 10.2.1.5 p2.
7049       ArrayExprLowering::lowerElementalUserAssignment(
7050           converter, symMap, stmtCtx, explicitIterSpace, implicitIterSpace,
7051           call);
7052     } else if (explicitIterSpace.isActive() && lhs->Rank() == 0) {
7053       // Scalar defined assignment (elemental or not) in a FORALL context.
7054       mlir::FuncOp func =
7055           Fortran::lower::CallerInterface(call, converter).getFuncOp();
7056       ArrayExprLowering::lowerScalarUserAssignment(
7057           converter, symMap, stmtCtx, explicitIterSpace, func, *lhs, *rhs);
7058     } else if (explicitIterSpace.isActive()) {
7059       // TODO: need to array fetch/modify sub-arrays?
7060       TODO(loc, "non elemental user defined array assignment inside FORALL");
7061     } else {
7062       if (!implicitIterSpace.empty())
7063         fir::emitFatalError(
7064             loc,
7065             "C1032: user defined assignment inside WHERE must be elemental");
7066       // Non elemental user defined assignment outside of FORALL and WHERE.
7067       // FIXME: The non elemental user defined assignment case with array
7068       // arguments must be take into account potential overlap. So far the front
7069       // end does not add parentheses around the RHS argument in the call as it
7070       // should according to 15.4.3.4.3 p2.
7071       Fortran::lower::createSomeExtendedExpression(
7072           loc, converter, toEvExpr(call), symMap, stmtCtx);
7073     }
7074     return {};
7075   }
7076 
7077   assert(implicitIterSpace.empty() && !explicitIterSpace.isActive() &&
7078          "subroutine calls are not allowed inside WHERE and FORALL");
7079 
7080   if (isElementalProcWithArrayArgs(call)) {
7081     ArrayExprLowering::lowerElementalSubroutine(converter, symMap, stmtCtx,
7082                                                 toEvExpr(call));
7083     return {};
7084   }
7085   // Simple subroutine call, with potential alternate return.
7086   auto res = Fortran::lower::createSomeExtendedExpression(
7087       loc, converter, toEvExpr(call), symMap, stmtCtx);
7088   return fir::getBase(res);
7089 }
7090 
7091 template <typename A>
7092 fir::ArrayLoadOp genArrayLoad(mlir::Location loc,
7093                               Fortran::lower::AbstractConverter &converter,
7094                               fir::FirOpBuilder &builder, const A *x,
7095                               Fortran::lower::SymMap &symMap,
7096                               Fortran::lower::StatementContext &stmtCtx) {
7097   auto exv = ScalarExprLowering{loc, converter, symMap, stmtCtx}.gen(*x);
7098   mlir::Value addr = fir::getBase(exv);
7099   mlir::Value shapeOp = builder.createShape(loc, exv);
7100   mlir::Type arrTy = fir::dyn_cast_ptrOrBoxEleTy(addr.getType());
7101   return builder.create<fir::ArrayLoadOp>(loc, arrTy, addr, shapeOp,
7102                                           /*slice=*/mlir::Value{},
7103                                           fir::getTypeParams(exv));
7104 }
7105 template <>
7106 fir::ArrayLoadOp
7107 genArrayLoad(mlir::Location loc, Fortran::lower::AbstractConverter &converter,
7108              fir::FirOpBuilder &builder, const Fortran::evaluate::ArrayRef *x,
7109              Fortran::lower::SymMap &symMap,
7110              Fortran::lower::StatementContext &stmtCtx) {
7111   if (x->base().IsSymbol())
7112     return genArrayLoad(loc, converter, builder, &getLastSym(x->base()), symMap,
7113                         stmtCtx);
7114   return genArrayLoad(loc, converter, builder, &x->base().GetComponent(),
7115                       symMap, stmtCtx);
7116 }
7117 
7118 void Fortran::lower::createArrayLoads(
7119     Fortran::lower::AbstractConverter &converter,
7120     Fortran::lower::ExplicitIterSpace &esp, Fortran::lower::SymMap &symMap) {
7121   std::size_t counter = esp.getCounter();
7122   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
7123   mlir::Location loc = converter.getCurrentLocation();
7124   Fortran::lower::StatementContext &stmtCtx = esp.stmtContext();
7125   // Gen the fir.array_load ops.
7126   auto genLoad = [&](const auto *x) -> fir::ArrayLoadOp {
7127     return genArrayLoad(loc, converter, builder, x, symMap, stmtCtx);
7128   };
7129   if (esp.lhsBases[counter].hasValue()) {
7130     auto &base = esp.lhsBases[counter].getValue();
7131     auto load = std::visit(genLoad, base);
7132     esp.initialArgs.push_back(load);
7133     esp.resetInnerArgs();
7134     esp.bindLoad(base, load);
7135   }
7136   for (const auto &base : esp.rhsBases[counter])
7137     esp.bindLoad(base, std::visit(genLoad, base));
7138 }
7139 
7140 void Fortran::lower::createArrayMergeStores(
7141     Fortran::lower::AbstractConverter &converter,
7142     Fortran::lower::ExplicitIterSpace &esp) {
7143   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
7144   mlir::Location loc = converter.getCurrentLocation();
7145   builder.setInsertionPointAfter(esp.getOuterLoop());
7146   // Gen the fir.array_merge_store ops for all LHS arrays.
7147   for (auto i : llvm::enumerate(esp.getOuterLoop().getResults()))
7148     if (llvm::Optional<fir::ArrayLoadOp> ldOpt = esp.getLhsLoad(i.index())) {
7149       fir::ArrayLoadOp load = ldOpt.getValue();
7150       builder.create<fir::ArrayMergeStoreOp>(loc, load, i.value(),
7151                                              load.getMemref(), load.getSlice(),
7152                                              load.getTypeparams());
7153     }
7154   if (esp.loopCleanup.hasValue()) {
7155     esp.loopCleanup.getValue()(builder);
7156     esp.loopCleanup = llvm::None;
7157   }
7158   esp.initialArgs.clear();
7159   esp.innerArgs.clear();
7160   esp.outerLoop = llvm::None;
7161   esp.resetBindings();
7162   esp.incrementCounter();
7163 }
7164 
7165 mlir::Value Fortran::lower::genMaxWithZero(fir::FirOpBuilder &builder,
7166                                            mlir::Location loc,
7167                                            mlir::Value value) {
7168   mlir::Value zero = builder.createIntegerConstant(loc, value.getType(), 0);
7169   if (mlir::Operation *definingOp = value.getDefiningOp())
7170     if (auto cst = mlir::dyn_cast<mlir::arith::ConstantOp>(definingOp))
7171       if (auto intAttr = cst.getValue().dyn_cast<mlir::IntegerAttr>())
7172         return intAttr.getInt() < 0 ? zero : value;
7173   return Fortran::lower::genMax(builder, loc,
7174                                 llvm::SmallVector<mlir::Value>{value, zero});
7175 }
7176