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