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