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