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/Evaluate/fold.h"
15 #include "flang/Evaluate/traverse.h"
16 #include "flang/Lower/AbstractConverter.h"
17 #include "flang/Lower/CallInterface.h"
18 #include "flang/Lower/ComponentPath.h"
19 #include "flang/Lower/ConvertType.h"
20 #include "flang/Lower/ConvertVariable.h"
21 #include "flang/Lower/CustomIntrinsicCall.h"
22 #include "flang/Lower/DumpEvaluateExpr.h"
23 #include "flang/Lower/IntrinsicCall.h"
24 #include "flang/Lower/Mangler.h"
25 #include "flang/Lower/StatementContext.h"
26 #include "flang/Lower/SymbolMap.h"
27 #include "flang/Lower/Todo.h"
28 #include "flang/Optimizer/Builder/Character.h"
29 #include "flang/Optimizer/Builder/Complex.h"
30 #include "flang/Optimizer/Builder/Factory.h"
31 #include "flang/Optimizer/Builder/LowLevelIntrinsics.h"
32 #include "flang/Optimizer/Builder/MutableBox.h"
33 #include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
34 #include "flang/Optimizer/Dialect/FIROpsSupport.h"
35 #include "flang/Semantics/expression.h"
36 #include "flang/Semantics/symbol.h"
37 #include "flang/Semantics/tools.h"
38 #include "flang/Semantics/type.h"
39 #include "mlir/Dialect/Func/IR/FuncOps.h"
40 #include "llvm/Support/CommandLine.h"
41 #include "llvm/Support/Debug.h"
42 
43 #define DEBUG_TYPE "flang-lower-expr"
44 
45 //===----------------------------------------------------------------------===//
46 // The composition and structure of Fortran::evaluate::Expr is defined in
47 // the various header files in include/flang/Evaluate. You are referred
48 // there for more information on these data structures. Generally speaking,
49 // these data structures are a strongly typed family of abstract data types
50 // that, composed as trees, describe the syntax of Fortran expressions.
51 //
52 // This part of the bridge can traverse these tree structures and lower them
53 // to the correct FIR representation in SSA form.
54 //===----------------------------------------------------------------------===//
55 
56 // The default attempts to balance a modest allocation size with expected user
57 // input to minimize bounds checks and reallocations during dynamic array
58 // construction. Some user codes may have very large array constructors for
59 // which the default can be increased.
60 static llvm::cl::opt<unsigned> clInitialBufferSize(
61     "array-constructor-initial-buffer-size",
62     llvm::cl::desc(
63         "set the incremental array construction buffer size (default=32)"),
64     llvm::cl::init(32u));
65 
66 /// The various semantics of a program constituent (or a part thereof) as it may
67 /// appear in an expression.
68 ///
69 /// Given the following Fortran declarations.
70 /// ```fortran
71 ///   REAL :: v1, v2, v3
72 ///   REAL, POINTER :: vp1
73 ///   REAL :: a1(c), a2(c)
74 ///   REAL ELEMENTAL FUNCTION f1(arg) ! array -> array
75 ///   FUNCTION f2(arg)                ! array -> array
76 ///   vp1 => v3       ! 1
77 ///   v1 = v2 * vp1   ! 2
78 ///   a1 = a1 + a2    ! 3
79 ///   a1 = f1(a2)     ! 4
80 ///   a1 = f2(a2)     ! 5
81 /// ```
82 ///
83 /// In line 1, `vp1` is a BoxAddr to copy a box value into. The box value is
84 /// constructed from the DataAddr of `v3`.
85 /// In line 2, `v1` is a DataAddr to copy a value into. The value is constructed
86 /// from the DataValue of `v2` and `vp1`. DataValue is implicitly a double
87 /// dereference in the `vp1` case.
88 /// In line 3, `a1` and `a2` on the rhs are RefTransparent. The `a1` on the lhs
89 /// is CopyInCopyOut as `a1` is replaced elementally by the additions.
90 /// In line 4, `a2` can be RefTransparent, ByValueArg, RefOpaque, or BoxAddr if
91 /// `arg` is declared as C-like pass-by-value, VALUE, INTENT(?), or ALLOCATABLE/
92 /// POINTER, respectively. `a1` on the lhs is CopyInCopyOut.
93 ///  In line 5, `a2` may be DataAddr or BoxAddr assuming f2 is transformational.
94 ///  `a1` on the lhs is again CopyInCopyOut.
95 enum class ConstituentSemantics {
96   // Scalar data reference semantics.
97   //
98   // For these let `v` be the location in memory of a variable with value `x`
99   DataValue, // refers to the value `x`
100   DataAddr,  // refers to the address `v`
101   BoxValue,  // refers to a box value containing `v`
102   BoxAddr,   // refers to the address of a box value containing `v`
103 
104   // Array data reference semantics.
105   //
106   // For these let `a` be the location in memory of a sequence of value `[xs]`.
107   // Let `x_i` be the `i`-th value in the sequence `[xs]`.
108 
109   // Referentially transparent. Refers to the array's value, `[xs]`.
110   RefTransparent,
111   // Refers to an ephemeral address `tmp` containing value `x_i` (15.5.2.3.p7
112   // note 2). (Passing a copy by reference to simulate pass-by-value.)
113   ByValueArg,
114   // Refers to the merge of array value `[xs]` with another array value `[ys]`.
115   // This merged array value will be written into memory location `a`.
116   CopyInCopyOut,
117   // Similar to CopyInCopyOut but `a` may be a transient projection (rather than
118   // a whole array).
119   ProjectedCopyInCopyOut,
120   // Similar to ProjectedCopyInCopyOut, except the merge value is not assigned
121   // automatically by the framework. Instead, and address for `[xs]` is made
122   // accessible so that custom assignments to `[xs]` can be implemented.
123   CustomCopyInCopyOut,
124   // Referentially opaque. Refers to the address of `x_i`.
125   RefOpaque
126 };
127 
128 /// Convert parser's INTEGER relational operators to MLIR.  TODO: using
129 /// unordered, but we may want to cons ordered in certain situation.
130 static mlir::arith::CmpIPredicate
131 translateRelational(Fortran::common::RelationalOperator rop) {
132   switch (rop) {
133   case Fortran::common::RelationalOperator::LT:
134     return mlir::arith::CmpIPredicate::slt;
135   case Fortran::common::RelationalOperator::LE:
136     return mlir::arith::CmpIPredicate::sle;
137   case Fortran::common::RelationalOperator::EQ:
138     return mlir::arith::CmpIPredicate::eq;
139   case Fortran::common::RelationalOperator::NE:
140     return mlir::arith::CmpIPredicate::ne;
141   case Fortran::common::RelationalOperator::GT:
142     return mlir::arith::CmpIPredicate::sgt;
143   case Fortran::common::RelationalOperator::GE:
144     return mlir::arith::CmpIPredicate::sge;
145   }
146   llvm_unreachable("unhandled INTEGER relational operator");
147 }
148 
149 /// Convert parser's REAL relational operators to MLIR.
150 /// The choice of order (O prefix) vs unorder (U prefix) follows Fortran 2018
151 /// requirements in the IEEE context (table 17.1 of F2018). This choice is
152 /// also applied in other contexts because it is easier and in line with
153 /// other Fortran compilers.
154 /// FIXME: The signaling/quiet aspect of the table 17.1 requirement is not
155 /// fully enforced. FIR and LLVM `fcmp` instructions do not give any guarantee
156 /// whether the comparison will signal or not in case of quiet NaN argument.
157 static mlir::arith::CmpFPredicate
158 translateFloatRelational(Fortran::common::RelationalOperator rop) {
159   switch (rop) {
160   case Fortran::common::RelationalOperator::LT:
161     return mlir::arith::CmpFPredicate::OLT;
162   case Fortran::common::RelationalOperator::LE:
163     return mlir::arith::CmpFPredicate::OLE;
164   case Fortran::common::RelationalOperator::EQ:
165     return mlir::arith::CmpFPredicate::OEQ;
166   case Fortran::common::RelationalOperator::NE:
167     return mlir::arith::CmpFPredicate::UNE;
168   case Fortran::common::RelationalOperator::GT:
169     return mlir::arith::CmpFPredicate::OGT;
170   case Fortran::common::RelationalOperator::GE:
171     return mlir::arith::CmpFPredicate::OGE;
172   }
173   llvm_unreachable("unhandled REAL relational operator");
174 }
175 
176 static mlir::Value genActualIsPresentTest(fir::FirOpBuilder &builder,
177                                           mlir::Location loc,
178                                           fir::ExtendedValue actual) {
179   if (const auto *ptrOrAlloc = actual.getBoxOf<fir::MutableBoxValue>())
180     return fir::factory::genIsAllocatedOrAssociatedTest(builder, loc,
181                                                         *ptrOrAlloc);
182   // Optional case (not that optional allocatable/pointer cannot be absent
183   // when passed to CMPLX as per 15.5.2.12 point 3 (7) and (8)). It is
184   // therefore possible to catch them in the `then` case above.
185   return builder.create<fir::IsPresentOp>(loc, builder.getI1Type(),
186                                           fir::getBase(actual));
187 }
188 
189 /// Place \p exv in memory if it is not already a memory reference. If
190 /// \p forceValueType is provided, the value is first casted to the provided
191 /// type before being stored (this is mainly intended for logicals whose value
192 /// may be `i1` but needed to be stored as Fortran logicals).
193 static fir::ExtendedValue
194 placeScalarValueInMemory(fir::FirOpBuilder &builder, mlir::Location loc,
195                          const fir::ExtendedValue &exv,
196                          mlir::Type storageType) {
197   mlir::Value valBase = fir::getBase(exv);
198   if (fir::conformsWithPassByRef(valBase.getType()))
199     return exv;
200 
201   assert(!fir::hasDynamicSize(storageType) &&
202          "only expect statically sized scalars to be by value");
203 
204   // Since `a` is not itself a valid referent, determine its value and
205   // create a temporary location at the beginning of the function for
206   // referencing.
207   mlir::Value val = builder.createConvert(loc, storageType, valBase);
208   mlir::Value temp = builder.createTemporary(
209       loc, storageType,
210       llvm::ArrayRef<mlir::NamedAttribute>{
211           Fortran::lower::getAdaptToByRefAttr(builder)});
212   builder.create<fir::StoreOp>(loc, val, temp);
213   return fir::substBase(exv, temp);
214 }
215 
216 // Copy a copy of scalar \p exv in a new temporary.
217 static fir::ExtendedValue
218 createInMemoryScalarCopy(fir::FirOpBuilder &builder, mlir::Location loc,
219                          const fir::ExtendedValue &exv) {
220   assert(exv.rank() == 0 && "input to scalar memory copy must be a scalar");
221   if (exv.getCharBox() != nullptr)
222     return fir::factory::CharacterExprHelper{builder, loc}.createTempFrom(exv);
223   if (fir::isDerivedWithLengthParameters(exv))
224     TODO(loc, "copy derived type with length parameters");
225   mlir::Type type = fir::unwrapPassByRefType(fir::getBase(exv).getType());
226   fir::ExtendedValue temp = builder.createTemporary(loc, type);
227   fir::factory::genScalarAssignment(builder, loc, temp, exv);
228   return temp;
229 }
230 
231 /// Is this a variable wrapped in parentheses?
232 template <typename A>
233 static bool isParenthesizedVariable(const A &) {
234   return false;
235 }
236 template <typename T>
237 static bool isParenthesizedVariable(const Fortran::evaluate::Expr<T> &expr) {
238   using ExprVariant = decltype(Fortran::evaluate::Expr<T>::u);
239   using Parentheses = Fortran::evaluate::Parentheses<T>;
240   if constexpr (Fortran::common::HasMember<Parentheses, ExprVariant>) {
241     if (const auto *parentheses = std::get_if<Parentheses>(&expr.u))
242       return Fortran::evaluate::IsVariable(parentheses->left());
243     return false;
244   } else {
245     return std::visit([&](const auto &x) { return isParenthesizedVariable(x); },
246                       expr.u);
247   }
248 }
249 
250 /// Generate a load of a value from an address. Beware that this will lose
251 /// any dynamic type information for polymorphic entities (note that unlimited
252 /// polymorphic cannot be loaded and must not be provided here).
253 static fir::ExtendedValue genLoad(fir::FirOpBuilder &builder,
254                                   mlir::Location loc,
255                                   const fir::ExtendedValue &addr) {
256   return addr.match(
257       [](const fir::CharBoxValue &box) -> fir::ExtendedValue { return box; },
258       [&](const fir::UnboxedValue &v) -> fir::ExtendedValue {
259         if (fir::unwrapRefType(fir::getBase(v).getType())
260                 .isa<fir::RecordType>())
261           return v;
262         return builder.create<fir::LoadOp>(loc, fir::getBase(v));
263       },
264       [&](const fir::MutableBoxValue &box) -> fir::ExtendedValue {
265         TODO(loc, "genLoad for MutableBoxValue");
266       },
267       [&](const fir::BoxValue &box) -> fir::ExtendedValue {
268         TODO(loc, "genLoad for BoxValue");
269       },
270       [&](const auto &) -> fir::ExtendedValue {
271         fir::emitFatalError(
272             loc, "attempting to load whole array or procedure address");
273       });
274 }
275 
276 /// Create an optional dummy argument value from entity \p exv that may be
277 /// absent. This can only be called with numerical or logical scalar \p exv.
278 /// If \p exv is considered absent according to 15.5.2.12 point 1., the returned
279 /// value is zero (or false), otherwise it is the value of \p exv.
280 static fir::ExtendedValue genOptionalValue(fir::FirOpBuilder &builder,
281                                            mlir::Location loc,
282                                            const fir::ExtendedValue &exv,
283                                            mlir::Value isPresent) {
284   mlir::Type eleType = fir::getBaseTypeOf(exv);
285   assert(exv.rank() == 0 && fir::isa_trivial(eleType) &&
286          "must be a numerical or logical scalar");
287   return builder
288       .genIfOp(loc, {eleType}, isPresent,
289                /*withElseRegion=*/true)
290       .genThen([&]() {
291         mlir::Value val = fir::getBase(genLoad(builder, loc, exv));
292         builder.create<fir::ResultOp>(loc, val);
293       })
294       .genElse([&]() {
295         mlir::Value zero = fir::factory::createZeroValue(builder, loc, eleType);
296         builder.create<fir::ResultOp>(loc, zero);
297       })
298       .getResults()[0];
299 }
300 
301 /// Create an optional dummy argument address from entity \p exv that may be
302 /// absent. If \p exv is considered absent according to 15.5.2.12 point 1., the
303 /// returned value is a null pointer, otherwise it is the address of \p exv.
304 static fir::ExtendedValue genOptionalAddr(fir::FirOpBuilder &builder,
305                                           mlir::Location loc,
306                                           const fir::ExtendedValue &exv,
307                                           mlir::Value isPresent) {
308   // If it is an exv pointer/allocatable, then it cannot be absent
309   // because it is passed to a non-pointer/non-allocatable.
310   if (const auto *box = exv.getBoxOf<fir::MutableBoxValue>())
311     return fir::factory::genMutableBoxRead(builder, loc, *box);
312   // If this is not a POINTER or ALLOCATABLE, then it is already an OPTIONAL
313   // address and can be passed directly.
314   return exv;
315 }
316 
317 /// Create an optional dummy argument address from entity \p exv that may be
318 /// absent. If \p exv is considered absent according to 15.5.2.12 point 1., the
319 /// returned value is an absent fir.box, otherwise it is a fir.box describing \p
320 /// exv.
321 static fir::ExtendedValue genOptionalBox(fir::FirOpBuilder &builder,
322                                          mlir::Location loc,
323                                          const fir::ExtendedValue &exv,
324                                          mlir::Value isPresent) {
325   // Non allocatable/pointer optional box -> simply forward
326   if (exv.getBoxOf<fir::BoxValue>())
327     return exv;
328 
329   fir::ExtendedValue newExv = exv;
330   // Optional allocatable/pointer -> Cannot be absent, but need to translate
331   // unallocated/diassociated into absent fir.box.
332   if (const auto *box = exv.getBoxOf<fir::MutableBoxValue>())
333     newExv = fir::factory::genMutableBoxRead(builder, loc, *box);
334 
335   // createBox will not do create any invalid memory dereferences if exv is
336   // absent. The created fir.box will not be usable, but the SelectOp below
337   // ensures it won't be.
338   mlir::Value box = builder.createBox(loc, newExv);
339   mlir::Type boxType = box.getType();
340   auto absent = builder.create<fir::AbsentOp>(loc, boxType);
341   auto boxOrAbsent = builder.create<mlir::arith::SelectOp>(
342       loc, boxType, isPresent, box, absent);
343   return fir::BoxValue(boxOrAbsent);
344 }
345 
346 /// Is this a call to an elemental procedure with at least one array argument?
347 static bool
348 isElementalProcWithArrayArgs(const Fortran::evaluate::ProcedureRef &procRef) {
349   if (procRef.IsElemental())
350     for (const std::optional<Fortran::evaluate::ActualArgument> &arg :
351          procRef.arguments())
352       if (arg && arg->Rank() != 0)
353         return true;
354   return false;
355 }
356 template <typename T>
357 static bool isElementalProcWithArrayArgs(const Fortran::evaluate::Expr<T> &) {
358   return false;
359 }
360 template <>
361 bool isElementalProcWithArrayArgs(const Fortran::lower::SomeExpr &x) {
362   if (const auto *procRef = std::get_if<Fortran::evaluate::ProcedureRef>(&x.u))
363     return isElementalProcWithArrayArgs(*procRef);
364   return false;
365 }
366 
367 /// Some auxiliary data for processing initialization in ScalarExprLowering
368 /// below. This is currently used for generating dense attributed global
369 /// arrays.
370 struct InitializerData {
371   explicit InitializerData(bool getRawVals = false) : genRawVals{getRawVals} {}
372   llvm::SmallVector<mlir::Attribute> rawVals; // initialization raw values
373   mlir::Type rawType; // Type of elements processed for rawVals vector.
374   bool genRawVals;    // generate the rawVals vector if set.
375 };
376 
377 /// If \p arg is the address of a function with a denoted host-association tuple
378 /// argument, then return the host-associations tuple value of the current
379 /// procedure. Otherwise, return nullptr.
380 static mlir::Value
381 argumentHostAssocs(Fortran::lower::AbstractConverter &converter,
382                    mlir::Value arg) {
383   if (auto addr = mlir::dyn_cast_or_null<fir::AddrOfOp>(arg.getDefiningOp())) {
384     auto &builder = converter.getFirOpBuilder();
385     if (auto funcOp = builder.getNamedFunction(addr.getSymbol()))
386       if (fir::anyFuncArgsHaveAttr(funcOp, fir::getHostAssocAttrName()))
387         return converter.hostAssocTupleValue();
388   }
389   return {};
390 }
391 
392 namespace {
393 
394 /// Lowering of Fortran::evaluate::Expr<T> expressions
395 class ScalarExprLowering {
396 public:
397   using ExtValue = fir::ExtendedValue;
398 
399   explicit ScalarExprLowering(mlir::Location loc,
400                               Fortran::lower::AbstractConverter &converter,
401                               Fortran::lower::SymMap &symMap,
402                               Fortran::lower::StatementContext &stmtCtx,
403                               InitializerData *initializer = nullptr)
404       : location{loc}, converter{converter},
405         builder{converter.getFirOpBuilder()}, stmtCtx{stmtCtx}, symMap{symMap},
406         inInitializer{initializer} {}
407 
408   ExtValue genExtAddr(const Fortran::lower::SomeExpr &expr) {
409     return gen(expr);
410   }
411 
412   /// Lower `expr` to be passed as a fir.box argument. Do not create a temp
413   /// for the expr if it is a variable that can be described as a fir.box.
414   ExtValue genBoxArg(const Fortran::lower::SomeExpr &expr) {
415     bool saveUseBoxArg = useBoxArg;
416     useBoxArg = true;
417     ExtValue result = gen(expr);
418     useBoxArg = saveUseBoxArg;
419     return result;
420   }
421 
422   ExtValue genExtValue(const Fortran::lower::SomeExpr &expr) {
423     return genval(expr);
424   }
425 
426   /// Lower an expression that is a pointer or an allocatable to a
427   /// MutableBoxValue.
428   fir::MutableBoxValue
429   genMutableBoxValue(const Fortran::lower::SomeExpr &expr) {
430     // Pointers and allocatables can only be:
431     //    - a simple designator "x"
432     //    - a component designator "a%b(i,j)%x"
433     //    - a function reference "foo()"
434     //    - result of NULL() or NULL(MOLD) intrinsic.
435     //    NULL() requires some context to be lowered, so it is not handled
436     //    here and must be lowered according to the context where it appears.
437     ExtValue exv = std::visit(
438         [&](const auto &x) { return genMutableBoxValueImpl(x); }, expr.u);
439     const fir::MutableBoxValue *mutableBox =
440         exv.getBoxOf<fir::MutableBoxValue>();
441     if (!mutableBox)
442       fir::emitFatalError(getLoc(), "expr was not lowered to MutableBoxValue");
443     return *mutableBox;
444   }
445 
446   template <typename T>
447   ExtValue genMutableBoxValueImpl(const T &) {
448     // NULL() case should not be handled here.
449     fir::emitFatalError(getLoc(), "NULL() must be lowered in its context");
450   }
451 
452   template <typename T>
453   ExtValue
454   genMutableBoxValueImpl(const Fortran::evaluate::FunctionRef<T> &funRef) {
455     return genRawProcedureRef(funRef, converter.genType(toEvExpr(funRef)));
456   }
457 
458   template <typename T>
459   ExtValue
460   genMutableBoxValueImpl(const Fortran::evaluate::Designator<T> &designator) {
461     return std::visit(
462         Fortran::common::visitors{
463             [&](const Fortran::evaluate::SymbolRef &sym) -> ExtValue {
464               return symMap.lookupSymbol(*sym).toExtendedValue();
465             },
466             [&](const Fortran::evaluate::Component &comp) -> ExtValue {
467               return genComponent(comp);
468             },
469             [&](const auto &) -> ExtValue {
470               fir::emitFatalError(getLoc(),
471                                   "not an allocatable or pointer designator");
472             }},
473         designator.u);
474   }
475 
476   template <typename T>
477   ExtValue genMutableBoxValueImpl(const Fortran::evaluate::Expr<T> &expr) {
478     return std::visit([&](const auto &x) { return genMutableBoxValueImpl(x); },
479                       expr.u);
480   }
481 
482   mlir::Location getLoc() { return location; }
483 
484   template <typename A>
485   mlir::Value genunbox(const A &expr) {
486     ExtValue e = genval(expr);
487     if (const fir::UnboxedValue *r = e.getUnboxed())
488       return *r;
489     fir::emitFatalError(getLoc(), "unboxed expression expected");
490   }
491 
492   /// Generate an integral constant of `value`
493   template <int KIND>
494   mlir::Value genIntegerConstant(mlir::MLIRContext *context,
495                                  std::int64_t value) {
496     mlir::Type type =
497         converter.genType(Fortran::common::TypeCategory::Integer, KIND);
498     return builder.createIntegerConstant(getLoc(), type, value);
499   }
500 
501   /// Generate a logical/boolean constant of `value`
502   mlir::Value genBoolConstant(bool value) {
503     return builder.createBool(getLoc(), value);
504   }
505 
506   /// Generate a real constant with a value `value`.
507   template <int KIND>
508   mlir::Value genRealConstant(mlir::MLIRContext *context,
509                               const llvm::APFloat &value) {
510     mlir::Type fltTy = Fortran::lower::convertReal(context, KIND);
511     return builder.createRealConstant(getLoc(), fltTy, value);
512   }
513 
514   template <typename OpTy>
515   mlir::Value createCompareOp(mlir::arith::CmpIPredicate pred,
516                               const ExtValue &left, const ExtValue &right) {
517     if (const fir::UnboxedValue *lhs = left.getUnboxed())
518       if (const fir::UnboxedValue *rhs = right.getUnboxed())
519         return builder.create<OpTy>(getLoc(), pred, *lhs, *rhs);
520     fir::emitFatalError(getLoc(), "array compare should be handled in genarr");
521   }
522   template <typename OpTy, typename A>
523   mlir::Value createCompareOp(const A &ex, mlir::arith::CmpIPredicate pred) {
524     ExtValue left = genval(ex.left());
525     return createCompareOp<OpTy>(pred, left, genval(ex.right()));
526   }
527 
528   template <typename OpTy>
529   mlir::Value createFltCmpOp(mlir::arith::CmpFPredicate pred,
530                              const ExtValue &left, const ExtValue &right) {
531     if (const fir::UnboxedValue *lhs = left.getUnboxed())
532       if (const fir::UnboxedValue *rhs = right.getUnboxed())
533         return builder.create<OpTy>(getLoc(), pred, *lhs, *rhs);
534     fir::emitFatalError(getLoc(), "array compare should be handled in genarr");
535   }
536   template <typename OpTy, typename A>
537   mlir::Value createFltCmpOp(const A &ex, mlir::arith::CmpFPredicate pred) {
538     ExtValue left = genval(ex.left());
539     return createFltCmpOp<OpTy>(pred, left, genval(ex.right()));
540   }
541 
542   /// Returns a reference to a symbol or its box/boxChar descriptor if it has
543   /// one.
544   ExtValue gen(Fortran::semantics::SymbolRef sym) {
545     if (Fortran::lower::SymbolBox val = symMap.lookupSymbol(sym))
546       return val.match(
547           [&](const Fortran::lower::SymbolBox::PointerOrAllocatable &boxAddr) {
548             return fir::factory::genMutableBoxRead(builder, getLoc(), boxAddr);
549           },
550           [&val](auto &) { return val.toExtendedValue(); });
551     LLVM_DEBUG(llvm::dbgs()
552                << "unknown symbol: " << sym << "\nmap: " << symMap << '\n');
553     fir::emitFatalError(getLoc(), "symbol is not mapped to any IR value");
554   }
555 
556   ExtValue genLoad(const ExtValue &exv) {
557     return ::genLoad(builder, getLoc(), exv);
558   }
559 
560   ExtValue genval(Fortran::semantics::SymbolRef sym) {
561     ExtValue var = gen(sym);
562     if (const fir::UnboxedValue *s = var.getUnboxed())
563       if (fir::isReferenceLike(s->getType()))
564         return genLoad(*s);
565     return var;
566   }
567 
568   ExtValue genval(const Fortran::evaluate::BOZLiteralConstant &) {
569     TODO(getLoc(), "genval BOZ");
570   }
571 
572   /// Return indirection to function designated in ProcedureDesignator.
573   /// The type of the function indirection is not guaranteed to match the one
574   /// of the ProcedureDesignator due to Fortran implicit typing rules.
575   ExtValue genval(const Fortran::evaluate::ProcedureDesignator &proc) {
576     TODO(getLoc(), "genval ProcedureDesignator");
577   }
578 
579   ExtValue genval(const Fortran::evaluate::NullPointer &) {
580     TODO(getLoc(), "genval NullPointer");
581   }
582 
583   ExtValue genval(const Fortran::evaluate::StructureConstructor &ctor) {
584     TODO(getLoc(), "genval StructureConstructor");
585   }
586 
587   /// Lowering of an <i>ac-do-variable</i>, which is not a Symbol.
588   ExtValue genval(const Fortran::evaluate::ImpliedDoIndex &var) {
589     return converter.impliedDoBinding(toStringRef(var.name));
590   }
591 
592   ExtValue genval(const Fortran::evaluate::DescriptorInquiry &desc) {
593     ExtValue exv = desc.base().IsSymbol() ? gen(desc.base().GetLastSymbol())
594                                           : gen(desc.base().GetComponent());
595     mlir::IndexType idxTy = builder.getIndexType();
596     mlir::Location loc = getLoc();
597     auto castResult = [&](mlir::Value v) {
598       using ResTy = Fortran::evaluate::DescriptorInquiry::Result;
599       return builder.createConvert(
600           loc, converter.genType(ResTy::category, ResTy::kind), v);
601     };
602     switch (desc.field()) {
603     case Fortran::evaluate::DescriptorInquiry::Field::Len:
604       return castResult(fir::factory::readCharLen(builder, loc, exv));
605     case Fortran::evaluate::DescriptorInquiry::Field::LowerBound:
606       return castResult(fir::factory::readLowerBound(
607           builder, loc, exv, desc.dimension(),
608           builder.createIntegerConstant(loc, idxTy, 1)));
609     case Fortran::evaluate::DescriptorInquiry::Field::Extent:
610       return castResult(
611           fir::factory::readExtent(builder, loc, exv, desc.dimension()));
612     case Fortran::evaluate::DescriptorInquiry::Field::Rank:
613       TODO(loc, "rank inquiry on assumed rank");
614     case Fortran::evaluate::DescriptorInquiry::Field::Stride:
615       // So far the front end does not generate this inquiry.
616       TODO(loc, "Stride inquiry");
617     }
618     llvm_unreachable("unknown descriptor inquiry");
619   }
620 
621   ExtValue genval(const Fortran::evaluate::TypeParamInquiry &) {
622     TODO(getLoc(), "genval TypeParamInquiry");
623   }
624 
625   template <int KIND>
626   ExtValue genval(const Fortran::evaluate::ComplexComponent<KIND> &part) {
627     TODO(getLoc(), "genval ComplexComponent");
628   }
629 
630   template <int KIND>
631   ExtValue genval(const Fortran::evaluate::Negate<Fortran::evaluate::Type<
632                       Fortran::common::TypeCategory::Integer, KIND>> &op) {
633     mlir::Value input = genunbox(op.left());
634     // Like LLVM, integer negation is the binary op "0 - value"
635     mlir::Value zero = genIntegerConstant<KIND>(builder.getContext(), 0);
636     return builder.create<mlir::arith::SubIOp>(getLoc(), zero, input);
637   }
638 
639   template <int KIND>
640   ExtValue genval(const Fortran::evaluate::Negate<Fortran::evaluate::Type<
641                       Fortran::common::TypeCategory::Real, KIND>> &op) {
642     return builder.create<mlir::arith::NegFOp>(getLoc(), genunbox(op.left()));
643   }
644   template <int KIND>
645   ExtValue genval(const Fortran::evaluate::Negate<Fortran::evaluate::Type<
646                       Fortran::common::TypeCategory::Complex, KIND>> &op) {
647     return builder.create<fir::NegcOp>(getLoc(), genunbox(op.left()));
648   }
649 
650   template <typename OpTy>
651   mlir::Value createBinaryOp(const ExtValue &left, const ExtValue &right) {
652     assert(fir::isUnboxedValue(left) && fir::isUnboxedValue(right));
653     mlir::Value lhs = fir::getBase(left);
654     mlir::Value rhs = fir::getBase(right);
655     assert(lhs.getType() == rhs.getType() && "types must be the same");
656     return builder.create<OpTy>(getLoc(), lhs, rhs);
657   }
658 
659   template <typename OpTy, typename A>
660   mlir::Value createBinaryOp(const A &ex) {
661     ExtValue left = genval(ex.left());
662     return createBinaryOp<OpTy>(left, genval(ex.right()));
663   }
664 
665 #undef GENBIN
666 #define GENBIN(GenBinEvOp, GenBinTyCat, GenBinFirOp)                           \
667   template <int KIND>                                                          \
668   ExtValue genval(const Fortran::evaluate::GenBinEvOp<Fortran::evaluate::Type< \
669                       Fortran::common::TypeCategory::GenBinTyCat, KIND>> &x) { \
670     return createBinaryOp<GenBinFirOp>(x);                                     \
671   }
672 
673   GENBIN(Add, Integer, mlir::arith::AddIOp)
674   GENBIN(Add, Real, mlir::arith::AddFOp)
675   GENBIN(Add, Complex, fir::AddcOp)
676   GENBIN(Subtract, Integer, mlir::arith::SubIOp)
677   GENBIN(Subtract, Real, mlir::arith::SubFOp)
678   GENBIN(Subtract, Complex, fir::SubcOp)
679   GENBIN(Multiply, Integer, mlir::arith::MulIOp)
680   GENBIN(Multiply, Real, mlir::arith::MulFOp)
681   GENBIN(Multiply, Complex, fir::MulcOp)
682   GENBIN(Divide, Integer, mlir::arith::DivSIOp)
683   GENBIN(Divide, Real, mlir::arith::DivFOp)
684   GENBIN(Divide, Complex, fir::DivcOp)
685 
686   template <Fortran::common::TypeCategory TC, int KIND>
687   ExtValue genval(
688       const Fortran::evaluate::Power<Fortran::evaluate::Type<TC, KIND>> &op) {
689     mlir::Type ty = converter.genType(TC, KIND);
690     mlir::Value lhs = genunbox(op.left());
691     mlir::Value rhs = genunbox(op.right());
692     return Fortran::lower::genPow(builder, getLoc(), ty, lhs, rhs);
693   }
694 
695   template <Fortran::common::TypeCategory TC, int KIND>
696   ExtValue genval(
697       const Fortran::evaluate::RealToIntPower<Fortran::evaluate::Type<TC, KIND>>
698           &op) {
699     mlir::Type ty = converter.genType(TC, KIND);
700     mlir::Value lhs = genunbox(op.left());
701     mlir::Value rhs = genunbox(op.right());
702     return Fortran::lower::genPow(builder, getLoc(), ty, lhs, rhs);
703   }
704 
705   template <int KIND>
706   ExtValue genval(const Fortran::evaluate::ComplexConstructor<KIND> &op) {
707     mlir::Value realPartValue = genunbox(op.left());
708     return fir::factory::Complex{builder, getLoc()}.createComplex(
709         KIND, realPartValue, genunbox(op.right()));
710   }
711 
712   template <int KIND>
713   ExtValue genval(const Fortran::evaluate::Concat<KIND> &op) {
714     TODO(getLoc(), "genval Concat<KIND>");
715   }
716 
717   /// MIN and MAX operations
718   template <Fortran::common::TypeCategory TC, int KIND>
719   ExtValue
720   genval(const Fortran::evaluate::Extremum<Fortran::evaluate::Type<TC, KIND>>
721              &op) {
722     TODO(getLoc(), "genval Extremum<TC, KIND>");
723   }
724 
725   template <int KIND>
726   ExtValue genval(const Fortran::evaluate::SetLength<KIND> &x) {
727     TODO(getLoc(), "genval SetLength<KIND>");
728   }
729 
730   template <int KIND>
731   ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
732                       Fortran::common::TypeCategory::Integer, KIND>> &op) {
733     return createCompareOp<mlir::arith::CmpIOp>(op,
734                                                 translateRelational(op.opr));
735   }
736   template <int KIND>
737   ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
738                       Fortran::common::TypeCategory::Real, KIND>> &op) {
739     return createFltCmpOp<mlir::arith::CmpFOp>(
740         op, translateFloatRelational(op.opr));
741   }
742   template <int KIND>
743   ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
744                       Fortran::common::TypeCategory::Complex, KIND>> &op) {
745     TODO(getLoc(), "genval complex comparison");
746   }
747   template <int KIND>
748   ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
749                       Fortran::common::TypeCategory::Character, KIND>> &op) {
750     TODO(getLoc(), "genval char comparison");
751   }
752 
753   ExtValue
754   genval(const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &op) {
755     return std::visit([&](const auto &x) { return genval(x); }, op.u);
756   }
757 
758   template <Fortran::common::TypeCategory TC1, int KIND,
759             Fortran::common::TypeCategory TC2>
760   ExtValue
761   genval(const Fortran::evaluate::Convert<Fortran::evaluate::Type<TC1, KIND>,
762                                           TC2> &convert) {
763     mlir::Type ty = converter.genType(TC1, KIND);
764     mlir::Value operand = genunbox(convert.left());
765     return builder.convertWithSemantics(getLoc(), ty, operand);
766   }
767 
768   template <typename A>
769   ExtValue genval(const Fortran::evaluate::Parentheses<A> &op) {
770     TODO(getLoc(), "genval parentheses<A>");
771   }
772 
773   template <int KIND>
774   ExtValue genval(const Fortran::evaluate::Not<KIND> &op) {
775     mlir::Value logical = genunbox(op.left());
776     mlir::Value one = genBoolConstant(true);
777     mlir::Value val =
778         builder.createConvert(getLoc(), builder.getI1Type(), logical);
779     return builder.create<mlir::arith::XOrIOp>(getLoc(), val, one);
780   }
781 
782   template <int KIND>
783   ExtValue genval(const Fortran::evaluate::LogicalOperation<KIND> &op) {
784     mlir::IntegerType i1Type = builder.getI1Type();
785     mlir::Value slhs = genunbox(op.left());
786     mlir::Value srhs = genunbox(op.right());
787     mlir::Value lhs = builder.createConvert(getLoc(), i1Type, slhs);
788     mlir::Value rhs = builder.createConvert(getLoc(), i1Type, srhs);
789     switch (op.logicalOperator) {
790     case Fortran::evaluate::LogicalOperator::And:
791       return createBinaryOp<mlir::arith::AndIOp>(lhs, rhs);
792     case Fortran::evaluate::LogicalOperator::Or:
793       return createBinaryOp<mlir::arith::OrIOp>(lhs, rhs);
794     case Fortran::evaluate::LogicalOperator::Eqv:
795       return createCompareOp<mlir::arith::CmpIOp>(
796           mlir::arith::CmpIPredicate::eq, lhs, rhs);
797     case Fortran::evaluate::LogicalOperator::Neqv:
798       return createCompareOp<mlir::arith::CmpIOp>(
799           mlir::arith::CmpIPredicate::ne, lhs, rhs);
800     case Fortran::evaluate::LogicalOperator::Not:
801       // lib/evaluate expression for .NOT. is Fortran::evaluate::Not<KIND>.
802       llvm_unreachable(".NOT. is not a binary operator");
803     }
804     llvm_unreachable("unhandled logical operation");
805   }
806 
807   /// Convert a scalar literal constant to IR.
808   template <Fortran::common::TypeCategory TC, int KIND>
809   ExtValue genScalarLit(
810       const Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>>
811           &value) {
812     if constexpr (TC == Fortran::common::TypeCategory::Integer) {
813       return genIntegerConstant<KIND>(builder.getContext(), value.ToInt64());
814     } else if constexpr (TC == Fortran::common::TypeCategory::Logical) {
815       return genBoolConstant(value.IsTrue());
816     } else if constexpr (TC == Fortran::common::TypeCategory::Real) {
817       std::string str = value.DumpHexadecimal();
818       if constexpr (KIND == 2) {
819         llvm::APFloat floatVal{llvm::APFloatBase::IEEEhalf(), str};
820         return genRealConstant<KIND>(builder.getContext(), floatVal);
821       } else if constexpr (KIND == 3) {
822         llvm::APFloat floatVal{llvm::APFloatBase::BFloat(), str};
823         return genRealConstant<KIND>(builder.getContext(), floatVal);
824       } else if constexpr (KIND == 4) {
825         llvm::APFloat floatVal{llvm::APFloatBase::IEEEsingle(), str};
826         return genRealConstant<KIND>(builder.getContext(), floatVal);
827       } else if constexpr (KIND == 10) {
828         llvm::APFloat floatVal{llvm::APFloatBase::x87DoubleExtended(), str};
829         return genRealConstant<KIND>(builder.getContext(), floatVal);
830       } else if constexpr (KIND == 16) {
831         llvm::APFloat floatVal{llvm::APFloatBase::IEEEquad(), str};
832         return genRealConstant<KIND>(builder.getContext(), floatVal);
833       } else {
834         // convert everything else to double
835         llvm::APFloat floatVal{llvm::APFloatBase::IEEEdouble(), str};
836         return genRealConstant<KIND>(builder.getContext(), floatVal);
837       }
838     } else if constexpr (TC == Fortran::common::TypeCategory::Complex) {
839       using TR =
840           Fortran::evaluate::Type<Fortran::common::TypeCategory::Real, KIND>;
841       Fortran::evaluate::ComplexConstructor<KIND> ctor(
842           Fortran::evaluate::Expr<TR>{
843               Fortran::evaluate::Constant<TR>{value.REAL()}},
844           Fortran::evaluate::Expr<TR>{
845               Fortran::evaluate::Constant<TR>{value.AIMAG()}});
846       return genunbox(ctor);
847     } else /*constexpr*/ {
848       llvm_unreachable("unhandled constant");
849     }
850   }
851 
852   /// Generate a raw literal value and store it in the rawVals vector.
853   template <Fortran::common::TypeCategory TC, int KIND>
854   void
855   genRawLit(const Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>>
856                 &value) {
857     mlir::Attribute val;
858     assert(inInitializer != nullptr);
859     if constexpr (TC == Fortran::common::TypeCategory::Integer) {
860       inInitializer->rawType = converter.genType(TC, KIND);
861       val = builder.getIntegerAttr(inInitializer->rawType, value.ToInt64());
862     } else if constexpr (TC == Fortran::common::TypeCategory::Logical) {
863       inInitializer->rawType =
864           converter.genType(Fortran::common::TypeCategory::Integer, KIND);
865       val = builder.getIntegerAttr(inInitializer->rawType, value.IsTrue());
866     } else if constexpr (TC == Fortran::common::TypeCategory::Real) {
867       std::string str = value.DumpHexadecimal();
868       inInitializer->rawType = converter.genType(TC, KIND);
869       llvm::APFloat floatVal{builder.getKindMap().getFloatSemantics(KIND), str};
870       val = builder.getFloatAttr(inInitializer->rawType, floatVal);
871     } else if constexpr (TC == Fortran::common::TypeCategory::Complex) {
872       std::string strReal = value.REAL().DumpHexadecimal();
873       std::string strImg = value.AIMAG().DumpHexadecimal();
874       inInitializer->rawType = converter.genType(TC, KIND);
875       llvm::APFloat realVal{builder.getKindMap().getFloatSemantics(KIND),
876                             strReal};
877       val = builder.getFloatAttr(inInitializer->rawType, realVal);
878       inInitializer->rawVals.push_back(val);
879       llvm::APFloat imgVal{builder.getKindMap().getFloatSemantics(KIND),
880                            strImg};
881       val = builder.getFloatAttr(inInitializer->rawType, imgVal);
882     }
883     inInitializer->rawVals.push_back(val);
884   }
885 
886   /// Convert a ascii scalar literal CHARACTER to IR. (specialization)
887   ExtValue
888   genAsciiScalarLit(const Fortran::evaluate::Scalar<Fortran::evaluate::Type<
889                         Fortran::common::TypeCategory::Character, 1>> &value,
890                     int64_t len) {
891     assert(value.size() == static_cast<std::uint64_t>(len));
892     // Outline character constant in ro data if it is not in an initializer.
893     if (!inInitializer)
894       return fir::factory::createStringLiteral(builder, getLoc(), value);
895     // When in an initializer context, construct the literal op itself and do
896     // not construct another constant object in rodata.
897     fir::StringLitOp stringLit = builder.createStringLitOp(getLoc(), value);
898     mlir::Value lenp = builder.createIntegerConstant(
899         getLoc(), builder.getCharacterLengthType(), len);
900     return fir::CharBoxValue{stringLit.getResult(), lenp};
901   }
902   /// Convert a non ascii scalar literal CHARACTER to IR. (specialization)
903   template <int KIND>
904   ExtValue
905   genScalarLit(const Fortran::evaluate::Scalar<Fortran::evaluate::Type<
906                    Fortran::common::TypeCategory::Character, KIND>> &value,
907                int64_t len) {
908     using ET = typename std::decay_t<decltype(value)>::value_type;
909     if constexpr (KIND == 1) {
910       return genAsciiScalarLit(value, len);
911     }
912     fir::CharacterType type =
913         fir::CharacterType::get(builder.getContext(), KIND, len);
914     auto consLit = [&]() -> fir::StringLitOp {
915       mlir::MLIRContext *context = builder.getContext();
916       std::int64_t size = static_cast<std::int64_t>(value.size());
917       mlir::ShapedType shape = mlir::VectorType::get(
918           llvm::ArrayRef<std::int64_t>{size},
919           mlir::IntegerType::get(builder.getContext(), sizeof(ET) * 8));
920       auto strAttr = mlir::DenseElementsAttr::get(
921           shape, llvm::ArrayRef<ET>{value.data(), value.size()});
922       auto valTag = mlir::StringAttr::get(context, fir::StringLitOp::value());
923       mlir::NamedAttribute dataAttr(valTag, strAttr);
924       auto sizeTag = mlir::StringAttr::get(context, fir::StringLitOp::size());
925       mlir::NamedAttribute sizeAttr(sizeTag, builder.getI64IntegerAttr(len));
926       llvm::SmallVector<mlir::NamedAttribute> attrs = {dataAttr, sizeAttr};
927       return builder.create<fir::StringLitOp>(
928           getLoc(), llvm::ArrayRef<mlir::Type>{type}, llvm::None, attrs);
929     };
930 
931     mlir::Value lenp = builder.createIntegerConstant(
932         getLoc(), builder.getCharacterLengthType(), len);
933     // When in an initializer context, construct the literal op itself and do
934     // not construct another constant object in rodata.
935     if (inInitializer)
936       return fir::CharBoxValue{consLit().getResult(), lenp};
937 
938     // Otherwise, the string is in a plain old expression so "outline" the value
939     // by hashconsing it to a constant literal object.
940 
941     // FIXME: For wider char types, lowering ought to use an array of i16 or
942     // i32. But for now, lowering just fakes that the string value is a range of
943     // i8 to get it past the C++ compiler.
944     std::string globalName =
945         fir::factory::uniqueCGIdent("cl", (const char *)value.c_str());
946     fir::GlobalOp global = builder.getNamedGlobal(globalName);
947     if (!global)
948       global = builder.createGlobalConstant(
949           getLoc(), type, globalName,
950           [&](fir::FirOpBuilder &builder) {
951             fir::StringLitOp str = consLit();
952             builder.create<fir::HasValueOp>(getLoc(), str);
953           },
954           builder.createLinkOnceLinkage());
955     auto addr = builder.create<fir::AddrOfOp>(getLoc(), global.resultType(),
956                                               global.getSymbol());
957     return fir::CharBoxValue{addr, lenp};
958   }
959 
960   template <Fortran::common::TypeCategory TC, int KIND>
961   ExtValue genArrayLit(
962       const Fortran::evaluate::Constant<Fortran::evaluate::Type<TC, KIND>>
963           &con) {
964     mlir::Location loc = getLoc();
965     mlir::IndexType idxTy = builder.getIndexType();
966     Fortran::evaluate::ConstantSubscript size =
967         Fortran::evaluate::GetSize(con.shape());
968     fir::SequenceType::Shape shape(con.shape().begin(), con.shape().end());
969     mlir::Type eleTy;
970     if constexpr (TC == Fortran::common::TypeCategory::Character)
971       eleTy = converter.genType(TC, KIND, {con.LEN()});
972     else
973       eleTy = converter.genType(TC, KIND);
974     auto arrayTy = fir::SequenceType::get(shape, eleTy);
975     mlir::Value array;
976     llvm::SmallVector<mlir::Value> lbounds;
977     llvm::SmallVector<mlir::Value> extents;
978     if (!inInitializer || !inInitializer->genRawVals) {
979       array = builder.create<fir::UndefOp>(loc, arrayTy);
980       for (auto [lb, extent] : llvm::zip(con.lbounds(), shape)) {
981         lbounds.push_back(builder.createIntegerConstant(loc, idxTy, lb - 1));
982         extents.push_back(builder.createIntegerConstant(loc, idxTy, extent));
983       }
984     }
985     if (size == 0) {
986       if constexpr (TC == Fortran::common::TypeCategory::Character) {
987         mlir::Value len = builder.createIntegerConstant(loc, idxTy, con.LEN());
988         return fir::CharArrayBoxValue{array, len, extents, lbounds};
989       } else {
990         return fir::ArrayBoxValue{array, extents, lbounds};
991       }
992     }
993     Fortran::evaluate::ConstantSubscripts subscripts = con.lbounds();
994     auto createIdx = [&]() {
995       llvm::SmallVector<mlir::Attribute> idx;
996       for (size_t i = 0; i < subscripts.size(); ++i)
997         idx.push_back(
998             builder.getIntegerAttr(idxTy, subscripts[i] - con.lbounds()[i]));
999       return idx;
1000     };
1001     if constexpr (TC == Fortran::common::TypeCategory::Character) {
1002       assert(array && "array must not be nullptr");
1003       do {
1004         mlir::Value elementVal =
1005             fir::getBase(genScalarLit<KIND>(con.At(subscripts), con.LEN()));
1006         array = builder.create<fir::InsertValueOp>(
1007             loc, arrayTy, array, elementVal, builder.getArrayAttr(createIdx()));
1008       } while (con.IncrementSubscripts(subscripts));
1009       mlir::Value len = builder.createIntegerConstant(loc, idxTy, con.LEN());
1010       return fir::CharArrayBoxValue{array, len, extents, lbounds};
1011     } else {
1012       llvm::SmallVector<mlir::Attribute> rangeStartIdx;
1013       uint64_t rangeSize = 0;
1014       do {
1015         if (inInitializer && inInitializer->genRawVals) {
1016           genRawLit<TC, KIND>(con.At(subscripts));
1017           continue;
1018         }
1019         auto getElementVal = [&]() {
1020           return builder.createConvert(
1021               loc, eleTy,
1022               fir::getBase(genScalarLit<TC, KIND>(con.At(subscripts))));
1023         };
1024         Fortran::evaluate::ConstantSubscripts nextSubscripts = subscripts;
1025         bool nextIsSame = con.IncrementSubscripts(nextSubscripts) &&
1026                           con.At(subscripts) == con.At(nextSubscripts);
1027         if (!rangeSize && !nextIsSame) { // single (non-range) value
1028           array = builder.create<fir::InsertValueOp>(
1029               loc, arrayTy, array, getElementVal(),
1030               builder.getArrayAttr(createIdx()));
1031         } else if (!rangeSize) { // start a range
1032           rangeStartIdx = createIdx();
1033           rangeSize = 1;
1034         } else if (nextIsSame) { // expand a range
1035           ++rangeSize;
1036         } else { // end a range
1037           llvm::SmallVector<int64_t> rangeBounds;
1038           llvm::SmallVector<mlir::Attribute> idx = createIdx();
1039           for (size_t i = 0; i < idx.size(); ++i) {
1040             rangeBounds.push_back(rangeStartIdx[i]
1041                                       .cast<mlir::IntegerAttr>()
1042                                       .getValue()
1043                                       .getSExtValue());
1044             rangeBounds.push_back(
1045                 idx[i].cast<mlir::IntegerAttr>().getValue().getSExtValue());
1046           }
1047           array = builder.create<fir::InsertOnRangeOp>(
1048               loc, arrayTy, array, getElementVal(),
1049               builder.getIndexVectorAttr(rangeBounds));
1050           rangeSize = 0;
1051         }
1052       } while (con.IncrementSubscripts(subscripts));
1053       return fir::ArrayBoxValue{array, extents, lbounds};
1054     }
1055   }
1056 
1057   template <Fortran::common::TypeCategory TC, int KIND>
1058   ExtValue
1059   genval(const Fortran::evaluate::Constant<Fortran::evaluate::Type<TC, KIND>>
1060              &con) {
1061     if (con.Rank() > 0)
1062       return genArrayLit(con);
1063     std::optional<Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>>>
1064         opt = con.GetScalarValue();
1065     assert(opt.has_value() && "constant has no value");
1066     if constexpr (TC == Fortran::common::TypeCategory::Character) {
1067       return genScalarLit<KIND>(opt.value(), con.LEN());
1068     } else {
1069       return genScalarLit<TC, KIND>(opt.value());
1070     }
1071   }
1072 
1073   fir::ExtendedValue genval(
1074       const Fortran::evaluate::Constant<Fortran::evaluate::SomeDerived> &con) {
1075     TODO(getLoc(), "genval constant derived");
1076   }
1077 
1078   template <typename A>
1079   ExtValue genval(const Fortran::evaluate::ArrayConstructor<A> &) {
1080     TODO(getLoc(), "genval ArrayConstructor<A>");
1081   }
1082 
1083   ExtValue gen(const Fortran::evaluate::ComplexPart &x) {
1084     TODO(getLoc(), "gen ComplexPart");
1085   }
1086   ExtValue genval(const Fortran::evaluate::ComplexPart &x) {
1087     TODO(getLoc(), "genval ComplexPart");
1088   }
1089 
1090   ExtValue gen(const Fortran::evaluate::Substring &s) {
1091     TODO(getLoc(), "gen Substring");
1092   }
1093   ExtValue genval(const Fortran::evaluate::Substring &ss) {
1094     TODO(getLoc(), "genval Substring");
1095   }
1096 
1097   ExtValue genval(const Fortran::evaluate::Subscript &subs) {
1098     if (auto *s = std::get_if<Fortran::evaluate::IndirectSubscriptIntegerExpr>(
1099             &subs.u)) {
1100       if (s->value().Rank() > 0)
1101         fir::emitFatalError(getLoc(), "vector subscript is not scalar");
1102       return {genval(s->value())};
1103     }
1104     fir::emitFatalError(getLoc(), "subscript triple notation is not scalar");
1105   }
1106 
1107   ExtValue genSubscript(const Fortran::evaluate::Subscript &subs) {
1108     return genval(subs);
1109   }
1110 
1111   ExtValue gen(const Fortran::evaluate::DataRef &dref) {
1112     TODO(getLoc(), "gen DataRef");
1113   }
1114   ExtValue genval(const Fortran::evaluate::DataRef &dref) {
1115     TODO(getLoc(), "genval DataRef");
1116   }
1117 
1118   // Helper function to turn the Component structure into a list of nested
1119   // components, ordered from largest/leftmost to smallest/rightmost:
1120   //  - where only the smallest/rightmost item may be allocatable or a pointer
1121   //    (nested allocatable/pointer components require nested coordinate_of ops)
1122   //  - that does not contain any parent components
1123   //    (the front end places parent components directly in the object)
1124   // Return the object used as the base coordinate for the component chain.
1125   static Fortran::evaluate::DataRef const *
1126   reverseComponents(const Fortran::evaluate::Component &cmpt,
1127                     std::list<const Fortran::evaluate::Component *> &list) {
1128     if (!cmpt.GetLastSymbol().test(
1129             Fortran::semantics::Symbol::Flag::ParentComp))
1130       list.push_front(&cmpt);
1131     return std::visit(
1132         Fortran::common::visitors{
1133             [&](const Fortran::evaluate::Component &x) {
1134               if (Fortran::semantics::IsAllocatableOrPointer(x.GetLastSymbol()))
1135                 return &cmpt.base();
1136               return reverseComponents(x, list);
1137             },
1138             [&](auto &) { return &cmpt.base(); },
1139         },
1140         cmpt.base().u);
1141   }
1142 
1143   // Return the coordinate of the component reference
1144   ExtValue genComponent(const Fortran::evaluate::Component &cmpt) {
1145     std::list<const Fortran::evaluate::Component *> list;
1146     const Fortran::evaluate::DataRef *base = reverseComponents(cmpt, list);
1147     llvm::SmallVector<mlir::Value> coorArgs;
1148     ExtValue obj = gen(*base);
1149     mlir::Type ty = fir::dyn_cast_ptrOrBoxEleTy(fir::getBase(obj).getType());
1150     mlir::Location loc = getLoc();
1151     auto fldTy = fir::FieldType::get(&converter.getMLIRContext());
1152     // FIXME: need to thread the LEN type parameters here.
1153     for (const Fortran::evaluate::Component *field : list) {
1154       auto recTy = ty.cast<fir::RecordType>();
1155       const Fortran::semantics::Symbol &sym = field->GetLastSymbol();
1156       llvm::StringRef name = toStringRef(sym.name());
1157       coorArgs.push_back(builder.create<fir::FieldIndexOp>(
1158           loc, fldTy, name, recTy, fir::getTypeParams(obj)));
1159       ty = recTy.getType(name);
1160     }
1161     ty = builder.getRefType(ty);
1162     return fir::factory::componentToExtendedValue(
1163         builder, loc,
1164         builder.create<fir::CoordinateOp>(loc, ty, fir::getBase(obj),
1165                                           coorArgs));
1166   }
1167 
1168   ExtValue gen(const Fortran::evaluate::Component &cmpt) {
1169     TODO(getLoc(), "gen Component");
1170   }
1171   ExtValue genval(const Fortran::evaluate::Component &cmpt) {
1172     TODO(getLoc(), "genval Component");
1173   }
1174 
1175   ExtValue genval(const Fortran::semantics::Bound &bound) {
1176     TODO(getLoc(), "genval Bound");
1177   }
1178 
1179   /// Return lower bounds of \p box in dimension \p dim. The returned value
1180   /// has type \ty.
1181   mlir::Value getLBound(const ExtValue &box, unsigned dim, mlir::Type ty) {
1182     assert(box.rank() > 0 && "must be an array");
1183     mlir::Location loc = getLoc();
1184     mlir::Value one = builder.createIntegerConstant(loc, ty, 1);
1185     mlir::Value lb = fir::factory::readLowerBound(builder, loc, box, dim, one);
1186     return builder.createConvert(loc, ty, lb);
1187   }
1188 
1189   static bool isSlice(const Fortran::evaluate::ArrayRef &aref) {
1190     for (const Fortran::evaluate::Subscript &sub : aref.subscript())
1191       if (std::holds_alternative<Fortran::evaluate::Triplet>(sub.u))
1192         return true;
1193     return false;
1194   }
1195 
1196   /// Lower an ArrayRef to a fir.coordinate_of given its lowered base.
1197   ExtValue genCoordinateOp(const ExtValue &array,
1198                            const Fortran::evaluate::ArrayRef &aref) {
1199     mlir::Location loc = getLoc();
1200     // References to array of rank > 1 with non constant shape that are not
1201     // fir.box must be collapsed into an offset computation in lowering already.
1202     // The same is needed with dynamic length character arrays of all ranks.
1203     mlir::Type baseType =
1204         fir::dyn_cast_ptrOrBoxEleTy(fir::getBase(array).getType());
1205     if ((array.rank() > 1 && fir::hasDynamicSize(baseType)) ||
1206         fir::characterWithDynamicLen(fir::unwrapSequenceType(baseType)))
1207       if (!array.getBoxOf<fir::BoxValue>())
1208         return genOffsetAndCoordinateOp(array, aref);
1209     // Generate a fir.coordinate_of with zero based array indexes.
1210     llvm::SmallVector<mlir::Value> args;
1211     for (const auto &subsc : llvm::enumerate(aref.subscript())) {
1212       ExtValue subVal = genSubscript(subsc.value());
1213       assert(fir::isUnboxedValue(subVal) && "subscript must be simple scalar");
1214       mlir::Value val = fir::getBase(subVal);
1215       mlir::Type ty = val.getType();
1216       mlir::Value lb = getLBound(array, subsc.index(), ty);
1217       args.push_back(builder.create<mlir::arith::SubIOp>(loc, ty, val, lb));
1218     }
1219 
1220     mlir::Value base = fir::getBase(array);
1221     auto seqTy =
1222         fir::dyn_cast_ptrOrBoxEleTy(base.getType()).cast<fir::SequenceType>();
1223     assert(args.size() == seqTy.getDimension());
1224     mlir::Type ty = builder.getRefType(seqTy.getEleTy());
1225     auto addr = builder.create<fir::CoordinateOp>(loc, ty, base, args);
1226     return fir::factory::arrayElementToExtendedValue(builder, loc, array, addr);
1227   }
1228 
1229   /// Lower an ArrayRef to a fir.coordinate_of using an element offset instead
1230   /// of array indexes.
1231   /// This generates offset computation from the indexes and length parameters,
1232   /// and use the offset to access the element with a fir.coordinate_of. This
1233   /// must only be used if it is not possible to generate a normal
1234   /// fir.coordinate_of using array indexes (i.e. when the shape information is
1235   /// unavailable in the IR).
1236   ExtValue genOffsetAndCoordinateOp(const ExtValue &array,
1237                                     const Fortran::evaluate::ArrayRef &aref) {
1238     mlir::Location loc = getLoc();
1239     mlir::Value addr = fir::getBase(array);
1240     mlir::Type arrTy = fir::dyn_cast_ptrEleTy(addr.getType());
1241     auto eleTy = arrTy.cast<fir::SequenceType>().getEleTy();
1242     mlir::Type seqTy = builder.getRefType(builder.getVarLenSeqTy(eleTy));
1243     mlir::Type refTy = builder.getRefType(eleTy);
1244     mlir::Value base = builder.createConvert(loc, seqTy, addr);
1245     mlir::IndexType idxTy = builder.getIndexType();
1246     mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
1247     mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
1248     auto getLB = [&](const auto &arr, unsigned dim) -> mlir::Value {
1249       return arr.getLBounds().empty() ? one : arr.getLBounds()[dim];
1250     };
1251     auto genFullDim = [&](const auto &arr, mlir::Value delta) -> mlir::Value {
1252       mlir::Value total = zero;
1253       assert(arr.getExtents().size() == aref.subscript().size());
1254       delta = builder.createConvert(loc, idxTy, delta);
1255       unsigned dim = 0;
1256       for (auto [ext, sub] : llvm::zip(arr.getExtents(), aref.subscript())) {
1257         ExtValue subVal = genSubscript(sub);
1258         assert(fir::isUnboxedValue(subVal));
1259         mlir::Value val =
1260             builder.createConvert(loc, idxTy, fir::getBase(subVal));
1261         mlir::Value lb = builder.createConvert(loc, idxTy, getLB(arr, dim));
1262         mlir::Value diff = builder.create<mlir::arith::SubIOp>(loc, val, lb);
1263         mlir::Value prod =
1264             builder.create<mlir::arith::MulIOp>(loc, delta, diff);
1265         total = builder.create<mlir::arith::AddIOp>(loc, prod, total);
1266         if (ext)
1267           delta = builder.create<mlir::arith::MulIOp>(loc, delta, ext);
1268         ++dim;
1269       }
1270       mlir::Type origRefTy = refTy;
1271       if (fir::factory::CharacterExprHelper::isCharacterScalar(refTy)) {
1272         fir::CharacterType chTy =
1273             fir::factory::CharacterExprHelper::getCharacterType(refTy);
1274         if (fir::characterWithDynamicLen(chTy)) {
1275           mlir::MLIRContext *ctx = builder.getContext();
1276           fir::KindTy kind =
1277               fir::factory::CharacterExprHelper::getCharacterKind(chTy);
1278           fir::CharacterType singleTy =
1279               fir::CharacterType::getSingleton(ctx, kind);
1280           refTy = builder.getRefType(singleTy);
1281           mlir::Type seqRefTy =
1282               builder.getRefType(builder.getVarLenSeqTy(singleTy));
1283           base = builder.createConvert(loc, seqRefTy, base);
1284         }
1285       }
1286       auto coor = builder.create<fir::CoordinateOp>(
1287           loc, refTy, base, llvm::ArrayRef<mlir::Value>{total});
1288       // Convert to expected, original type after address arithmetic.
1289       return builder.createConvert(loc, origRefTy, coor);
1290     };
1291     return array.match(
1292         [&](const fir::ArrayBoxValue &arr) -> ExtValue {
1293           // FIXME: this check can be removed when slicing is implemented
1294           if (isSlice(aref))
1295             fir::emitFatalError(
1296                 getLoc(),
1297                 "slice should be handled in array expression context");
1298           return genFullDim(arr, one);
1299         },
1300         [&](const fir::CharArrayBoxValue &arr) -> ExtValue {
1301           mlir::Value delta = arr.getLen();
1302           // If the length is known in the type, fir.coordinate_of will
1303           // already take the length into account.
1304           if (fir::factory::CharacterExprHelper::hasConstantLengthInType(arr))
1305             delta = one;
1306           return fir::CharBoxValue(genFullDim(arr, delta), arr.getLen());
1307         },
1308         [&](const fir::BoxValue &arr) -> ExtValue {
1309           // CoordinateOp for BoxValue is not generated here. The dimensions
1310           // must be kept in the fir.coordinate_op so that potential fir.box
1311           // strides can be applied by codegen.
1312           fir::emitFatalError(
1313               loc, "internal: BoxValue in dim-collapsed fir.coordinate_of");
1314         },
1315         [&](const auto &) -> ExtValue {
1316           fir::emitFatalError(loc, "internal: array lowering failed");
1317         });
1318   }
1319 
1320   ExtValue gen(const Fortran::evaluate::ArrayRef &aref) {
1321     ExtValue base = aref.base().IsSymbol() ? gen(aref.base().GetFirstSymbol())
1322                                            : gen(aref.base().GetComponent());
1323     return genCoordinateOp(base, aref);
1324   }
1325   ExtValue genval(const Fortran::evaluate::ArrayRef &aref) {
1326     return genLoad(gen(aref));
1327   }
1328 
1329   ExtValue gen(const Fortran::evaluate::CoarrayRef &coref) {
1330     TODO(getLoc(), "gen CoarrayRef");
1331   }
1332   ExtValue genval(const Fortran::evaluate::CoarrayRef &coref) {
1333     TODO(getLoc(), "genval CoarrayRef");
1334   }
1335 
1336   template <typename A>
1337   ExtValue gen(const Fortran::evaluate::Designator<A> &des) {
1338     return std::visit([&](const auto &x) { return gen(x); }, des.u);
1339   }
1340   template <typename A>
1341   ExtValue genval(const Fortran::evaluate::Designator<A> &des) {
1342     return std::visit([&](const auto &x) { return genval(x); }, des.u);
1343   }
1344 
1345   mlir::Type genType(const Fortran::evaluate::DynamicType &dt) {
1346     if (dt.category() != Fortran::common::TypeCategory::Derived)
1347       return converter.genType(dt.category(), dt.kind());
1348     TODO(getLoc(), "genType Derived Type");
1349   }
1350 
1351   /// Lower a function reference
1352   template <typename A>
1353   ExtValue genFunctionRef(const Fortran::evaluate::FunctionRef<A> &funcRef) {
1354     if (!funcRef.GetType().has_value())
1355       fir::emitFatalError(getLoc(), "internal: a function must have a type");
1356     mlir::Type resTy = genType(*funcRef.GetType());
1357     return genProcedureRef(funcRef, {resTy});
1358   }
1359 
1360   /// Lower function call `funcRef` and return a reference to the resultant
1361   /// value. This is required for lowering expressions such as `f1(f2(v))`.
1362   template <typename A>
1363   ExtValue gen(const Fortran::evaluate::FunctionRef<A> &funcRef) {
1364     ExtValue retVal = genFunctionRef(funcRef);
1365     mlir::Value retValBase = fir::getBase(retVal);
1366     if (fir::conformsWithPassByRef(retValBase.getType()))
1367       return retVal;
1368     auto mem = builder.create<fir::AllocaOp>(getLoc(), retValBase.getType());
1369     builder.create<fir::StoreOp>(getLoc(), retValBase, mem);
1370     return fir::substBase(retVal, mem.getResult());
1371   }
1372 
1373   /// helper to detect statement functions
1374   static bool
1375   isStatementFunctionCall(const Fortran::evaluate::ProcedureRef &procRef) {
1376     if (const Fortran::semantics::Symbol *symbol = procRef.proc().GetSymbol())
1377       if (const auto *details =
1378               symbol->detailsIf<Fortran::semantics::SubprogramDetails>())
1379         return details->stmtFunction().has_value();
1380     return false;
1381   }
1382 
1383   /// Helper to package a Value and its properties into an ExtendedValue.
1384   static ExtValue toExtendedValue(mlir::Location loc, mlir::Value base,
1385                                   llvm::ArrayRef<mlir::Value> extents,
1386                                   llvm::ArrayRef<mlir::Value> lengths) {
1387     mlir::Type type = base.getType();
1388     if (type.isa<fir::BoxType>())
1389       return fir::BoxValue(base, /*lbounds=*/{}, lengths, extents);
1390     type = fir::unwrapRefType(type);
1391     if (type.isa<fir::BoxType>())
1392       return fir::MutableBoxValue(base, lengths, /*mutableProperties*/ {});
1393     if (auto seqTy = type.dyn_cast<fir::SequenceType>()) {
1394       if (seqTy.getDimension() != extents.size())
1395         fir::emitFatalError(loc, "incorrect number of extents for array");
1396       if (seqTy.getEleTy().isa<fir::CharacterType>()) {
1397         if (lengths.empty())
1398           fir::emitFatalError(loc, "missing length for character");
1399         assert(lengths.size() == 1);
1400         return fir::CharArrayBoxValue(base, lengths[0], extents);
1401       }
1402       return fir::ArrayBoxValue(base, extents);
1403     }
1404     if (type.isa<fir::CharacterType>()) {
1405       if (lengths.empty())
1406         fir::emitFatalError(loc, "missing length for character");
1407       assert(lengths.size() == 1);
1408       return fir::CharBoxValue(base, lengths[0]);
1409     }
1410     return base;
1411   }
1412 
1413   // Find the argument that corresponds to the host associations.
1414   // Verify some assumptions about how the signature was built here.
1415   [[maybe_unused]] static unsigned findHostAssocTuplePos(mlir::FuncOp fn) {
1416     // Scan the argument list from last to first as the host associations are
1417     // appended for now.
1418     for (unsigned i = fn.getNumArguments(); i > 0; --i)
1419       if (fn.getArgAttr(i - 1, fir::getHostAssocAttrName())) {
1420         // Host assoc tuple must be last argument (for now).
1421         assert(i == fn.getNumArguments() && "tuple must be last");
1422         return i - 1;
1423       }
1424     llvm_unreachable("anyFuncArgsHaveAttr failed");
1425   }
1426 
1427   /// Create a contiguous temporary array with the same shape,
1428   /// length parameters and type as mold. It is up to the caller to deallocate
1429   /// the temporary.
1430   ExtValue genArrayTempFromMold(const ExtValue &mold,
1431                                 llvm::StringRef tempName) {
1432     mlir::Type type = fir::dyn_cast_ptrOrBoxEleTy(fir::getBase(mold).getType());
1433     assert(type && "expected descriptor or memory type");
1434     mlir::Location loc = getLoc();
1435     llvm::SmallVector<mlir::Value> extents =
1436         fir::factory::getExtents(builder, loc, mold);
1437     llvm::SmallVector<mlir::Value> allocMemTypeParams =
1438         fir::getTypeParams(mold);
1439     mlir::Value charLen;
1440     mlir::Type elementType = fir::unwrapSequenceType(type);
1441     if (auto charType = elementType.dyn_cast<fir::CharacterType>()) {
1442       charLen = allocMemTypeParams.empty()
1443                     ? fir::factory::readCharLen(builder, loc, mold)
1444                     : allocMemTypeParams[0];
1445       if (charType.hasDynamicLen() && allocMemTypeParams.empty())
1446         allocMemTypeParams.push_back(charLen);
1447     } else if (fir::hasDynamicSize(elementType)) {
1448       TODO(loc, "Creating temporary for derived type with length parameters");
1449     }
1450 
1451     mlir::Value temp = builder.create<fir::AllocMemOp>(
1452         loc, type, tempName, allocMemTypeParams, extents);
1453     if (fir::unwrapSequenceType(type).isa<fir::CharacterType>())
1454       return fir::CharArrayBoxValue{temp, charLen, extents};
1455     return fir::ArrayBoxValue{temp, extents};
1456   }
1457 
1458   /// Copy \p source array into \p dest array. Both arrays must be
1459   /// conforming, but neither array must be contiguous.
1460   void genArrayCopy(ExtValue dest, ExtValue source) {
1461     return createSomeArrayAssignment(converter, dest, source, symMap, stmtCtx);
1462   }
1463 
1464   /// Lower a non-elemental procedure reference and read allocatable and pointer
1465   /// results into normal values.
1466   ExtValue genProcedureRef(const Fortran::evaluate::ProcedureRef &procRef,
1467                            llvm::Optional<mlir::Type> resultType) {
1468     ExtValue res = genRawProcedureRef(procRef, resultType);
1469     return res;
1470   }
1471 
1472   /// Given a call site for which the arguments were already lowered, generate
1473   /// the call and return the result. This function deals with explicit result
1474   /// allocation and lowering if needed. It also deals with passing the host
1475   /// link to internal procedures.
1476   ExtValue genCallOpAndResult(Fortran::lower::CallerInterface &caller,
1477                               mlir::FunctionType callSiteType,
1478                               llvm::Optional<mlir::Type> resultType) {
1479     mlir::Location loc = getLoc();
1480     using PassBy = Fortran::lower::CallerInterface::PassEntityBy;
1481     // Handle cases where caller must allocate the result or a fir.box for it.
1482     bool mustPopSymMap = false;
1483     if (caller.mustMapInterfaceSymbols()) {
1484       symMap.pushScope();
1485       mustPopSymMap = true;
1486       Fortran::lower::mapCallInterfaceSymbols(converter, caller, symMap);
1487     }
1488     // If this is an indirect call, retrieve the function address. Also retrieve
1489     // the result length if this is a character function (note that this length
1490     // will be used only if there is no explicit length in the local interface).
1491     mlir::Value funcPointer;
1492     mlir::Value charFuncPointerLength;
1493     if (const Fortran::semantics::Symbol *sym =
1494             caller.getIfIndirectCallSymbol()) {
1495       funcPointer = symMap.lookupSymbol(*sym).getAddr();
1496       if (!funcPointer)
1497         fir::emitFatalError(loc, "failed to find indirect call symbol address");
1498       if (fir::isCharacterProcedureTuple(funcPointer.getType(),
1499                                          /*acceptRawFunc=*/false))
1500         std::tie(funcPointer, charFuncPointerLength) =
1501             fir::factory::extractCharacterProcedureTuple(builder, loc,
1502                                                          funcPointer);
1503     }
1504 
1505     mlir::IndexType idxTy = builder.getIndexType();
1506     auto lowerSpecExpr = [&](const auto &expr) -> mlir::Value {
1507       return builder.createConvert(
1508           loc, idxTy, fir::getBase(converter.genExprValue(expr, stmtCtx)));
1509     };
1510     llvm::SmallVector<mlir::Value> resultLengths;
1511     auto allocatedResult = [&]() -> llvm::Optional<ExtValue> {
1512       llvm::SmallVector<mlir::Value> extents;
1513       llvm::SmallVector<mlir::Value> lengths;
1514       if (!caller.callerAllocateResult())
1515         return {};
1516       mlir::Type type = caller.getResultStorageType();
1517       if (type.isa<fir::SequenceType>())
1518         caller.walkResultExtents([&](const Fortran::lower::SomeExpr &e) {
1519           extents.emplace_back(lowerSpecExpr(e));
1520         });
1521       caller.walkResultLengths([&](const Fortran::lower::SomeExpr &e) {
1522         lengths.emplace_back(lowerSpecExpr(e));
1523       });
1524 
1525       // Result length parameters should not be provided to box storage
1526       // allocation and save_results, but they are still useful information to
1527       // keep in the ExtendedValue if non-deferred.
1528       if (!type.isa<fir::BoxType>()) {
1529         if (fir::isa_char(fir::unwrapSequenceType(type)) && lengths.empty()) {
1530           // Calling an assumed length function. This is only possible if this
1531           // is a call to a character dummy procedure.
1532           if (!charFuncPointerLength)
1533             fir::emitFatalError(loc, "failed to retrieve character function "
1534                                      "length while calling it");
1535           lengths.push_back(charFuncPointerLength);
1536         }
1537         resultLengths = lengths;
1538       }
1539 
1540       if (!extents.empty() || !lengths.empty()) {
1541         auto *bldr = &converter.getFirOpBuilder();
1542         auto stackSaveFn = fir::factory::getLlvmStackSave(builder);
1543         auto stackSaveSymbol = bldr->getSymbolRefAttr(stackSaveFn.getName());
1544         mlir::Value sp =
1545             bldr->create<fir::CallOp>(loc, stackSaveFn.getType().getResults(),
1546                                       stackSaveSymbol, mlir::ValueRange{})
1547                 .getResult(0);
1548         stmtCtx.attachCleanup([bldr, loc, sp]() {
1549           auto stackRestoreFn = fir::factory::getLlvmStackRestore(*bldr);
1550           auto stackRestoreSymbol =
1551               bldr->getSymbolRefAttr(stackRestoreFn.getName());
1552           bldr->create<fir::CallOp>(loc, stackRestoreFn.getType().getResults(),
1553                                     stackRestoreSymbol, mlir::ValueRange{sp});
1554         });
1555       }
1556       mlir::Value temp =
1557           builder.createTemporary(loc, type, ".result", extents, resultLengths);
1558       return toExtendedValue(loc, temp, extents, lengths);
1559     }();
1560 
1561     if (mustPopSymMap)
1562       symMap.popScope();
1563 
1564     // Place allocated result or prepare the fir.save_result arguments.
1565     mlir::Value arrayResultShape;
1566     if (allocatedResult) {
1567       if (std::optional<Fortran::lower::CallInterface<
1568               Fortran::lower::CallerInterface>::PassedEntity>
1569               resultArg = caller.getPassedResult()) {
1570         if (resultArg->passBy == PassBy::AddressAndLength)
1571           caller.placeAddressAndLengthInput(*resultArg,
1572                                             fir::getBase(*allocatedResult),
1573                                             fir::getLen(*allocatedResult));
1574         else if (resultArg->passBy == PassBy::BaseAddress)
1575           caller.placeInput(*resultArg, fir::getBase(*allocatedResult));
1576         else
1577           fir::emitFatalError(
1578               loc, "only expect character scalar result to be passed by ref");
1579       } else {
1580         assert(caller.mustSaveResult());
1581         arrayResultShape = allocatedResult->match(
1582             [&](const fir::CharArrayBoxValue &) {
1583               return builder.createShape(loc, *allocatedResult);
1584             },
1585             [&](const fir::ArrayBoxValue &) {
1586               return builder.createShape(loc, *allocatedResult);
1587             },
1588             [&](const auto &) { return mlir::Value{}; });
1589       }
1590     }
1591 
1592     // In older Fortran, procedure argument types are inferred. This may lead
1593     // different view of what the function signature is in different locations.
1594     // Casts are inserted as needed below to accommodate this.
1595 
1596     // The mlir::FuncOp type prevails, unless it has a different number of
1597     // arguments which can happen in legal program if it was passed as a dummy
1598     // procedure argument earlier with no further type information.
1599     mlir::SymbolRefAttr funcSymbolAttr;
1600     bool addHostAssociations = false;
1601     if (!funcPointer) {
1602       mlir::FunctionType funcOpType = caller.getFuncOp().getType();
1603       mlir::SymbolRefAttr symbolAttr =
1604           builder.getSymbolRefAttr(caller.getMangledName());
1605       if (callSiteType.getNumResults() == funcOpType.getNumResults() &&
1606           callSiteType.getNumInputs() + 1 == funcOpType.getNumInputs() &&
1607           fir::anyFuncArgsHaveAttr(caller.getFuncOp(),
1608                                    fir::getHostAssocAttrName())) {
1609         // The number of arguments is off by one, and we're lowering a function
1610         // with host associations. Modify call to include host associations
1611         // argument by appending the value at the end of the operands.
1612         assert(funcOpType.getInput(findHostAssocTuplePos(caller.getFuncOp())) ==
1613                converter.hostAssocTupleValue().getType());
1614         addHostAssociations = true;
1615       }
1616       if (!addHostAssociations &&
1617           (callSiteType.getNumResults() != funcOpType.getNumResults() ||
1618            callSiteType.getNumInputs() != funcOpType.getNumInputs())) {
1619         // Deal with argument number mismatch by making a function pointer so
1620         // that function type cast can be inserted. Do not emit a warning here
1621         // because this can happen in legal program if the function is not
1622         // defined here and it was first passed as an argument without any more
1623         // information.
1624         funcPointer =
1625             builder.create<fir::AddrOfOp>(loc, funcOpType, symbolAttr);
1626       } else if (callSiteType.getResults() != funcOpType.getResults()) {
1627         // Implicit interface result type mismatch are not standard Fortran, but
1628         // some compilers are not complaining about it.  The front end is not
1629         // protecting lowering from this currently. Support this with a
1630         // discouraging warning.
1631         LLVM_DEBUG(mlir::emitWarning(
1632             loc, "a return type mismatch is not standard compliant and may "
1633                  "lead to undefined behavior."));
1634         // Cast the actual function to the current caller implicit type because
1635         // that is the behavior we would get if we could not see the definition.
1636         funcPointer =
1637             builder.create<fir::AddrOfOp>(loc, funcOpType, symbolAttr);
1638       } else {
1639         funcSymbolAttr = symbolAttr;
1640       }
1641     }
1642 
1643     mlir::FunctionType funcType =
1644         funcPointer ? callSiteType : caller.getFuncOp().getType();
1645     llvm::SmallVector<mlir::Value> operands;
1646     // First operand of indirect call is the function pointer. Cast it to
1647     // required function type for the call to handle procedures that have a
1648     // compatible interface in Fortran, but that have different signatures in
1649     // FIR.
1650     if (funcPointer) {
1651       operands.push_back(
1652           funcPointer.getType().isa<fir::BoxProcType>()
1653               ? builder.create<fir::BoxAddrOp>(loc, funcType, funcPointer)
1654               : builder.createConvert(loc, funcType, funcPointer));
1655     }
1656 
1657     // Deal with potential mismatches in arguments types. Passing an array to a
1658     // scalar argument should for instance be tolerated here.
1659     bool callingImplicitInterface = caller.canBeCalledViaImplicitInterface();
1660     for (auto [fst, snd] :
1661          llvm::zip(caller.getInputs(), funcType.getInputs())) {
1662       // When passing arguments to a procedure that can be called an implicit
1663       // interface, allow character actual arguments to be passed to dummy
1664       // arguments of any type and vice versa
1665       mlir::Value cast;
1666       auto *context = builder.getContext();
1667       if (snd.isa<fir::BoxProcType>() &&
1668           fst.getType().isa<mlir::FunctionType>()) {
1669         auto funcTy = mlir::FunctionType::get(context, llvm::None, llvm::None);
1670         auto boxProcTy = builder.getBoxProcType(funcTy);
1671         if (mlir::Value host = argumentHostAssocs(converter, fst)) {
1672           cast = builder.create<fir::EmboxProcOp>(
1673               loc, boxProcTy, llvm::ArrayRef<mlir::Value>{fst, host});
1674         } else {
1675           cast = builder.create<fir::EmboxProcOp>(loc, boxProcTy, fst);
1676         }
1677       } else {
1678         cast = builder.convertWithSemantics(loc, snd, fst,
1679                                             callingImplicitInterface);
1680       }
1681       operands.push_back(cast);
1682     }
1683 
1684     // Add host associations as necessary.
1685     if (addHostAssociations)
1686       operands.push_back(converter.hostAssocTupleValue());
1687 
1688     auto call = builder.create<fir::CallOp>(loc, funcType.getResults(),
1689                                             funcSymbolAttr, operands);
1690 
1691     if (caller.mustSaveResult())
1692       builder.create<fir::SaveResultOp>(
1693           loc, call.getResult(0), fir::getBase(allocatedResult.getValue()),
1694           arrayResultShape, resultLengths);
1695 
1696     if (allocatedResult) {
1697       allocatedResult->match(
1698           [&](const fir::MutableBoxValue &box) {
1699             if (box.isAllocatable()) {
1700               // 9.7.3.2 point 4. Finalize allocatables.
1701               fir::FirOpBuilder *bldr = &converter.getFirOpBuilder();
1702               stmtCtx.attachCleanup([bldr, loc, box]() {
1703                 fir::factory::genFinalization(*bldr, loc, box);
1704               });
1705             }
1706           },
1707           [](const auto &) {});
1708       return *allocatedResult;
1709     }
1710 
1711     if (!resultType.hasValue())
1712       return mlir::Value{}; // subroutine call
1713     // For now, Fortran return values are implemented with a single MLIR
1714     // function return value.
1715     assert(call.getNumResults() == 1 &&
1716            "Expected exactly one result in FUNCTION call");
1717     return call.getResult(0);
1718   }
1719 
1720   /// Like genExtAddr, but ensure the address returned is a temporary even if \p
1721   /// expr is variable inside parentheses.
1722   ExtValue genTempExtAddr(const Fortran::lower::SomeExpr &expr) {
1723     // In general, genExtAddr might not create a temp for variable inside
1724     // parentheses to avoid creating array temporary in sub-expressions. It only
1725     // ensures the sub-expression is not re-associated with other parts of the
1726     // expression. In the call semantics, there is a difference between expr and
1727     // variable (see R1524). For expressions, a variable storage must not be
1728     // argument associated since it could be modified inside the call, or the
1729     // variable could also be modified by other means during the call.
1730     if (!isParenthesizedVariable(expr))
1731       return genExtAddr(expr);
1732     mlir::Location loc = getLoc();
1733     if (expr.Rank() > 0)
1734       TODO(loc, "genTempExtAddr array");
1735     return genExtValue(expr).match(
1736         [&](const fir::CharBoxValue &boxChar) -> ExtValue {
1737           TODO(loc, "genTempExtAddr CharBoxValue");
1738         },
1739         [&](const fir::UnboxedValue &v) -> ExtValue {
1740           mlir::Type type = v.getType();
1741           mlir::Value value = v;
1742           if (fir::isa_ref_type(type))
1743             value = builder.create<fir::LoadOp>(loc, value);
1744           mlir::Value temp = builder.createTemporary(loc, value.getType());
1745           builder.create<fir::StoreOp>(loc, value, temp);
1746           return temp;
1747         },
1748         [&](const fir::BoxValue &x) -> ExtValue {
1749           // Derived type scalar that may be polymorphic.
1750           assert(!x.hasRank() && x.isDerived());
1751           if (x.isDerivedWithLengthParameters())
1752             fir::emitFatalError(
1753                 loc, "making temps for derived type with length parameters");
1754           // TODO: polymorphic aspects should be kept but for now the temp
1755           // created always has the declared type.
1756           mlir::Value var =
1757               fir::getBase(fir::factory::readBoxValue(builder, loc, x));
1758           auto value = builder.create<fir::LoadOp>(loc, var);
1759           mlir::Value temp = builder.createTemporary(loc, value.getType());
1760           builder.create<fir::StoreOp>(loc, value, temp);
1761           return temp;
1762         },
1763         [&](const auto &) -> ExtValue {
1764           fir::emitFatalError(loc, "expr is not a scalar value");
1765         });
1766   }
1767 
1768   /// Helper structure to track potential copy-in of non contiguous variable
1769   /// argument into a contiguous temp. It is used to deallocate the temp that
1770   /// may have been created as well as to the copy-out from the temp to the
1771   /// variable after the call.
1772   struct CopyOutPair {
1773     ExtValue var;
1774     ExtValue temp;
1775     // Flag to indicate if the argument may have been modified by the
1776     // callee, in which case it must be copied-out to the variable.
1777     bool argMayBeModifiedByCall;
1778     // Optional boolean value that, if present and false, prevents
1779     // the copy-out and temp deallocation.
1780     llvm::Optional<mlir::Value> restrictCopyAndFreeAtRuntime;
1781   };
1782   using CopyOutPairs = llvm::SmallVector<CopyOutPair, 4>;
1783 
1784   /// Helper to read any fir::BoxValue into other fir::ExtendedValue categories
1785   /// not based on fir.box.
1786   /// This will lose any non contiguous stride information and dynamic type and
1787   /// should only be called if \p exv is known to be contiguous or if its base
1788   /// address will be replaced by a contiguous one. If \p exv is not a
1789   /// fir::BoxValue, this is a no-op.
1790   ExtValue readIfBoxValue(const ExtValue &exv) {
1791     if (const auto *box = exv.getBoxOf<fir::BoxValue>())
1792       return fir::factory::readBoxValue(builder, getLoc(), *box);
1793     return exv;
1794   }
1795 
1796   /// Generate a contiguous temp to pass \p actualArg as argument \p arg. The
1797   /// creation of the temp and copy-in can be made conditional at runtime by
1798   /// providing a runtime boolean flag \p restrictCopyAtRuntime (in which case
1799   /// the temp and copy will only be made if the value is true at runtime).
1800   ExtValue genCopyIn(const ExtValue &actualArg,
1801                      const Fortran::lower::CallerInterface::PassedEntity &arg,
1802                      CopyOutPairs &copyOutPairs,
1803                      llvm::Optional<mlir::Value> restrictCopyAtRuntime) {
1804     if (!restrictCopyAtRuntime) {
1805       ExtValue temp = genArrayTempFromMold(actualArg, ".copyinout");
1806       if (arg.mayBeReadByCall())
1807         genArrayCopy(temp, actualArg);
1808       copyOutPairs.emplace_back(CopyOutPair{
1809           actualArg, temp, arg.mayBeModifiedByCall(), restrictCopyAtRuntime});
1810       return temp;
1811     }
1812     // Otherwise, need to be careful to only copy-in if allowed at runtime.
1813     mlir::Location loc = getLoc();
1814     auto addrType = fir::HeapType::get(
1815         fir::unwrapPassByRefType(fir::getBase(actualArg).getType()));
1816     mlir::Value addr =
1817         builder
1818             .genIfOp(loc, {addrType}, *restrictCopyAtRuntime,
1819                      /*withElseRegion=*/true)
1820             .genThen([&]() {
1821               auto temp = genArrayTempFromMold(actualArg, ".copyinout");
1822               if (arg.mayBeReadByCall())
1823                 genArrayCopy(temp, actualArg);
1824               builder.create<fir::ResultOp>(loc, fir::getBase(temp));
1825             })
1826             .genElse([&]() {
1827               auto nullPtr = builder.createNullConstant(loc, addrType);
1828               builder.create<fir::ResultOp>(loc, nullPtr);
1829             })
1830             .getResults()[0];
1831     // Associate the temp address with actualArg lengths and extents.
1832     fir::ExtendedValue temp = fir::substBase(readIfBoxValue(actualArg), addr);
1833     copyOutPairs.emplace_back(CopyOutPair{
1834         actualArg, temp, arg.mayBeModifiedByCall(), restrictCopyAtRuntime});
1835     return temp;
1836   }
1837 
1838   /// Lower a non-elemental procedure reference.
1839   ExtValue genRawProcedureRef(const Fortran::evaluate::ProcedureRef &procRef,
1840                               llvm::Optional<mlir::Type> resultType) {
1841     mlir::Location loc = getLoc();
1842     if (isElementalProcWithArrayArgs(procRef))
1843       fir::emitFatalError(loc, "trying to lower elemental procedure with array "
1844                                "arguments as normal procedure");
1845     if (const Fortran::evaluate::SpecificIntrinsic *intrinsic =
1846             procRef.proc().GetSpecificIntrinsic())
1847       return genIntrinsicRef(procRef, *intrinsic, resultType);
1848 
1849     if (isStatementFunctionCall(procRef))
1850       TODO(loc, "Lower statement function call");
1851 
1852     Fortran::lower::CallerInterface caller(procRef, converter);
1853     using PassBy = Fortran::lower::CallerInterface::PassEntityBy;
1854 
1855     llvm::SmallVector<fir::MutableBoxValue> mutableModifiedByCall;
1856     // List of <var, temp> where temp must be copied into var after the call.
1857     CopyOutPairs copyOutPairs;
1858 
1859     mlir::FunctionType callSiteType = caller.genFunctionType();
1860 
1861     // Lower the actual arguments and map the lowered values to the dummy
1862     // arguments.
1863     for (const Fortran::lower::CallInterface<
1864              Fortran::lower::CallerInterface>::PassedEntity &arg :
1865          caller.getPassedArguments()) {
1866       const auto *actual = arg.entity;
1867       mlir::Type argTy = callSiteType.getInput(arg.firArgument);
1868       if (!actual) {
1869         // Optional dummy argument for which there is no actual argument.
1870         caller.placeInput(arg, builder.create<fir::AbsentOp>(loc, argTy));
1871         continue;
1872       }
1873       const auto *expr = actual->UnwrapExpr();
1874       if (!expr)
1875         TODO(loc, "assumed type actual argument lowering");
1876 
1877       if (arg.passBy == PassBy::Value) {
1878         ExtValue argVal = genval(*expr);
1879         if (!fir::isUnboxedValue(argVal))
1880           fir::emitFatalError(
1881               loc, "internal error: passing non trivial value by value");
1882         caller.placeInput(arg, fir::getBase(argVal));
1883         continue;
1884       }
1885 
1886       if (arg.passBy == PassBy::MutableBox) {
1887         if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
1888                 *expr)) {
1889           // If expr is NULL(), the mutableBox created must be a deallocated
1890           // pointer with the dummy argument characteristics (see table 16.5
1891           // in Fortran 2018 standard).
1892           // No length parameters are set for the created box because any non
1893           // deferred type parameters of the dummy will be evaluated on the
1894           // callee side, and it is illegal to use NULL without a MOLD if any
1895           // dummy length parameters are assumed.
1896           mlir::Type boxTy = fir::dyn_cast_ptrEleTy(argTy);
1897           assert(boxTy && boxTy.isa<fir::BoxType>() &&
1898                  "must be a fir.box type");
1899           mlir::Value boxStorage = builder.createTemporary(loc, boxTy);
1900           mlir::Value nullBox = fir::factory::createUnallocatedBox(
1901               builder, loc, boxTy, /*nonDeferredParams=*/{});
1902           builder.create<fir::StoreOp>(loc, nullBox, boxStorage);
1903           caller.placeInput(arg, boxStorage);
1904           continue;
1905         }
1906         fir::MutableBoxValue mutableBox = genMutableBoxValue(*expr);
1907         mlir::Value irBox =
1908             fir::factory::getMutableIRBox(builder, loc, mutableBox);
1909         caller.placeInput(arg, irBox);
1910         if (arg.mayBeModifiedByCall())
1911           mutableModifiedByCall.emplace_back(std::move(mutableBox));
1912         continue;
1913       }
1914       const bool actualArgIsVariable = Fortran::evaluate::IsVariable(*expr);
1915       if (arg.passBy == PassBy::BaseAddress || arg.passBy == PassBy::BoxChar) {
1916         const bool actualIsSimplyContiguous =
1917             !actualArgIsVariable || Fortran::evaluate::IsSimplyContiguous(
1918                                         *expr, converter.getFoldingContext());
1919         auto argAddr = [&]() -> ExtValue {
1920           ExtValue baseAddr;
1921           if (actualArgIsVariable && arg.isOptional()) {
1922             if (Fortran::evaluate::IsAllocatableOrPointerObject(
1923                     *expr, converter.getFoldingContext())) {
1924               TODO(loc, "Allocatable or pointer argument");
1925             }
1926             if (const Fortran::semantics::Symbol *wholeSymbol =
1927                     Fortran::evaluate::UnwrapWholeSymbolOrComponentDataRef(
1928                         *expr))
1929               if (Fortran::semantics::IsOptional(*wholeSymbol)) {
1930                 TODO(loc, "procedureref optional arg");
1931               }
1932             // Fall through: The actual argument can safely be
1933             // copied-in/copied-out without any care if needed.
1934           }
1935           if (actualArgIsVariable && expr->Rank() > 0) {
1936             ExtValue box = genBoxArg(*expr);
1937             if (!actualIsSimplyContiguous)
1938               return genCopyIn(box, arg, copyOutPairs,
1939                                /*restrictCopyAtRuntime=*/llvm::None);
1940             // Contiguous: just use the box we created above!
1941             // This gets "unboxed" below, if needed.
1942             return box;
1943           }
1944           // Actual argument is a non optional/non pointer/non allocatable
1945           // scalar.
1946           if (actualArgIsVariable)
1947             return genExtAddr(*expr);
1948           // Actual argument is not a variable. Make sure a variable address is
1949           // not passed.
1950           return genTempExtAddr(*expr);
1951         }();
1952         // Scalar and contiguous expressions may be lowered to a fir.box,
1953         // either to account for potential polymorphism, or because lowering
1954         // did not account for some contiguity hints.
1955         // Here, polymorphism does not matter (an entity of the declared type
1956         // is passed, not one of the dynamic type), and the expr is known to
1957         // be simply contiguous, so it is safe to unbox it and pass the
1958         // address without making a copy.
1959         argAddr = readIfBoxValue(argAddr);
1960 
1961         if (arg.passBy == PassBy::BaseAddress) {
1962           caller.placeInput(arg, fir::getBase(argAddr));
1963         } else {
1964           assert(arg.passBy == PassBy::BoxChar);
1965           auto helper = fir::factory::CharacterExprHelper{builder, loc};
1966           auto boxChar = argAddr.match(
1967               [&](const fir::CharBoxValue &x) { return helper.createEmbox(x); },
1968               [&](const fir::CharArrayBoxValue &x) {
1969                 return helper.createEmbox(x);
1970               },
1971               [&](const auto &x) -> mlir::Value {
1972                 // Fortran allows an actual argument of a completely different
1973                 // type to be passed to a procedure expecting a CHARACTER in the
1974                 // dummy argument position. When this happens, the data pointer
1975                 // argument is simply assumed to point to CHARACTER data and the
1976                 // LEN argument used is garbage. Simulate this behavior by
1977                 // free-casting the base address to be a !fir.char reference and
1978                 // setting the LEN argument to undefined. What could go wrong?
1979                 auto dataPtr = fir::getBase(x);
1980                 assert(!dataPtr.getType().template isa<fir::BoxType>());
1981                 return builder.convertWithSemantics(
1982                     loc, argTy, dataPtr,
1983                     /*allowCharacterConversion=*/true);
1984               });
1985           caller.placeInput(arg, boxChar);
1986         }
1987       } else if (arg.passBy == PassBy::Box) {
1988         // Before lowering to an address, handle the allocatable/pointer actual
1989         // argument to optional fir.box dummy. It is legal to pass
1990         // unallocated/disassociated entity to an optional. In this case, an
1991         // absent fir.box must be created instead of a fir.box with a null value
1992         // (Fortran 2018 15.5.2.12 point 1).
1993         if (arg.isOptional() && Fortran::evaluate::IsAllocatableOrPointerObject(
1994                                     *expr, converter.getFoldingContext())) {
1995           TODO(loc, "optional allocatable or pointer argument");
1996         } else {
1997           // Make sure a variable address is only passed if the expression is
1998           // actually a variable.
1999           mlir::Value box =
2000               actualArgIsVariable
2001                   ? builder.createBox(loc, genBoxArg(*expr))
2002                   : builder.createBox(getLoc(), genTempExtAddr(*expr));
2003           caller.placeInput(arg, box);
2004         }
2005       } else if (arg.passBy == PassBy::AddressAndLength) {
2006         ExtValue argRef = genExtAddr(*expr);
2007         caller.placeAddressAndLengthInput(arg, fir::getBase(argRef),
2008                                           fir::getLen(argRef));
2009       } else if (arg.passBy == PassBy::CharProcTuple) {
2010         TODO(loc, "procedureref CharProcTuple");
2011       } else {
2012         TODO(loc, "pass by value in non elemental function call");
2013       }
2014     }
2015 
2016     ExtValue result = genCallOpAndResult(caller, callSiteType, resultType);
2017 
2018     // // Copy-out temps that were created for non contiguous variable arguments
2019     // if
2020     // // needed.
2021     // for (const auto &copyOutPair : copyOutPairs)
2022     //   genCopyOut(copyOutPair);
2023 
2024     return result;
2025   }
2026 
2027   template <typename A>
2028   ExtValue genval(const Fortran::evaluate::FunctionRef<A> &funcRef) {
2029     ExtValue result = genFunctionRef(funcRef);
2030     if (result.rank() == 0 && fir::isa_ref_type(fir::getBase(result).getType()))
2031       return genLoad(result);
2032     return result;
2033   }
2034 
2035   ExtValue genval(const Fortran::evaluate::ProcedureRef &procRef) {
2036     llvm::Optional<mlir::Type> resTy;
2037     if (procRef.hasAlternateReturns())
2038       resTy = builder.getIndexType();
2039     return genProcedureRef(procRef, resTy);
2040   }
2041 
2042   /// Helper to lower intrinsic arguments for inquiry intrinsic.
2043   ExtValue
2044   lowerIntrinsicArgumentAsInquired(const Fortran::lower::SomeExpr &expr) {
2045     if (Fortran::evaluate::IsAllocatableOrPointerObject(
2046             expr, converter.getFoldingContext()))
2047       return genMutableBoxValue(expr);
2048     return gen(expr);
2049   }
2050 
2051   /// Helper to lower intrinsic arguments to a fir::BoxValue.
2052   /// It preserves all the non default lower bounds/non deferred length
2053   /// parameter information.
2054   ExtValue lowerIntrinsicArgumentAsBox(const Fortran::lower::SomeExpr &expr) {
2055     mlir::Location loc = getLoc();
2056     ExtValue exv = genBoxArg(expr);
2057     mlir::Value box = builder.createBox(loc, exv);
2058     return fir::BoxValue(
2059         box, fir::factory::getNonDefaultLowerBounds(builder, loc, exv),
2060         fir::factory::getNonDeferredLengthParams(exv));
2061   }
2062 
2063   /// Generate a call to an intrinsic function.
2064   ExtValue
2065   genIntrinsicRef(const Fortran::evaluate::ProcedureRef &procRef,
2066                   const Fortran::evaluate::SpecificIntrinsic &intrinsic,
2067                   llvm::Optional<mlir::Type> resultType) {
2068     llvm::SmallVector<ExtValue> operands;
2069 
2070     llvm::StringRef name = intrinsic.name;
2071     mlir::Location loc = getLoc();
2072 
2073     const Fortran::lower::IntrinsicArgumentLoweringRules *argLowering =
2074         Fortran::lower::getIntrinsicArgumentLowering(name);
2075     for (const auto &[arg, dummy] :
2076          llvm::zip(procRef.arguments(),
2077                    intrinsic.characteristics.value().dummyArguments)) {
2078       auto *expr = Fortran::evaluate::UnwrapExpr<Fortran::lower::SomeExpr>(arg);
2079       if (!expr) {
2080         // Absent optional.
2081         operands.emplace_back(Fortran::lower::getAbsentIntrinsicArgument());
2082         continue;
2083       }
2084       if (!argLowering) {
2085         // No argument lowering instruction, lower by value.
2086         operands.emplace_back(genval(*expr));
2087         continue;
2088       }
2089       // Ad-hoc argument lowering handling.
2090       Fortran::lower::ArgLoweringRule argRules =
2091           Fortran::lower::lowerIntrinsicArgumentAs(loc, *argLowering,
2092                                                    dummy.name);
2093       if (argRules.handleDynamicOptional &&
2094           Fortran::evaluate::MayBePassedAsAbsentOptional(
2095               *expr, converter.getFoldingContext())) {
2096         ExtValue optional = lowerIntrinsicArgumentAsInquired(*expr);
2097         mlir::Value isPresent = genActualIsPresentTest(builder, loc, optional);
2098         switch (argRules.lowerAs) {
2099         case Fortran::lower::LowerIntrinsicArgAs::Value:
2100           operands.emplace_back(
2101               genOptionalValue(builder, loc, optional, isPresent));
2102           continue;
2103         case Fortran::lower::LowerIntrinsicArgAs::Addr:
2104           operands.emplace_back(
2105               genOptionalAddr(builder, loc, optional, isPresent));
2106           continue;
2107         case Fortran::lower::LowerIntrinsicArgAs::Box:
2108           operands.emplace_back(
2109               genOptionalBox(builder, loc, optional, isPresent));
2110           continue;
2111         case Fortran::lower::LowerIntrinsicArgAs::Inquired:
2112           operands.emplace_back(optional);
2113           continue;
2114         }
2115         llvm_unreachable("bad switch");
2116       }
2117       switch (argRules.lowerAs) {
2118       case Fortran::lower::LowerIntrinsicArgAs::Value:
2119         operands.emplace_back(genval(*expr));
2120         continue;
2121       case Fortran::lower::LowerIntrinsicArgAs::Addr:
2122         operands.emplace_back(gen(*expr));
2123         continue;
2124       case Fortran::lower::LowerIntrinsicArgAs::Box:
2125         operands.emplace_back(lowerIntrinsicArgumentAsBox(*expr));
2126         continue;
2127       case Fortran::lower::LowerIntrinsicArgAs::Inquired:
2128         operands.emplace_back(lowerIntrinsicArgumentAsInquired(*expr));
2129         continue;
2130       }
2131       llvm_unreachable("bad switch");
2132     }
2133     // Let the intrinsic library lower the intrinsic procedure call
2134     return Fortran::lower::genIntrinsicCall(builder, getLoc(), name, resultType,
2135                                             operands, stmtCtx);
2136   }
2137 
2138   template <typename A>
2139   ExtValue genval(const Fortran::evaluate::Expr<A> &x) {
2140     if (isScalar(x) || Fortran::evaluate::UnwrapWholeSymbolDataRef(x) ||
2141         inInitializer)
2142       return std::visit([&](const auto &e) { return genval(e); }, x.u);
2143     return asArray(x);
2144   }
2145 
2146   /// Helper to detect Transformational function reference.
2147   template <typename T>
2148   bool isTransformationalRef(const T &) {
2149     return false;
2150   }
2151   template <typename T>
2152   bool isTransformationalRef(const Fortran::evaluate::FunctionRef<T> &funcRef) {
2153     return !funcRef.IsElemental() && funcRef.Rank();
2154   }
2155   template <typename T>
2156   bool isTransformationalRef(Fortran::evaluate::Expr<T> expr) {
2157     return std::visit([&](const auto &e) { return isTransformationalRef(e); },
2158                       expr.u);
2159   }
2160 
2161   template <typename A>
2162   ExtValue asArray(const A &x) {
2163     return Fortran::lower::createSomeArrayTempValue(converter, toEvExpr(x),
2164                                                     symMap, stmtCtx);
2165   }
2166 
2167   /// Lower an array value as an argument. This argument can be passed as a box
2168   /// value, so it may be possible to avoid making a temporary.
2169   template <typename A>
2170   ExtValue asArrayArg(const Fortran::evaluate::Expr<A> &x) {
2171     return std::visit([&](const auto &e) { return asArrayArg(e, x); }, x.u);
2172   }
2173   template <typename A, typename B>
2174   ExtValue asArrayArg(const Fortran::evaluate::Expr<A> &x, const B &y) {
2175     return std::visit([&](const auto &e) { return asArrayArg(e, y); }, x.u);
2176   }
2177   template <typename A, typename B>
2178   ExtValue asArrayArg(const Fortran::evaluate::Designator<A> &, const B &x) {
2179     // Designator is being passed as an argument to a procedure. Lower the
2180     // expression to a boxed value.
2181     auto someExpr = toEvExpr(x);
2182     return Fortran::lower::createBoxValue(getLoc(), converter, someExpr, symMap,
2183                                           stmtCtx);
2184   }
2185   template <typename A, typename B>
2186   ExtValue asArrayArg(const A &, const B &x) {
2187     // If the expression to pass as an argument is not a designator, then create
2188     // an array temp.
2189     return asArray(x);
2190   }
2191 
2192   template <typename A>
2193   ExtValue gen(const Fortran::evaluate::Expr<A> &x) {
2194     // Whole array symbols or components, and results of transformational
2195     // functions already have a storage and the scalar expression lowering path
2196     // is used to not create a new temporary storage.
2197     if (isScalar(x) ||
2198         Fortran::evaluate::UnwrapWholeSymbolOrComponentDataRef(x) ||
2199         isTransformationalRef(x))
2200       return std::visit([&](const auto &e) { return genref(e); }, x.u);
2201     if (useBoxArg)
2202       return asArrayArg(x);
2203     return asArray(x);
2204   }
2205 
2206   template <typename A>
2207   bool isScalar(const A &x) {
2208     return x.Rank() == 0;
2209   }
2210 
2211   template <int KIND>
2212   ExtValue genval(const Fortran::evaluate::Expr<Fortran::evaluate::Type<
2213                       Fortran::common::TypeCategory::Logical, KIND>> &exp) {
2214     return std::visit([&](const auto &e) { return genval(e); }, exp.u);
2215   }
2216 
2217   using RefSet =
2218       std::tuple<Fortran::evaluate::ComplexPart, Fortran::evaluate::Substring,
2219                  Fortran::evaluate::DataRef, Fortran::evaluate::Component,
2220                  Fortran::evaluate::ArrayRef, Fortran::evaluate::CoarrayRef,
2221                  Fortran::semantics::SymbolRef>;
2222   template <typename A>
2223   static constexpr bool inRefSet = Fortran::common::HasMember<A, RefSet>;
2224 
2225   template <typename A, typename = std::enable_if_t<inRefSet<A>>>
2226   ExtValue genref(const A &a) {
2227     return gen(a);
2228   }
2229   template <typename A>
2230   ExtValue genref(const A &a) {
2231     mlir::Type storageType = converter.genType(toEvExpr(a));
2232     return placeScalarValueInMemory(builder, getLoc(), genval(a), storageType);
2233   }
2234 
2235   template <typename A, template <typename> typename T,
2236             typename B = std::decay_t<T<A>>,
2237             std::enable_if_t<
2238                 std::is_same_v<B, Fortran::evaluate::Expr<A>> ||
2239                     std::is_same_v<B, Fortran::evaluate::Designator<A>> ||
2240                     std::is_same_v<B, Fortran::evaluate::FunctionRef<A>>,
2241                 bool> = true>
2242   ExtValue genref(const T<A> &x) {
2243     return gen(x);
2244   }
2245 
2246 private:
2247   mlir::Location location;
2248   Fortran::lower::AbstractConverter &converter;
2249   fir::FirOpBuilder &builder;
2250   Fortran::lower::StatementContext &stmtCtx;
2251   Fortran::lower::SymMap &symMap;
2252   InitializerData *inInitializer = nullptr;
2253   bool useBoxArg = false; // expression lowered as argument
2254 };
2255 } // namespace
2256 
2257 // Helper for changing the semantics in a given context. Preserves the current
2258 // semantics which is resumed when the "push" goes out of scope.
2259 #define PushSemantics(PushVal)                                                 \
2260   [[maybe_unused]] auto pushSemanticsLocalVariable##__LINE__ =                 \
2261       Fortran::common::ScopedSet(semant, PushVal);
2262 
2263 static bool isAdjustedArrayElementType(mlir::Type t) {
2264   return fir::isa_char(t) || fir::isa_derived(t) || t.isa<fir::SequenceType>();
2265 }
2266 
2267 /// Build an ExtendedValue from a fir.array<?x...?xT> without actually setting
2268 /// the actual extents and lengths. This is only to allow their propagation as
2269 /// ExtendedValue without triggering verifier failures when propagating
2270 /// character/arrays as unboxed values. Only the base of the resulting
2271 /// ExtendedValue should be used, it is undefined to use the length or extents
2272 /// of the extended value returned,
2273 inline static fir::ExtendedValue
2274 convertToArrayBoxValue(mlir::Location loc, fir::FirOpBuilder &builder,
2275                        mlir::Value val, mlir::Value len) {
2276   mlir::Type ty = fir::unwrapRefType(val.getType());
2277   mlir::IndexType idxTy = builder.getIndexType();
2278   auto seqTy = ty.cast<fir::SequenceType>();
2279   auto undef = builder.create<fir::UndefOp>(loc, idxTy);
2280   llvm::SmallVector<mlir::Value> extents(seqTy.getDimension(), undef);
2281   if (fir::isa_char(seqTy.getEleTy()))
2282     return fir::CharArrayBoxValue(val, len ? len : undef, extents);
2283   return fir::ArrayBoxValue(val, extents);
2284 }
2285 
2286 //===----------------------------------------------------------------------===//
2287 //
2288 // Lowering of scalar expressions in an explicit iteration space context.
2289 //
2290 //===----------------------------------------------------------------------===//
2291 
2292 // Shared code for creating a copy of a derived type element. This function is
2293 // called from a continuation.
2294 inline static fir::ArrayAmendOp
2295 createDerivedArrayAmend(mlir::Location loc, fir::ArrayLoadOp destLoad,
2296                         fir::FirOpBuilder &builder, fir::ArrayAccessOp destAcc,
2297                         const fir::ExtendedValue &elementExv, mlir::Type eleTy,
2298                         mlir::Value innerArg) {
2299   if (destLoad.getTypeparams().empty()) {
2300     fir::factory::genRecordAssignment(builder, loc, destAcc, elementExv);
2301   } else {
2302     auto boxTy = fir::BoxType::get(eleTy);
2303     auto toBox = builder.create<fir::EmboxOp>(loc, boxTy, destAcc.getResult(),
2304                                               mlir::Value{}, mlir::Value{},
2305                                               destLoad.getTypeparams());
2306     auto fromBox = builder.create<fir::EmboxOp>(
2307         loc, boxTy, fir::getBase(elementExv), mlir::Value{}, mlir::Value{},
2308         destLoad.getTypeparams());
2309     fir::factory::genRecordAssignment(builder, loc, fir::BoxValue(toBox),
2310                                       fir::BoxValue(fromBox));
2311   }
2312   return builder.create<fir::ArrayAmendOp>(loc, innerArg.getType(), innerArg,
2313                                            destAcc);
2314 }
2315 
2316 inline static fir::ArrayAmendOp
2317 createCharArrayAmend(mlir::Location loc, fir::FirOpBuilder &builder,
2318                      fir::ArrayAccessOp dstOp, mlir::Value &dstLen,
2319                      const fir::ExtendedValue &srcExv, mlir::Value innerArg,
2320                      llvm::ArrayRef<mlir::Value> bounds) {
2321   fir::CharBoxValue dstChar(dstOp, dstLen);
2322   fir::factory::CharacterExprHelper helper{builder, loc};
2323   if (!bounds.empty()) {
2324     dstChar = helper.createSubstring(dstChar, bounds);
2325     fir::factory::genCharacterCopy(fir::getBase(srcExv), fir::getLen(srcExv),
2326                                    dstChar.getAddr(), dstChar.getLen(), builder,
2327                                    loc);
2328     // Update the LEN to the substring's LEN.
2329     dstLen = dstChar.getLen();
2330   }
2331   // For a CHARACTER, we generate the element assignment loops inline.
2332   helper.createAssign(fir::ExtendedValue{dstChar}, srcExv);
2333   // Mark this array element as amended.
2334   mlir::Type ty = innerArg.getType();
2335   auto amend = builder.create<fir::ArrayAmendOp>(loc, ty, innerArg, dstOp);
2336   return amend;
2337 }
2338 
2339 //===----------------------------------------------------------------------===//
2340 //
2341 // Lowering of array expressions.
2342 //
2343 //===----------------------------------------------------------------------===//
2344 
2345 namespace {
2346 class ArrayExprLowering {
2347   using ExtValue = fir::ExtendedValue;
2348 
2349   /// Structure to keep track of lowered array operands in the
2350   /// array expression. Useful to later deduce the shape of the
2351   /// array expression.
2352   struct ArrayOperand {
2353     /// Array base (can be a fir.box).
2354     mlir::Value memref;
2355     /// ShapeOp, ShapeShiftOp or ShiftOp
2356     mlir::Value shape;
2357     /// SliceOp
2358     mlir::Value slice;
2359     /// Can this operand be absent ?
2360     bool mayBeAbsent = false;
2361   };
2362 
2363   using ImplicitSubscripts = Fortran::lower::details::ImplicitSubscripts;
2364   using PathComponent = Fortran::lower::PathComponent;
2365 
2366   /// Active iteration space.
2367   using IterationSpace = Fortran::lower::IterationSpace;
2368   using IterSpace = const Fortran::lower::IterationSpace &;
2369 
2370   /// Current continuation. Function that will generate IR for a single
2371   /// iteration of the pending iterative loop structure.
2372   using CC = Fortran::lower::GenerateElementalArrayFunc;
2373 
2374   /// Projection continuation. Function that will project one iteration space
2375   /// into another.
2376   using PC = std::function<IterationSpace(IterSpace)>;
2377   using ArrayBaseTy =
2378       std::variant<std::monostate, const Fortran::evaluate::ArrayRef *,
2379                    const Fortran::evaluate::DataRef *>;
2380   using ComponentPath = Fortran::lower::ComponentPath;
2381 
2382 public:
2383   //===--------------------------------------------------------------------===//
2384   // Regular array assignment
2385   //===--------------------------------------------------------------------===//
2386 
2387   /// Entry point for array assignments. Both the left-hand and right-hand sides
2388   /// can either be ExtendedValue or evaluate::Expr.
2389   template <typename TL, typename TR>
2390   static void lowerArrayAssignment(Fortran::lower::AbstractConverter &converter,
2391                                    Fortran::lower::SymMap &symMap,
2392                                    Fortran::lower::StatementContext &stmtCtx,
2393                                    const TL &lhs, const TR &rhs) {
2394     ArrayExprLowering ael{converter, stmtCtx, symMap,
2395                           ConstituentSemantics::CopyInCopyOut};
2396     ael.lowerArrayAssignment(lhs, rhs);
2397   }
2398 
2399   template <typename TL, typename TR>
2400   void lowerArrayAssignment(const TL &lhs, const TR &rhs) {
2401     mlir::Location loc = getLoc();
2402     /// Here the target subspace is not necessarily contiguous. The ArrayUpdate
2403     /// continuation is implicitly returned in `ccStoreToDest` and the ArrayLoad
2404     /// in `destination`.
2405     PushSemantics(ConstituentSemantics::ProjectedCopyInCopyOut);
2406     ccStoreToDest = genarr(lhs);
2407     determineShapeOfDest(lhs);
2408     semant = ConstituentSemantics::RefTransparent;
2409     ExtValue exv = lowerArrayExpression(rhs);
2410     if (explicitSpaceIsActive()) {
2411       explicitSpace->finalizeContext();
2412       builder.create<fir::ResultOp>(loc, fir::getBase(exv));
2413     } else {
2414       builder.create<fir::ArrayMergeStoreOp>(
2415           loc, destination, fir::getBase(exv), destination.getMemref(),
2416           destination.getSlice(), destination.getTypeparams());
2417     }
2418   }
2419 
2420   //===--------------------------------------------------------------------===//
2421   // Array assignment to allocatable array
2422   //===--------------------------------------------------------------------===//
2423 
2424   /// Entry point for assignment to allocatable array.
2425   static void lowerAllocatableArrayAssignment(
2426       Fortran::lower::AbstractConverter &converter,
2427       Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx,
2428       const Fortran::lower::SomeExpr &lhs, const Fortran::lower::SomeExpr &rhs,
2429       Fortran::lower::ExplicitIterSpace &explicitSpace,
2430       Fortran::lower::ImplicitIterSpace &implicitSpace) {
2431     ArrayExprLowering ael(converter, stmtCtx, symMap,
2432                           ConstituentSemantics::CopyInCopyOut, &explicitSpace,
2433                           &implicitSpace);
2434     ael.lowerAllocatableArrayAssignment(lhs, rhs);
2435   }
2436 
2437   /// Assignment to allocatable array.
2438   ///
2439   /// The semantics are reverse that of a "regular" array assignment. The rhs
2440   /// defines the iteration space of the computation and the lhs is
2441   /// resized/reallocated to fit if necessary.
2442   void lowerAllocatableArrayAssignment(const Fortran::lower::SomeExpr &lhs,
2443                                        const Fortran::lower::SomeExpr &rhs) {
2444     // With assignment to allocatable, we want to lower the rhs first and use
2445     // its shape to determine if we need to reallocate, etc.
2446     mlir::Location loc = getLoc();
2447     // FIXME: If the lhs is in an explicit iteration space, the assignment may
2448     // be to an array of allocatable arrays rather than a single allocatable
2449     // array.
2450     fir::MutableBoxValue mutableBox =
2451         createMutableBox(loc, converter, lhs, symMap);
2452     mlir::Type resultTy = converter.genType(rhs);
2453     if (rhs.Rank() > 0)
2454       determineShapeOfDest(rhs);
2455     auto rhsCC = [&]() {
2456       PushSemantics(ConstituentSemantics::RefTransparent);
2457       return genarr(rhs);
2458     }();
2459 
2460     llvm::SmallVector<mlir::Value> lengthParams;
2461     // Currently no safe way to gather length from rhs (at least for
2462     // character, it cannot be taken from array_loads since it may be
2463     // changed by concatenations).
2464     if ((mutableBox.isCharacter() && !mutableBox.hasNonDeferredLenParams()) ||
2465         mutableBox.isDerivedWithLengthParameters())
2466       TODO(loc, "gather rhs length parameters in assignment to allocatable");
2467 
2468     // The allocatable must take lower bounds from the expr if it is
2469     // reallocated and the right hand side is not a scalar.
2470     const bool takeLboundsIfRealloc = rhs.Rank() > 0;
2471     llvm::SmallVector<mlir::Value> lbounds;
2472     // When the reallocated LHS takes its lower bounds from the RHS,
2473     // they will be non default only if the RHS is a whole array
2474     // variable. Otherwise, lbounds is left empty and default lower bounds
2475     // will be used.
2476     if (takeLboundsIfRealloc &&
2477         Fortran::evaluate::UnwrapWholeSymbolOrComponentDataRef(rhs)) {
2478       assert(arrayOperands.size() == 1 &&
2479              "lbounds can only come from one array");
2480       std::vector<mlir::Value> lbs =
2481           fir::factory::getOrigins(arrayOperands[0].shape);
2482       lbounds.append(lbs.begin(), lbs.end());
2483     }
2484     fir::factory::MutableBoxReallocation realloc =
2485         fir::factory::genReallocIfNeeded(builder, loc, mutableBox, destShape,
2486                                          lengthParams);
2487     // Create ArrayLoad for the mutable box and save it into `destination`.
2488     PushSemantics(ConstituentSemantics::ProjectedCopyInCopyOut);
2489     ccStoreToDest = genarr(realloc.newValue);
2490     // If the rhs is scalar, get shape from the allocatable ArrayLoad.
2491     if (destShape.empty())
2492       destShape = getShape(destination);
2493     // Finish lowering the loop nest.
2494     assert(destination && "destination must have been set");
2495     ExtValue exv = lowerArrayExpression(rhsCC, resultTy);
2496     if (explicitSpaceIsActive()) {
2497       explicitSpace->finalizeContext();
2498       builder.create<fir::ResultOp>(loc, fir::getBase(exv));
2499     } else {
2500       builder.create<fir::ArrayMergeStoreOp>(
2501           loc, destination, fir::getBase(exv), destination.getMemref(),
2502           destination.getSlice(), destination.getTypeparams());
2503     }
2504     fir::factory::finalizeRealloc(builder, loc, mutableBox, lbounds,
2505                                   takeLboundsIfRealloc, realloc);
2506   }
2507 
2508   /// Entry point for when an array expression appears in a context where the
2509   /// result must be boxed. (BoxValue semantics.)
2510   static ExtValue
2511   lowerBoxedArrayExpression(Fortran::lower::AbstractConverter &converter,
2512                             Fortran::lower::SymMap &symMap,
2513                             Fortran::lower::StatementContext &stmtCtx,
2514                             const Fortran::lower::SomeExpr &expr) {
2515     ArrayExprLowering ael{converter, stmtCtx, symMap,
2516                           ConstituentSemantics::BoxValue};
2517     return ael.lowerBoxedArrayExpr(expr);
2518   }
2519 
2520   ExtValue lowerBoxedArrayExpr(const Fortran::lower::SomeExpr &exp) {
2521     return std::visit(
2522         [&](const auto &e) {
2523           auto f = genarr(e);
2524           ExtValue exv = f(IterationSpace{});
2525           if (fir::getBase(exv).getType().template isa<fir::BoxType>())
2526             return exv;
2527           fir::emitFatalError(getLoc(), "array must be emboxed");
2528         },
2529         exp.u);
2530   }
2531 
2532   /// Entry point into lowering an expression with rank. This entry point is for
2533   /// lowering a rhs expression, for example. (RefTransparent semantics.)
2534   static ExtValue
2535   lowerNewArrayExpression(Fortran::lower::AbstractConverter &converter,
2536                           Fortran::lower::SymMap &symMap,
2537                           Fortran::lower::StatementContext &stmtCtx,
2538                           const Fortran::lower::SomeExpr &expr) {
2539     ArrayExprLowering ael{converter, stmtCtx, symMap};
2540     ael.determineShapeOfDest(expr);
2541     ExtValue loopRes = ael.lowerArrayExpression(expr);
2542     fir::ArrayLoadOp dest = ael.destination;
2543     mlir::Value tempRes = dest.getMemref();
2544     fir::FirOpBuilder &builder = converter.getFirOpBuilder();
2545     mlir::Location loc = converter.getCurrentLocation();
2546     builder.create<fir::ArrayMergeStoreOp>(loc, dest, fir::getBase(loopRes),
2547                                            tempRes, dest.getSlice(),
2548                                            dest.getTypeparams());
2549 
2550     auto arrTy =
2551         fir::dyn_cast_ptrEleTy(tempRes.getType()).cast<fir::SequenceType>();
2552     if (auto charTy =
2553             arrTy.getEleTy().template dyn_cast<fir::CharacterType>()) {
2554       if (fir::characterWithDynamicLen(charTy))
2555         TODO(loc, "CHARACTER does not have constant LEN");
2556       mlir::Value len = builder.createIntegerConstant(
2557           loc, builder.getCharacterLengthType(), charTy.getLen());
2558       return fir::CharArrayBoxValue(tempRes, len, dest.getExtents());
2559     }
2560     return fir::ArrayBoxValue(tempRes, dest.getExtents());
2561   }
2562 
2563   // FIXME: should take multiple inner arguments.
2564   std::pair<IterationSpace, mlir::OpBuilder::InsertPoint>
2565   genImplicitLoops(mlir::ValueRange shape, mlir::Value innerArg) {
2566     mlir::Location loc = getLoc();
2567     mlir::IndexType idxTy = builder.getIndexType();
2568     mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
2569     mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
2570     llvm::SmallVector<mlir::Value> loopUppers;
2571 
2572     // Convert any implied shape to closed interval form. The fir.do_loop will
2573     // run from 0 to `extent - 1` inclusive.
2574     for (auto extent : shape)
2575       loopUppers.push_back(
2576           builder.create<mlir::arith::SubIOp>(loc, extent, one));
2577 
2578     // Iteration space is created with outermost columns, innermost rows
2579     llvm::SmallVector<fir::DoLoopOp> loops;
2580 
2581     const std::size_t loopDepth = loopUppers.size();
2582     llvm::SmallVector<mlir::Value> ivars;
2583 
2584     for (auto i : llvm::enumerate(llvm::reverse(loopUppers))) {
2585       if (i.index() > 0) {
2586         assert(!loops.empty());
2587         builder.setInsertionPointToStart(loops.back().getBody());
2588       }
2589       fir::DoLoopOp loop;
2590       if (innerArg) {
2591         loop = builder.create<fir::DoLoopOp>(
2592             loc, zero, i.value(), one, isUnordered(),
2593             /*finalCount=*/false, mlir::ValueRange{innerArg});
2594         innerArg = loop.getRegionIterArgs().front();
2595         if (explicitSpaceIsActive())
2596           explicitSpace->setInnerArg(0, innerArg);
2597       } else {
2598         loop = builder.create<fir::DoLoopOp>(loc, zero, i.value(), one,
2599                                              isUnordered(),
2600                                              /*finalCount=*/false);
2601       }
2602       ivars.push_back(loop.getInductionVar());
2603       loops.push_back(loop);
2604     }
2605 
2606     if (innerArg)
2607       for (std::remove_const_t<decltype(loopDepth)> i = 0; i + 1 < loopDepth;
2608            ++i) {
2609         builder.setInsertionPointToEnd(loops[i].getBody());
2610         builder.create<fir::ResultOp>(loc, loops[i + 1].getResult(0));
2611       }
2612 
2613     // Move insertion point to the start of the innermost loop in the nest.
2614     builder.setInsertionPointToStart(loops.back().getBody());
2615     // Set `afterLoopNest` to just after the entire loop nest.
2616     auto currPt = builder.saveInsertionPoint();
2617     builder.setInsertionPointAfter(loops[0]);
2618     auto afterLoopNest = builder.saveInsertionPoint();
2619     builder.restoreInsertionPoint(currPt);
2620 
2621     // Put the implicit loop variables in row to column order to match FIR's
2622     // Ops. (The loops were constructed from outermost column to innermost
2623     // row.)
2624     mlir::Value outerRes = loops[0].getResult(0);
2625     return {IterationSpace(innerArg, outerRes, llvm::reverse(ivars)),
2626             afterLoopNest};
2627   }
2628 
2629   /// Build the iteration space into which the array expression will be
2630   /// lowered. The resultType is used to create a temporary, if needed.
2631   std::pair<IterationSpace, mlir::OpBuilder::InsertPoint>
2632   genIterSpace(mlir::Type resultType) {
2633     mlir::Location loc = getLoc();
2634     llvm::SmallVector<mlir::Value> shape = genIterationShape();
2635     if (!destination) {
2636       // Allocate storage for the result if it is not already provided.
2637       destination = createAndLoadSomeArrayTemp(resultType, shape);
2638     }
2639 
2640     // Generate the lazy mask allocation, if one was given.
2641     if (ccPrelude.hasValue())
2642       ccPrelude.getValue()(shape);
2643 
2644     // Now handle the implicit loops.
2645     mlir::Value inner = explicitSpaceIsActive()
2646                             ? explicitSpace->getInnerArgs().front()
2647                             : destination.getResult();
2648     auto [iters, afterLoopNest] = genImplicitLoops(shape, inner);
2649     mlir::Value innerArg = iters.innerArgument();
2650 
2651     // Generate the mask conditional structure, if there are masks. Unlike the
2652     // explicit masks, which are interleaved, these mask expression appear in
2653     // the innermost loop.
2654     if (implicitSpaceHasMasks()) {
2655       // Recover the cached condition from the mask buffer.
2656       auto genCond = [&](Fortran::lower::FrontEndExpr e, IterSpace iters) {
2657         return implicitSpace->getBoundClosure(e)(iters);
2658       };
2659 
2660       // Handle the negated conditions in topological order of the WHERE
2661       // clauses. See 10.2.3.2p4 as to why this control structure is produced.
2662       for (llvm::SmallVector<Fortran::lower::FrontEndExpr> maskExprs :
2663            implicitSpace->getMasks()) {
2664         const std::size_t size = maskExprs.size() - 1;
2665         auto genFalseBlock = [&](const auto *e, auto &&cond) {
2666           auto ifOp = builder.create<fir::IfOp>(
2667               loc, mlir::TypeRange{innerArg.getType()}, fir::getBase(cond),
2668               /*withElseRegion=*/true);
2669           builder.create<fir::ResultOp>(loc, ifOp.getResult(0));
2670           builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
2671           builder.create<fir::ResultOp>(loc, innerArg);
2672           builder.setInsertionPointToStart(&ifOp.getElseRegion().front());
2673         };
2674         auto genTrueBlock = [&](const auto *e, auto &&cond) {
2675           auto ifOp = builder.create<fir::IfOp>(
2676               loc, mlir::TypeRange{innerArg.getType()}, fir::getBase(cond),
2677               /*withElseRegion=*/true);
2678           builder.create<fir::ResultOp>(loc, ifOp.getResult(0));
2679           builder.setInsertionPointToStart(&ifOp.getElseRegion().front());
2680           builder.create<fir::ResultOp>(loc, innerArg);
2681           builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
2682         };
2683         for (std::remove_const_t<decltype(size)> i = 0; i < size; ++i)
2684           if (const auto *e = maskExprs[i])
2685             genFalseBlock(e, genCond(e, iters));
2686 
2687         // The last condition is either non-negated or unconditionally negated.
2688         if (const auto *e = maskExprs[size])
2689           genTrueBlock(e, genCond(e, iters));
2690       }
2691     }
2692 
2693     // We're ready to lower the body (an assignment statement) for this context
2694     // of loop nests at this point.
2695     return {iters, afterLoopNest};
2696   }
2697 
2698   fir::ArrayLoadOp
2699   createAndLoadSomeArrayTemp(mlir::Type type,
2700                              llvm::ArrayRef<mlir::Value> shape) {
2701     if (ccLoadDest.hasValue())
2702       return ccLoadDest.getValue()(shape);
2703     auto seqTy = type.dyn_cast<fir::SequenceType>();
2704     assert(seqTy && "must be an array");
2705     mlir::Location loc = getLoc();
2706     // TODO: Need to thread the length parameters here. For character, they may
2707     // differ from the operands length (e.g concatenation). So the array loads
2708     // type parameters are not enough.
2709     if (auto charTy = seqTy.getEleTy().dyn_cast<fir::CharacterType>())
2710       if (charTy.hasDynamicLen())
2711         TODO(loc, "character array expression temp with dynamic length");
2712     if (auto recTy = seqTy.getEleTy().dyn_cast<fir::RecordType>())
2713       if (recTy.getNumLenParams() > 0)
2714         TODO(loc, "derived type array expression temp with length parameters");
2715     mlir::Value temp = seqTy.hasConstantShape()
2716                            ? builder.create<fir::AllocMemOp>(loc, type)
2717                            : builder.create<fir::AllocMemOp>(
2718                                  loc, type, ".array.expr", llvm::None, shape);
2719     fir::FirOpBuilder *bldr = &converter.getFirOpBuilder();
2720     stmtCtx.attachCleanup(
2721         [bldr, loc, temp]() { bldr->create<fir::FreeMemOp>(loc, temp); });
2722     mlir::Value shapeOp = genShapeOp(shape);
2723     return builder.create<fir::ArrayLoadOp>(loc, seqTy, temp, shapeOp,
2724                                             /*slice=*/mlir::Value{},
2725                                             llvm::None);
2726   }
2727 
2728   static fir::ShapeOp genShapeOp(mlir::Location loc, fir::FirOpBuilder &builder,
2729                                  llvm::ArrayRef<mlir::Value> shape) {
2730     mlir::IndexType idxTy = builder.getIndexType();
2731     llvm::SmallVector<mlir::Value> idxShape;
2732     for (auto s : shape)
2733       idxShape.push_back(builder.createConvert(loc, idxTy, s));
2734     auto shapeTy = fir::ShapeType::get(builder.getContext(), idxShape.size());
2735     return builder.create<fir::ShapeOp>(loc, shapeTy, idxShape);
2736   }
2737 
2738   fir::ShapeOp genShapeOp(llvm::ArrayRef<mlir::Value> shape) {
2739     return genShapeOp(getLoc(), builder, shape);
2740   }
2741 
2742   //===--------------------------------------------------------------------===//
2743   // Expression traversal and lowering.
2744   //===--------------------------------------------------------------------===//
2745 
2746   /// Lower the expression, \p x, in a scalar context.
2747   template <typename A>
2748   ExtValue asScalar(const A &x) {
2749     return ScalarExprLowering{getLoc(), converter, symMap, stmtCtx}.genval(x);
2750   }
2751 
2752   /// Lower the expression in a scalar context to a memory reference.
2753   template <typename A>
2754   ExtValue asScalarRef(const A &x) {
2755     return ScalarExprLowering{getLoc(), converter, symMap, stmtCtx}.gen(x);
2756   }
2757 
2758   /// Lower an expression without dereferencing any indirection that may be
2759   /// a nullptr (because this is an absent optional or unallocated/disassociated
2760   /// descriptor). The returned expression cannot be addressed directly, it is
2761   /// meant to inquire about its status before addressing the related entity.
2762   template <typename A>
2763   ExtValue asInquired(const A &x) {
2764     return ScalarExprLowering{getLoc(), converter, symMap, stmtCtx}
2765         .lowerIntrinsicArgumentAsInquired(x);
2766   }
2767 
2768   // An expression with non-zero rank is an array expression.
2769   template <typename A>
2770   bool isArray(const A &x) const {
2771     return x.Rank() != 0;
2772   }
2773 
2774   /// Some temporaries are allocated on an element-by-element basis during the
2775   /// array expression evaluation. Collect the cleanups here so the resources
2776   /// can be freed before the next loop iteration, avoiding memory leaks. etc.
2777   Fortran::lower::StatementContext &getElementCtx() {
2778     if (!elementCtx) {
2779       stmtCtx.pushScope();
2780       elementCtx = true;
2781     }
2782     return stmtCtx;
2783   }
2784 
2785   /// If there were temporaries created for this element evaluation, finalize
2786   /// and deallocate the resources now. This should be done just prior the the
2787   /// fir::ResultOp at the end of the innermost loop.
2788   void finalizeElementCtx() {
2789     if (elementCtx) {
2790       stmtCtx.finalize(/*popScope=*/true);
2791       elementCtx = false;
2792     }
2793   }
2794 
2795   /// Lower an elemental function array argument. This ensures array
2796   /// sub-expressions that are not variables and must be passed by address
2797   /// are lowered by value and placed in memory.
2798   template <typename A>
2799   CC genElementalArgument(const A &x) {
2800     // Ensure the returned element is in memory if this is what was requested.
2801     if ((semant == ConstituentSemantics::RefOpaque ||
2802          semant == ConstituentSemantics::DataAddr ||
2803          semant == ConstituentSemantics::ByValueArg)) {
2804       if (!Fortran::evaluate::IsVariable(x)) {
2805         PushSemantics(ConstituentSemantics::DataValue);
2806         CC cc = genarr(x);
2807         mlir::Location loc = getLoc();
2808         if (isParenthesizedVariable(x)) {
2809           // Parenthesised variables are lowered to a reference to the variable
2810           // storage. When passing it as an argument, a copy must be passed.
2811           return [=](IterSpace iters) -> ExtValue {
2812             return createInMemoryScalarCopy(builder, loc, cc(iters));
2813           };
2814         }
2815         mlir::Type storageType =
2816             fir::unwrapSequenceType(converter.genType(toEvExpr(x)));
2817         return [=](IterSpace iters) -> ExtValue {
2818           return placeScalarValueInMemory(builder, loc, cc(iters), storageType);
2819         };
2820       }
2821     }
2822     return genarr(x);
2823   }
2824 
2825   // A procedure reference to a Fortran elemental intrinsic procedure.
2826   CC genElementalIntrinsicProcRef(
2827       const Fortran::evaluate::ProcedureRef &procRef,
2828       llvm::Optional<mlir::Type> retTy,
2829       const Fortran::evaluate::SpecificIntrinsic &intrinsic) {
2830     llvm::SmallVector<CC> operands;
2831     llvm::StringRef name = intrinsic.name;
2832     const Fortran::lower::IntrinsicArgumentLoweringRules *argLowering =
2833         Fortran::lower::getIntrinsicArgumentLowering(name);
2834     mlir::Location loc = getLoc();
2835     if (Fortran::lower::intrinsicRequiresCustomOptionalHandling(
2836             procRef, intrinsic, converter)) {
2837       using CcPairT = std::pair<CC, llvm::Optional<mlir::Value>>;
2838       llvm::SmallVector<CcPairT> operands;
2839       auto prepareOptionalArg = [&](const Fortran::lower::SomeExpr &expr) {
2840         if (expr.Rank() == 0) {
2841           ExtValue optionalArg = this->asInquired(expr);
2842           mlir::Value isPresent =
2843               genActualIsPresentTest(builder, loc, optionalArg);
2844           operands.emplace_back(
2845               [=](IterSpace iters) -> ExtValue {
2846                 return genLoad(builder, loc, optionalArg);
2847               },
2848               isPresent);
2849         } else {
2850           auto [cc, isPresent, _] = this->genOptionalArrayFetch(expr);
2851           operands.emplace_back(cc, isPresent);
2852         }
2853       };
2854       auto prepareOtherArg = [&](const Fortran::lower::SomeExpr &expr) {
2855         PushSemantics(ConstituentSemantics::RefTransparent);
2856         operands.emplace_back(genElementalArgument(expr), llvm::None);
2857       };
2858       Fortran::lower::prepareCustomIntrinsicArgument(
2859           procRef, intrinsic, retTy, prepareOptionalArg, prepareOtherArg,
2860           converter);
2861 
2862       fir::FirOpBuilder *bldr = &converter.getFirOpBuilder();
2863       llvm::StringRef name = intrinsic.name;
2864       return [=](IterSpace iters) -> ExtValue {
2865         auto getArgument = [&](std::size_t i) -> ExtValue {
2866           return operands[i].first(iters);
2867         };
2868         auto isPresent = [&](std::size_t i) -> llvm::Optional<mlir::Value> {
2869           return operands[i].second;
2870         };
2871         return Fortran::lower::lowerCustomIntrinsic(
2872             *bldr, loc, name, retTy, isPresent, getArgument, operands.size(),
2873             getElementCtx());
2874       };
2875     }
2876     /// Otherwise, pre-lower arguments and use intrinsic lowering utility.
2877     for (const auto &[arg, dummy] :
2878          llvm::zip(procRef.arguments(),
2879                    intrinsic.characteristics.value().dummyArguments)) {
2880       const auto *expr =
2881           Fortran::evaluate::UnwrapExpr<Fortran::lower::SomeExpr>(arg);
2882       if (!expr) {
2883         // Absent optional.
2884         operands.emplace_back([=](IterSpace) { return mlir::Value{}; });
2885       } else if (!argLowering) {
2886         // No argument lowering instruction, lower by value.
2887         PushSemantics(ConstituentSemantics::RefTransparent);
2888         operands.emplace_back(genElementalArgument(*expr));
2889       } else {
2890         // Ad-hoc argument lowering handling.
2891         Fortran::lower::ArgLoweringRule argRules =
2892             Fortran::lower::lowerIntrinsicArgumentAs(getLoc(), *argLowering,
2893                                                      dummy.name);
2894         if (argRules.handleDynamicOptional &&
2895             Fortran::evaluate::MayBePassedAsAbsentOptional(
2896                 *expr, converter.getFoldingContext())) {
2897           // Currently, there is not elemental intrinsic that requires lowering
2898           // a potentially absent argument to something else than a value (apart
2899           // from character MAX/MIN that are handled elsewhere.)
2900           if (argRules.lowerAs != Fortran::lower::LowerIntrinsicArgAs::Value)
2901             TODO(loc, "lowering non trivial optional elemental intrinsic array "
2902                       "argument");
2903           PushSemantics(ConstituentSemantics::RefTransparent);
2904           operands.emplace_back(genarrForwardOptionalArgumentToCall(*expr));
2905           continue;
2906         }
2907         switch (argRules.lowerAs) {
2908         case Fortran::lower::LowerIntrinsicArgAs::Value: {
2909           PushSemantics(ConstituentSemantics::RefTransparent);
2910           operands.emplace_back(genElementalArgument(*expr));
2911         } break;
2912         case Fortran::lower::LowerIntrinsicArgAs::Addr: {
2913           // Note: assume does not have Fortran VALUE attribute semantics.
2914           PushSemantics(ConstituentSemantics::RefOpaque);
2915           operands.emplace_back(genElementalArgument(*expr));
2916         } break;
2917         case Fortran::lower::LowerIntrinsicArgAs::Box: {
2918           PushSemantics(ConstituentSemantics::RefOpaque);
2919           auto lambda = genElementalArgument(*expr);
2920           operands.emplace_back([=](IterSpace iters) {
2921             return builder.createBox(loc, lambda(iters));
2922           });
2923         } break;
2924         case Fortran::lower::LowerIntrinsicArgAs::Inquired:
2925           TODO(loc, "intrinsic function with inquired argument");
2926           break;
2927         }
2928       }
2929     }
2930 
2931     // Let the intrinsic library lower the intrinsic procedure call
2932     return [=](IterSpace iters) {
2933       llvm::SmallVector<ExtValue> args;
2934       for (const auto &cc : operands)
2935         args.push_back(cc(iters));
2936       return Fortran::lower::genIntrinsicCall(builder, loc, name, retTy, args,
2937                                               getElementCtx());
2938     };
2939   }
2940 
2941   /// Generate a procedure reference. This code is shared for both functions and
2942   /// subroutines, the difference being reflected by `retTy`.
2943   CC genProcRef(const Fortran::evaluate::ProcedureRef &procRef,
2944                 llvm::Optional<mlir::Type> retTy) {
2945     mlir::Location loc = getLoc();
2946     if (procRef.IsElemental()) {
2947       if (const Fortran::evaluate::SpecificIntrinsic *intrin =
2948               procRef.proc().GetSpecificIntrinsic()) {
2949         // All elemental intrinsic functions are pure and cannot modify their
2950         // arguments. The only elemental subroutine, MVBITS has an Intent(inout)
2951         // argument. So for this last one, loops must be in element order
2952         // according to 15.8.3 p1.
2953         if (!retTy)
2954           setUnordered(false);
2955 
2956         // Elemental intrinsic call.
2957         // The intrinsic procedure is called once per element of the array.
2958         return genElementalIntrinsicProcRef(procRef, retTy, *intrin);
2959       }
2960       if (ScalarExprLowering::isStatementFunctionCall(procRef))
2961         fir::emitFatalError(loc, "statement function cannot be elemental");
2962 
2963       TODO(loc, "elemental user defined proc ref");
2964     }
2965 
2966     // Transformational call.
2967     // The procedure is called once and produces a value of rank > 0.
2968     if (const Fortran::evaluate::SpecificIntrinsic *intrinsic =
2969             procRef.proc().GetSpecificIntrinsic()) {
2970       if (explicitSpaceIsActive() && procRef.Rank() == 0) {
2971         // Elide any implicit loop iters.
2972         return [=, &procRef](IterSpace) {
2973           return ScalarExprLowering{loc, converter, symMap, stmtCtx}
2974               .genIntrinsicRef(procRef, *intrinsic, retTy);
2975         };
2976       }
2977       return genarr(
2978           ScalarExprLowering{loc, converter, symMap, stmtCtx}.genIntrinsicRef(
2979               procRef, *intrinsic, retTy));
2980     }
2981 
2982     if (explicitSpaceIsActive() && procRef.Rank() == 0) {
2983       // Elide any implicit loop iters.
2984       return [=, &procRef](IterSpace) {
2985         return ScalarExprLowering{loc, converter, symMap, stmtCtx}
2986             .genProcedureRef(procRef, retTy);
2987       };
2988     }
2989     // In the default case, the call can be hoisted out of the loop nest. Apply
2990     // the iterations to the result, which may be an array value.
2991     return genarr(
2992         ScalarExprLowering{loc, converter, symMap, stmtCtx}.genProcedureRef(
2993             procRef, retTy));
2994   }
2995 
2996   template <typename A>
2997   CC genScalarAndForwardValue(const A &x) {
2998     ExtValue result = asScalar(x);
2999     return [=](IterSpace) { return result; };
3000   }
3001 
3002   template <typename A, typename = std::enable_if_t<Fortran::common::HasMember<
3003                             A, Fortran::evaluate::TypelessExpression>>>
3004   CC genarr(const A &x) {
3005     return genScalarAndForwardValue(x);
3006   }
3007 
3008   template <typename A>
3009   CC genarr(const Fortran::evaluate::Expr<A> &x) {
3010     LLVM_DEBUG(Fortran::lower::DumpEvaluateExpr::dump(llvm::dbgs(), x));
3011     if (isArray(x) || explicitSpaceIsActive() ||
3012         isElementalProcWithArrayArgs(x))
3013       return std::visit([&](const auto &e) { return genarr(e); }, x.u);
3014     return genScalarAndForwardValue(x);
3015   }
3016 
3017   template <Fortran::common::TypeCategory TC1, int KIND,
3018             Fortran::common::TypeCategory TC2>
3019   CC genarr(const Fortran::evaluate::Convert<Fortran::evaluate::Type<TC1, KIND>,
3020                                              TC2> &x) {
3021     TODO(getLoc(), "");
3022   }
3023 
3024   template <int KIND>
3025   CC genarr(const Fortran::evaluate::ComplexComponent<KIND> &x) {
3026     TODO(getLoc(), "");
3027   }
3028 
3029   template <typename T>
3030   CC genarr(const Fortran::evaluate::Parentheses<T> &x) {
3031     TODO(getLoc(), "");
3032   }
3033 
3034   template <int KIND>
3035   CC genarr(const Fortran::evaluate::Negate<Fortran::evaluate::Type<
3036                 Fortran::common::TypeCategory::Integer, KIND>> &x) {
3037     TODO(getLoc(), "");
3038   }
3039 
3040   template <int KIND>
3041   CC genarr(const Fortran::evaluate::Negate<Fortran::evaluate::Type<
3042                 Fortran::common::TypeCategory::Real, KIND>> &x) {
3043     TODO(getLoc(), "");
3044   }
3045   template <int KIND>
3046   CC genarr(const Fortran::evaluate::Negate<Fortran::evaluate::Type<
3047                 Fortran::common::TypeCategory::Complex, KIND>> &x) {
3048     TODO(getLoc(), "");
3049   }
3050 
3051   //===--------------------------------------------------------------------===//
3052   // Binary elemental ops
3053   //===--------------------------------------------------------------------===//
3054 
3055   template <typename OP, typename A>
3056   CC createBinaryOp(const A &evEx) {
3057     mlir::Location loc = getLoc();
3058     auto lambda = genarr(evEx.left());
3059     auto rf = genarr(evEx.right());
3060     return [=](IterSpace iters) -> ExtValue {
3061       mlir::Value left = fir::getBase(lambda(iters));
3062       mlir::Value right = fir::getBase(rf(iters));
3063       return builder.create<OP>(loc, left, right);
3064     };
3065   }
3066 
3067 #undef GENBIN
3068 #define GENBIN(GenBinEvOp, GenBinTyCat, GenBinFirOp)                           \
3069   template <int KIND>                                                          \
3070   CC genarr(const Fortran::evaluate::GenBinEvOp<Fortran::evaluate::Type<       \
3071                 Fortran::common::TypeCategory::GenBinTyCat, KIND>> &x) {       \
3072     return createBinaryOp<GenBinFirOp>(x);                                     \
3073   }
3074 
3075   GENBIN(Add, Integer, mlir::arith::AddIOp)
3076   GENBIN(Add, Real, mlir::arith::AddFOp)
3077   GENBIN(Add, Complex, fir::AddcOp)
3078   GENBIN(Subtract, Integer, mlir::arith::SubIOp)
3079   GENBIN(Subtract, Real, mlir::arith::SubFOp)
3080   GENBIN(Subtract, Complex, fir::SubcOp)
3081   GENBIN(Multiply, Integer, mlir::arith::MulIOp)
3082   GENBIN(Multiply, Real, mlir::arith::MulFOp)
3083   GENBIN(Multiply, Complex, fir::MulcOp)
3084   GENBIN(Divide, Integer, mlir::arith::DivSIOp)
3085   GENBIN(Divide, Real, mlir::arith::DivFOp)
3086   GENBIN(Divide, Complex, fir::DivcOp)
3087 
3088   template <Fortran::common::TypeCategory TC, int KIND>
3089   CC genarr(
3090       const Fortran::evaluate::Power<Fortran::evaluate::Type<TC, KIND>> &x) {
3091     TODO(getLoc(), "genarr Power<Fortran::evaluate::Type<TC, KIND>>");
3092   }
3093   template <Fortran::common::TypeCategory TC, int KIND>
3094   CC genarr(
3095       const Fortran::evaluate::Extremum<Fortran::evaluate::Type<TC, KIND>> &x) {
3096     TODO(getLoc(), "genarr Extremum<Fortran::evaluate::Type<TC, KIND>>");
3097   }
3098   template <Fortran::common::TypeCategory TC, int KIND>
3099   CC genarr(
3100       const Fortran::evaluate::RealToIntPower<Fortran::evaluate::Type<TC, KIND>>
3101           &x) {
3102     TODO(getLoc(), "genarr RealToIntPower<Fortran::evaluate::Type<TC, KIND>>");
3103   }
3104   template <int KIND>
3105   CC genarr(const Fortran::evaluate::ComplexConstructor<KIND> &x) {
3106     TODO(getLoc(), "genarr ComplexConstructor<KIND>");
3107   }
3108 
3109   template <int KIND>
3110   CC genarr(const Fortran::evaluate::Concat<KIND> &x) {
3111     TODO(getLoc(), "genarr Concat<KIND>");
3112   }
3113 
3114   template <int KIND>
3115   CC genarr(const Fortran::evaluate::SetLength<KIND> &x) {
3116     TODO(getLoc(), "genarr SetLength<KIND>");
3117   }
3118 
3119   template <typename A>
3120   CC genarr(const Fortran::evaluate::Constant<A> &x) {
3121     if (/*explicitSpaceIsActive() &&*/ x.Rank() == 0)
3122       return genScalarAndForwardValue(x);
3123     mlir::Location loc = getLoc();
3124     mlir::IndexType idxTy = builder.getIndexType();
3125     mlir::Type arrTy = converter.genType(toEvExpr(x));
3126     std::string globalName = Fortran::lower::mangle::mangleArrayLiteral(x);
3127     fir::GlobalOp global = builder.getNamedGlobal(globalName);
3128     if (!global) {
3129       mlir::Type symTy = arrTy;
3130       mlir::Type eleTy = symTy.cast<fir::SequenceType>().getEleTy();
3131       // If we have a rank-1 array of integer, real, or logical, then we can
3132       // create a global array with the dense attribute.
3133       //
3134       // The mlir tensor type can only handle integer, real, or logical. It
3135       // does not currently support nested structures which is required for
3136       // complex.
3137       //
3138       // Also, we currently handle just rank-1 since tensor type assumes
3139       // row major array ordering. We will need to reorder the dimensions
3140       // in the tensor type to support Fortran's column major array ordering.
3141       // How to create this tensor type is to be determined.
3142       if (x.Rank() == 1 &&
3143           eleTy.isa<fir::LogicalType, mlir::IntegerType, mlir::FloatType>())
3144         global = Fortran::lower::createDenseGlobal(
3145             loc, arrTy, globalName, builder.createInternalLinkage(), true,
3146             toEvExpr(x), converter);
3147       // Note: If call to createDenseGlobal() returns 0, then call
3148       // createGlobalConstant() below.
3149       if (!global)
3150         global = builder.createGlobalConstant(
3151             loc, arrTy, globalName,
3152             [&](fir::FirOpBuilder &builder) {
3153               Fortran::lower::StatementContext stmtCtx(
3154                   /*cleanupProhibited=*/true);
3155               fir::ExtendedValue result =
3156                   Fortran::lower::createSomeInitializerExpression(
3157                       loc, converter, toEvExpr(x), symMap, stmtCtx);
3158               mlir::Value castTo =
3159                   builder.createConvert(loc, arrTy, fir::getBase(result));
3160               builder.create<fir::HasValueOp>(loc, castTo);
3161             },
3162             builder.createInternalLinkage());
3163     }
3164     auto addr = builder.create<fir::AddrOfOp>(getLoc(), global.resultType(),
3165                                               global.getSymbol());
3166     auto seqTy = global.getType().cast<fir::SequenceType>();
3167     llvm::SmallVector<mlir::Value> extents;
3168     for (auto extent : seqTy.getShape())
3169       extents.push_back(builder.createIntegerConstant(loc, idxTy, extent));
3170     if (auto charTy = seqTy.getEleTy().dyn_cast<fir::CharacterType>()) {
3171       mlir::Value len = builder.createIntegerConstant(loc, builder.getI64Type(),
3172                                                       charTy.getLen());
3173       return genarr(fir::CharArrayBoxValue{addr, len, extents});
3174     }
3175     return genarr(fir::ArrayBoxValue{addr, extents});
3176   }
3177 
3178   CC genarr(const Fortran::semantics::SymbolRef &sym,
3179             ComponentPath &components) {
3180     return genarr(sym.get(), components);
3181   }
3182 
3183   ExtValue abstractArrayExtValue(mlir::Value val, mlir::Value len = {}) {
3184     return convertToArrayBoxValue(getLoc(), builder, val, len);
3185   }
3186 
3187   CC genarr(const ExtValue &extMemref) {
3188     ComponentPath dummy(/*isImplicit=*/true);
3189     return genarr(extMemref, dummy);
3190   }
3191 
3192   //===--------------------------------------------------------------------===//
3193   // Array construction
3194   //===--------------------------------------------------------------------===//
3195 
3196   /// Target agnostic computation of the size of an element in the array.
3197   /// Returns the size in bytes with type `index` or a null Value if the element
3198   /// size is not constant.
3199   mlir::Value computeElementSize(const ExtValue &exv, mlir::Type eleTy,
3200                                  mlir::Type resTy) {
3201     mlir::Location loc = getLoc();
3202     mlir::IndexType idxTy = builder.getIndexType();
3203     mlir::Value multiplier = builder.createIntegerConstant(loc, idxTy, 1);
3204     if (fir::hasDynamicSize(eleTy)) {
3205       if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) {
3206         // Array of char with dynamic length parameter. Downcast to an array
3207         // of singleton char, and scale by the len type parameter from
3208         // `exv`.
3209         exv.match(
3210             [&](const fir::CharBoxValue &cb) { multiplier = cb.getLen(); },
3211             [&](const fir::CharArrayBoxValue &cb) { multiplier = cb.getLen(); },
3212             [&](const fir::BoxValue &box) {
3213               multiplier = fir::factory::CharacterExprHelper(builder, loc)
3214                                .readLengthFromBox(box.getAddr());
3215             },
3216             [&](const fir::MutableBoxValue &box) {
3217               multiplier = fir::factory::CharacterExprHelper(builder, loc)
3218                                .readLengthFromBox(box.getAddr());
3219             },
3220             [&](const auto &) {
3221               fir::emitFatalError(loc,
3222                                   "array constructor element has unknown size");
3223             });
3224         fir::CharacterType newEleTy = fir::CharacterType::getSingleton(
3225             eleTy.getContext(), charTy.getFKind());
3226         if (auto seqTy = resTy.dyn_cast<fir::SequenceType>()) {
3227           assert(eleTy == seqTy.getEleTy());
3228           resTy = fir::SequenceType::get(seqTy.getShape(), newEleTy);
3229         }
3230         eleTy = newEleTy;
3231       } else {
3232         TODO(loc, "dynamic sized type");
3233       }
3234     }
3235     mlir::Type eleRefTy = builder.getRefType(eleTy);
3236     mlir::Type resRefTy = builder.getRefType(resTy);
3237     mlir::Value nullPtr = builder.createNullConstant(loc, resRefTy);
3238     auto offset = builder.create<fir::CoordinateOp>(
3239         loc, eleRefTy, nullPtr, mlir::ValueRange{multiplier});
3240     return builder.createConvert(loc, idxTy, offset);
3241   }
3242 
3243   /// Get the function signature of the LLVM memcpy intrinsic.
3244   mlir::FunctionType memcpyType() {
3245     return fir::factory::getLlvmMemcpy(builder).getType();
3246   }
3247 
3248   /// Create a call to the LLVM memcpy intrinsic.
3249   void createCallMemcpy(llvm::ArrayRef<mlir::Value> args) {
3250     mlir::Location loc = getLoc();
3251     mlir::FuncOp memcpyFunc = fir::factory::getLlvmMemcpy(builder);
3252     mlir::SymbolRefAttr funcSymAttr =
3253         builder.getSymbolRefAttr(memcpyFunc.getName());
3254     mlir::FunctionType funcTy = memcpyFunc.getType();
3255     builder.create<fir::CallOp>(loc, funcTy.getResults(), funcSymAttr, args);
3256   }
3257 
3258   // Construct code to check for a buffer overrun and realloc the buffer when
3259   // space is depleted. This is done between each item in the ac-value-list.
3260   mlir::Value growBuffer(mlir::Value mem, mlir::Value needed,
3261                          mlir::Value bufferSize, mlir::Value buffSize,
3262                          mlir::Value eleSz) {
3263     mlir::Location loc = getLoc();
3264     mlir::FuncOp reallocFunc = fir::factory::getRealloc(builder);
3265     auto cond = builder.create<mlir::arith::CmpIOp>(
3266         loc, mlir::arith::CmpIPredicate::sle, bufferSize, needed);
3267     auto ifOp = builder.create<fir::IfOp>(loc, mem.getType(), cond,
3268                                           /*withElseRegion=*/true);
3269     auto insPt = builder.saveInsertionPoint();
3270     builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
3271     // Not enough space, resize the buffer.
3272     mlir::IndexType idxTy = builder.getIndexType();
3273     mlir::Value two = builder.createIntegerConstant(loc, idxTy, 2);
3274     auto newSz = builder.create<mlir::arith::MulIOp>(loc, needed, two);
3275     builder.create<fir::StoreOp>(loc, newSz, buffSize);
3276     mlir::Value byteSz = builder.create<mlir::arith::MulIOp>(loc, newSz, eleSz);
3277     mlir::SymbolRefAttr funcSymAttr =
3278         builder.getSymbolRefAttr(reallocFunc.getName());
3279     mlir::FunctionType funcTy = reallocFunc.getType();
3280     auto newMem = builder.create<fir::CallOp>(
3281         loc, funcTy.getResults(), funcSymAttr,
3282         llvm::ArrayRef<mlir::Value>{
3283             builder.createConvert(loc, funcTy.getInputs()[0], mem),
3284             builder.createConvert(loc, funcTy.getInputs()[1], byteSz)});
3285     mlir::Value castNewMem =
3286         builder.createConvert(loc, mem.getType(), newMem.getResult(0));
3287     builder.create<fir::ResultOp>(loc, castNewMem);
3288     builder.setInsertionPointToStart(&ifOp.getElseRegion().front());
3289     // Otherwise, just forward the buffer.
3290     builder.create<fir::ResultOp>(loc, mem);
3291     builder.restoreInsertionPoint(insPt);
3292     return ifOp.getResult(0);
3293   }
3294 
3295   /// Copy the next value (or vector of values) into the array being
3296   /// constructed.
3297   mlir::Value copyNextArrayCtorSection(const ExtValue &exv, mlir::Value buffPos,
3298                                        mlir::Value buffSize, mlir::Value mem,
3299                                        mlir::Value eleSz, mlir::Type eleTy,
3300                                        mlir::Type eleRefTy, mlir::Type resTy) {
3301     mlir::Location loc = getLoc();
3302     auto off = builder.create<fir::LoadOp>(loc, buffPos);
3303     auto limit = builder.create<fir::LoadOp>(loc, buffSize);
3304     mlir::IndexType idxTy = builder.getIndexType();
3305     mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
3306 
3307     if (fir::isRecordWithAllocatableMember(eleTy))
3308       TODO(loc, "deep copy on allocatable members");
3309 
3310     if (!eleSz) {
3311       // Compute the element size at runtime.
3312       assert(fir::hasDynamicSize(eleTy));
3313       if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) {
3314         auto charBytes =
3315             builder.getKindMap().getCharacterBitsize(charTy.getFKind()) / 8;
3316         mlir::Value bytes =
3317             builder.createIntegerConstant(loc, idxTy, charBytes);
3318         mlir::Value length = fir::getLen(exv);
3319         if (!length)
3320           fir::emitFatalError(loc, "result is not boxed character");
3321         eleSz = builder.create<mlir::arith::MulIOp>(loc, bytes, length);
3322       } else {
3323         TODO(loc, "PDT size");
3324         // Will call the PDT's size function with the type parameters.
3325       }
3326     }
3327 
3328     // Compute the coordinate using `fir.coordinate_of`, or, if the type has
3329     // dynamic size, generating the pointer arithmetic.
3330     auto computeCoordinate = [&](mlir::Value buff, mlir::Value off) {
3331       mlir::Type refTy = eleRefTy;
3332       if (fir::hasDynamicSize(eleTy)) {
3333         if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) {
3334           // Scale a simple pointer using dynamic length and offset values.
3335           auto chTy = fir::CharacterType::getSingleton(charTy.getContext(),
3336                                                        charTy.getFKind());
3337           refTy = builder.getRefType(chTy);
3338           mlir::Type toTy = builder.getRefType(builder.getVarLenSeqTy(chTy));
3339           buff = builder.createConvert(loc, toTy, buff);
3340           off = builder.create<mlir::arith::MulIOp>(loc, off, eleSz);
3341         } else {
3342           TODO(loc, "PDT offset");
3343         }
3344       }
3345       auto coor = builder.create<fir::CoordinateOp>(loc, refTy, buff,
3346                                                     mlir::ValueRange{off});
3347       return builder.createConvert(loc, eleRefTy, coor);
3348     };
3349 
3350     // Lambda to lower an abstract array box value.
3351     auto doAbstractArray = [&](const auto &v) {
3352       // Compute the array size.
3353       mlir::Value arrSz = one;
3354       for (auto ext : v.getExtents())
3355         arrSz = builder.create<mlir::arith::MulIOp>(loc, arrSz, ext);
3356 
3357       // Grow the buffer as needed.
3358       auto endOff = builder.create<mlir::arith::AddIOp>(loc, off, arrSz);
3359       mem = growBuffer(mem, endOff, limit, buffSize, eleSz);
3360 
3361       // Copy the elements to the buffer.
3362       mlir::Value byteSz =
3363           builder.create<mlir::arith::MulIOp>(loc, arrSz, eleSz);
3364       auto buff = builder.createConvert(loc, fir::HeapType::get(resTy), mem);
3365       mlir::Value buffi = computeCoordinate(buff, off);
3366       llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
3367           builder, loc, memcpyType(), buffi, v.getAddr(), byteSz,
3368           /*volatile=*/builder.createBool(loc, false));
3369       createCallMemcpy(args);
3370 
3371       // Save the incremented buffer position.
3372       builder.create<fir::StoreOp>(loc, endOff, buffPos);
3373     };
3374 
3375     // Copy a trivial scalar value into the buffer.
3376     auto doTrivialScalar = [&](const ExtValue &v, mlir::Value len = {}) {
3377       // Increment the buffer position.
3378       auto plusOne = builder.create<mlir::arith::AddIOp>(loc, off, one);
3379 
3380       // Grow the buffer as needed.
3381       mem = growBuffer(mem, plusOne, limit, buffSize, eleSz);
3382 
3383       // Store the element in the buffer.
3384       mlir::Value buff =
3385           builder.createConvert(loc, fir::HeapType::get(resTy), mem);
3386       auto buffi = builder.create<fir::CoordinateOp>(loc, eleRefTy, buff,
3387                                                      mlir::ValueRange{off});
3388       fir::factory::genScalarAssignment(
3389           builder, loc,
3390           [&]() -> ExtValue {
3391             if (len)
3392               return fir::CharBoxValue(buffi, len);
3393             return buffi;
3394           }(),
3395           v);
3396       builder.create<fir::StoreOp>(loc, plusOne, buffPos);
3397     };
3398 
3399     // Copy the value.
3400     exv.match(
3401         [&](mlir::Value) { doTrivialScalar(exv); },
3402         [&](const fir::CharBoxValue &v) {
3403           auto buffer = v.getBuffer();
3404           if (fir::isa_char(buffer.getType())) {
3405             doTrivialScalar(exv, eleSz);
3406           } else {
3407             // Increment the buffer position.
3408             auto plusOne = builder.create<mlir::arith::AddIOp>(loc, off, one);
3409 
3410             // Grow the buffer as needed.
3411             mem = growBuffer(mem, plusOne, limit, buffSize, eleSz);
3412 
3413             // Store the element in the buffer.
3414             mlir::Value buff =
3415                 builder.createConvert(loc, fir::HeapType::get(resTy), mem);
3416             mlir::Value buffi = computeCoordinate(buff, off);
3417             llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
3418                 builder, loc, memcpyType(), buffi, v.getAddr(), eleSz,
3419                 /*volatile=*/builder.createBool(loc, false));
3420             createCallMemcpy(args);
3421 
3422             builder.create<fir::StoreOp>(loc, plusOne, buffPos);
3423           }
3424         },
3425         [&](const fir::ArrayBoxValue &v) { doAbstractArray(v); },
3426         [&](const fir::CharArrayBoxValue &v) { doAbstractArray(v); },
3427         [&](const auto &) {
3428           TODO(loc, "unhandled array constructor expression");
3429         });
3430     return mem;
3431   }
3432 
3433   // Lower the expr cases in an ac-value-list.
3434   template <typename A>
3435   std::pair<ExtValue, bool>
3436   genArrayCtorInitializer(const Fortran::evaluate::Expr<A> &x, mlir::Type,
3437                           mlir::Value, mlir::Value, mlir::Value,
3438                           Fortran::lower::StatementContext &stmtCtx) {
3439     if (isArray(x))
3440       return {lowerNewArrayExpression(converter, symMap, stmtCtx, toEvExpr(x)),
3441               /*needCopy=*/true};
3442     return {asScalar(x), /*needCopy=*/true};
3443   }
3444 
3445   // Lower an ac-implied-do in an ac-value-list.
3446   template <typename A>
3447   std::pair<ExtValue, bool>
3448   genArrayCtorInitializer(const Fortran::evaluate::ImpliedDo<A> &x,
3449                           mlir::Type resTy, mlir::Value mem,
3450                           mlir::Value buffPos, mlir::Value buffSize,
3451                           Fortran::lower::StatementContext &) {
3452     mlir::Location loc = getLoc();
3453     mlir::IndexType idxTy = builder.getIndexType();
3454     mlir::Value lo =
3455         builder.createConvert(loc, idxTy, fir::getBase(asScalar(x.lower())));
3456     mlir::Value up =
3457         builder.createConvert(loc, idxTy, fir::getBase(asScalar(x.upper())));
3458     mlir::Value step =
3459         builder.createConvert(loc, idxTy, fir::getBase(asScalar(x.stride())));
3460     auto seqTy = resTy.template cast<fir::SequenceType>();
3461     mlir::Type eleTy = fir::unwrapSequenceType(seqTy);
3462     auto loop =
3463         builder.create<fir::DoLoopOp>(loc, lo, up, step, /*unordered=*/false,
3464                                       /*finalCount=*/false, mem);
3465     // create a new binding for x.name(), to ac-do-variable, to the iteration
3466     // value.
3467     symMap.pushImpliedDoBinding(toStringRef(x.name()), loop.getInductionVar());
3468     auto insPt = builder.saveInsertionPoint();
3469     builder.setInsertionPointToStart(loop.getBody());
3470     // Thread mem inside the loop via loop argument.
3471     mem = loop.getRegionIterArgs()[0];
3472 
3473     mlir::Type eleRefTy = builder.getRefType(eleTy);
3474 
3475     // Any temps created in the loop body must be freed inside the loop body.
3476     stmtCtx.pushScope();
3477     llvm::Optional<mlir::Value> charLen;
3478     for (const Fortran::evaluate::ArrayConstructorValue<A> &acv : x.values()) {
3479       auto [exv, copyNeeded] = std::visit(
3480           [&](const auto &v) {
3481             return genArrayCtorInitializer(v, resTy, mem, buffPos, buffSize,
3482                                            stmtCtx);
3483           },
3484           acv.u);
3485       mlir::Value eleSz = computeElementSize(exv, eleTy, resTy);
3486       mem = copyNeeded ? copyNextArrayCtorSection(exv, buffPos, buffSize, mem,
3487                                                   eleSz, eleTy, eleRefTy, resTy)
3488                        : fir::getBase(exv);
3489       if (fir::isa_char(seqTy.getEleTy()) && !charLen.hasValue()) {
3490         charLen = builder.createTemporary(loc, builder.getI64Type());
3491         mlir::Value castLen =
3492             builder.createConvert(loc, builder.getI64Type(), fir::getLen(exv));
3493         builder.create<fir::StoreOp>(loc, castLen, charLen.getValue());
3494       }
3495     }
3496     stmtCtx.finalize(/*popScope=*/true);
3497 
3498     builder.create<fir::ResultOp>(loc, mem);
3499     builder.restoreInsertionPoint(insPt);
3500     mem = loop.getResult(0);
3501     symMap.popImpliedDoBinding();
3502     llvm::SmallVector<mlir::Value> extents = {
3503         builder.create<fir::LoadOp>(loc, buffPos).getResult()};
3504 
3505     // Convert to extended value.
3506     if (fir::isa_char(seqTy.getEleTy())) {
3507       auto len = builder.create<fir::LoadOp>(loc, charLen.getValue());
3508       return {fir::CharArrayBoxValue{mem, len, extents}, /*needCopy=*/false};
3509     }
3510     return {fir::ArrayBoxValue{mem, extents}, /*needCopy=*/false};
3511   }
3512 
3513   // To simplify the handling and interaction between the various cases, array
3514   // constructors are always lowered to the incremental construction code
3515   // pattern, even if the extent of the array value is constant. After the
3516   // MemToReg pass and constant folding, the optimizer should be able to
3517   // determine that all the buffer overrun tests are false when the
3518   // incremental construction wasn't actually required.
3519   template <typename A>
3520   CC genarr(const Fortran::evaluate::ArrayConstructor<A> &x) {
3521     mlir::Location loc = getLoc();
3522     auto evExpr = toEvExpr(x);
3523     mlir::Type resTy = translateSomeExprToFIRType(converter, evExpr);
3524     mlir::IndexType idxTy = builder.getIndexType();
3525     auto seqTy = resTy.template cast<fir::SequenceType>();
3526     mlir::Type eleTy = fir::unwrapSequenceType(resTy);
3527     mlir::Value buffSize = builder.createTemporary(loc, idxTy, ".buff.size");
3528     mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
3529     mlir::Value buffPos = builder.createTemporary(loc, idxTy, ".buff.pos");
3530     builder.create<fir::StoreOp>(loc, zero, buffPos);
3531     // Allocate space for the array to be constructed.
3532     mlir::Value mem;
3533     if (fir::hasDynamicSize(resTy)) {
3534       if (fir::hasDynamicSize(eleTy)) {
3535         // The size of each element may depend on a general expression. Defer
3536         // creating the buffer until after the expression is evaluated.
3537         mem = builder.createNullConstant(loc, builder.getRefType(eleTy));
3538         builder.create<fir::StoreOp>(loc, zero, buffSize);
3539       } else {
3540         mlir::Value initBuffSz =
3541             builder.createIntegerConstant(loc, idxTy, clInitialBufferSize);
3542         mem = builder.create<fir::AllocMemOp>(
3543             loc, eleTy, /*typeparams=*/llvm::None, initBuffSz);
3544         builder.create<fir::StoreOp>(loc, initBuffSz, buffSize);
3545       }
3546     } else {
3547       mem = builder.create<fir::AllocMemOp>(loc, resTy);
3548       int64_t buffSz = 1;
3549       for (auto extent : seqTy.getShape())
3550         buffSz *= extent;
3551       mlir::Value initBuffSz =
3552           builder.createIntegerConstant(loc, idxTy, buffSz);
3553       builder.create<fir::StoreOp>(loc, initBuffSz, buffSize);
3554     }
3555     // Compute size of element
3556     mlir::Type eleRefTy = builder.getRefType(eleTy);
3557 
3558     // Populate the buffer with the elements, growing as necessary.
3559     llvm::Optional<mlir::Value> charLen;
3560     for (const auto &expr : x) {
3561       auto [exv, copyNeeded] = std::visit(
3562           [&](const auto &e) {
3563             return genArrayCtorInitializer(e, resTy, mem, buffPos, buffSize,
3564                                            stmtCtx);
3565           },
3566           expr.u);
3567       mlir::Value eleSz = computeElementSize(exv, eleTy, resTy);
3568       mem = copyNeeded ? copyNextArrayCtorSection(exv, buffPos, buffSize, mem,
3569                                                   eleSz, eleTy, eleRefTy, resTy)
3570                        : fir::getBase(exv);
3571       if (fir::isa_char(seqTy.getEleTy()) && !charLen.hasValue()) {
3572         charLen = builder.createTemporary(loc, builder.getI64Type());
3573         mlir::Value castLen =
3574             builder.createConvert(loc, builder.getI64Type(), fir::getLen(exv));
3575         builder.create<fir::StoreOp>(loc, castLen, charLen.getValue());
3576       }
3577     }
3578     mem = builder.createConvert(loc, fir::HeapType::get(resTy), mem);
3579     llvm::SmallVector<mlir::Value> extents = {
3580         builder.create<fir::LoadOp>(loc, buffPos)};
3581 
3582     // Cleanup the temporary.
3583     fir::FirOpBuilder *bldr = &converter.getFirOpBuilder();
3584     stmtCtx.attachCleanup(
3585         [bldr, loc, mem]() { bldr->create<fir::FreeMemOp>(loc, mem); });
3586 
3587     // Return the continuation.
3588     if (fir::isa_char(seqTy.getEleTy())) {
3589       if (charLen.hasValue()) {
3590         auto len = builder.create<fir::LoadOp>(loc, charLen.getValue());
3591         return genarr(fir::CharArrayBoxValue{mem, len, extents});
3592       }
3593       return genarr(fir::CharArrayBoxValue{mem, zero, extents});
3594     }
3595     return genarr(fir::ArrayBoxValue{mem, extents});
3596   }
3597 
3598   CC genarr(const Fortran::evaluate::ImpliedDoIndex &) {
3599     TODO(getLoc(), "genarr ImpliedDoIndex");
3600   }
3601 
3602   CC genarr(const Fortran::evaluate::TypeParamInquiry &x) {
3603     TODO(getLoc(), "genarr TypeParamInquiry");
3604   }
3605 
3606   CC genarr(const Fortran::evaluate::DescriptorInquiry &x) {
3607     TODO(getLoc(), "genarr DescriptorInquiry");
3608   }
3609 
3610   CC genarr(const Fortran::evaluate::StructureConstructor &x) {
3611     TODO(getLoc(), "genarr StructureConstructor");
3612   }
3613 
3614   template <int KIND>
3615   CC genarr(const Fortran::evaluate::Not<KIND> &x) {
3616     TODO(getLoc(), "genarr Not");
3617   }
3618 
3619   template <int KIND>
3620   CC genarr(const Fortran::evaluate::LogicalOperation<KIND> &x) {
3621     TODO(getLoc(), "genarr LogicalOperation");
3622   }
3623 
3624   template <int KIND>
3625   CC genarr(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
3626                 Fortran::common::TypeCategory::Integer, KIND>> &x) {
3627     TODO(getLoc(), "genarr Relational Integer");
3628   }
3629   template <int KIND>
3630   CC genarr(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
3631                 Fortran::common::TypeCategory::Character, KIND>> &x) {
3632     TODO(getLoc(), "genarr Relational Character");
3633   }
3634   template <int KIND>
3635   CC genarr(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
3636                 Fortran::common::TypeCategory::Real, KIND>> &x) {
3637     TODO(getLoc(), "genarr Relational Real");
3638   }
3639   template <int KIND>
3640   CC genarr(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
3641                 Fortran::common::TypeCategory::Complex, KIND>> &x) {
3642     TODO(getLoc(), "genarr Relational Complex");
3643   }
3644   CC genarr(
3645       const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &r) {
3646     TODO(getLoc(), "genarr Relational SomeType");
3647   }
3648 
3649   template <typename A>
3650   CC genarr(const Fortran::evaluate::Designator<A> &des) {
3651     ComponentPath components(des.Rank() > 0);
3652     return std::visit([&](const auto &x) { return genarr(x, components); },
3653                       des.u);
3654   }
3655 
3656   template <typename T>
3657   CC genarr(const Fortran::evaluate::FunctionRef<T> &funRef) {
3658     // Note that it's possible that the function being called returns either an
3659     // array or a scalar.  In the first case, use the element type of the array.
3660     return genProcRef(
3661         funRef, fir::unwrapSequenceType(converter.genType(toEvExpr(funRef))));
3662   }
3663 
3664   template <typename A>
3665   CC genImplicitArrayAccess(const A &x, ComponentPath &components) {
3666     components.reversePath.push_back(ImplicitSubscripts{});
3667     ExtValue exv = asScalarRef(x);
3668     // lowerPath(exv, components);
3669     auto lambda = genarr(exv, components);
3670     return [=](IterSpace iters) { return lambda(components.pc(iters)); };
3671   }
3672   CC genImplicitArrayAccess(const Fortran::evaluate::NamedEntity &x,
3673                             ComponentPath &components) {
3674     if (x.IsSymbol())
3675       return genImplicitArrayAccess(x.GetFirstSymbol(), components);
3676     return genImplicitArrayAccess(x.GetComponent(), components);
3677   }
3678 
3679   template <typename A>
3680   CC genAsScalar(const A &x) {
3681     mlir::Location loc = getLoc();
3682     if (isProjectedCopyInCopyOut()) {
3683       return [=, &x, builder = &converter.getFirOpBuilder()](
3684                  IterSpace iters) -> ExtValue {
3685         ExtValue exv = asScalarRef(x);
3686         mlir::Value val = fir::getBase(exv);
3687         mlir::Type eleTy = fir::unwrapRefType(val.getType());
3688         if (isAdjustedArrayElementType(eleTy)) {
3689           if (fir::isa_char(eleTy)) {
3690             TODO(getLoc(), "assignment of character type");
3691           } else if (fir::isa_derived(eleTy)) {
3692             TODO(loc, "assignment of derived type");
3693           } else {
3694             fir::emitFatalError(loc, "array type not expected in scalar");
3695           }
3696         } else {
3697           builder->create<fir::StoreOp>(loc, iters.getElement(), val);
3698         }
3699         return exv;
3700       };
3701     }
3702     return [=, &x](IterSpace) { return asScalar(x); };
3703   }
3704 
3705   CC genarr(const Fortran::semantics::Symbol &x, ComponentPath &components) {
3706     if (explicitSpaceIsActive()) {
3707       TODO(getLoc(), "genarr Symbol explicitSpace");
3708     } else {
3709       return genImplicitArrayAccess(x, components);
3710     }
3711   }
3712 
3713   CC genarr(const Fortran::evaluate::Component &x, ComponentPath &components) {
3714     TODO(getLoc(), "genarr Component");
3715   }
3716 
3717   /// Array reference with subscripts. If this has rank > 0, this is a form
3718   /// of an array section (slice).
3719   ///
3720   /// There are two "slicing" primitives that may be applied on a dimension by
3721   /// dimension basis: (1) triple notation and (2) vector addressing. Since
3722   /// dimensions can be selectively sliced, some dimensions may contain
3723   /// regular scalar expressions and those dimensions do not participate in
3724   /// the array expression evaluation.
3725   CC genarr(const Fortran::evaluate::ArrayRef &x, ComponentPath &components) {
3726     if (explicitSpaceIsActive()) {
3727       TODO(getLoc(), "genarr ArrayRef explicitSpace");
3728     } else {
3729       if (Fortran::lower::isRankedArrayAccess(x)) {
3730         components.reversePath.push_back(&x);
3731         return genImplicitArrayAccess(x.base(), components);
3732       }
3733     }
3734     bool atEnd = pathIsEmpty(components);
3735     components.reversePath.push_back(&x);
3736     auto result = genarr(x.base(), components);
3737     if (components.applied)
3738       return result;
3739     mlir::Location loc = getLoc();
3740     if (atEnd) {
3741       if (x.Rank() == 0)
3742         return genAsScalar(x);
3743       fir::emitFatalError(loc, "expected scalar");
3744     }
3745     return [=](IterSpace) -> ExtValue {
3746       fir::emitFatalError(loc, "reached arrayref with path");
3747     };
3748   }
3749 
3750   CC genarr(const Fortran::evaluate::CoarrayRef &x, ComponentPath &components) {
3751     TODO(getLoc(), "coarray reference");
3752   }
3753 
3754   CC genarr(const Fortran::evaluate::NamedEntity &x,
3755             ComponentPath &components) {
3756     return x.IsSymbol() ? genarr(x.GetFirstSymbol(), components)
3757                         : genarr(x.GetComponent(), components);
3758   }
3759 
3760   CC genarr(const Fortran::evaluate::DataRef &x, ComponentPath &components) {
3761     return std::visit([&](const auto &v) { return genarr(v, components); },
3762                       x.u);
3763   }
3764 
3765   bool pathIsEmpty(const ComponentPath &components) {
3766     return components.reversePath.empty();
3767   }
3768 
3769   /// Given an optional fir.box, returns an fir.box that is the original one if
3770   /// it is present and it otherwise an unallocated box.
3771   /// Absent fir.box are implemented as a null pointer descriptor. Generated
3772   /// code may need to unconditionally read a fir.box that can be absent.
3773   /// This helper allows creating a fir.box that can be read in all cases
3774   /// outside of a fir.if (isPresent) region. However, the usages of the value
3775   /// read from such box should still only be done in a fir.if(isPresent).
3776   static fir::ExtendedValue
3777   absentBoxToUnalllocatedBox(fir::FirOpBuilder &builder, mlir::Location loc,
3778                              const fir::ExtendedValue &exv,
3779                              mlir::Value isPresent) {
3780     mlir::Value box = fir::getBase(exv);
3781     mlir::Type boxType = box.getType();
3782     assert(boxType.isa<fir::BoxType>() && "argument must be a fir.box");
3783     mlir::Value emptyBox =
3784         fir::factory::createUnallocatedBox(builder, loc, boxType, llvm::None);
3785     auto safeToReadBox =
3786         builder.create<mlir::arith::SelectOp>(loc, isPresent, box, emptyBox);
3787     return fir::substBase(exv, safeToReadBox);
3788   }
3789 
3790   std::tuple<CC, mlir::Value, mlir::Type>
3791   genOptionalArrayFetch(const Fortran::lower::SomeExpr &expr) {
3792     assert(expr.Rank() > 0 && "expr must be an array");
3793     mlir::Location loc = getLoc();
3794     ExtValue optionalArg = asInquired(expr);
3795     mlir::Value isPresent = genActualIsPresentTest(builder, loc, optionalArg);
3796     // Generate an array load and access to an array that may be an absent
3797     // optional or an unallocated optional.
3798     mlir::Value base = getBase(optionalArg);
3799     const bool hasOptionalAttr =
3800         fir::valueHasFirAttribute(base, fir::getOptionalAttrName());
3801     mlir::Type baseType = fir::unwrapRefType(base.getType());
3802     const bool isBox = baseType.isa<fir::BoxType>();
3803     const bool isAllocOrPtr = Fortran::evaluate::IsAllocatableOrPointerObject(
3804         expr, converter.getFoldingContext());
3805     mlir::Type arrType = fir::unwrapPassByRefType(baseType);
3806     mlir::Type eleType = fir::unwrapSequenceType(arrType);
3807     ExtValue exv = optionalArg;
3808     if (hasOptionalAttr && isBox && !isAllocOrPtr) {
3809       // Elemental argument cannot be allocatable or pointers (C15100).
3810       // Hence, per 15.5.2.12 3 (8) and (9), the provided Allocatable and
3811       // Pointer optional arrays cannot be absent. The only kind of entities
3812       // that can get here are optional assumed shape and polymorphic entities.
3813       exv = absentBoxToUnalllocatedBox(builder, loc, exv, isPresent);
3814     }
3815     // All the properties can be read from any fir.box but the read values may
3816     // be undefined and should only be used inside a fir.if (canBeRead) region.
3817     if (const auto *mutableBox = exv.getBoxOf<fir::MutableBoxValue>())
3818       exv = fir::factory::genMutableBoxRead(builder, loc, *mutableBox);
3819 
3820     mlir::Value memref = fir::getBase(exv);
3821     mlir::Value shape = builder.createShape(loc, exv);
3822     mlir::Value noSlice;
3823     auto arrLoad = builder.create<fir::ArrayLoadOp>(
3824         loc, arrType, memref, shape, noSlice, fir::getTypeParams(exv));
3825     mlir::Operation::operand_range arrLdTypeParams = arrLoad.getTypeparams();
3826     mlir::Value arrLd = arrLoad.getResult();
3827     // Mark the load to tell later passes it is unsafe to use this array_load
3828     // shape unconditionally.
3829     arrLoad->setAttr(fir::getOptionalAttrName(), builder.getUnitAttr());
3830 
3831     // Place the array as optional on the arrayOperands stack so that its
3832     // shape will only be used as a fallback to induce the implicit loop nest
3833     // (that is if there is no non optional array arguments).
3834     arrayOperands.push_back(
3835         ArrayOperand{memref, shape, noSlice, /*mayBeAbsent=*/true});
3836 
3837     // By value semantics.
3838     auto cc = [=](IterSpace iters) -> ExtValue {
3839       auto arrFetch = builder.create<fir::ArrayFetchOp>(
3840           loc, eleType, arrLd, iters.iterVec(), arrLdTypeParams);
3841       return fir::factory::arraySectionElementToExtendedValue(
3842           builder, loc, exv, arrFetch, noSlice);
3843     };
3844     return {cc, isPresent, eleType};
3845   }
3846 
3847   /// Generate a continuation to pass \p expr to an OPTIONAL argument of an
3848   /// elemental procedure. This is meant to handle the cases where \p expr might
3849   /// be dynamically absent (i.e. when it is a POINTER, an ALLOCATABLE or an
3850   /// OPTIONAL variable). If p\ expr is guaranteed to be present genarr() can
3851   /// directly be called instead.
3852   CC genarrForwardOptionalArgumentToCall(const Fortran::lower::SomeExpr &expr) {
3853     mlir::Location loc = getLoc();
3854     // Only by-value numerical and logical so far.
3855     if (semant != ConstituentSemantics::RefTransparent)
3856       TODO(loc, "optional arguments in user defined elemental procedures");
3857 
3858     // Handle scalar argument case (the if-then-else is generated outside of the
3859     // implicit loop nest).
3860     if (expr.Rank() == 0) {
3861       ExtValue optionalArg = asInquired(expr);
3862       mlir::Value isPresent = genActualIsPresentTest(builder, loc, optionalArg);
3863       mlir::Value elementValue =
3864           fir::getBase(genOptionalValue(builder, loc, optionalArg, isPresent));
3865       return [=](IterSpace iters) -> ExtValue { return elementValue; };
3866     }
3867 
3868     CC cc;
3869     mlir::Value isPresent;
3870     mlir::Type eleType;
3871     std::tie(cc, isPresent, eleType) = genOptionalArrayFetch(expr);
3872     return [=](IterSpace iters) -> ExtValue {
3873       mlir::Value elementValue =
3874           builder
3875               .genIfOp(loc, {eleType}, isPresent,
3876                        /*withElseRegion=*/true)
3877               .genThen([&]() {
3878                 builder.create<fir::ResultOp>(loc, fir::getBase(cc(iters)));
3879               })
3880               .genElse([&]() {
3881                 mlir::Value zero =
3882                     fir::factory::createZeroValue(builder, loc, eleType);
3883                 builder.create<fir::ResultOp>(loc, zero);
3884               })
3885               .getResults()[0];
3886       return elementValue;
3887     };
3888   }
3889 
3890   /// Reduce the rank of a array to be boxed based on the slice's operands.
3891   static mlir::Type reduceRank(mlir::Type arrTy, mlir::Value slice) {
3892     if (slice) {
3893       auto slOp = mlir::dyn_cast<fir::SliceOp>(slice.getDefiningOp());
3894       assert(slOp && "expected slice op");
3895       auto seqTy = arrTy.dyn_cast<fir::SequenceType>();
3896       assert(seqTy && "expected array type");
3897       mlir::Operation::operand_range triples = slOp.getTriples();
3898       fir::SequenceType::Shape shape;
3899       // reduce the rank for each invariant dimension
3900       for (unsigned i = 1, end = triples.size(); i < end; i += 3)
3901         if (!mlir::isa_and_nonnull<fir::UndefOp>(triples[i].getDefiningOp()))
3902           shape.push_back(fir::SequenceType::getUnknownExtent());
3903       return fir::SequenceType::get(shape, seqTy.getEleTy());
3904     }
3905     // not sliced, so no change in rank
3906     return arrTy;
3907   }
3908 
3909   CC genarr(const Fortran::evaluate::ComplexPart &x,
3910             ComponentPath &components) {
3911     TODO(getLoc(), "genarr ComplexPart");
3912   }
3913 
3914   CC genarr(const Fortran::evaluate::StaticDataObject::Pointer &,
3915             ComponentPath &components) {
3916     TODO(getLoc(), "genarr StaticDataObject::Pointer");
3917   }
3918 
3919   /// Substrings (see 9.4.1)
3920   CC genarr(const Fortran::evaluate::Substring &x, ComponentPath &components) {
3921     TODO(getLoc(), "genarr Substring");
3922   }
3923 
3924   /// Base case of generating an array reference,
3925   CC genarr(const ExtValue &extMemref, ComponentPath &components) {
3926     mlir::Location loc = getLoc();
3927     mlir::Value memref = fir::getBase(extMemref);
3928     mlir::Type arrTy = fir::dyn_cast_ptrOrBoxEleTy(memref.getType());
3929     assert(arrTy.isa<fir::SequenceType>() && "memory ref must be an array");
3930     mlir::Value shape = builder.createShape(loc, extMemref);
3931     mlir::Value slice;
3932     if (components.isSlice()) {
3933       if (isBoxValue() && components.substring) {
3934         // Append the substring operator to emboxing Op as it will become an
3935         // interior adjustment (add offset, adjust LEN) to the CHARACTER value
3936         // being referenced in the descriptor.
3937         llvm::SmallVector<mlir::Value> substringBounds;
3938         populateBounds(substringBounds, components.substring);
3939         // Convert to (offset, size)
3940         mlir::Type iTy = substringBounds[0].getType();
3941         if (substringBounds.size() != 2) {
3942           fir::CharacterType charTy =
3943               fir::factory::CharacterExprHelper::getCharType(arrTy);
3944           if (charTy.hasConstantLen()) {
3945             mlir::IndexType idxTy = builder.getIndexType();
3946             fir::CharacterType::LenType charLen = charTy.getLen();
3947             mlir::Value lenValue =
3948                 builder.createIntegerConstant(loc, idxTy, charLen);
3949             substringBounds.push_back(lenValue);
3950           } else {
3951             llvm::SmallVector<mlir::Value> typeparams =
3952                 fir::getTypeParams(extMemref);
3953             substringBounds.push_back(typeparams.back());
3954           }
3955         }
3956         // Convert the lower bound to 0-based substring.
3957         mlir::Value one =
3958             builder.createIntegerConstant(loc, substringBounds[0].getType(), 1);
3959         substringBounds[0] =
3960             builder.create<mlir::arith::SubIOp>(loc, substringBounds[0], one);
3961         // Convert the upper bound to a length.
3962         mlir::Value cast = builder.createConvert(loc, iTy, substringBounds[1]);
3963         mlir::Value zero = builder.createIntegerConstant(loc, iTy, 0);
3964         auto size =
3965             builder.create<mlir::arith::SubIOp>(loc, cast, substringBounds[0]);
3966         auto cmp = builder.create<mlir::arith::CmpIOp>(
3967             loc, mlir::arith::CmpIPredicate::sgt, size, zero);
3968         // size = MAX(upper - (lower - 1), 0)
3969         substringBounds[1] =
3970             builder.create<mlir::arith::SelectOp>(loc, cmp, size, zero);
3971         slice = builder.create<fir::SliceOp>(loc, components.trips,
3972                                              components.suffixComponents,
3973                                              substringBounds);
3974       } else {
3975         slice = builder.createSlice(loc, extMemref, components.trips,
3976                                     components.suffixComponents);
3977       }
3978       if (components.hasComponents()) {
3979         auto seqTy = arrTy.cast<fir::SequenceType>();
3980         mlir::Type eleTy =
3981             fir::applyPathToType(seqTy.getEleTy(), components.suffixComponents);
3982         if (!eleTy)
3983           fir::emitFatalError(loc, "slicing path is ill-formed");
3984         if (auto realTy = eleTy.dyn_cast<fir::RealType>())
3985           eleTy = Fortran::lower::convertReal(realTy.getContext(),
3986                                               realTy.getFKind());
3987 
3988         // create the type of the projected array.
3989         arrTy = fir::SequenceType::get(seqTy.getShape(), eleTy);
3990         LLVM_DEBUG(llvm::dbgs()
3991                    << "type of array projection from component slicing: "
3992                    << eleTy << ", " << arrTy << '\n');
3993       }
3994     }
3995     arrayOperands.push_back(ArrayOperand{memref, shape, slice});
3996     if (destShape.empty())
3997       destShape = getShape(arrayOperands.back());
3998     if (isBoxValue()) {
3999       // Semantics are a reference to a boxed array.
4000       // This case just requires that an embox operation be created to box the
4001       // value. The value of the box is forwarded in the continuation.
4002       mlir::Type reduceTy = reduceRank(arrTy, slice);
4003       auto boxTy = fir::BoxType::get(reduceTy);
4004       if (components.substring) {
4005         // Adjust char length to substring size.
4006         fir::CharacterType charTy =
4007             fir::factory::CharacterExprHelper::getCharType(reduceTy);
4008         auto seqTy = reduceTy.cast<fir::SequenceType>();
4009         // TODO: Use a constant for fir.char LEN if we can compute it.
4010         boxTy = fir::BoxType::get(
4011             fir::SequenceType::get(fir::CharacterType::getUnknownLen(
4012                                        builder.getContext(), charTy.getFKind()),
4013                                    seqTy.getDimension()));
4014       }
4015       mlir::Value embox =
4016           memref.getType().isa<fir::BoxType>()
4017               ? builder.create<fir::ReboxOp>(loc, boxTy, memref, shape, slice)
4018                     .getResult()
4019               : builder
4020                     .create<fir::EmboxOp>(loc, boxTy, memref, shape, slice,
4021                                           fir::getTypeParams(extMemref))
4022                     .getResult();
4023       return [=](IterSpace) -> ExtValue { return fir::BoxValue(embox); };
4024     }
4025     auto eleTy = arrTy.cast<fir::SequenceType>().getEleTy();
4026     if (isReferentiallyOpaque()) {
4027       // Semantics are an opaque reference to an array.
4028       // This case forwards a continuation that will generate the address
4029       // arithmetic to the array element. This does not have copy-in/copy-out
4030       // semantics. No attempt to copy the array value will be made during the
4031       // interpretation of the Fortran statement.
4032       mlir::Type refEleTy = builder.getRefType(eleTy);
4033       return [=](IterSpace iters) -> ExtValue {
4034         // ArrayCoorOp does not expect zero based indices.
4035         llvm::SmallVector<mlir::Value> indices = fir::factory::originateIndices(
4036             loc, builder, memref.getType(), shape, iters.iterVec());
4037         mlir::Value coor = builder.create<fir::ArrayCoorOp>(
4038             loc, refEleTy, memref, shape, slice, indices,
4039             fir::getTypeParams(extMemref));
4040         if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) {
4041           llvm::SmallVector<mlir::Value> substringBounds;
4042           populateBounds(substringBounds, components.substring);
4043           if (!substringBounds.empty()) {
4044             mlir::Value dstLen = fir::factory::genLenOfCharacter(
4045                 builder, loc, arrTy.cast<fir::SequenceType>(), memref,
4046                 fir::getTypeParams(extMemref), iters.iterVec(),
4047                 substringBounds);
4048             fir::CharBoxValue dstChar(coor, dstLen);
4049             return fir::factory::CharacterExprHelper{builder, loc}
4050                 .createSubstring(dstChar, substringBounds);
4051           }
4052         }
4053         return fir::factory::arraySectionElementToExtendedValue(
4054             builder, loc, extMemref, coor, slice);
4055       };
4056     }
4057     auto arrLoad = builder.create<fir::ArrayLoadOp>(
4058         loc, arrTy, memref, shape, slice, fir::getTypeParams(extMemref));
4059     mlir::Value arrLd = arrLoad.getResult();
4060     if (isProjectedCopyInCopyOut()) {
4061       // Semantics are projected copy-in copy-out.
4062       // The backing store of the destination of an array expression may be
4063       // partially modified. These updates are recorded in FIR by forwarding a
4064       // continuation that generates an `array_update` Op. The destination is
4065       // always loaded at the beginning of the statement and merged at the
4066       // end.
4067       destination = arrLoad;
4068       auto lambda = ccStoreToDest.hasValue()
4069                         ? ccStoreToDest.getValue()
4070                         : defaultStoreToDestination(components.substring);
4071       return [=](IterSpace iters) -> ExtValue { return lambda(iters); };
4072     }
4073     if (isCustomCopyInCopyOut()) {
4074       // Create an array_modify to get the LHS element address and indicate
4075       // the assignment, the actual assignment must be implemented in
4076       // ccStoreToDest.
4077       destination = arrLoad;
4078       return [=](IterSpace iters) -> ExtValue {
4079         mlir::Value innerArg = iters.innerArgument();
4080         mlir::Type resTy = innerArg.getType();
4081         mlir::Type eleTy = fir::applyPathToType(resTy, iters.iterVec());
4082         mlir::Type refEleTy =
4083             fir::isa_ref_type(eleTy) ? eleTy : builder.getRefType(eleTy);
4084         auto arrModify = builder.create<fir::ArrayModifyOp>(
4085             loc, mlir::TypeRange{refEleTy, resTy}, innerArg, iters.iterVec(),
4086             destination.getTypeparams());
4087         return abstractArrayExtValue(arrModify.getResult(1));
4088       };
4089     }
4090     if (isCopyInCopyOut()) {
4091       // Semantics are copy-in copy-out.
4092       // The continuation simply forwards the result of the `array_load` Op,
4093       // which is the value of the array as it was when loaded. All data
4094       // references with rank > 0 in an array expression typically have
4095       // copy-in copy-out semantics.
4096       return [=](IterSpace) -> ExtValue { return arrLd; };
4097     }
4098     mlir::Operation::operand_range arrLdTypeParams = arrLoad.getTypeparams();
4099     if (isValueAttribute()) {
4100       // Semantics are value attribute.
4101       // Here the continuation will `array_fetch` a value from an array and
4102       // then store that value in a temporary. One can thus imitate pass by
4103       // value even when the call is pass by reference.
4104       return [=](IterSpace iters) -> ExtValue {
4105         mlir::Value base;
4106         mlir::Type eleTy = fir::applyPathToType(arrTy, iters.iterVec());
4107         if (isAdjustedArrayElementType(eleTy)) {
4108           mlir::Type eleRefTy = builder.getRefType(eleTy);
4109           base = builder.create<fir::ArrayAccessOp>(
4110               loc, eleRefTy, arrLd, iters.iterVec(), arrLdTypeParams);
4111         } else {
4112           base = builder.create<fir::ArrayFetchOp>(
4113               loc, eleTy, arrLd, iters.iterVec(), arrLdTypeParams);
4114         }
4115         mlir::Value temp = builder.createTemporary(
4116             loc, base.getType(),
4117             llvm::ArrayRef<mlir::NamedAttribute>{
4118                 Fortran::lower::getAdaptToByRefAttr(builder)});
4119         builder.create<fir::StoreOp>(loc, base, temp);
4120         return fir::factory::arraySectionElementToExtendedValue(
4121             builder, loc, extMemref, temp, slice);
4122       };
4123     }
4124     // In the default case, the array reference forwards an `array_fetch` or
4125     // `array_access` Op in the continuation.
4126     return [=](IterSpace iters) -> ExtValue {
4127       mlir::Type eleTy = fir::applyPathToType(arrTy, iters.iterVec());
4128       if (isAdjustedArrayElementType(eleTy)) {
4129         mlir::Type eleRefTy = builder.getRefType(eleTy);
4130         mlir::Value arrayOp = builder.create<fir::ArrayAccessOp>(
4131             loc, eleRefTy, arrLd, iters.iterVec(), arrLdTypeParams);
4132         if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) {
4133           llvm::SmallVector<mlir::Value> substringBounds;
4134           populateBounds(substringBounds, components.substring);
4135           if (!substringBounds.empty()) {
4136             mlir::Value dstLen = fir::factory::genLenOfCharacter(
4137                 builder, loc, arrLoad, iters.iterVec(), substringBounds);
4138             fir::CharBoxValue dstChar(arrayOp, dstLen);
4139             return fir::factory::CharacterExprHelper{builder, loc}
4140                 .createSubstring(dstChar, substringBounds);
4141           }
4142         }
4143         return fir::factory::arraySectionElementToExtendedValue(
4144             builder, loc, extMemref, arrayOp, slice);
4145       }
4146       auto arrFetch = builder.create<fir::ArrayFetchOp>(
4147           loc, eleTy, arrLd, iters.iterVec(), arrLdTypeParams);
4148       return fir::factory::arraySectionElementToExtendedValue(
4149           builder, loc, extMemref, arrFetch, slice);
4150     };
4151   }
4152 
4153 private:
4154   void determineShapeOfDest(const fir::ExtendedValue &lhs) {
4155     destShape = fir::factory::getExtents(builder, getLoc(), lhs);
4156   }
4157 
4158   void determineShapeOfDest(const Fortran::lower::SomeExpr &lhs) {
4159     if (!destShape.empty())
4160       return;
4161     // if (explicitSpaceIsActive() && determineShapeWithSlice(lhs))
4162     //   return;
4163     mlir::Type idxTy = builder.getIndexType();
4164     mlir::Location loc = getLoc();
4165     if (std::optional<Fortran::evaluate::ConstantSubscripts> constantShape =
4166             Fortran::evaluate::GetConstantExtents(converter.getFoldingContext(),
4167                                                   lhs))
4168       for (Fortran::common::ConstantSubscript extent : *constantShape)
4169         destShape.push_back(builder.createIntegerConstant(loc, idxTy, extent));
4170   }
4171 
4172   ExtValue lowerArrayExpression(const Fortran::lower::SomeExpr &exp) {
4173     mlir::Type resTy = converter.genType(exp);
4174     return std::visit(
4175         [&](const auto &e) { return lowerArrayExpression(genarr(e), resTy); },
4176         exp.u);
4177   }
4178   ExtValue lowerArrayExpression(const ExtValue &exv) {
4179     assert(!explicitSpace);
4180     mlir::Type resTy = fir::unwrapPassByRefType(fir::getBase(exv).getType());
4181     return lowerArrayExpression(genarr(exv), resTy);
4182   }
4183 
4184   void populateBounds(llvm::SmallVectorImpl<mlir::Value> &bounds,
4185                       const Fortran::evaluate::Substring *substring) {
4186     if (!substring)
4187       return;
4188     bounds.push_back(fir::getBase(asScalar(substring->lower())));
4189     if (auto upper = substring->upper())
4190       bounds.push_back(fir::getBase(asScalar(*upper)));
4191   }
4192 
4193   /// Default store to destination implementation.
4194   /// This implements the default case, which is to assign the value in
4195   /// `iters.element` into the destination array, `iters.innerArgument`. Handles
4196   /// by value and by reference assignment.
4197   CC defaultStoreToDestination(const Fortran::evaluate::Substring *substring) {
4198     return [=](IterSpace iterSpace) -> ExtValue {
4199       mlir::Location loc = getLoc();
4200       mlir::Value innerArg = iterSpace.innerArgument();
4201       fir::ExtendedValue exv = iterSpace.elementExv();
4202       mlir::Type arrTy = innerArg.getType();
4203       mlir::Type eleTy = fir::applyPathToType(arrTy, iterSpace.iterVec());
4204       if (isAdjustedArrayElementType(eleTy)) {
4205         // The elemental update is in the memref domain. Under this semantics,
4206         // we must always copy the computed new element from its location in
4207         // memory into the destination array.
4208         mlir::Type resRefTy = builder.getRefType(eleTy);
4209         // Get a reference to the array element to be amended.
4210         auto arrayOp = builder.create<fir::ArrayAccessOp>(
4211             loc, resRefTy, innerArg, iterSpace.iterVec(),
4212             destination.getTypeparams());
4213         if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) {
4214           llvm::SmallVector<mlir::Value> substringBounds;
4215           populateBounds(substringBounds, substring);
4216           mlir::Value dstLen = fir::factory::genLenOfCharacter(
4217               builder, loc, destination, iterSpace.iterVec(), substringBounds);
4218           fir::ArrayAmendOp amend = createCharArrayAmend(
4219               loc, builder, arrayOp, dstLen, exv, innerArg, substringBounds);
4220           return abstractArrayExtValue(amend, dstLen);
4221         }
4222         if (fir::isa_derived(eleTy)) {
4223           fir::ArrayAmendOp amend = createDerivedArrayAmend(
4224               loc, destination, builder, arrayOp, exv, eleTy, innerArg);
4225           return abstractArrayExtValue(amend /*FIXME: typeparams?*/);
4226         }
4227         assert(eleTy.isa<fir::SequenceType>() && "must be an array");
4228         TODO(loc, "array (as element) assignment");
4229       }
4230       // By value semantics. The element is being assigned by value.
4231       mlir::Value ele = builder.createConvert(loc, eleTy, fir::getBase(exv));
4232       auto update = builder.create<fir::ArrayUpdateOp>(
4233           loc, arrTy, innerArg, ele, iterSpace.iterVec(),
4234           destination.getTypeparams());
4235       return abstractArrayExtValue(update);
4236     };
4237   }
4238 
4239   /// For an elemental array expression.
4240   ///   1. Lower the scalars and array loads.
4241   ///   2. Create the iteration space.
4242   ///   3. Create the element-by-element computation in the loop.
4243   ///   4. Return the resulting array value.
4244   /// If no destination was set in the array context, a temporary of
4245   /// \p resultTy will be created to hold the evaluated expression.
4246   /// Otherwise, \p resultTy is ignored and the expression is evaluated
4247   /// in the destination. \p f is a continuation built from an
4248   /// evaluate::Expr or an ExtendedValue.
4249   ExtValue lowerArrayExpression(CC f, mlir::Type resultTy) {
4250     mlir::Location loc = getLoc();
4251     auto [iterSpace, insPt] = genIterSpace(resultTy);
4252     auto exv = f(iterSpace);
4253     iterSpace.setElement(std::move(exv));
4254     auto lambda = ccStoreToDest.hasValue()
4255                       ? ccStoreToDest.getValue()
4256                       : defaultStoreToDestination(/*substring=*/nullptr);
4257     mlir::Value updVal = fir::getBase(lambda(iterSpace));
4258     finalizeElementCtx();
4259     builder.create<fir::ResultOp>(loc, updVal);
4260     builder.restoreInsertionPoint(insPt);
4261     return abstractArrayExtValue(iterSpace.outerResult());
4262   }
4263 
4264   /// Get the shape from an ArrayOperand. The shape of the array is adjusted if
4265   /// the array was sliced.
4266   llvm::SmallVector<mlir::Value> getShape(ArrayOperand array) {
4267     // if (array.slice)
4268     //   return computeSliceShape(array.slice);
4269     if (array.memref.getType().isa<fir::BoxType>())
4270       return fir::factory::readExtents(builder, getLoc(),
4271                                        fir::BoxValue{array.memref});
4272     std::vector<mlir::Value, std::allocator<mlir::Value>> extents =
4273         fir::factory::getExtents(array.shape);
4274     return {extents.begin(), extents.end()};
4275   }
4276 
4277   /// Get the shape from an ArrayLoad.
4278   llvm::SmallVector<mlir::Value> getShape(fir::ArrayLoadOp arrayLoad) {
4279     return getShape(ArrayOperand{arrayLoad.getMemref(), arrayLoad.getShape(),
4280                                  arrayLoad.getSlice()});
4281   }
4282 
4283   /// Returns the first array operand that may not be absent. If all
4284   /// array operands may be absent, return the first one.
4285   const ArrayOperand &getInducingShapeArrayOperand() const {
4286     assert(!arrayOperands.empty());
4287     for (const ArrayOperand &op : arrayOperands)
4288       if (!op.mayBeAbsent)
4289         return op;
4290     // If all arrays operand appears in optional position, then none of them
4291     // is allowed to be absent as per 15.5.2.12 point 3. (6). Just pick the
4292     // first operands.
4293     // TODO: There is an opportunity to add a runtime check here that
4294     // this array is present as required.
4295     return arrayOperands[0];
4296   }
4297 
4298   /// Generate the shape of the iteration space over the array expression. The
4299   /// iteration space may be implicit, explicit, or both. If it is implied it is
4300   /// based on the destination and operand array loads, or an optional
4301   /// Fortran::evaluate::Shape from the front end. If the shape is explicit,
4302   /// this returns any implicit shape component, if it exists.
4303   llvm::SmallVector<mlir::Value> genIterationShape() {
4304     // Use the precomputed destination shape.
4305     if (!destShape.empty())
4306       return destShape;
4307     // Otherwise, use the destination's shape.
4308     if (destination)
4309       return getShape(destination);
4310     // Otherwise, use the first ArrayLoad operand shape.
4311     if (!arrayOperands.empty())
4312       return getShape(getInducingShapeArrayOperand());
4313     fir::emitFatalError(getLoc(),
4314                         "failed to compute the array expression shape");
4315   }
4316 
4317   bool explicitSpaceIsActive() const {
4318     return explicitSpace && explicitSpace->isActive();
4319   }
4320 
4321   bool implicitSpaceHasMasks() const {
4322     return implicitSpace && !implicitSpace->empty();
4323   }
4324 
4325   explicit ArrayExprLowering(Fortran::lower::AbstractConverter &converter,
4326                              Fortran::lower::StatementContext &stmtCtx,
4327                              Fortran::lower::SymMap &symMap)
4328       : converter{converter}, builder{converter.getFirOpBuilder()},
4329         stmtCtx{stmtCtx}, symMap{symMap} {}
4330 
4331   explicit ArrayExprLowering(Fortran::lower::AbstractConverter &converter,
4332                              Fortran::lower::StatementContext &stmtCtx,
4333                              Fortran::lower::SymMap &symMap,
4334                              ConstituentSemantics sem)
4335       : converter{converter}, builder{converter.getFirOpBuilder()},
4336         stmtCtx{stmtCtx}, symMap{symMap}, semant{sem} {}
4337 
4338   explicit ArrayExprLowering(Fortran::lower::AbstractConverter &converter,
4339                              Fortran::lower::StatementContext &stmtCtx,
4340                              Fortran::lower::SymMap &symMap,
4341                              ConstituentSemantics sem,
4342                              Fortran::lower::ExplicitIterSpace *expSpace,
4343                              Fortran::lower::ImplicitIterSpace *impSpace)
4344       : converter{converter}, builder{converter.getFirOpBuilder()},
4345         stmtCtx{stmtCtx}, symMap{symMap},
4346         explicitSpace(expSpace->isActive() ? expSpace : nullptr),
4347         implicitSpace(impSpace->empty() ? nullptr : impSpace), semant{sem} {
4348     // Generate any mask expressions, as necessary. This is the compute step
4349     // that creates the effective masks. See 10.2.3.2 in particular.
4350     // genMasks();
4351   }
4352 
4353   mlir::Location getLoc() { return converter.getCurrentLocation(); }
4354 
4355   /// Array appears in a lhs context such that it is assigned after the rhs is
4356   /// fully evaluated.
4357   inline bool isCopyInCopyOut() {
4358     return semant == ConstituentSemantics::CopyInCopyOut;
4359   }
4360 
4361   /// Array appears in a lhs (or temp) context such that a projected,
4362   /// discontiguous subspace of the array is assigned after the rhs is fully
4363   /// evaluated. That is, the rhs array value is merged into a section of the
4364   /// lhs array.
4365   inline bool isProjectedCopyInCopyOut() {
4366     return semant == ConstituentSemantics::ProjectedCopyInCopyOut;
4367   }
4368 
4369   inline bool isCustomCopyInCopyOut() {
4370     return semant == ConstituentSemantics::CustomCopyInCopyOut;
4371   }
4372 
4373   /// Array appears in a context where it must be boxed.
4374   inline bool isBoxValue() { return semant == ConstituentSemantics::BoxValue; }
4375 
4376   /// Array appears in a context where differences in the memory reference can
4377   /// be observable in the computational results. For example, an array
4378   /// element is passed to an impure procedure.
4379   inline bool isReferentiallyOpaque() {
4380     return semant == ConstituentSemantics::RefOpaque;
4381   }
4382 
4383   /// Array appears in a context where it is passed as a VALUE argument.
4384   inline bool isValueAttribute() {
4385     return semant == ConstituentSemantics::ByValueArg;
4386   }
4387 
4388   /// Can the loops over the expression be unordered?
4389   inline bool isUnordered() const { return unordered; }
4390 
4391   void setUnordered(bool b) { unordered = b; }
4392 
4393   Fortran::lower::AbstractConverter &converter;
4394   fir::FirOpBuilder &builder;
4395   Fortran::lower::StatementContext &stmtCtx;
4396   bool elementCtx = false;
4397   Fortran::lower::SymMap &symMap;
4398   /// The continuation to generate code to update the destination.
4399   llvm::Optional<CC> ccStoreToDest;
4400   llvm::Optional<std::function<void(llvm::ArrayRef<mlir::Value>)>> ccPrelude;
4401   llvm::Optional<std::function<fir::ArrayLoadOp(llvm::ArrayRef<mlir::Value>)>>
4402       ccLoadDest;
4403   /// The destination is the loaded array into which the results will be
4404   /// merged.
4405   fir::ArrayLoadOp destination;
4406   /// The shape of the destination.
4407   llvm::SmallVector<mlir::Value> destShape;
4408   /// List of arrays in the expression that have been loaded.
4409   llvm::SmallVector<ArrayOperand> arrayOperands;
4410   /// If there is a user-defined iteration space, explicitShape will hold the
4411   /// information from the front end.
4412   Fortran::lower::ExplicitIterSpace *explicitSpace = nullptr;
4413   Fortran::lower::ImplicitIterSpace *implicitSpace = nullptr;
4414   ConstituentSemantics semant = ConstituentSemantics::RefTransparent;
4415   // Can the array expression be evaluated in any order?
4416   // Will be set to false if any of the expression parts prevent this.
4417   bool unordered = true;
4418 };
4419 } // namespace
4420 
4421 fir::ExtendedValue Fortran::lower::createSomeExtendedExpression(
4422     mlir::Location loc, Fortran::lower::AbstractConverter &converter,
4423     const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap,
4424     Fortran::lower::StatementContext &stmtCtx) {
4425   LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "expr: ") << '\n');
4426   return ScalarExprLowering{loc, converter, symMap, stmtCtx}.genval(expr);
4427 }
4428 
4429 fir::GlobalOp Fortran::lower::createDenseGlobal(
4430     mlir::Location loc, mlir::Type symTy, llvm::StringRef globalName,
4431     mlir::StringAttr linkage, bool isConst,
4432     const Fortran::lower::SomeExpr &expr,
4433     Fortran::lower::AbstractConverter &converter) {
4434 
4435   Fortran::lower::StatementContext stmtCtx(/*prohibited=*/true);
4436   Fortran::lower::SymMap emptyMap;
4437   InitializerData initData(/*genRawVals=*/true);
4438   ScalarExprLowering sel(loc, converter, emptyMap, stmtCtx,
4439                          /*initializer=*/&initData);
4440   sel.genval(expr);
4441 
4442   size_t sz = initData.rawVals.size();
4443   llvm::ArrayRef<mlir::Attribute> ar = {initData.rawVals.data(), sz};
4444 
4445   mlir::RankedTensorType tensorTy;
4446   auto &builder = converter.getFirOpBuilder();
4447   mlir::Type iTy = initData.rawType;
4448   if (!iTy)
4449     return 0; // array extent is probably 0 in this case, so just return 0.
4450   tensorTy = mlir::RankedTensorType::get(sz, iTy);
4451   auto init = mlir::DenseElementsAttr::get(tensorTy, ar);
4452   return builder.createGlobal(loc, symTy, globalName, linkage, init, isConst);
4453 }
4454 
4455 fir::ExtendedValue Fortran::lower::createSomeInitializerExpression(
4456     mlir::Location loc, Fortran::lower::AbstractConverter &converter,
4457     const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap,
4458     Fortran::lower::StatementContext &stmtCtx) {
4459   LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "expr: ") << '\n');
4460   InitializerData initData; // needed for initializations
4461   return ScalarExprLowering{loc, converter, symMap, stmtCtx,
4462                             /*initializer=*/&initData}
4463       .genval(expr);
4464 }
4465 
4466 fir::ExtendedValue Fortran::lower::createSomeExtendedAddress(
4467     mlir::Location loc, Fortran::lower::AbstractConverter &converter,
4468     const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap,
4469     Fortran::lower::StatementContext &stmtCtx) {
4470   LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "address: ") << '\n');
4471   return ScalarExprLowering{loc, converter, symMap, stmtCtx}.gen(expr);
4472 }
4473 
4474 fir::ExtendedValue Fortran::lower::createInitializerAddress(
4475     mlir::Location loc, Fortran::lower::AbstractConverter &converter,
4476     const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap,
4477     Fortran::lower::StatementContext &stmtCtx) {
4478   LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "address: ") << '\n');
4479   InitializerData init;
4480   return ScalarExprLowering(loc, converter, symMap, stmtCtx, &init).gen(expr);
4481 }
4482 
4483 fir::ExtendedValue
4484 Fortran::lower::createSomeArrayBox(Fortran::lower::AbstractConverter &converter,
4485                                    const Fortran::lower::SomeExpr &expr,
4486                                    Fortran::lower::SymMap &symMap,
4487                                    Fortran::lower::StatementContext &stmtCtx) {
4488   LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "box designator: ") << '\n');
4489   return ArrayExprLowering::lowerBoxedArrayExpression(converter, symMap,
4490                                                       stmtCtx, expr);
4491 }
4492 
4493 fir::MutableBoxValue Fortran::lower::createMutableBox(
4494     mlir::Location loc, Fortran::lower::AbstractConverter &converter,
4495     const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap) {
4496   // MutableBox lowering StatementContext does not need to be propagated
4497   // to the caller because the result value is a variable, not a temporary
4498   // expression. The StatementContext clean-up can occur before using the
4499   // resulting MutableBoxValue. Variables of all other types are handled in the
4500   // bridge.
4501   Fortran::lower::StatementContext dummyStmtCtx;
4502   return ScalarExprLowering{loc, converter, symMap, dummyStmtCtx}
4503       .genMutableBoxValue(expr);
4504 }
4505 
4506 fir::ExtendedValue Fortran::lower::createBoxValue(
4507     mlir::Location loc, Fortran::lower::AbstractConverter &converter,
4508     const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap,
4509     Fortran::lower::StatementContext &stmtCtx) {
4510   if (expr.Rank() > 0 && Fortran::evaluate::IsVariable(expr) &&
4511       !Fortran::evaluate::HasVectorSubscript(expr))
4512     return Fortran::lower::createSomeArrayBox(converter, expr, symMap, stmtCtx);
4513   fir::ExtendedValue addr = Fortran::lower::createSomeExtendedAddress(
4514       loc, converter, expr, symMap, stmtCtx);
4515   return fir::BoxValue(converter.getFirOpBuilder().createBox(loc, addr));
4516 }
4517 
4518 mlir::Value Fortran::lower::createSubroutineCall(
4519     AbstractConverter &converter, const evaluate::ProcedureRef &call,
4520     SymMap &symMap, StatementContext &stmtCtx) {
4521   mlir::Location loc = converter.getCurrentLocation();
4522 
4523   // Simple subroutine call, with potential alternate return.
4524   auto res = Fortran::lower::createSomeExtendedExpression(
4525       loc, converter, toEvExpr(call), symMap, stmtCtx);
4526   return fir::getBase(res);
4527 }
4528 
4529 void Fortran::lower::createSomeArrayAssignment(
4530     Fortran::lower::AbstractConverter &converter,
4531     const Fortran::lower::SomeExpr &lhs, const Fortran::lower::SomeExpr &rhs,
4532     Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx) {
4533   LLVM_DEBUG(lhs.AsFortran(llvm::dbgs() << "onto array: ") << '\n';
4534              rhs.AsFortran(llvm::dbgs() << "assign expression: ") << '\n';);
4535   ArrayExprLowering::lowerArrayAssignment(converter, symMap, stmtCtx, lhs, rhs);
4536 }
4537 
4538 void Fortran::lower::createSomeArrayAssignment(
4539     Fortran::lower::AbstractConverter &converter, const fir::ExtendedValue &lhs,
4540     const fir::ExtendedValue &rhs, Fortran::lower::SymMap &symMap,
4541     Fortran::lower::StatementContext &stmtCtx) {
4542   LLVM_DEBUG(llvm::dbgs() << "onto array: " << lhs << '\n';
4543              llvm::dbgs() << "assign expression: " << rhs << '\n';);
4544   ArrayExprLowering::lowerArrayAssignment(converter, symMap, stmtCtx, lhs, rhs);
4545 }
4546 
4547 void Fortran::lower::createAllocatableArrayAssignment(
4548     Fortran::lower::AbstractConverter &converter,
4549     const Fortran::lower::SomeExpr &lhs, const Fortran::lower::SomeExpr &rhs,
4550     Fortran::lower::ExplicitIterSpace &explicitSpace,
4551     Fortran::lower::ImplicitIterSpace &implicitSpace,
4552     Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx) {
4553   LLVM_DEBUG(lhs.AsFortran(llvm::dbgs() << "defining array: ") << '\n';
4554              rhs.AsFortran(llvm::dbgs() << "assign expression: ")
4555              << " given the explicit iteration space:\n"
4556              << explicitSpace << "\n and implied mask conditions:\n"
4557              << implicitSpace << '\n';);
4558   ArrayExprLowering::lowerAllocatableArrayAssignment(
4559       converter, symMap, stmtCtx, lhs, rhs, explicitSpace, implicitSpace);
4560 }
4561 
4562 fir::ExtendedValue Fortran::lower::createSomeArrayTempValue(
4563     Fortran::lower::AbstractConverter &converter,
4564     const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap,
4565     Fortran::lower::StatementContext &stmtCtx) {
4566   LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "array value: ") << '\n');
4567   return ArrayExprLowering::lowerNewArrayExpression(converter, symMap, stmtCtx,
4568                                                     expr);
4569 }
4570 
4571 mlir::Value Fortran::lower::genMaxWithZero(fir::FirOpBuilder &builder,
4572                                            mlir::Location loc,
4573                                            mlir::Value value) {
4574   mlir::Value zero = builder.createIntegerConstant(loc, value.getType(), 0);
4575   if (mlir::Operation *definingOp = value.getDefiningOp())
4576     if (auto cst = mlir::dyn_cast<mlir::arith::ConstantOp>(definingOp))
4577       if (auto intAttr = cst.getValue().dyn_cast<mlir::IntegerAttr>())
4578         return intAttr.getInt() < 0 ? zero : value;
4579   return Fortran::lower::genMax(builder, loc,
4580                                 llvm::SmallVector<mlir::Value>{value, zero});
4581 }
4582