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