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