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