1 //===-- Bridge.cpp -- bridge to lower to MLIR -----------------------------===//
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/Bridge.h"
14 #include "flang/Lower/Allocatable.h"
15 #include "flang/Lower/CallInterface.h"
16 #include "flang/Lower/Coarray.h"
17 #include "flang/Lower/ConvertExpr.h"
18 #include "flang/Lower/ConvertType.h"
19 #include "flang/Lower/ConvertVariable.h"
20 #include "flang/Lower/HostAssociations.h"
21 #include "flang/Lower/IO.h"
22 #include "flang/Lower/IterationSpace.h"
23 #include "flang/Lower/Mangler.h"
24 #include "flang/Lower/OpenACC.h"
25 #include "flang/Lower/OpenMP.h"
26 #include "flang/Lower/PFTBuilder.h"
27 #include "flang/Lower/Runtime.h"
28 #include "flang/Lower/StatementContext.h"
29 #include "flang/Lower/Support/Utils.h"
30 #include "flang/Optimizer/Builder/BoxValue.h"
31 #include "flang/Optimizer/Builder/Character.h"
32 #include "flang/Optimizer/Builder/FIRBuilder.h"
33 #include "flang/Optimizer/Builder/Runtime/Character.h"
34 #include "flang/Optimizer/Builder/Runtime/Ragged.h"
35 #include "flang/Optimizer/Builder/Todo.h"
36 #include "flang/Optimizer/Dialect/FIRAttr.h"
37 #include "flang/Optimizer/Dialect/FIRDialect.h"
38 #include "flang/Optimizer/Dialect/FIROps.h"
39 #include "flang/Optimizer/Support/FIRContext.h"
40 #include "flang/Optimizer/Support/FatalError.h"
41 #include "flang/Optimizer/Support/InternalNames.h"
42 #include "flang/Optimizer/Transforms/Passes.h"
43 #include "flang/Parser/parse-tree.h"
44 #include "flang/Runtime/iostat.h"
45 #include "flang/Semantics/tools.h"
46 #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
47 #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
48 #include "mlir/IR/PatternMatch.h"
49 #include "mlir/Parser/Parser.h"
50 #include "mlir/Transforms/RegionUtils.h"
51 #include "llvm/Support/CommandLine.h"
52 #include "llvm/Support/Debug.h"
53 #include "llvm/Support/ErrorHandling.h"
54 
55 #define DEBUG_TYPE "flang-lower-bridge"
56 
57 static llvm::cl::opt<bool> dumpBeforeFir(
58     "fdebug-dump-pre-fir", llvm::cl::init(false),
59     llvm::cl::desc("dump the Pre-FIR tree prior to FIR generation"));
60 
61 static llvm::cl::opt<bool> forceLoopToExecuteOnce(
62     "always-execute-loop-body", llvm::cl::init(false),
63     llvm::cl::desc("force the body of a loop to execute at least once"));
64 
65 namespace {
66 /// Information for generating a structured or unstructured increment loop.
67 struct IncrementLoopInfo {
68   template <typename T>
69   explicit IncrementLoopInfo(Fortran::semantics::Symbol &sym, const T &lower,
70                              const T &upper, const std::optional<T> &step,
71                              bool isUnordered = false)
72       : loopVariableSym{sym}, lowerExpr{Fortran::semantics::GetExpr(lower)},
73         upperExpr{Fortran::semantics::GetExpr(upper)},
74         stepExpr{Fortran::semantics::GetExpr(step)}, isUnordered{isUnordered} {}
75 
76   IncrementLoopInfo(IncrementLoopInfo &&) = default;
77   IncrementLoopInfo &operator=(IncrementLoopInfo &&x) { return x; }
78 
79   bool isStructured() const { return !headerBlock; }
80 
81   mlir::Type getLoopVariableType() const {
82     assert(loopVariable && "must be set");
83     return fir::unwrapRefType(loopVariable.getType());
84   }
85 
86   // Data members common to both structured and unstructured loops.
87   const Fortran::semantics::Symbol &loopVariableSym;
88   const Fortran::lower::SomeExpr *lowerExpr;
89   const Fortran::lower::SomeExpr *upperExpr;
90   const Fortran::lower::SomeExpr *stepExpr;
91   const Fortran::lower::SomeExpr *maskExpr = nullptr;
92   bool isUnordered; // do concurrent, forall
93   llvm::SmallVector<const Fortran::semantics::Symbol *> localInitSymList;
94   llvm::SmallVector<const Fortran::semantics::Symbol *> sharedSymList;
95   mlir::Value loopVariable = nullptr;
96   mlir::Value stepValue = nullptr; // possible uses in multiple blocks
97 
98   // Data members for structured loops.
99   fir::DoLoopOp doLoop = nullptr;
100 
101   // Data members for unstructured loops.
102   bool hasRealControl = false;
103   mlir::Value tripVariable = nullptr;
104   mlir::Block *headerBlock = nullptr; // loop entry and test block
105   mlir::Block *maskBlock = nullptr;   // concurrent loop mask block
106   mlir::Block *bodyBlock = nullptr;   // first loop body block
107   mlir::Block *exitBlock = nullptr;   // loop exit target block
108 };
109 
110 /// Helper class to generate the runtime type info global data. This data
111 /// is required to describe the derived type to the runtime so that it can
112 /// operate over it. It must be ensured this data will be generated for every
113 /// derived type lowered in the current translated unit. However, this data
114 /// cannot be generated before FuncOp have been created for functions since the
115 /// initializers may take their address (e.g for type bound procedures). This
116 /// class allows registering all the required runtime type info while it is not
117 /// possible to create globals, and to generate this data after function
118 /// lowering.
119 class RuntimeTypeInfoConverter {
120   /// Store the location and symbols of derived type info to be generated.
121   /// The location of the derived type instantiation is also stored because
122   /// runtime type descriptor symbol are compiler generated and cannot be mapped
123   /// to user code on their own.
124   struct TypeInfoSymbol {
125     Fortran::semantics::SymbolRef symbol;
126     mlir::Location loc;
127   };
128 
129 public:
130   void registerTypeInfoSymbol(Fortran::lower::AbstractConverter &converter,
131                               mlir::Location loc,
132                               Fortran::semantics::SymbolRef typeInfoSym) {
133     if (seen.contains(typeInfoSym))
134       return;
135     seen.insert(typeInfoSym);
136     if (!skipRegistration) {
137       registeredTypeInfoSymbols.emplace_back(TypeInfoSymbol{typeInfoSym, loc});
138       return;
139     }
140     // Once the registration is closed, symbols cannot be added to the
141     // registeredTypeInfoSymbols list because it may be iterated over.
142     // However, after registration is closed, it is safe to directly generate
143     // the globals because all FuncOps whose addresses may be required by the
144     // initializers have been generated.
145     Fortran::lower::createRuntimeTypeInfoGlobal(converter, loc,
146                                                 typeInfoSym.get());
147   }
148 
149   void createTypeInfoGlobals(Fortran::lower::AbstractConverter &converter) {
150     skipRegistration = true;
151     for (const TypeInfoSymbol &info : registeredTypeInfoSymbols)
152       Fortran::lower::createRuntimeTypeInfoGlobal(converter, info.loc,
153                                                   info.symbol.get());
154     registeredTypeInfoSymbols.clear();
155   }
156 
157 private:
158   /// Store the runtime type descriptors that will be required for the
159   /// derived type that have been converted to FIR derived types.
160   llvm::SmallVector<TypeInfoSymbol> registeredTypeInfoSymbols;
161   /// Create derived type runtime info global immediately without storing the
162   /// symbol in registeredTypeInfoSymbols.
163   bool skipRegistration = false;
164   /// Track symbols symbols processed during and after the registration
165   /// to avoid infinite loops between type conversions and global variable
166   /// creation.
167   llvm::SmallSetVector<Fortran::semantics::SymbolRef, 64> seen;
168 };
169 
170 using IncrementLoopNestInfo = llvm::SmallVector<IncrementLoopInfo>;
171 } // namespace
172 
173 //===----------------------------------------------------------------------===//
174 // FirConverter
175 //===----------------------------------------------------------------------===//
176 
177 namespace {
178 
179 /// Traverse the pre-FIR tree (PFT) to generate the FIR dialect of MLIR.
180 class FirConverter : public Fortran::lower::AbstractConverter {
181 public:
182   explicit FirConverter(Fortran::lower::LoweringBridge &bridge)
183       : bridge{bridge}, foldingContext{bridge.createFoldingContext()} {}
184   virtual ~FirConverter() = default;
185 
186   /// Convert the PFT to FIR.
187   void run(Fortran::lower::pft::Program &pft) {
188     // Preliminary translation pass.
189 
190     // - Lower common blocks from the PFT common block list that contains a
191     // consolidated list of the common blocks (with the initialization if any in
192     // the Program, and with the common block biggest size in all its
193     // appearance). This is done before lowering any scope declarations because
194     // it is not know at the local scope level what MLIR type common blocks
195     // should have to suit all its usage in the compilation unit.
196     lowerCommonBlocks(pft.getCommonBlocks());
197 
198     //  - Declare all functions that have definitions so that definition
199     //    signatures prevail over call site signatures.
200     //  - Define module variables and OpenMP/OpenACC declarative construct so
201     //    that they are available before lowering any function that may use
202     //    them.
203     for (Fortran::lower::pft::Program::Units &u : pft.getUnits()) {
204       std::visit(Fortran::common::visitors{
205                      [&](Fortran::lower::pft::FunctionLikeUnit &f) {
206                        declareFunction(f);
207                      },
208                      [&](Fortran::lower::pft::ModuleLikeUnit &m) {
209                        lowerModuleDeclScope(m);
210                        for (Fortran::lower::pft::FunctionLikeUnit &f :
211                             m.nestedFunctions)
212                          declareFunction(f);
213                      },
214                      [&](Fortran::lower::pft::BlockDataUnit &b) {},
215                      [&](Fortran::lower::pft::CompilerDirectiveUnit &d) {},
216                  },
217                  u);
218     }
219 
220     // Primary translation pass.
221     for (Fortran::lower::pft::Program::Units &u : pft.getUnits()) {
222       std::visit(
223           Fortran::common::visitors{
224               [&](Fortran::lower::pft::FunctionLikeUnit &f) { lowerFunc(f); },
225               [&](Fortran::lower::pft::ModuleLikeUnit &m) { lowerMod(m); },
226               [&](Fortran::lower::pft::BlockDataUnit &b) {},
227               [&](Fortran::lower::pft::CompilerDirectiveUnit &d) {
228                 setCurrentPosition(
229                     d.get<Fortran::parser::CompilerDirective>().source);
230                 mlir::emitWarning(toLocation(),
231                                   "ignoring all compiler directives");
232               },
233           },
234           u);
235     }
236 
237     /// Once all the code has been translated, create runtime type info
238     /// global data structure for the derived types that have been
239     /// processed.
240     createGlobalOutsideOfFunctionLowering(
241         [&]() { runtimeTypeInfoConverter.createTypeInfoGlobals(*this); });
242   }
243 
244   /// Declare a function.
245   void declareFunction(Fortran::lower::pft::FunctionLikeUnit &funit) {
246     setCurrentPosition(funit.getStartingSourceLoc());
247     for (int entryIndex = 0, last = funit.entryPointList.size();
248          entryIndex < last; ++entryIndex) {
249       funit.setActiveEntry(entryIndex);
250       // Calling CalleeInterface ctor will build a declaration
251       // mlir::func::FuncOp with no other side effects.
252       // TODO: when doing some compiler profiling on real apps, it may be worth
253       // to check it's better to save the CalleeInterface instead of recomputing
254       // it later when lowering the body. CalleeInterface ctor should be linear
255       // with the number of arguments, so it is not awful to do it that way for
256       // now, but the linear coefficient might be non negligible. Until
257       // measured, stick to the solution that impacts the code less.
258       Fortran::lower::CalleeInterface{funit, *this};
259     }
260     funit.setActiveEntry(0);
261 
262     // Compute the set of host associated entities from the nested functions.
263     llvm::SetVector<const Fortran::semantics::Symbol *> escapeHost;
264     for (Fortran::lower::pft::FunctionLikeUnit &f : funit.nestedFunctions)
265       collectHostAssociatedVariables(f, escapeHost);
266     funit.setHostAssociatedSymbols(escapeHost);
267 
268     // Declare internal procedures
269     for (Fortran::lower::pft::FunctionLikeUnit &f : funit.nestedFunctions)
270       declareFunction(f);
271   }
272 
273   /// Collects the canonical list of all host associated symbols. These bindings
274   /// must be aggregated into a tuple which can then be added to each of the
275   /// internal procedure declarations and passed at each call site.
276   void collectHostAssociatedVariables(
277       Fortran::lower::pft::FunctionLikeUnit &funit,
278       llvm::SetVector<const Fortran::semantics::Symbol *> &escapees) {
279     const Fortran::semantics::Scope *internalScope =
280         funit.getSubprogramSymbol().scope();
281     assert(internalScope && "internal procedures symbol must create a scope");
282     auto addToListIfEscapee = [&](const Fortran::semantics::Symbol &sym) {
283       const Fortran::semantics::Symbol &ultimate = sym.GetUltimate();
284       const auto *namelistDetails =
285           ultimate.detailsIf<Fortran::semantics::NamelistDetails>();
286       if (ultimate.has<Fortran::semantics::ObjectEntityDetails>() ||
287           Fortran::semantics::IsProcedurePointer(ultimate) ||
288           Fortran::semantics::IsDummy(sym) || namelistDetails) {
289         const Fortran::semantics::Scope &ultimateScope = ultimate.owner();
290         if (ultimateScope.kind() ==
291                 Fortran::semantics::Scope::Kind::MainProgram ||
292             ultimateScope.kind() == Fortran::semantics::Scope::Kind::Subprogram)
293           if (ultimateScope != *internalScope &&
294               ultimateScope.Contains(*internalScope)) {
295             if (namelistDetails) {
296               // So far, namelist symbols are processed on the fly in IO and
297               // the related namelist data structure is not added to the symbol
298               // map, so it cannot be passed to the internal procedures.
299               // Instead, all the symbols of the host namelist used in the
300               // internal procedure must be considered as host associated so
301               // that IO lowering can find them when needed.
302               for (const auto &namelistObject : namelistDetails->objects())
303                 escapees.insert(&*namelistObject);
304             } else {
305               escapees.insert(&ultimate);
306             }
307           }
308       }
309     };
310     Fortran::lower::pft::visitAllSymbols(funit, addToListIfEscapee);
311   }
312 
313   //===--------------------------------------------------------------------===//
314   // AbstractConverter overrides
315   //===--------------------------------------------------------------------===//
316 
317   mlir::Value getSymbolAddress(Fortran::lower::SymbolRef sym) override final {
318     return lookupSymbol(sym).getAddr();
319   }
320 
321   fir::ExtendedValue
322   getSymbolExtendedValue(const Fortran::semantics::Symbol &sym) override final {
323     Fortran::lower::SymbolBox sb = localSymbols.lookupSymbol(sym);
324     assert(sb && "symbol box not found");
325     return sb.toExtendedValue();
326   }
327 
328   mlir::Value impliedDoBinding(llvm::StringRef name) override final {
329     mlir::Value val = localSymbols.lookupImpliedDo(name);
330     if (!val)
331       fir::emitFatalError(toLocation(), "ac-do-variable has no binding");
332     return val;
333   }
334 
335   void copySymbolBinding(Fortran::lower::SymbolRef src,
336                          Fortran::lower::SymbolRef target) override final {
337     localSymbols.addSymbol(target, lookupSymbol(src).toExtendedValue());
338   }
339 
340   /// Add the symbol binding to the inner-most level of the symbol map and
341   /// return true if it is not already present. Otherwise, return false.
342   bool bindIfNewSymbol(Fortran::lower::SymbolRef sym,
343                        const fir::ExtendedValue &exval) {
344     if (shallowLookupSymbol(sym))
345       return false;
346     bindSymbol(sym, exval);
347     return true;
348   }
349 
350   void bindSymbol(Fortran::lower::SymbolRef sym,
351                   const fir::ExtendedValue &exval) override final {
352     localSymbols.addSymbol(sym, exval, /*forced=*/true);
353   }
354 
355   bool lookupLabelSet(Fortran::lower::SymbolRef sym,
356                       Fortran::lower::pft::LabelSet &labelSet) override final {
357     Fortran::lower::pft::FunctionLikeUnit &owningProc =
358         *getEval().getOwningProcedure();
359     auto iter = owningProc.assignSymbolLabelMap.find(sym);
360     if (iter == owningProc.assignSymbolLabelMap.end())
361       return false;
362     labelSet = iter->second;
363     return true;
364   }
365 
366   Fortran::lower::pft::Evaluation *
367   lookupLabel(Fortran::lower::pft::Label label) override final {
368     Fortran::lower::pft::FunctionLikeUnit &owningProc =
369         *getEval().getOwningProcedure();
370     auto iter = owningProc.labelEvaluationMap.find(label);
371     if (iter == owningProc.labelEvaluationMap.end())
372       return nullptr;
373     return iter->second;
374   }
375 
376   fir::ExtendedValue genExprAddr(const Fortran::lower::SomeExpr &expr,
377                                  Fortran::lower::StatementContext &context,
378                                  mlir::Location *loc = nullptr) override final {
379     return Fortran::lower::createSomeExtendedAddress(
380         loc ? *loc : toLocation(), *this, expr, localSymbols, context);
381   }
382   fir::ExtendedValue
383   genExprValue(const Fortran::lower::SomeExpr &expr,
384                Fortran::lower::StatementContext &context,
385                mlir::Location *loc = nullptr) override final {
386     return Fortran::lower::createSomeExtendedExpression(
387         loc ? *loc : toLocation(), *this, expr, localSymbols, context);
388   }
389 
390   fir::ExtendedValue
391   genExprBox(mlir::Location loc, const Fortran::lower::SomeExpr &expr,
392              Fortran::lower::StatementContext &stmtCtx) override final {
393     return Fortran::lower::createBoxValue(loc, *this, expr, localSymbols,
394                                           stmtCtx);
395   }
396 
397   Fortran::evaluate::FoldingContext &getFoldingContext() override final {
398     return foldingContext;
399   }
400 
401   mlir::Type genType(const Fortran::lower::SomeExpr &expr) override final {
402     return Fortran::lower::translateSomeExprToFIRType(*this, expr);
403   }
404   mlir::Type genType(const Fortran::lower::pft::Variable &var) override final {
405     return Fortran::lower::translateVariableToFIRType(*this, var);
406   }
407   mlir::Type genType(Fortran::lower::SymbolRef sym) override final {
408     return Fortran::lower::translateSymbolToFIRType(*this, sym);
409   }
410   mlir::Type
411   genType(Fortran::common::TypeCategory tc, int kind,
412           llvm::ArrayRef<std::int64_t> lenParameters) override final {
413     return Fortran::lower::getFIRType(&getMLIRContext(), tc, kind,
414                                       lenParameters);
415   }
416   mlir::Type
417   genType(const Fortran::semantics::DerivedTypeSpec &tySpec) override final {
418     return Fortran::lower::translateDerivedTypeToFIRType(*this, tySpec);
419   }
420   mlir::Type genType(Fortran::common::TypeCategory tc) override final {
421     return Fortran::lower::getFIRType(
422         &getMLIRContext(), tc, bridge.getDefaultKinds().GetDefaultKind(tc),
423         llvm::None);
424   }
425 
426   bool createHostAssociateVarClone(
427       const Fortran::semantics::Symbol &sym) override final {
428     mlir::Location loc = genLocation(sym.name());
429     mlir::Type symType = genType(sym);
430     const auto *details = sym.detailsIf<Fortran::semantics::HostAssocDetails>();
431     assert(details && "No host-association found");
432     const Fortran::semantics::Symbol &hsym = details->symbol();
433     Fortran::lower::SymbolBox hsb = lookupSymbol(hsym);
434 
435     auto allocate = [&](llvm::ArrayRef<mlir::Value> shape,
436                         llvm::ArrayRef<mlir::Value> typeParams) -> mlir::Value {
437       mlir::Value allocVal = builder->allocateLocal(
438           loc, symType, mangleName(sym), toStringRef(sym.GetUltimate().name()),
439           /*pinned=*/true, shape, typeParams,
440           sym.GetUltimate().attrs().test(Fortran::semantics::Attr::TARGET));
441       return allocVal;
442     };
443 
444     fir::ExtendedValue hexv = getExtendedValue(hsb);
445     fir::ExtendedValue exv = hexv.match(
446         [&](const fir::BoxValue &box) -> fir::ExtendedValue {
447           const Fortran::semantics::DeclTypeSpec *type = sym.GetType();
448           if (type && type->IsPolymorphic())
449             TODO(loc, "create polymorphic host associated copy");
450           // Create a contiguous temp with the same shape and length as
451           // the original variable described by a fir.box.
452           llvm::SmallVector<mlir::Value> extents =
453               fir::factory::getExtents(loc, *builder, hexv);
454           if (box.isDerivedWithLenParameters())
455             TODO(loc, "get length parameters from derived type BoxValue");
456           if (box.isCharacter()) {
457             mlir::Value len = fir::factory::readCharLen(*builder, loc, box);
458             mlir::Value temp = allocate(extents, {len});
459             return fir::CharArrayBoxValue{temp, len, extents};
460           }
461           return fir::ArrayBoxValue{allocate(extents, {}), extents};
462         },
463         [&](const fir::MutableBoxValue &box) -> fir::ExtendedValue {
464           // Allocate storage for a pointer/allocatble descriptor.
465           // No shape/lengths to be passed to the alloca.
466           return fir::MutableBoxValue(allocate({}, {}),
467                                       box.nonDeferredLenParams(), {});
468         },
469         [&](const auto &) -> fir::ExtendedValue {
470           mlir::Value temp =
471               allocate(fir::factory::getExtents(loc, *builder, hexv),
472                        fir::factory::getTypeParams(loc, *builder, hexv));
473           return fir::substBase(hexv, temp);
474         });
475 
476     // Replace all uses of the original with the clone/copy,
477     // esepcially for loop bounds (that uses the variable being privatised)
478     // since loop bounds use old values that need to be fixed by using the
479     // new copied value.
480     // Not able to use replaceAllUsesWith() because uses outside
481     // the loop body should not use the clone.
482     mlir::Region &curRegion = getFirOpBuilder().getRegion();
483     mlir::Value oldVal = fir::getBase(hexv);
484     mlir::Value cloneVal = fir::getBase(exv);
485     for (auto &oper : curRegion.getOps()) {
486       for (unsigned int ii = 0; ii < oper.getNumOperands(); ++ii) {
487         if (oper.getOperand(ii) == oldVal) {
488           oper.setOperand(ii, cloneVal);
489         }
490       }
491     }
492     return bindIfNewSymbol(sym, exv);
493   }
494 
495   // FIXME: Generalize this function, so that lastPrivBlock can be removed
496   void
497   copyHostAssociateVar(const Fortran::semantics::Symbol &sym,
498                        mlir::Block *lastPrivBlock = nullptr) override final {
499     // 1) Fetch the original copy of the variable.
500     assert(sym.has<Fortran::semantics::HostAssocDetails>() &&
501            "No host-association found");
502     const Fortran::semantics::Symbol &hsym = sym.GetUltimate();
503     Fortran::lower::SymbolBox hsb = lookupOneLevelUpSymbol(hsym);
504     assert(hsb && "Host symbol box not found");
505     fir::ExtendedValue hexv = getExtendedValue(hsb);
506 
507     // 2) Fetch the copied one that will mask the original.
508     Fortran::lower::SymbolBox sb = shallowLookupSymbol(sym);
509     assert(sb && "Host-associated symbol box not found");
510     assert(hsb.getAddr() != sb.getAddr() &&
511            "Host and associated symbol boxes are the same");
512     fir::ExtendedValue exv = getExtendedValue(sb);
513 
514     // 3) Perform the assignment.
515     mlir::OpBuilder::InsertPoint insPt = builder->saveInsertionPoint();
516     if (lastPrivBlock)
517       builder->setInsertionPointToStart(lastPrivBlock);
518     else
519       builder->setInsertionPointAfter(fir::getBase(exv).getDefiningOp());
520 
521     fir::ExtendedValue lhs, rhs;
522     if (lastPrivBlock) {
523       // lastprivate case
524       lhs = hexv;
525       rhs = exv;
526     } else {
527       lhs = exv;
528       rhs = hexv;
529     }
530 
531     mlir::Location loc = genLocation(sym.name());
532     mlir::Type symType = genType(sym);
533     if (auto seqTy = symType.dyn_cast<fir::SequenceType>()) {
534       Fortran::lower::StatementContext stmtCtx;
535       Fortran::lower::createSomeArrayAssignment(*this, lhs, rhs, localSymbols,
536                                                 stmtCtx);
537       stmtCtx.finalize();
538     } else if (hexv.getBoxOf<fir::CharBoxValue>()) {
539       fir::factory::CharacterExprHelper{*builder, loc}.createAssign(lhs, rhs);
540     } else if (hexv.getBoxOf<fir::MutableBoxValue>()) {
541       TODO(loc, "firstprivatisation of allocatable variables");
542     } else {
543       auto loadVal = builder->create<fir::LoadOp>(loc, fir::getBase(rhs));
544       builder->create<fir::StoreOp>(loc, loadVal, fir::getBase(lhs));
545     }
546 
547     if (lastPrivBlock)
548       builder->restoreInsertionPoint(insPt);
549   }
550 
551   //===--------------------------------------------------------------------===//
552   // Utility methods
553   //===--------------------------------------------------------------------===//
554 
555   void collectSymbolSet(
556       Fortran::lower::pft::Evaluation &eval,
557       llvm::SetVector<const Fortran::semantics::Symbol *> &symbolSet,
558       Fortran::semantics::Symbol::Flag flag,
559       bool checkHostAssoicatedSymbols) override final {
560     auto addToList = [&](const Fortran::semantics::Symbol &sym) {
561       std::function<void(const Fortran::semantics::Symbol &)> insertSymbols =
562           [&](const Fortran::semantics::Symbol &oriSymbol) {
563             if (oriSymbol.test(flag))
564               symbolSet.insert(&oriSymbol);
565             if (checkHostAssoicatedSymbols)
566               if (const auto *details{
567                       oriSymbol
568                           .detailsIf<Fortran::semantics::HostAssocDetails>()})
569                 insertSymbols(details->symbol());
570           };
571       insertSymbols(sym);
572     };
573     Fortran::lower::pft::visitAllSymbols(eval, addToList);
574   }
575 
576   mlir::Location getCurrentLocation() override final { return toLocation(); }
577 
578   /// Generate a dummy location.
579   mlir::Location genUnknownLocation() override final {
580     // Note: builder may not be instantiated yet
581     return mlir::UnknownLoc::get(&getMLIRContext());
582   }
583 
584   /// Generate a `Location` from the `CharBlock`.
585   mlir::Location
586   genLocation(const Fortran::parser::CharBlock &block) override final {
587     if (const Fortran::parser::AllCookedSources *cooked =
588             bridge.getCookedSource()) {
589       if (std::optional<std::pair<Fortran::parser::SourcePosition,
590                                   Fortran::parser::SourcePosition>>
591               loc = cooked->GetSourcePositionRange(block)) {
592         // loc is a pair (begin, end); use the beginning position
593         Fortran::parser::SourcePosition &filePos = loc->first;
594         return mlir::FileLineColLoc::get(&getMLIRContext(), filePos.file.path(),
595                                          filePos.line, filePos.column);
596       }
597     }
598     return genUnknownLocation();
599   }
600 
601   fir::FirOpBuilder &getFirOpBuilder() override final { return *builder; }
602 
603   mlir::ModuleOp &getModuleOp() override final { return bridge.getModule(); }
604 
605   mlir::MLIRContext &getMLIRContext() override final {
606     return bridge.getMLIRContext();
607   }
608   std::string
609   mangleName(const Fortran::semantics::Symbol &symbol) override final {
610     return Fortran::lower::mangle::mangleName(symbol);
611   }
612 
613   const fir::KindMapping &getKindMap() override final {
614     return bridge.getKindMap();
615   }
616 
617   mlir::Value hostAssocTupleValue() override final { return hostAssocTuple; }
618 
619   /// Record a binding for the ssa-value of the tuple for this function.
620   void bindHostAssocTuple(mlir::Value val) override final {
621     assert(!hostAssocTuple && val);
622     hostAssocTuple = val;
623   }
624 
625   void registerRuntimeTypeInfo(
626       mlir::Location loc,
627       Fortran::lower::SymbolRef typeInfoSym) override final {
628     runtimeTypeInfoConverter.registerTypeInfoSymbol(*this, loc, typeInfoSym);
629   }
630 
631 private:
632   FirConverter() = delete;
633   FirConverter(const FirConverter &) = delete;
634   FirConverter &operator=(const FirConverter &) = delete;
635 
636   //===--------------------------------------------------------------------===//
637   // Helper member functions
638   //===--------------------------------------------------------------------===//
639 
640   mlir::Value createFIRExpr(mlir::Location loc,
641                             const Fortran::lower::SomeExpr *expr,
642                             Fortran::lower::StatementContext &stmtCtx) {
643     return fir::getBase(genExprValue(*expr, stmtCtx, &loc));
644   }
645 
646   /// Find the symbol in the local map or return null.
647   Fortran::lower::SymbolBox
648   lookupSymbol(const Fortran::semantics::Symbol &sym) {
649     if (Fortran::lower::SymbolBox v = localSymbols.lookupSymbol(sym))
650       return v;
651     return {};
652   }
653 
654   /// Find the symbol in the inner-most level of the local map or return null.
655   Fortran::lower::SymbolBox
656   shallowLookupSymbol(const Fortran::semantics::Symbol &sym) {
657     if (Fortran::lower::SymbolBox v = localSymbols.shallowLookupSymbol(sym))
658       return v;
659     return {};
660   }
661 
662   /// Find the symbol in one level up of symbol map such as for host-association
663   /// in OpenMP code or return null.
664   Fortran::lower::SymbolBox
665   lookupOneLevelUpSymbol(const Fortran::semantics::Symbol &sym) {
666     if (Fortran::lower::SymbolBox v = localSymbols.lookupOneLevelUpSymbol(sym))
667       return v;
668     return {};
669   }
670 
671   /// Add the symbol to the local map and return `true`. If the symbol is
672   /// already in the map and \p forced is `false`, the map is not updated.
673   /// Instead the value `false` is returned.
674   bool addSymbol(const Fortran::semantics::SymbolRef sym, mlir::Value val,
675                  bool forced = false) {
676     if (!forced && lookupSymbol(sym))
677       return false;
678     localSymbols.addSymbol(sym, val, forced);
679     return true;
680   }
681 
682   bool addCharSymbol(const Fortran::semantics::SymbolRef sym, mlir::Value val,
683                      mlir::Value len, bool forced = false) {
684     if (!forced && lookupSymbol(sym))
685       return false;
686     // TODO: ensure val type is fir.array<len x fir.char<kind>> like. Insert
687     // cast if needed.
688     localSymbols.addCharSymbol(sym, val, len, forced);
689     return true;
690   }
691 
692   fir::ExtendedValue getExtendedValue(Fortran::lower::SymbolBox sb) {
693     return sb.match(
694         [&](const Fortran::lower::SymbolBox::PointerOrAllocatable &box) {
695           return fir::factory::genMutableBoxRead(*builder, getCurrentLocation(),
696                                                  box);
697         },
698         [&sb](auto &) { return sb.toExtendedValue(); });
699   }
700 
701   /// Generate the address of loop variable \p sym.
702   /// If \p sym is not mapped yet, allocate local storage for it.
703   mlir::Value genLoopVariableAddress(mlir::Location loc,
704                                      const Fortran::semantics::Symbol &sym,
705                                      bool isUnordered) {
706     if (isUnordered || sym.has<Fortran::semantics::HostAssocDetails>() ||
707         sym.has<Fortran::semantics::UseDetails>()) {
708       if (!shallowLookupSymbol(sym)) {
709         // Do concurrent loop variables are not mapped yet since they are local
710         // to the Do concurrent scope (same for OpenMP loops).
711         auto newVal = builder->createTemporary(loc, genType(sym),
712                                                toStringRef(sym.name()));
713         bindIfNewSymbol(sym, newVal);
714         return newVal;
715       }
716     }
717     auto entry = lookupSymbol(sym);
718     (void)entry;
719     assert(entry && "loop control variable must already be in map");
720     Fortran::lower::StatementContext stmtCtx;
721     return fir::getBase(
722         genExprAddr(Fortran::evaluate::AsGenericExpr(sym).value(), stmtCtx));
723   }
724 
725   static bool isNumericScalarCategory(Fortran::common::TypeCategory cat) {
726     return cat == Fortran::common::TypeCategory::Integer ||
727            cat == Fortran::common::TypeCategory::Real ||
728            cat == Fortran::common::TypeCategory::Complex ||
729            cat == Fortran::common::TypeCategory::Logical;
730   }
731   static bool isLogicalCategory(Fortran::common::TypeCategory cat) {
732     return cat == Fortran::common::TypeCategory::Logical;
733   }
734   static bool isCharacterCategory(Fortran::common::TypeCategory cat) {
735     return cat == Fortran::common::TypeCategory::Character;
736   }
737   static bool isDerivedCategory(Fortran::common::TypeCategory cat) {
738     return cat == Fortran::common::TypeCategory::Derived;
739   }
740 
741   /// Insert a new block before \p block.  Leave the insertion point unchanged.
742   mlir::Block *insertBlock(mlir::Block *block) {
743     mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint();
744     mlir::Block *newBlock = builder->createBlock(block);
745     builder->restoreInsertionPoint(insertPt);
746     return newBlock;
747   }
748 
749   mlir::Block *blockOfLabel(Fortran::lower::pft::Evaluation &eval,
750                             Fortran::parser::Label label) {
751     const Fortran::lower::pft::LabelEvalMap &labelEvaluationMap =
752         eval.getOwningProcedure()->labelEvaluationMap;
753     const auto iter = labelEvaluationMap.find(label);
754     assert(iter != labelEvaluationMap.end() && "label missing from map");
755     mlir::Block *block = iter->second->block;
756     assert(block && "missing labeled evaluation block");
757     return block;
758   }
759 
760   void genFIRBranch(mlir::Block *targetBlock) {
761     assert(targetBlock && "missing unconditional target block");
762     builder->create<mlir::cf::BranchOp>(toLocation(), targetBlock);
763   }
764 
765   void genFIRConditionalBranch(mlir::Value cond, mlir::Block *trueTarget,
766                                mlir::Block *falseTarget) {
767     assert(trueTarget && "missing conditional branch true block");
768     assert(falseTarget && "missing conditional branch false block");
769     mlir::Location loc = toLocation();
770     mlir::Value bcc = builder->createConvert(loc, builder->getI1Type(), cond);
771     builder->create<mlir::cf::CondBranchOp>(loc, bcc, trueTarget, llvm::None,
772                                             falseTarget, llvm::None);
773   }
774   void genFIRConditionalBranch(mlir::Value cond,
775                                Fortran::lower::pft::Evaluation *trueTarget,
776                                Fortran::lower::pft::Evaluation *falseTarget) {
777     genFIRConditionalBranch(cond, trueTarget->block, falseTarget->block);
778   }
779   void genFIRConditionalBranch(const Fortran::parser::ScalarLogicalExpr &expr,
780                                mlir::Block *trueTarget,
781                                mlir::Block *falseTarget) {
782     Fortran::lower::StatementContext stmtCtx;
783     mlir::Value cond =
784         createFIRExpr(toLocation(), Fortran::semantics::GetExpr(expr), stmtCtx);
785     stmtCtx.finalize();
786     genFIRConditionalBranch(cond, trueTarget, falseTarget);
787   }
788   void genFIRConditionalBranch(const Fortran::parser::ScalarLogicalExpr &expr,
789                                Fortran::lower::pft::Evaluation *trueTarget,
790                                Fortran::lower::pft::Evaluation *falseTarget) {
791     Fortran::lower::StatementContext stmtCtx;
792     mlir::Value cond =
793         createFIRExpr(toLocation(), Fortran::semantics::GetExpr(expr), stmtCtx);
794     stmtCtx.finalize();
795     genFIRConditionalBranch(cond, trueTarget->block, falseTarget->block);
796   }
797 
798   //===--------------------------------------------------------------------===//
799   // Termination of symbolically referenced execution units
800   //===--------------------------------------------------------------------===//
801 
802   /// END of program
803   ///
804   /// Generate the cleanup block before the program exits
805   void genExitRoutine() {
806     if (blockIsUnterminated())
807       builder->create<mlir::func::ReturnOp>(toLocation());
808   }
809   void genFIR(const Fortran::parser::EndProgramStmt &) { genExitRoutine(); }
810 
811   /// END of procedure-like constructs
812   ///
813   /// Generate the cleanup block before the procedure exits
814   void genReturnSymbol(const Fortran::semantics::Symbol &functionSymbol) {
815     const Fortran::semantics::Symbol &resultSym =
816         functionSymbol.get<Fortran::semantics::SubprogramDetails>().result();
817     Fortran::lower::SymbolBox resultSymBox = lookupSymbol(resultSym);
818     mlir::Location loc = toLocation();
819     if (!resultSymBox) {
820       mlir::emitError(loc, "internal error when processing function return");
821       return;
822     }
823     mlir::Value resultVal = resultSymBox.match(
824         [&](const fir::CharBoxValue &x) -> mlir::Value {
825           return fir::factory::CharacterExprHelper{*builder, loc}
826               .createEmboxChar(x.getBuffer(), x.getLen());
827         },
828         [&](const auto &) -> mlir::Value {
829           mlir::Value resultRef = resultSymBox.getAddr();
830           mlir::Type resultType = genType(resultSym);
831           mlir::Type resultRefType = builder->getRefType(resultType);
832           // A function with multiple entry points returning different types
833           // tags all result variables with one of the largest types to allow
834           // them to share the same storage.  Convert this to the actual type.
835           if (resultRef.getType() != resultRefType)
836             resultRef = builder->createConvert(loc, resultRefType, resultRef);
837           return builder->create<fir::LoadOp>(loc, resultRef);
838         });
839     builder->create<mlir::func::ReturnOp>(loc, resultVal);
840   }
841 
842   /// Get the return value of a call to \p symbol, which is a subroutine entry
843   /// point that has alternative return specifiers.
844   const mlir::Value
845   getAltReturnResult(const Fortran::semantics::Symbol &symbol) {
846     assert(Fortran::semantics::HasAlternateReturns(symbol) &&
847            "subroutine does not have alternate returns");
848     return getSymbolAddress(symbol);
849   }
850 
851   void genFIRProcedureExit(Fortran::lower::pft::FunctionLikeUnit &funit,
852                            const Fortran::semantics::Symbol &symbol) {
853     if (mlir::Block *finalBlock = funit.finalBlock) {
854       // The current block must end with a terminator.
855       if (blockIsUnterminated())
856         builder->create<mlir::cf::BranchOp>(toLocation(), finalBlock);
857       // Set insertion point to final block.
858       builder->setInsertionPoint(finalBlock, finalBlock->end());
859     }
860     if (Fortran::semantics::IsFunction(symbol)) {
861       genReturnSymbol(symbol);
862     } else if (Fortran::semantics::HasAlternateReturns(symbol)) {
863       mlir::Value retval = builder->create<fir::LoadOp>(
864           toLocation(), getAltReturnResult(symbol));
865       builder->create<mlir::func::ReturnOp>(toLocation(), retval);
866     } else {
867       genExitRoutine();
868     }
869   }
870 
871   //
872   // Statements that have control-flow semantics
873   //
874 
875   /// Generate an If[Then]Stmt condition or its negation.
876   template <typename A>
877   mlir::Value genIfCondition(const A *stmt, bool negate = false) {
878     mlir::Location loc = toLocation();
879     Fortran::lower::StatementContext stmtCtx;
880     mlir::Value condExpr = createFIRExpr(
881         loc,
882         Fortran::semantics::GetExpr(
883             std::get<Fortran::parser::ScalarLogicalExpr>(stmt->t)),
884         stmtCtx);
885     stmtCtx.finalize();
886     mlir::Value cond =
887         builder->createConvert(loc, builder->getI1Type(), condExpr);
888     if (negate)
889       cond = builder->create<mlir::arith::XOrIOp>(
890           loc, cond, builder->createIntegerConstant(loc, cond.getType(), 1));
891     return cond;
892   }
893 
894   mlir::func::FuncOp getFunc(llvm::StringRef name, mlir::FunctionType ty) {
895     if (mlir::func::FuncOp func = builder->getNamedFunction(name)) {
896       assert(func.getFunctionType() == ty);
897       return func;
898     }
899     return builder->createFunction(toLocation(), name, ty);
900   }
901 
902   /// Lowering of CALL statement
903   void genFIR(const Fortran::parser::CallStmt &stmt) {
904     Fortran::lower::StatementContext stmtCtx;
905     Fortran::lower::pft::Evaluation &eval = getEval();
906     setCurrentPosition(stmt.v.source);
907     assert(stmt.typedCall && "Call was not analyzed");
908     // Call statement lowering shares code with function call lowering.
909     mlir::Value res = Fortran::lower::createSubroutineCall(
910         *this, *stmt.typedCall, explicitIterSpace, implicitIterSpace,
911         localSymbols, stmtCtx, /*isUserDefAssignment=*/false);
912     if (!res)
913       return; // "Normal" subroutine call.
914     // Call with alternate return specifiers.
915     // The call returns an index that selects an alternate return branch target.
916     llvm::SmallVector<int64_t> indexList;
917     llvm::SmallVector<mlir::Block *> blockList;
918     int64_t index = 0;
919     for (const Fortran::parser::ActualArgSpec &arg :
920          std::get<std::list<Fortran::parser::ActualArgSpec>>(stmt.v.t)) {
921       const auto &actual = std::get<Fortran::parser::ActualArg>(arg.t);
922       if (const auto *altReturn =
923               std::get_if<Fortran::parser::AltReturnSpec>(&actual.u)) {
924         indexList.push_back(++index);
925         blockList.push_back(blockOfLabel(eval, altReturn->v));
926       }
927     }
928     blockList.push_back(eval.nonNopSuccessor().block); // default = fallthrough
929     stmtCtx.finalize();
930     builder->create<fir::SelectOp>(toLocation(), res, indexList, blockList);
931   }
932 
933   void genFIR(const Fortran::parser::ComputedGotoStmt &stmt) {
934     Fortran::lower::StatementContext stmtCtx;
935     Fortran::lower::pft::Evaluation &eval = getEval();
936     mlir::Value selectExpr =
937         createFIRExpr(toLocation(),
938                       Fortran::semantics::GetExpr(
939                           std::get<Fortran::parser::ScalarIntExpr>(stmt.t)),
940                       stmtCtx);
941     stmtCtx.finalize();
942     llvm::SmallVector<int64_t> indexList;
943     llvm::SmallVector<mlir::Block *> blockList;
944     int64_t index = 0;
945     for (Fortran::parser::Label label :
946          std::get<std::list<Fortran::parser::Label>>(stmt.t)) {
947       indexList.push_back(++index);
948       blockList.push_back(blockOfLabel(eval, label));
949     }
950     blockList.push_back(eval.nonNopSuccessor().block); // default
951     builder->create<fir::SelectOp>(toLocation(), selectExpr, indexList,
952                                    blockList);
953   }
954 
955   void genFIR(const Fortran::parser::ArithmeticIfStmt &stmt) {
956     Fortran::lower::StatementContext stmtCtx;
957     Fortran::lower::pft::Evaluation &eval = getEval();
958     mlir::Value expr = createFIRExpr(
959         toLocation(),
960         Fortran::semantics::GetExpr(std::get<Fortran::parser::Expr>(stmt.t)),
961         stmtCtx);
962     stmtCtx.finalize();
963     mlir::Type exprType = expr.getType();
964     mlir::Location loc = toLocation();
965     if (exprType.isSignlessInteger()) {
966       // Arithmetic expression has Integer type.  Generate a SelectCaseOp
967       // with ranges {(-inf:-1], 0=default, [1:inf)}.
968       mlir::MLIRContext *context = builder->getContext();
969       llvm::SmallVector<mlir::Attribute> attrList;
970       llvm::SmallVector<mlir::Value> valueList;
971       llvm::SmallVector<mlir::Block *> blockList;
972       attrList.push_back(fir::UpperBoundAttr::get(context));
973       valueList.push_back(builder->createIntegerConstant(loc, exprType, -1));
974       blockList.push_back(blockOfLabel(eval, std::get<1>(stmt.t)));
975       attrList.push_back(fir::LowerBoundAttr::get(context));
976       valueList.push_back(builder->createIntegerConstant(loc, exprType, 1));
977       blockList.push_back(blockOfLabel(eval, std::get<3>(stmt.t)));
978       attrList.push_back(mlir::UnitAttr::get(context)); // 0 is the "default"
979       blockList.push_back(blockOfLabel(eval, std::get<2>(stmt.t)));
980       builder->create<fir::SelectCaseOp>(loc, expr, attrList, valueList,
981                                          blockList);
982       return;
983     }
984     // Arithmetic expression has Real type.  Generate
985     //   sum = expr + expr  [ raise an exception if expr is a NaN ]
986     //   if (sum < 0.0) goto L1 else if (sum > 0.0) goto L3 else goto L2
987     auto sum = builder->create<mlir::arith::AddFOp>(loc, expr, expr);
988     auto zero = builder->create<mlir::arith::ConstantOp>(
989         loc, exprType, builder->getFloatAttr(exprType, 0.0));
990     auto cond1 = builder->create<mlir::arith::CmpFOp>(
991         loc, mlir::arith::CmpFPredicate::OLT, sum, zero);
992     mlir::Block *elseIfBlock =
993         builder->getBlock()->splitBlock(builder->getInsertionPoint());
994     genFIRConditionalBranch(cond1, blockOfLabel(eval, std::get<1>(stmt.t)),
995                             elseIfBlock);
996     startBlock(elseIfBlock);
997     auto cond2 = builder->create<mlir::arith::CmpFOp>(
998         loc, mlir::arith::CmpFPredicate::OGT, sum, zero);
999     genFIRConditionalBranch(cond2, blockOfLabel(eval, std::get<3>(stmt.t)),
1000                             blockOfLabel(eval, std::get<2>(stmt.t)));
1001   }
1002 
1003   void genFIR(const Fortran::parser::AssignedGotoStmt &stmt) {
1004     // Program requirement 1990 8.2.4 -
1005     //
1006     //   At the time of execution of an assigned GOTO statement, the integer
1007     //   variable must be defined with the value of a statement label of a
1008     //   branch target statement that appears in the same scoping unit.
1009     //   Note that the variable may be defined with a statement label value
1010     //   only by an ASSIGN statement in the same scoping unit as the assigned
1011     //   GOTO statement.
1012 
1013     mlir::Location loc = toLocation();
1014     Fortran::lower::pft::Evaluation &eval = getEval();
1015     const Fortran::lower::pft::SymbolLabelMap &symbolLabelMap =
1016         eval.getOwningProcedure()->assignSymbolLabelMap;
1017     const Fortran::semantics::Symbol &symbol =
1018         *std::get<Fortran::parser::Name>(stmt.t).symbol;
1019     auto selectExpr =
1020         builder->create<fir::LoadOp>(loc, getSymbolAddress(symbol));
1021     auto iter = symbolLabelMap.find(symbol);
1022     if (iter == symbolLabelMap.end()) {
1023       // Fail for a nonconforming program unit that does not have any ASSIGN
1024       // statements.  The front end should check for this.
1025       mlir::emitError(loc, "(semantics issue) no assigned goto targets");
1026       exit(1);
1027     }
1028     auto labelSet = iter->second;
1029     llvm::SmallVector<int64_t> indexList;
1030     llvm::SmallVector<mlir::Block *> blockList;
1031     auto addLabel = [&](Fortran::parser::Label label) {
1032       indexList.push_back(label);
1033       blockList.push_back(blockOfLabel(eval, label));
1034     };
1035     // Add labels from an explicit list.  The list may have duplicates.
1036     for (Fortran::parser::Label label :
1037          std::get<std::list<Fortran::parser::Label>>(stmt.t)) {
1038       if (labelSet.count(label) &&
1039           std::find(indexList.begin(), indexList.end(), label) ==
1040               indexList.end()) { // ignore duplicates
1041         addLabel(label);
1042       }
1043     }
1044     // Absent an explicit list, add all possible label targets.
1045     if (indexList.empty())
1046       for (auto &label : labelSet)
1047         addLabel(label);
1048     // Add a nop/fallthrough branch to the switch for a nonconforming program
1049     // unit that violates the program requirement above.
1050     blockList.push_back(eval.nonNopSuccessor().block); // default
1051     builder->create<fir::SelectOp>(loc, selectExpr, indexList, blockList);
1052   }
1053 
1054   /// Collect DO CONCURRENT or FORALL loop control information.
1055   IncrementLoopNestInfo getConcurrentControl(
1056       const Fortran::parser::ConcurrentHeader &header,
1057       const std::list<Fortran::parser::LocalitySpec> &localityList = {}) {
1058     IncrementLoopNestInfo incrementLoopNestInfo;
1059     for (const Fortran::parser::ConcurrentControl &control :
1060          std::get<std::list<Fortran::parser::ConcurrentControl>>(header.t))
1061       incrementLoopNestInfo.emplace_back(
1062           *std::get<0>(control.t).symbol, std::get<1>(control.t),
1063           std::get<2>(control.t), std::get<3>(control.t), /*isUnordered=*/true);
1064     IncrementLoopInfo &info = incrementLoopNestInfo.back();
1065     info.maskExpr = Fortran::semantics::GetExpr(
1066         std::get<std::optional<Fortran::parser::ScalarLogicalExpr>>(header.t));
1067     for (const Fortran::parser::LocalitySpec &x : localityList) {
1068       if (const auto *localInitList =
1069               std::get_if<Fortran::parser::LocalitySpec::LocalInit>(&x.u))
1070         for (const Fortran::parser::Name &x : localInitList->v)
1071           info.localInitSymList.push_back(x.symbol);
1072       if (const auto *sharedList =
1073               std::get_if<Fortran::parser::LocalitySpec::Shared>(&x.u))
1074         for (const Fortran::parser::Name &x : sharedList->v)
1075           info.sharedSymList.push_back(x.symbol);
1076       if (std::get_if<Fortran::parser::LocalitySpec::Local>(&x.u))
1077         TODO(toLocation(), "do concurrent locality specs not implemented");
1078     }
1079     return incrementLoopNestInfo;
1080   }
1081 
1082   /// Generate FIR for a DO construct.  There are six variants:
1083   ///  - unstructured infinite and while loops
1084   ///  - structured and unstructured increment loops
1085   ///  - structured and unstructured concurrent loops
1086   void genFIR(const Fortran::parser::DoConstruct &doConstruct) {
1087     setCurrentPositionAt(doConstruct);
1088     // Collect loop nest information.
1089     // Generate begin loop code directly for infinite and while loops.
1090     Fortran::lower::pft::Evaluation &eval = getEval();
1091     bool unstructuredContext = eval.lowerAsUnstructured();
1092     Fortran::lower::pft::Evaluation &doStmtEval =
1093         eval.getFirstNestedEvaluation();
1094     auto *doStmt = doStmtEval.getIf<Fortran::parser::NonLabelDoStmt>();
1095     const auto &loopControl =
1096         std::get<std::optional<Fortran::parser::LoopControl>>(doStmt->t);
1097     mlir::Block *preheaderBlock = doStmtEval.block;
1098     mlir::Block *beginBlock =
1099         preheaderBlock ? preheaderBlock : builder->getBlock();
1100     auto createNextBeginBlock = [&]() {
1101       // Step beginBlock through unstructured preheader, header, and mask
1102       // blocks, created in outermost to innermost order.
1103       return beginBlock = beginBlock->splitBlock(beginBlock->end());
1104     };
1105     mlir::Block *headerBlock =
1106         unstructuredContext ? createNextBeginBlock() : nullptr;
1107     mlir::Block *bodyBlock = doStmtEval.lexicalSuccessor->block;
1108     mlir::Block *exitBlock = doStmtEval.parentConstruct->constructExit->block;
1109     IncrementLoopNestInfo incrementLoopNestInfo;
1110     const Fortran::parser::ScalarLogicalExpr *whileCondition = nullptr;
1111     bool infiniteLoop = !loopControl.has_value();
1112     if (infiniteLoop) {
1113       assert(unstructuredContext && "infinite loop must be unstructured");
1114       startBlock(headerBlock);
1115     } else if ((whileCondition =
1116                     std::get_if<Fortran::parser::ScalarLogicalExpr>(
1117                         &loopControl->u))) {
1118       assert(unstructuredContext && "while loop must be unstructured");
1119       maybeStartBlock(preheaderBlock); // no block or empty block
1120       startBlock(headerBlock);
1121       genFIRConditionalBranch(*whileCondition, bodyBlock, exitBlock);
1122     } else if (const auto *bounds =
1123                    std::get_if<Fortran::parser::LoopControl::Bounds>(
1124                        &loopControl->u)) {
1125       // Non-concurrent increment loop.
1126       IncrementLoopInfo &info = incrementLoopNestInfo.emplace_back(
1127           *bounds->name.thing.symbol, bounds->lower, bounds->upper,
1128           bounds->step);
1129       if (unstructuredContext) {
1130         maybeStartBlock(preheaderBlock);
1131         info.hasRealControl = info.loopVariableSym.GetType()->IsNumeric(
1132             Fortran::common::TypeCategory::Real);
1133         info.headerBlock = headerBlock;
1134         info.bodyBlock = bodyBlock;
1135         info.exitBlock = exitBlock;
1136       }
1137     } else {
1138       const auto *concurrent =
1139           std::get_if<Fortran::parser::LoopControl::Concurrent>(
1140               &loopControl->u);
1141       assert(concurrent && "invalid DO loop variant");
1142       incrementLoopNestInfo = getConcurrentControl(
1143           std::get<Fortran::parser::ConcurrentHeader>(concurrent->t),
1144           std::get<std::list<Fortran::parser::LocalitySpec>>(concurrent->t));
1145       if (unstructuredContext) {
1146         maybeStartBlock(preheaderBlock);
1147         for (IncrementLoopInfo &info : incrementLoopNestInfo) {
1148           // The original loop body provides the body and latch blocks of the
1149           // innermost dimension.  The (first) body block of a non-innermost
1150           // dimension is the preheader block of the immediately enclosed
1151           // dimension.  The latch block of a non-innermost dimension is the
1152           // exit block of the immediately enclosed dimension.
1153           auto createNextExitBlock = [&]() {
1154             // Create unstructured loop exit blocks, outermost to innermost.
1155             return exitBlock = insertBlock(exitBlock);
1156           };
1157           bool isInnermost = &info == &incrementLoopNestInfo.back();
1158           bool isOutermost = &info == &incrementLoopNestInfo.front();
1159           info.headerBlock = isOutermost ? headerBlock : createNextBeginBlock();
1160           info.bodyBlock = isInnermost ? bodyBlock : createNextBeginBlock();
1161           info.exitBlock = isOutermost ? exitBlock : createNextExitBlock();
1162           if (info.maskExpr)
1163             info.maskBlock = createNextBeginBlock();
1164         }
1165       }
1166     }
1167 
1168     // Increment loop begin code.  (Infinite/while code was already generated.)
1169     if (!infiniteLoop && !whileCondition)
1170       genFIRIncrementLoopBegin(incrementLoopNestInfo);
1171 
1172     // Loop body code - NonLabelDoStmt and EndDoStmt code is generated here.
1173     // Their genFIR calls are nops except for block management in some cases.
1174     for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations())
1175       genFIR(e, unstructuredContext);
1176 
1177     // Loop end code.
1178     if (infiniteLoop || whileCondition)
1179       genFIRBranch(headerBlock);
1180     else
1181       genFIRIncrementLoopEnd(incrementLoopNestInfo);
1182   }
1183 
1184   /// Generate FIR to begin a structured or unstructured increment loop nest.
1185   void genFIRIncrementLoopBegin(IncrementLoopNestInfo &incrementLoopNestInfo) {
1186     assert(!incrementLoopNestInfo.empty() && "empty loop nest");
1187     mlir::Location loc = toLocation();
1188     auto genControlValue = [&](const Fortran::lower::SomeExpr *expr,
1189                                const IncrementLoopInfo &info) {
1190       mlir::Type controlType = info.isStructured() ? builder->getIndexType()
1191                                                    : info.getLoopVariableType();
1192       Fortran::lower::StatementContext stmtCtx;
1193       if (expr)
1194         return builder->createConvert(loc, controlType,
1195                                       createFIRExpr(loc, expr, stmtCtx));
1196 
1197       if (info.hasRealControl)
1198         return builder->createRealConstant(loc, controlType, 1u);
1199       return builder->createIntegerConstant(loc, controlType, 1); // step
1200     };
1201     auto handleLocalitySpec = [&](IncrementLoopInfo &info) {
1202       // Generate Local Init Assignments
1203       for (const Fortran::semantics::Symbol *sym : info.localInitSymList) {
1204         const auto *hostDetails =
1205             sym->detailsIf<Fortran::semantics::HostAssocDetails>();
1206         assert(hostDetails && "missing local_init variable host variable");
1207         const Fortran::semantics::Symbol &hostSym = hostDetails->symbol();
1208         (void)hostSym;
1209         TODO(loc, "do concurrent locality specs not implemented");
1210       }
1211       // Handle shared locality spec
1212       for (const Fortran::semantics::Symbol *sym : info.sharedSymList) {
1213         const auto *hostDetails =
1214             sym->detailsIf<Fortran::semantics::HostAssocDetails>();
1215         assert(hostDetails && "missing shared variable host variable");
1216         const Fortran::semantics::Symbol &hostSym = hostDetails->symbol();
1217         copySymbolBinding(hostSym, *sym);
1218       }
1219     };
1220     for (IncrementLoopInfo &info : incrementLoopNestInfo) {
1221       info.loopVariable =
1222           genLoopVariableAddress(loc, info.loopVariableSym, info.isUnordered);
1223       mlir::Value lowerValue = genControlValue(info.lowerExpr, info);
1224       mlir::Value upperValue = genControlValue(info.upperExpr, info);
1225       info.stepValue = genControlValue(info.stepExpr, info);
1226 
1227       // Structured loop - generate fir.do_loop.
1228       if (info.isStructured()) {
1229         info.doLoop = builder->create<fir::DoLoopOp>(
1230             loc, lowerValue, upperValue, info.stepValue, info.isUnordered,
1231             /*finalCountValue=*/!info.isUnordered);
1232         builder->setInsertionPointToStart(info.doLoop.getBody());
1233         // Update the loop variable value, as it may have non-index references.
1234         mlir::Value value = builder->createConvert(
1235             loc, info.getLoopVariableType(), info.doLoop.getInductionVar());
1236         builder->create<fir::StoreOp>(loc, value, info.loopVariable);
1237         if (info.maskExpr) {
1238           Fortran::lower::StatementContext stmtCtx;
1239           mlir::Value maskCond = createFIRExpr(loc, info.maskExpr, stmtCtx);
1240           stmtCtx.finalize();
1241           mlir::Value maskCondCast =
1242               builder->createConvert(loc, builder->getI1Type(), maskCond);
1243           auto ifOp = builder->create<fir::IfOp>(loc, maskCondCast,
1244                                                  /*withElseRegion=*/false);
1245           builder->setInsertionPointToStart(&ifOp.getThenRegion().front());
1246         }
1247         handleLocalitySpec(info);
1248         continue;
1249       }
1250 
1251       // Unstructured loop preheader - initialize tripVariable and loopVariable.
1252       mlir::Value tripCount;
1253       if (info.hasRealControl) {
1254         auto diff1 =
1255             builder->create<mlir::arith::SubFOp>(loc, upperValue, lowerValue);
1256         auto diff2 =
1257             builder->create<mlir::arith::AddFOp>(loc, diff1, info.stepValue);
1258         tripCount =
1259             builder->create<mlir::arith::DivFOp>(loc, diff2, info.stepValue);
1260         tripCount =
1261             builder->createConvert(loc, builder->getIndexType(), tripCount);
1262 
1263       } else {
1264         auto diff1 =
1265             builder->create<mlir::arith::SubIOp>(loc, upperValue, lowerValue);
1266         auto diff2 =
1267             builder->create<mlir::arith::AddIOp>(loc, diff1, info.stepValue);
1268         tripCount =
1269             builder->create<mlir::arith::DivSIOp>(loc, diff2, info.stepValue);
1270       }
1271       if (forceLoopToExecuteOnce) { // minimum tripCount is 1
1272         mlir::Value one =
1273             builder->createIntegerConstant(loc, tripCount.getType(), 1);
1274         auto cond = builder->create<mlir::arith::CmpIOp>(
1275             loc, mlir::arith::CmpIPredicate::slt, tripCount, one);
1276         tripCount =
1277             builder->create<mlir::arith::SelectOp>(loc, cond, one, tripCount);
1278       }
1279       info.tripVariable = builder->createTemporary(loc, tripCount.getType());
1280       builder->create<fir::StoreOp>(loc, tripCount, info.tripVariable);
1281       builder->create<fir::StoreOp>(loc, lowerValue, info.loopVariable);
1282 
1283       // Unstructured loop header - generate loop condition and mask.
1284       // Note - Currently there is no way to tag a loop as a concurrent loop.
1285       startBlock(info.headerBlock);
1286       tripCount = builder->create<fir::LoadOp>(loc, info.tripVariable);
1287       mlir::Value zero =
1288           builder->createIntegerConstant(loc, tripCount.getType(), 0);
1289       auto cond = builder->create<mlir::arith::CmpIOp>(
1290           loc, mlir::arith::CmpIPredicate::sgt, tripCount, zero);
1291       if (info.maskExpr) {
1292         genFIRConditionalBranch(cond, info.maskBlock, info.exitBlock);
1293         startBlock(info.maskBlock);
1294         mlir::Block *latchBlock = getEval().getLastNestedEvaluation().block;
1295         assert(latchBlock && "missing masked concurrent loop latch block");
1296         Fortran::lower::StatementContext stmtCtx;
1297         mlir::Value maskCond = createFIRExpr(loc, info.maskExpr, stmtCtx);
1298         stmtCtx.finalize();
1299         genFIRConditionalBranch(maskCond, info.bodyBlock, latchBlock);
1300       } else {
1301         genFIRConditionalBranch(cond, info.bodyBlock, info.exitBlock);
1302         if (&info != &incrementLoopNestInfo.back()) // not innermost
1303           startBlock(info.bodyBlock); // preheader block of enclosed dimension
1304       }
1305       if (!info.localInitSymList.empty()) {
1306         mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint();
1307         builder->setInsertionPointToStart(info.bodyBlock);
1308         handleLocalitySpec(info);
1309         builder->restoreInsertionPoint(insertPt);
1310       }
1311     }
1312   }
1313 
1314   /// Generate FIR to end a structured or unstructured increment loop nest.
1315   void genFIRIncrementLoopEnd(IncrementLoopNestInfo &incrementLoopNestInfo) {
1316     assert(!incrementLoopNestInfo.empty() && "empty loop nest");
1317     mlir::Location loc = toLocation();
1318     for (auto it = incrementLoopNestInfo.rbegin(),
1319               rend = incrementLoopNestInfo.rend();
1320          it != rend; ++it) {
1321       IncrementLoopInfo &info = *it;
1322       if (info.isStructured()) {
1323         // End fir.do_loop.
1324         if (!info.isUnordered) {
1325           builder->setInsertionPointToEnd(info.doLoop.getBody());
1326           mlir::Value result = builder->create<mlir::arith::AddIOp>(
1327               loc, info.doLoop.getInductionVar(), info.doLoop.getStep());
1328           builder->create<fir::ResultOp>(loc, result);
1329         }
1330         builder->setInsertionPointAfter(info.doLoop);
1331         if (info.isUnordered)
1332           continue;
1333         // The loop control variable may be used after loop execution.
1334         mlir::Value lcv = builder->createConvert(
1335             loc, info.getLoopVariableType(), info.doLoop.getResult(0));
1336         builder->create<fir::StoreOp>(loc, lcv, info.loopVariable);
1337         continue;
1338       }
1339 
1340       // Unstructured loop - decrement tripVariable and step loopVariable.
1341       mlir::Value tripCount =
1342           builder->create<fir::LoadOp>(loc, info.tripVariable);
1343       mlir::Value one =
1344           builder->createIntegerConstant(loc, tripCount.getType(), 1);
1345       tripCount = builder->create<mlir::arith::SubIOp>(loc, tripCount, one);
1346       builder->create<fir::StoreOp>(loc, tripCount, info.tripVariable);
1347       mlir::Value value = builder->create<fir::LoadOp>(loc, info.loopVariable);
1348       if (info.hasRealControl)
1349         value =
1350             builder->create<mlir::arith::AddFOp>(loc, value, info.stepValue);
1351       else
1352         value =
1353             builder->create<mlir::arith::AddIOp>(loc, value, info.stepValue);
1354       builder->create<fir::StoreOp>(loc, value, info.loopVariable);
1355 
1356       genFIRBranch(info.headerBlock);
1357       if (&info != &incrementLoopNestInfo.front()) // not outermost
1358         startBlock(info.exitBlock); // latch block of enclosing dimension
1359     }
1360   }
1361 
1362   /// Generate structured or unstructured FIR for an IF construct.
1363   /// The initial statement may be either an IfStmt or an IfThenStmt.
1364   void genFIR(const Fortran::parser::IfConstruct &) {
1365     mlir::Location loc = toLocation();
1366     Fortran::lower::pft::Evaluation &eval = getEval();
1367     if (eval.lowerAsStructured()) {
1368       // Structured fir.if nest.
1369       fir::IfOp topIfOp, currentIfOp;
1370       for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations()) {
1371         auto genIfOp = [&](mlir::Value cond) {
1372           auto ifOp = builder->create<fir::IfOp>(loc, cond, /*withElse=*/true);
1373           builder->setInsertionPointToStart(&ifOp.getThenRegion().front());
1374           return ifOp;
1375         };
1376         if (auto *s = e.getIf<Fortran::parser::IfThenStmt>()) {
1377           topIfOp = currentIfOp = genIfOp(genIfCondition(s, e.negateCondition));
1378         } else if (auto *s = e.getIf<Fortran::parser::IfStmt>()) {
1379           topIfOp = currentIfOp = genIfOp(genIfCondition(s, e.negateCondition));
1380         } else if (auto *s = e.getIf<Fortran::parser::ElseIfStmt>()) {
1381           builder->setInsertionPointToStart(
1382               &currentIfOp.getElseRegion().front());
1383           currentIfOp = genIfOp(genIfCondition(s));
1384         } else if (e.isA<Fortran::parser::ElseStmt>()) {
1385           builder->setInsertionPointToStart(
1386               &currentIfOp.getElseRegion().front());
1387         } else if (e.isA<Fortran::parser::EndIfStmt>()) {
1388           builder->setInsertionPointAfter(topIfOp);
1389         } else {
1390           genFIR(e, /*unstructuredContext=*/false);
1391         }
1392       }
1393       return;
1394     }
1395 
1396     // Unstructured branch sequence.
1397     for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations()) {
1398       auto genIfBranch = [&](mlir::Value cond) {
1399         if (e.lexicalSuccessor == e.controlSuccessor) // empty block -> exit
1400           genFIRConditionalBranch(cond, e.parentConstruct->constructExit,
1401                                   e.controlSuccessor);
1402         else // non-empty block
1403           genFIRConditionalBranch(cond, e.lexicalSuccessor, e.controlSuccessor);
1404       };
1405       if (auto *s = e.getIf<Fortran::parser::IfThenStmt>()) {
1406         maybeStartBlock(e.block);
1407         genIfBranch(genIfCondition(s, e.negateCondition));
1408       } else if (auto *s = e.getIf<Fortran::parser::IfStmt>()) {
1409         maybeStartBlock(e.block);
1410         genIfBranch(genIfCondition(s, e.negateCondition));
1411       } else if (auto *s = e.getIf<Fortran::parser::ElseIfStmt>()) {
1412         startBlock(e.block);
1413         genIfBranch(genIfCondition(s));
1414       } else {
1415         genFIR(e);
1416       }
1417     }
1418   }
1419 
1420   void genFIR(const Fortran::parser::CaseConstruct &) {
1421     for (Fortran::lower::pft::Evaluation &e : getEval().getNestedEvaluations())
1422       genFIR(e);
1423   }
1424 
1425   template <typename A>
1426   void genNestedStatement(const Fortran::parser::Statement<A> &stmt) {
1427     setCurrentPosition(stmt.source);
1428     genFIR(stmt.statement);
1429   }
1430 
1431   /// Force the binding of an explicit symbol. This is used to bind and re-bind
1432   /// a concurrent control symbol to its value.
1433   void forceControlVariableBinding(const Fortran::semantics::Symbol *sym,
1434                                    mlir::Value inducVar) {
1435     mlir::Location loc = toLocation();
1436     assert(sym && "There must be a symbol to bind");
1437     mlir::Type toTy = genType(*sym);
1438     // FIXME: this should be a "per iteration" temporary.
1439     mlir::Value tmp = builder->createTemporary(
1440         loc, toTy, toStringRef(sym->name()),
1441         llvm::ArrayRef<mlir::NamedAttribute>{
1442             Fortran::lower::getAdaptToByRefAttr(*builder)});
1443     mlir::Value cast = builder->createConvert(loc, toTy, inducVar);
1444     builder->create<fir::StoreOp>(loc, cast, tmp);
1445     localSymbols.addSymbol(*sym, tmp, /*force=*/true);
1446   }
1447 
1448   /// Process a concurrent header for a FORALL. (Concurrent headers for DO
1449   /// CONCURRENT loops are lowered elsewhere.)
1450   void genFIR(const Fortran::parser::ConcurrentHeader &header) {
1451     llvm::SmallVector<mlir::Value> lows;
1452     llvm::SmallVector<mlir::Value> highs;
1453     llvm::SmallVector<mlir::Value> steps;
1454     if (explicitIterSpace.isOutermostForall()) {
1455       // For the outermost forall, we evaluate the bounds expressions once.
1456       // Contrastingly, if this forall is nested, the bounds expressions are
1457       // assumed to be pure, possibly dependent on outer concurrent control
1458       // variables, possibly variant with respect to arguments, and will be
1459       // re-evaluated.
1460       mlir::Location loc = toLocation();
1461       mlir::Type idxTy = builder->getIndexType();
1462       Fortran::lower::StatementContext &stmtCtx =
1463           explicitIterSpace.stmtContext();
1464       auto lowerExpr = [&](auto &e) {
1465         return fir::getBase(genExprValue(e, stmtCtx));
1466       };
1467       for (const Fortran::parser::ConcurrentControl &ctrl :
1468            std::get<std::list<Fortran::parser::ConcurrentControl>>(header.t)) {
1469         const Fortran::lower::SomeExpr *lo =
1470             Fortran::semantics::GetExpr(std::get<1>(ctrl.t));
1471         const Fortran::lower::SomeExpr *hi =
1472             Fortran::semantics::GetExpr(std::get<2>(ctrl.t));
1473         auto &optStep =
1474             std::get<std::optional<Fortran::parser::ScalarIntExpr>>(ctrl.t);
1475         lows.push_back(builder->createConvert(loc, idxTy, lowerExpr(*lo)));
1476         highs.push_back(builder->createConvert(loc, idxTy, lowerExpr(*hi)));
1477         steps.push_back(
1478             optStep.has_value()
1479                 ? builder->createConvert(
1480                       loc, idxTy,
1481                       lowerExpr(*Fortran::semantics::GetExpr(*optStep)))
1482                 : builder->createIntegerConstant(loc, idxTy, 1));
1483       }
1484     }
1485     auto lambda = [&, lows, highs, steps]() {
1486       // Create our iteration space from the header spec.
1487       mlir::Location loc = toLocation();
1488       mlir::Type idxTy = builder->getIndexType();
1489       llvm::SmallVector<fir::DoLoopOp> loops;
1490       Fortran::lower::StatementContext &stmtCtx =
1491           explicitIterSpace.stmtContext();
1492       auto lowerExpr = [&](auto &e) {
1493         return fir::getBase(genExprValue(e, stmtCtx));
1494       };
1495       const bool outermost = !lows.empty();
1496       std::size_t headerIndex = 0;
1497       for (const Fortran::parser::ConcurrentControl &ctrl :
1498            std::get<std::list<Fortran::parser::ConcurrentControl>>(header.t)) {
1499         const Fortran::semantics::Symbol *ctrlVar =
1500             std::get<Fortran::parser::Name>(ctrl.t).symbol;
1501         mlir::Value lb;
1502         mlir::Value ub;
1503         mlir::Value by;
1504         if (outermost) {
1505           assert(headerIndex < lows.size());
1506           if (headerIndex == 0)
1507             explicitIterSpace.resetInnerArgs();
1508           lb = lows[headerIndex];
1509           ub = highs[headerIndex];
1510           by = steps[headerIndex++];
1511         } else {
1512           const Fortran::lower::SomeExpr *lo =
1513               Fortran::semantics::GetExpr(std::get<1>(ctrl.t));
1514           const Fortran::lower::SomeExpr *hi =
1515               Fortran::semantics::GetExpr(std::get<2>(ctrl.t));
1516           auto &optStep =
1517               std::get<std::optional<Fortran::parser::ScalarIntExpr>>(ctrl.t);
1518           lb = builder->createConvert(loc, idxTy, lowerExpr(*lo));
1519           ub = builder->createConvert(loc, idxTy, lowerExpr(*hi));
1520           by = optStep.has_value()
1521                    ? builder->createConvert(
1522                          loc, idxTy,
1523                          lowerExpr(*Fortran::semantics::GetExpr(*optStep)))
1524                    : builder->createIntegerConstant(loc, idxTy, 1);
1525         }
1526         auto lp = builder->create<fir::DoLoopOp>(
1527             loc, lb, ub, by, /*unordered=*/true,
1528             /*finalCount=*/false, explicitIterSpace.getInnerArgs());
1529         if ((!loops.empty() || !outermost) && !lp.getRegionIterArgs().empty())
1530           builder->create<fir::ResultOp>(loc, lp.getResults());
1531         explicitIterSpace.setInnerArgs(lp.getRegionIterArgs());
1532         builder->setInsertionPointToStart(lp.getBody());
1533         forceControlVariableBinding(ctrlVar, lp.getInductionVar());
1534         loops.push_back(lp);
1535       }
1536       if (outermost)
1537         explicitIterSpace.setOuterLoop(loops[0]);
1538       explicitIterSpace.appendLoops(loops);
1539       if (const auto &mask =
1540               std::get<std::optional<Fortran::parser::ScalarLogicalExpr>>(
1541                   header.t);
1542           mask.has_value()) {
1543         mlir::Type i1Ty = builder->getI1Type();
1544         fir::ExtendedValue maskExv =
1545             genExprValue(*Fortran::semantics::GetExpr(mask.value()), stmtCtx);
1546         mlir::Value cond =
1547             builder->createConvert(loc, i1Ty, fir::getBase(maskExv));
1548         auto ifOp = builder->create<fir::IfOp>(
1549             loc, explicitIterSpace.innerArgTypes(), cond,
1550             /*withElseRegion=*/true);
1551         builder->create<fir::ResultOp>(loc, ifOp.getResults());
1552         builder->setInsertionPointToStart(&ifOp.getElseRegion().front());
1553         builder->create<fir::ResultOp>(loc, explicitIterSpace.getInnerArgs());
1554         builder->setInsertionPointToStart(&ifOp.getThenRegion().front());
1555       }
1556     };
1557     // Push the lambda to gen the loop nest context.
1558     explicitIterSpace.pushLoopNest(lambda);
1559   }
1560 
1561   void genFIR(const Fortran::parser::ForallAssignmentStmt &stmt) {
1562     std::visit([&](const auto &x) { genFIR(x); }, stmt.u);
1563   }
1564 
1565   void genFIR(const Fortran::parser::EndForallStmt &) {
1566     cleanupExplicitSpace();
1567   }
1568 
1569   template <typename A>
1570   void prepareExplicitSpace(const A &forall) {
1571     if (!explicitIterSpace.isActive())
1572       analyzeExplicitSpace(forall);
1573     localSymbols.pushScope();
1574     explicitIterSpace.enter();
1575   }
1576 
1577   /// Cleanup all the FORALL context information when we exit.
1578   void cleanupExplicitSpace() {
1579     explicitIterSpace.leave();
1580     localSymbols.popScope();
1581   }
1582 
1583   /// Generate FIR for a FORALL statement.
1584   void genFIR(const Fortran::parser::ForallStmt &stmt) {
1585     prepareExplicitSpace(stmt);
1586     genFIR(std::get<
1587                Fortran::common::Indirection<Fortran::parser::ConcurrentHeader>>(
1588                stmt.t)
1589                .value());
1590     genFIR(std::get<Fortran::parser::UnlabeledStatement<
1591                Fortran::parser::ForallAssignmentStmt>>(stmt.t)
1592                .statement);
1593     cleanupExplicitSpace();
1594   }
1595 
1596   /// Generate FIR for a FORALL construct.
1597   void genFIR(const Fortran::parser::ForallConstruct &forall) {
1598     prepareExplicitSpace(forall);
1599     genNestedStatement(
1600         std::get<
1601             Fortran::parser::Statement<Fortran::parser::ForallConstructStmt>>(
1602             forall.t));
1603     for (const Fortran::parser::ForallBodyConstruct &s :
1604          std::get<std::list<Fortran::parser::ForallBodyConstruct>>(forall.t)) {
1605       std::visit(
1606           Fortran::common::visitors{
1607               [&](const Fortran::parser::WhereConstruct &b) { genFIR(b); },
1608               [&](const Fortran::common::Indirection<
1609                   Fortran::parser::ForallConstruct> &b) { genFIR(b.value()); },
1610               [&](const auto &b) { genNestedStatement(b); }},
1611           s.u);
1612     }
1613     genNestedStatement(
1614         std::get<Fortran::parser::Statement<Fortran::parser::EndForallStmt>>(
1615             forall.t));
1616   }
1617 
1618   /// Lower the concurrent header specification.
1619   void genFIR(const Fortran::parser::ForallConstructStmt &stmt) {
1620     genFIR(std::get<
1621                Fortran::common::Indirection<Fortran::parser::ConcurrentHeader>>(
1622                stmt.t)
1623                .value());
1624   }
1625 
1626   void genFIR(const Fortran::parser::CompilerDirective &) {
1627     mlir::emitWarning(toLocation(), "ignoring all compiler directives");
1628   }
1629 
1630   void genFIR(const Fortran::parser::OpenACCConstruct &acc) {
1631     mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint();
1632     genOpenACCConstruct(*this, getEval(), acc);
1633     for (Fortran::lower::pft::Evaluation &e : getEval().getNestedEvaluations())
1634       genFIR(e);
1635     builder->restoreInsertionPoint(insertPt);
1636   }
1637 
1638   void genFIR(const Fortran::parser::OpenACCDeclarativeConstruct &accDecl) {
1639     mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint();
1640     genOpenACCDeclarativeConstruct(*this, getEval(), accDecl);
1641     for (Fortran::lower::pft::Evaluation &e : getEval().getNestedEvaluations())
1642       genFIR(e);
1643     builder->restoreInsertionPoint(insertPt);
1644   }
1645 
1646   void genFIR(const Fortran::parser::OpenMPConstruct &omp) {
1647     mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint();
1648     localSymbols.pushScope();
1649     genOpenMPConstruct(*this, getEval(), omp);
1650 
1651     const Fortran::parser::OpenMPLoopConstruct *ompLoop =
1652         std::get_if<Fortran::parser::OpenMPLoopConstruct>(&omp.u);
1653 
1654     // If loop is part of an OpenMP Construct then the OpenMP dialect
1655     // workshare loop operation has already been created. Only the
1656     // body needs to be created here and the do_loop can be skipped.
1657     // Skip the number of collapsed loops, which is 1 when there is a
1658     // no collapse requested.
1659 
1660     Fortran::lower::pft::Evaluation *curEval = &getEval();
1661     const Fortran::parser::OmpClauseList *loopOpClauseList = nullptr;
1662     if (ompLoop) {
1663       loopOpClauseList = &std::get<Fortran::parser::OmpClauseList>(
1664           std::get<Fortran::parser::OmpBeginLoopDirective>(ompLoop->t).t);
1665       int64_t collapseValue =
1666           Fortran::lower::getCollapseValue(*loopOpClauseList);
1667 
1668       curEval = &curEval->getFirstNestedEvaluation();
1669       for (int64_t i = 1; i < collapseValue; i++) {
1670         curEval = &*std::next(curEval->getNestedEvaluations().begin());
1671       }
1672     }
1673 
1674     for (Fortran::lower::pft::Evaluation &e : curEval->getNestedEvaluations())
1675       genFIR(e);
1676 
1677     if (ompLoop)
1678       genOpenMPReduction(*this, *loopOpClauseList);
1679 
1680     localSymbols.popScope();
1681     builder->restoreInsertionPoint(insertPt);
1682   }
1683 
1684   void genFIR(const Fortran::parser::OpenMPDeclarativeConstruct &ompDecl) {
1685     mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint();
1686     genOpenMPDeclarativeConstruct(*this, getEval(), ompDecl);
1687     for (Fortran::lower::pft::Evaluation &e : getEval().getNestedEvaluations())
1688       genFIR(e);
1689     builder->restoreInsertionPoint(insertPt);
1690   }
1691 
1692   /// Generate FIR for a SELECT CASE statement.
1693   /// The type may be CHARACTER, INTEGER, or LOGICAL.
1694   void genFIR(const Fortran::parser::SelectCaseStmt &stmt) {
1695     Fortran::lower::pft::Evaluation &eval = getEval();
1696     mlir::MLIRContext *context = builder->getContext();
1697     mlir::Location loc = toLocation();
1698     Fortran::lower::StatementContext stmtCtx;
1699     const Fortran::lower::SomeExpr *expr = Fortran::semantics::GetExpr(
1700         std::get<Fortran::parser::Scalar<Fortran::parser::Expr>>(stmt.t));
1701     bool isCharSelector = isCharacterCategory(expr->GetType()->category());
1702     bool isLogicalSelector = isLogicalCategory(expr->GetType()->category());
1703     auto charValue = [&](const Fortran::lower::SomeExpr *expr) {
1704       fir::ExtendedValue exv = genExprAddr(*expr, stmtCtx, &loc);
1705       return exv.match(
1706           [&](const fir::CharBoxValue &cbv) {
1707             return fir::factory::CharacterExprHelper{*builder, loc}
1708                 .createEmboxChar(cbv.getAddr(), cbv.getLen());
1709           },
1710           [&](auto) {
1711             fir::emitFatalError(loc, "not a character");
1712             return mlir::Value{};
1713           });
1714     };
1715     mlir::Value selector;
1716     if (isCharSelector) {
1717       selector = charValue(expr);
1718     } else {
1719       selector = createFIRExpr(loc, expr, stmtCtx);
1720       if (isLogicalSelector)
1721         selector = builder->createConvert(loc, builder->getI1Type(), selector);
1722     }
1723     mlir::Type selectType = selector.getType();
1724     llvm::SmallVector<mlir::Attribute> attrList;
1725     llvm::SmallVector<mlir::Value> valueList;
1726     llvm::SmallVector<mlir::Block *> blockList;
1727     mlir::Block *defaultBlock = eval.parentConstruct->constructExit->block;
1728     using CaseValue = Fortran::parser::Scalar<Fortran::parser::ConstantExpr>;
1729     auto addValue = [&](const CaseValue &caseValue) {
1730       const Fortran::lower::SomeExpr *expr =
1731           Fortran::semantics::GetExpr(caseValue.thing);
1732       if (isCharSelector)
1733         valueList.push_back(charValue(expr));
1734       else if (isLogicalSelector)
1735         valueList.push_back(builder->createConvert(
1736             loc, selectType, createFIRExpr(toLocation(), expr, stmtCtx)));
1737       else
1738         valueList.push_back(builder->createIntegerConstant(
1739             loc, selectType, *Fortran::evaluate::ToInt64(*expr)));
1740     };
1741     for (Fortran::lower::pft::Evaluation *e = eval.controlSuccessor; e;
1742          e = e->controlSuccessor) {
1743       const auto &caseStmt = e->getIf<Fortran::parser::CaseStmt>();
1744       assert(e->block && "missing CaseStmt block");
1745       const auto &caseSelector =
1746           std::get<Fortran::parser::CaseSelector>(caseStmt->t);
1747       const auto *caseValueRangeList =
1748           std::get_if<std::list<Fortran::parser::CaseValueRange>>(
1749               &caseSelector.u);
1750       if (!caseValueRangeList) {
1751         defaultBlock = e->block;
1752         continue;
1753       }
1754       for (const Fortran::parser::CaseValueRange &caseValueRange :
1755            *caseValueRangeList) {
1756         blockList.push_back(e->block);
1757         if (const auto *caseValue = std::get_if<CaseValue>(&caseValueRange.u)) {
1758           attrList.push_back(fir::PointIntervalAttr::get(context));
1759           addValue(*caseValue);
1760           continue;
1761         }
1762         const auto &caseRange =
1763             std::get<Fortran::parser::CaseValueRange::Range>(caseValueRange.u);
1764         if (caseRange.lower && caseRange.upper) {
1765           attrList.push_back(fir::ClosedIntervalAttr::get(context));
1766           addValue(*caseRange.lower);
1767           addValue(*caseRange.upper);
1768         } else if (caseRange.lower) {
1769           attrList.push_back(fir::LowerBoundAttr::get(context));
1770           addValue(*caseRange.lower);
1771         } else {
1772           attrList.push_back(fir::UpperBoundAttr::get(context));
1773           addValue(*caseRange.upper);
1774         }
1775       }
1776     }
1777     // Skip a logical default block that can never be referenced.
1778     if (isLogicalSelector && attrList.size() == 2)
1779       defaultBlock = eval.parentConstruct->constructExit->block;
1780     attrList.push_back(mlir::UnitAttr::get(context));
1781     blockList.push_back(defaultBlock);
1782 
1783     // Generate a fir::SelectCaseOp.
1784     // Explicit branch code is better for the LOGICAL type.  The CHARACTER type
1785     // does not yet have downstream support, and also uses explicit branch code.
1786     // The -no-structured-fir option can be used to force generation of INTEGER
1787     // type branch code.
1788     if (!isLogicalSelector && !isCharSelector && eval.lowerAsStructured()) {
1789       // Numeric selector is a ssa register, all temps that may have
1790       // been generated while evaluating it can be cleaned-up before the
1791       // fir.select_case.
1792       stmtCtx.finalize();
1793       builder->create<fir::SelectCaseOp>(loc, selector, attrList, valueList,
1794                                          blockList);
1795       return;
1796     }
1797 
1798     // Generate a sequence of case value comparisons and branches.
1799     auto caseValue = valueList.begin();
1800     auto caseBlock = blockList.begin();
1801     bool skipFinalization = false;
1802     for (const auto &attr : llvm::enumerate(attrList)) {
1803       if (attr.value().isa<mlir::UnitAttr>()) {
1804         if (attrList.size() == 1)
1805           stmtCtx.finalize();
1806         genFIRBranch(*caseBlock++);
1807         break;
1808       }
1809       auto genCond = [&](mlir::Value rhs,
1810                          mlir::arith::CmpIPredicate pred) -> mlir::Value {
1811         if (!isCharSelector)
1812           return builder->create<mlir::arith::CmpIOp>(loc, pred, selector, rhs);
1813         fir::factory::CharacterExprHelper charHelper{*builder, loc};
1814         std::pair<mlir::Value, mlir::Value> lhsVal =
1815             charHelper.createUnboxChar(selector);
1816         mlir::Value &lhsAddr = lhsVal.first;
1817         mlir::Value &lhsLen = lhsVal.second;
1818         std::pair<mlir::Value, mlir::Value> rhsVal =
1819             charHelper.createUnboxChar(rhs);
1820         mlir::Value &rhsAddr = rhsVal.first;
1821         mlir::Value &rhsLen = rhsVal.second;
1822         mlir::Value result = fir::runtime::genCharCompare(
1823             *builder, loc, pred, lhsAddr, lhsLen, rhsAddr, rhsLen);
1824         if (stmtCtx.workListIsEmpty() || skipFinalization)
1825           return result;
1826         if (attr.index() == attrList.size() - 2) {
1827           stmtCtx.finalize();
1828           return result;
1829         }
1830         fir::IfOp ifOp = builder->create<fir::IfOp>(loc, result,
1831                                                     /*withElseRegion=*/false);
1832         builder->setInsertionPointToStart(&ifOp.getThenRegion().front());
1833         stmtCtx.finalizeAndKeep();
1834         builder->setInsertionPointAfter(ifOp);
1835         return result;
1836       };
1837       mlir::Block *newBlock = insertBlock(*caseBlock);
1838       if (attr.value().isa<fir::ClosedIntervalAttr>()) {
1839         mlir::Block *newBlock2 = insertBlock(*caseBlock);
1840         skipFinalization = true;
1841         mlir::Value cond =
1842             genCond(*caseValue++, mlir::arith::CmpIPredicate::sge);
1843         genFIRConditionalBranch(cond, newBlock, newBlock2);
1844         builder->setInsertionPointToEnd(newBlock);
1845         skipFinalization = false;
1846         mlir::Value cond2 =
1847             genCond(*caseValue++, mlir::arith::CmpIPredicate::sle);
1848         genFIRConditionalBranch(cond2, *caseBlock++, newBlock2);
1849         builder->setInsertionPointToEnd(newBlock2);
1850         continue;
1851       }
1852       mlir::arith::CmpIPredicate pred;
1853       if (attr.value().isa<fir::PointIntervalAttr>()) {
1854         pred = mlir::arith::CmpIPredicate::eq;
1855       } else if (attr.value().isa<fir::LowerBoundAttr>()) {
1856         pred = mlir::arith::CmpIPredicate::sge;
1857       } else {
1858         assert(attr.value().isa<fir::UpperBoundAttr>() &&
1859                "unexpected predicate");
1860         pred = mlir::arith::CmpIPredicate::sle;
1861       }
1862       mlir::Value cond = genCond(*caseValue++, pred);
1863       genFIRConditionalBranch(cond, *caseBlock++, newBlock);
1864       builder->setInsertionPointToEnd(newBlock);
1865     }
1866     assert(caseValue == valueList.end() && caseBlock == blockList.end() &&
1867            "select case list mismatch");
1868     assert(stmtCtx.workListIsEmpty() && "statement context must be empty");
1869   }
1870 
1871   fir::ExtendedValue
1872   genAssociateSelector(const Fortran::lower::SomeExpr &selector,
1873                        Fortran::lower::StatementContext &stmtCtx) {
1874     return Fortran::lower::isArraySectionWithoutVectorSubscript(selector)
1875                ? Fortran::lower::createSomeArrayBox(*this, selector,
1876                                                     localSymbols, stmtCtx)
1877                : genExprAddr(selector, stmtCtx);
1878   }
1879 
1880   void genFIR(const Fortran::parser::AssociateConstruct &) {
1881     Fortran::lower::StatementContext stmtCtx;
1882     Fortran::lower::pft::Evaluation &eval = getEval();
1883     for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations()) {
1884       if (auto *stmt = e.getIf<Fortran::parser::AssociateStmt>()) {
1885         if (eval.lowerAsUnstructured())
1886           maybeStartBlock(e.block);
1887         localSymbols.pushScope();
1888         for (const Fortran::parser::Association &assoc :
1889              std::get<std::list<Fortran::parser::Association>>(stmt->t)) {
1890           Fortran::semantics::Symbol &sym =
1891               *std::get<Fortran::parser::Name>(assoc.t).symbol;
1892           const Fortran::lower::SomeExpr &selector =
1893               *sym.get<Fortran::semantics::AssocEntityDetails>().expr();
1894           localSymbols.addSymbol(sym, genAssociateSelector(selector, stmtCtx));
1895         }
1896       } else if (e.getIf<Fortran::parser::EndAssociateStmt>()) {
1897         if (eval.lowerAsUnstructured())
1898           maybeStartBlock(e.block);
1899         stmtCtx.finalize();
1900         localSymbols.popScope();
1901       } else {
1902         genFIR(e);
1903       }
1904     }
1905   }
1906 
1907   void genFIR(const Fortran::parser::BlockConstruct &blockConstruct) {
1908     setCurrentPositionAt(blockConstruct);
1909     TODO(toLocation(), "BlockConstruct implementation");
1910   }
1911   void genFIR(const Fortran::parser::BlockStmt &) {
1912     TODO(toLocation(), "BlockStmt implementation");
1913   }
1914   void genFIR(const Fortran::parser::EndBlockStmt &) {
1915     TODO(toLocation(), "EndBlockStmt implementation");
1916   }
1917 
1918   void genFIR(const Fortran::parser::ChangeTeamConstruct &construct) {
1919     TODO(toLocation(), "ChangeTeamConstruct implementation");
1920   }
1921   void genFIR(const Fortran::parser::ChangeTeamStmt &stmt) {
1922     TODO(toLocation(), "ChangeTeamStmt implementation");
1923   }
1924   void genFIR(const Fortran::parser::EndChangeTeamStmt &stmt) {
1925     TODO(toLocation(), "EndChangeTeamStmt implementation");
1926   }
1927 
1928   void genFIR(const Fortran::parser::CriticalConstruct &criticalConstruct) {
1929     setCurrentPositionAt(criticalConstruct);
1930     TODO(toLocation(), "CriticalConstruct implementation");
1931   }
1932   void genFIR(const Fortran::parser::CriticalStmt &) {
1933     TODO(toLocation(), "CriticalStmt implementation");
1934   }
1935   void genFIR(const Fortran::parser::EndCriticalStmt &) {
1936     TODO(toLocation(), "EndCriticalStmt implementation");
1937   }
1938 
1939   void genFIR(const Fortran::parser::SelectRankConstruct &selectRankConstruct) {
1940     setCurrentPositionAt(selectRankConstruct);
1941     TODO(toLocation(), "SelectRankConstruct implementation");
1942   }
1943   void genFIR(const Fortran::parser::SelectRankStmt &) {
1944     TODO(toLocation(), "SelectRankStmt implementation");
1945   }
1946   void genFIR(const Fortran::parser::SelectRankCaseStmt &) {
1947     TODO(toLocation(), "SelectRankCaseStmt implementation");
1948   }
1949 
1950   void genFIR(const Fortran::parser::SelectTypeConstruct &selectTypeConstruct) {
1951     setCurrentPositionAt(selectTypeConstruct);
1952     TODO(toLocation(), "SelectTypeConstruct implementation");
1953   }
1954   void genFIR(const Fortran::parser::SelectTypeStmt &) {
1955     TODO(toLocation(), "SelectTypeStmt implementation");
1956   }
1957   void genFIR(const Fortran::parser::TypeGuardStmt &) {
1958     TODO(toLocation(), "TypeGuardStmt implementation");
1959   }
1960 
1961   //===--------------------------------------------------------------------===//
1962   // IO statements (see io.h)
1963   //===--------------------------------------------------------------------===//
1964 
1965   void genFIR(const Fortran::parser::BackspaceStmt &stmt) {
1966     mlir::Value iostat = genBackspaceStatement(*this, stmt);
1967     genIoConditionBranches(getEval(), stmt.v, iostat);
1968   }
1969   void genFIR(const Fortran::parser::CloseStmt &stmt) {
1970     mlir::Value iostat = genCloseStatement(*this, stmt);
1971     genIoConditionBranches(getEval(), stmt.v, iostat);
1972   }
1973   void genFIR(const Fortran::parser::EndfileStmt &stmt) {
1974     mlir::Value iostat = genEndfileStatement(*this, stmt);
1975     genIoConditionBranches(getEval(), stmt.v, iostat);
1976   }
1977   void genFIR(const Fortran::parser::FlushStmt &stmt) {
1978     mlir::Value iostat = genFlushStatement(*this, stmt);
1979     genIoConditionBranches(getEval(), stmt.v, iostat);
1980   }
1981   void genFIR(const Fortran::parser::InquireStmt &stmt) {
1982     mlir::Value iostat = genInquireStatement(*this, stmt);
1983     if (const auto *specs =
1984             std::get_if<std::list<Fortran::parser::InquireSpec>>(&stmt.u))
1985       genIoConditionBranches(getEval(), *specs, iostat);
1986   }
1987   void genFIR(const Fortran::parser::OpenStmt &stmt) {
1988     mlir::Value iostat = genOpenStatement(*this, stmt);
1989     genIoConditionBranches(getEval(), stmt.v, iostat);
1990   }
1991   void genFIR(const Fortran::parser::PrintStmt &stmt) {
1992     genPrintStatement(*this, stmt);
1993   }
1994   void genFIR(const Fortran::parser::ReadStmt &stmt) {
1995     mlir::Value iostat = genReadStatement(*this, stmt);
1996     genIoConditionBranches(getEval(), stmt.controls, iostat);
1997   }
1998   void genFIR(const Fortran::parser::RewindStmt &stmt) {
1999     mlir::Value iostat = genRewindStatement(*this, stmt);
2000     genIoConditionBranches(getEval(), stmt.v, iostat);
2001   }
2002   void genFIR(const Fortran::parser::WaitStmt &stmt) {
2003     mlir::Value iostat = genWaitStatement(*this, stmt);
2004     genIoConditionBranches(getEval(), stmt.v, iostat);
2005   }
2006   void genFIR(const Fortran::parser::WriteStmt &stmt) {
2007     mlir::Value iostat = genWriteStatement(*this, stmt);
2008     genIoConditionBranches(getEval(), stmt.controls, iostat);
2009   }
2010 
2011   template <typename A>
2012   void genIoConditionBranches(Fortran::lower::pft::Evaluation &eval,
2013                               const A &specList, mlir::Value iostat) {
2014     if (!iostat)
2015       return;
2016 
2017     mlir::Block *endBlock = nullptr;
2018     mlir::Block *eorBlock = nullptr;
2019     mlir::Block *errBlock = nullptr;
2020     for (const auto &spec : specList) {
2021       std::visit(Fortran::common::visitors{
2022                      [&](const Fortran::parser::EndLabel &label) {
2023                        endBlock = blockOfLabel(eval, label.v);
2024                      },
2025                      [&](const Fortran::parser::EorLabel &label) {
2026                        eorBlock = blockOfLabel(eval, label.v);
2027                      },
2028                      [&](const Fortran::parser::ErrLabel &label) {
2029                        errBlock = blockOfLabel(eval, label.v);
2030                      },
2031                      [](const auto &) {}},
2032                  spec.u);
2033     }
2034     if (!endBlock && !eorBlock && !errBlock)
2035       return;
2036 
2037     mlir::Location loc = toLocation();
2038     mlir::Type indexType = builder->getIndexType();
2039     mlir::Value selector = builder->createConvert(loc, indexType, iostat);
2040     llvm::SmallVector<int64_t> indexList;
2041     llvm::SmallVector<mlir::Block *> blockList;
2042     if (eorBlock) {
2043       indexList.push_back(Fortran::runtime::io::IostatEor);
2044       blockList.push_back(eorBlock);
2045     }
2046     if (endBlock) {
2047       indexList.push_back(Fortran::runtime::io::IostatEnd);
2048       blockList.push_back(endBlock);
2049     }
2050     if (errBlock) {
2051       indexList.push_back(0);
2052       blockList.push_back(eval.nonNopSuccessor().block);
2053       // ERR label statement is the default successor.
2054       blockList.push_back(errBlock);
2055     } else {
2056       // Fallthrough successor statement is the default successor.
2057       blockList.push_back(eval.nonNopSuccessor().block);
2058     }
2059     builder->create<fir::SelectOp>(loc, selector, indexList, blockList);
2060   }
2061 
2062   //===--------------------------------------------------------------------===//
2063   // Memory allocation and deallocation
2064   //===--------------------------------------------------------------------===//
2065 
2066   void genFIR(const Fortran::parser::AllocateStmt &stmt) {
2067     Fortran::lower::genAllocateStmt(*this, stmt, toLocation());
2068   }
2069 
2070   void genFIR(const Fortran::parser::DeallocateStmt &stmt) {
2071     Fortran::lower::genDeallocateStmt(*this, stmt, toLocation());
2072   }
2073 
2074   /// Nullify pointer object list
2075   ///
2076   /// For each pointer object, reset the pointer to a disassociated status.
2077   /// We do this by setting each pointer to null.
2078   void genFIR(const Fortran::parser::NullifyStmt &stmt) {
2079     mlir::Location loc = toLocation();
2080     for (auto &pointerObject : stmt.v) {
2081       const Fortran::lower::SomeExpr *expr =
2082           Fortran::semantics::GetExpr(pointerObject);
2083       assert(expr);
2084       fir::MutableBoxValue box = genExprMutableBox(loc, *expr);
2085       fir::factory::disassociateMutableBox(*builder, loc, box);
2086     }
2087   }
2088 
2089   //===--------------------------------------------------------------------===//
2090 
2091   void genFIR(const Fortran::parser::EventPostStmt &stmt) {
2092     genEventPostStatement(*this, stmt);
2093   }
2094 
2095   void genFIR(const Fortran::parser::EventWaitStmt &stmt) {
2096     genEventWaitStatement(*this, stmt);
2097   }
2098 
2099   void genFIR(const Fortran::parser::FormTeamStmt &stmt) {
2100     genFormTeamStatement(*this, getEval(), stmt);
2101   }
2102 
2103   void genFIR(const Fortran::parser::LockStmt &stmt) {
2104     genLockStatement(*this, stmt);
2105   }
2106 
2107   fir::ExtendedValue
2108   genInitializerExprValue(const Fortran::lower::SomeExpr &expr,
2109                           Fortran::lower::StatementContext &stmtCtx) {
2110     return Fortran::lower::createSomeInitializerExpression(
2111         toLocation(), *this, expr, localSymbols, stmtCtx);
2112   }
2113 
2114   /// Return true if the current context is a conditionalized and implied
2115   /// iteration space.
2116   bool implicitIterationSpace() { return !implicitIterSpace.empty(); }
2117 
2118   /// Return true if context is currently an explicit iteration space. A scalar
2119   /// assignment expression may be contextually within a user-defined iteration
2120   /// space, transforming it into an array expression.
2121   bool explicitIterationSpace() { return explicitIterSpace.isActive(); }
2122 
2123   /// Generate an array assignment.
2124   /// This is an assignment expression with rank > 0. The assignment may or may
2125   /// not be in a WHERE and/or FORALL context.
2126   /// In a FORALL context, the assignment may be a pointer assignment and the \p
2127   /// lbounds and \p ubounds parameters should only be used in such a pointer
2128   /// assignment case. (If both are None then the array assignment cannot be a
2129   /// pointer assignment.)
2130   void genArrayAssignment(
2131       const Fortran::evaluate::Assignment &assign,
2132       Fortran::lower::StatementContext &stmtCtx,
2133       llvm::Optional<llvm::SmallVector<mlir::Value>> lbounds = llvm::None,
2134       llvm::Optional<llvm::SmallVector<mlir::Value>> ubounds = llvm::None) {
2135     if (Fortran::lower::isWholeAllocatable(assign.lhs)) {
2136       // Assignment to allocatables may require the lhs to be
2137       // deallocated/reallocated. See Fortran 2018 10.2.1.3 p3
2138       Fortran::lower::createAllocatableArrayAssignment(
2139           *this, assign.lhs, assign.rhs, explicitIterSpace, implicitIterSpace,
2140           localSymbols, stmtCtx);
2141       return;
2142     }
2143 
2144     if (lbounds) {
2145       // Array of POINTER entities, with elemental assignment.
2146       if (!Fortran::lower::isWholePointer(assign.lhs))
2147         fir::emitFatalError(toLocation(), "pointer assignment to non-pointer");
2148 
2149       Fortran::lower::createArrayOfPointerAssignment(
2150           *this, assign.lhs, assign.rhs, explicitIterSpace, implicitIterSpace,
2151           *lbounds, ubounds, localSymbols, stmtCtx);
2152       return;
2153     }
2154 
2155     if (!implicitIterationSpace() && !explicitIterationSpace()) {
2156       // No masks and the iteration space is implied by the array, so create a
2157       // simple array assignment.
2158       Fortran::lower::createSomeArrayAssignment(*this, assign.lhs, assign.rhs,
2159                                                 localSymbols, stmtCtx);
2160       return;
2161     }
2162 
2163     // If there is an explicit iteration space, generate an array assignment
2164     // with a user-specified iteration space and possibly with masks. These
2165     // assignments may *appear* to be scalar expressions, but the scalar
2166     // expression is evaluated at all points in the user-defined space much like
2167     // an ordinary array assignment. More specifically, the semantics inside the
2168     // FORALL much more closely resembles that of WHERE than a scalar
2169     // assignment.
2170     // Otherwise, generate a masked array assignment. The iteration space is
2171     // implied by the lhs array expression.
2172     Fortran::lower::createAnyMaskedArrayAssignment(
2173         *this, assign.lhs, assign.rhs, explicitIterSpace, implicitIterSpace,
2174         localSymbols,
2175         explicitIterationSpace() ? explicitIterSpace.stmtContext()
2176                                  : implicitIterSpace.stmtContext());
2177   }
2178 
2179 #if !defined(NDEBUG)
2180   static bool isFuncResultDesignator(const Fortran::lower::SomeExpr &expr) {
2181     const Fortran::semantics::Symbol *sym =
2182         Fortran::evaluate::GetFirstSymbol(expr);
2183     return sym && sym->IsFuncResult();
2184   }
2185 #endif
2186 
2187   inline fir::MutableBoxValue
2188   genExprMutableBox(mlir::Location loc,
2189                     const Fortran::lower::SomeExpr &expr) override final {
2190     return Fortran::lower::createMutableBox(loc, *this, expr, localSymbols);
2191   }
2192 
2193   /// Shared for both assignments and pointer assignments.
2194   void genAssignment(const Fortran::evaluate::Assignment &assign) {
2195     Fortran::lower::StatementContext stmtCtx;
2196     mlir::Location loc = toLocation();
2197     if (explicitIterationSpace()) {
2198       Fortran::lower::createArrayLoads(*this, explicitIterSpace, localSymbols);
2199       explicitIterSpace.genLoopNest();
2200     }
2201     std::visit(
2202         Fortran::common::visitors{
2203             // [1] Plain old assignment.
2204             [&](const Fortran::evaluate::Assignment::Intrinsic &) {
2205               const Fortran::semantics::Symbol *sym =
2206                   Fortran::evaluate::GetLastSymbol(assign.lhs);
2207 
2208               if (!sym)
2209                 TODO(loc, "assignment to pointer result of function reference");
2210 
2211               std::optional<Fortran::evaluate::DynamicType> lhsType =
2212                   assign.lhs.GetType();
2213               assert(lhsType && "lhs cannot be typeless");
2214               // Assignment to polymorphic allocatables may require changing the
2215               // variable dynamic type (See Fortran 2018 10.2.1.3 p3).
2216               if (lhsType->IsPolymorphic() &&
2217                   Fortran::lower::isWholeAllocatable(assign.lhs))
2218                 TODO(loc, "assignment to polymorphic allocatable");
2219 
2220               // Note: No ad-hoc handling for pointers is required here. The
2221               // target will be assigned as per 2018 10.2.1.3 p2. genExprAddr
2222               // on a pointer returns the target address and not the address of
2223               // the pointer variable.
2224 
2225               if (assign.lhs.Rank() > 0 || explicitIterationSpace()) {
2226                 // Array assignment
2227                 // See Fortran 2018 10.2.1.3 p5, p6, and p7
2228                 genArrayAssignment(assign, stmtCtx);
2229                 return;
2230               }
2231 
2232               // Scalar assignment
2233               const bool isNumericScalar =
2234                   isNumericScalarCategory(lhsType->category());
2235               fir::ExtendedValue rhs = isNumericScalar
2236                                            ? genExprValue(assign.rhs, stmtCtx)
2237                                            : genExprAddr(assign.rhs, stmtCtx);
2238               const bool lhsIsWholeAllocatable =
2239                   Fortran::lower::isWholeAllocatable(assign.lhs);
2240               llvm::Optional<fir::factory::MutableBoxReallocation> lhsRealloc;
2241               llvm::Optional<fir::MutableBoxValue> lhsMutableBox;
2242               auto lhs = [&]() -> fir::ExtendedValue {
2243                 if (lhsIsWholeAllocatable) {
2244                   lhsMutableBox = genExprMutableBox(loc, assign.lhs);
2245                   llvm::SmallVector<mlir::Value> lengthParams;
2246                   if (const fir::CharBoxValue *charBox = rhs.getCharBox())
2247                     lengthParams.push_back(charBox->getLen());
2248                   else if (fir::isDerivedWithLenParameters(rhs))
2249                     TODO(loc, "assignment to derived type allocatable with "
2250                               "LEN parameters");
2251                   lhsRealloc = fir::factory::genReallocIfNeeded(
2252                       *builder, loc, *lhsMutableBox,
2253                       /*shape=*/llvm::None, lengthParams);
2254                   return lhsRealloc->newValue;
2255                 }
2256                 return genExprAddr(assign.lhs, stmtCtx);
2257               }();
2258 
2259               if (isNumericScalar) {
2260                 // Fortran 2018 10.2.1.3 p8 and p9
2261                 // Conversions should have been inserted by semantic analysis,
2262                 // but they can be incorrect between the rhs and lhs. Correct
2263                 // that here.
2264                 mlir::Value addr = fir::getBase(lhs);
2265                 mlir::Value val = fir::getBase(rhs);
2266                 // A function with multiple entry points returning different
2267                 // types tags all result variables with one of the largest
2268                 // types to allow them to share the same storage.  Assignment
2269                 // to a result variable of one of the other types requires
2270                 // conversion to the actual type.
2271                 mlir::Type toTy = genType(assign.lhs);
2272                 mlir::Value cast =
2273                     builder->convertWithSemantics(loc, toTy, val);
2274                 if (fir::dyn_cast_ptrEleTy(addr.getType()) != toTy) {
2275                   assert(isFuncResultDesignator(assign.lhs) && "type mismatch");
2276                   addr = builder->createConvert(
2277                       toLocation(), builder->getRefType(toTy), addr);
2278                 }
2279                 builder->create<fir::StoreOp>(loc, cast, addr);
2280               } else if (isCharacterCategory(lhsType->category())) {
2281                 // Fortran 2018 10.2.1.3 p10 and p11
2282                 fir::factory::CharacterExprHelper{*builder, loc}.createAssign(
2283                     lhs, rhs);
2284               } else if (isDerivedCategory(lhsType->category())) {
2285                 // Fortran 2018 10.2.1.3 p13 and p14
2286                 // Recursively gen an assignment on each element pair.
2287                 fir::factory::genRecordAssignment(*builder, loc, lhs, rhs);
2288               } else {
2289                 llvm_unreachable("unknown category");
2290               }
2291               if (lhsIsWholeAllocatable)
2292                 fir::factory::finalizeRealloc(
2293                     *builder, loc, lhsMutableBox.value(),
2294                     /*lbounds=*/llvm::None, /*takeLboundsIfRealloc=*/false,
2295                     lhsRealloc.value());
2296             },
2297 
2298             // [2] User defined assignment. If the context is a scalar
2299             // expression then call the procedure.
2300             [&](const Fortran::evaluate::ProcedureRef &procRef) {
2301               Fortran::lower::StatementContext &ctx =
2302                   explicitIterationSpace() ? explicitIterSpace.stmtContext()
2303                                            : stmtCtx;
2304               Fortran::lower::createSubroutineCall(
2305                   *this, procRef, explicitIterSpace, implicitIterSpace,
2306                   localSymbols, ctx, /*isUserDefAssignment=*/true);
2307             },
2308 
2309             // [3] Pointer assignment with possibly empty bounds-spec. R1035: a
2310             // bounds-spec is a lower bound value.
2311             [&](const Fortran::evaluate::Assignment::BoundsSpec &lbExprs) {
2312               if (Fortran::evaluate::IsProcedure(assign.rhs))
2313                 TODO(loc, "procedure pointer assignment");
2314               std::optional<Fortran::evaluate::DynamicType> lhsType =
2315                   assign.lhs.GetType();
2316               std::optional<Fortran::evaluate::DynamicType> rhsType =
2317                   assign.rhs.GetType();
2318               // Polymorphic lhs/rhs may need more care. See F2018 10.2.2.3.
2319               if ((lhsType && lhsType->IsPolymorphic()) ||
2320                   (rhsType && rhsType->IsPolymorphic()))
2321                 TODO(loc, "pointer assignment involving polymorphic entity");
2322 
2323               llvm::SmallVector<mlir::Value> lbounds;
2324               for (const Fortran::evaluate::ExtentExpr &lbExpr : lbExprs)
2325                 lbounds.push_back(
2326                     fir::getBase(genExprValue(toEvExpr(lbExpr), stmtCtx)));
2327               if (explicitIterationSpace()) {
2328                 // Pointer assignment in FORALL context. Copy the rhs box value
2329                 // into the lhs box variable.
2330                 genArrayAssignment(assign, stmtCtx, lbounds);
2331                 return;
2332               }
2333               fir::MutableBoxValue lhs = genExprMutableBox(loc, assign.lhs);
2334               Fortran::lower::associateMutableBox(*this, loc, lhs, assign.rhs,
2335                                                   lbounds, stmtCtx);
2336             },
2337 
2338             // [4] Pointer assignment with bounds-remapping. R1036: a
2339             // bounds-remapping is a pair, lower bound and upper bound.
2340             [&](const Fortran::evaluate::Assignment::BoundsRemapping
2341                     &boundExprs) {
2342               std::optional<Fortran::evaluate::DynamicType> lhsType =
2343                   assign.lhs.GetType();
2344               std::optional<Fortran::evaluate::DynamicType> rhsType =
2345                   assign.rhs.GetType();
2346               // Polymorphic lhs/rhs may need more care. See F2018 10.2.2.3.
2347               if ((lhsType && lhsType->IsPolymorphic()) ||
2348                   (rhsType && rhsType->IsPolymorphic()))
2349                 TODO(loc, "pointer assignment involving polymorphic entity");
2350 
2351               llvm::SmallVector<mlir::Value> lbounds;
2352               llvm::SmallVector<mlir::Value> ubounds;
2353               for (const std::pair<Fortran::evaluate::ExtentExpr,
2354                                    Fortran::evaluate::ExtentExpr> &pair :
2355                    boundExprs) {
2356                 const Fortran::evaluate::ExtentExpr &lbExpr = pair.first;
2357                 const Fortran::evaluate::ExtentExpr &ubExpr = pair.second;
2358                 lbounds.push_back(
2359                     fir::getBase(genExprValue(toEvExpr(lbExpr), stmtCtx)));
2360                 ubounds.push_back(
2361                     fir::getBase(genExprValue(toEvExpr(ubExpr), stmtCtx)));
2362               }
2363               if (explicitIterationSpace()) {
2364                 // Pointer assignment in FORALL context. Copy the rhs box value
2365                 // into the lhs box variable.
2366                 genArrayAssignment(assign, stmtCtx, lbounds, ubounds);
2367                 return;
2368               }
2369               fir::MutableBoxValue lhs = genExprMutableBox(loc, assign.lhs);
2370               if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
2371                       assign.rhs)) {
2372                 fir::factory::disassociateMutableBox(*builder, loc, lhs);
2373                 return;
2374               }
2375               // Do not generate a temp in case rhs is an array section.
2376               fir::ExtendedValue rhs =
2377                   Fortran::lower::isArraySectionWithoutVectorSubscript(
2378                       assign.rhs)
2379                       ? Fortran::lower::createSomeArrayBox(
2380                             *this, assign.rhs, localSymbols, stmtCtx)
2381                       : genExprAddr(assign.rhs, stmtCtx);
2382               fir::factory::associateMutableBoxWithRemap(*builder, loc, lhs,
2383                                                          rhs, lbounds, ubounds);
2384               if (explicitIterationSpace()) {
2385                 mlir::ValueRange inners = explicitIterSpace.getInnerArgs();
2386                 if (!inners.empty())
2387                   builder->create<fir::ResultOp>(loc, inners);
2388               }
2389             },
2390         },
2391         assign.u);
2392     if (explicitIterationSpace())
2393       Fortran::lower::createArrayMergeStores(*this, explicitIterSpace);
2394   }
2395 
2396   void genFIR(const Fortran::parser::WhereConstruct &c) {
2397     implicitIterSpace.growStack();
2398     genNestedStatement(
2399         std::get<
2400             Fortran::parser::Statement<Fortran::parser::WhereConstructStmt>>(
2401             c.t));
2402     for (const auto &body :
2403          std::get<std::list<Fortran::parser::WhereBodyConstruct>>(c.t))
2404       genFIR(body);
2405     for (const auto &e :
2406          std::get<std::list<Fortran::parser::WhereConstruct::MaskedElsewhere>>(
2407              c.t))
2408       genFIR(e);
2409     if (const auto &e =
2410             std::get<std::optional<Fortran::parser::WhereConstruct::Elsewhere>>(
2411                 c.t);
2412         e.has_value())
2413       genFIR(*e);
2414     genNestedStatement(
2415         std::get<Fortran::parser::Statement<Fortran::parser::EndWhereStmt>>(
2416             c.t));
2417   }
2418   void genFIR(const Fortran::parser::WhereBodyConstruct &body) {
2419     std::visit(
2420         Fortran::common::visitors{
2421             [&](const Fortran::parser::Statement<
2422                 Fortran::parser::AssignmentStmt> &stmt) {
2423               genNestedStatement(stmt);
2424             },
2425             [&](const Fortran::parser::Statement<Fortran::parser::WhereStmt>
2426                     &stmt) { genNestedStatement(stmt); },
2427             [&](const Fortran::common::Indirection<
2428                 Fortran::parser::WhereConstruct> &c) { genFIR(c.value()); },
2429         },
2430         body.u);
2431   }
2432   void genFIR(const Fortran::parser::WhereConstructStmt &stmt) {
2433     implicitIterSpace.append(Fortran::semantics::GetExpr(
2434         std::get<Fortran::parser::LogicalExpr>(stmt.t)));
2435   }
2436   void genFIR(const Fortran::parser::WhereConstruct::MaskedElsewhere &ew) {
2437     genNestedStatement(
2438         std::get<
2439             Fortran::parser::Statement<Fortran::parser::MaskedElsewhereStmt>>(
2440             ew.t));
2441     for (const auto &body :
2442          std::get<std::list<Fortran::parser::WhereBodyConstruct>>(ew.t))
2443       genFIR(body);
2444   }
2445   void genFIR(const Fortran::parser::MaskedElsewhereStmt &stmt) {
2446     implicitIterSpace.append(Fortran::semantics::GetExpr(
2447         std::get<Fortran::parser::LogicalExpr>(stmt.t)));
2448   }
2449   void genFIR(const Fortran::parser::WhereConstruct::Elsewhere &ew) {
2450     genNestedStatement(
2451         std::get<Fortran::parser::Statement<Fortran::parser::ElsewhereStmt>>(
2452             ew.t));
2453     for (const auto &body :
2454          std::get<std::list<Fortran::parser::WhereBodyConstruct>>(ew.t))
2455       genFIR(body);
2456   }
2457   void genFIR(const Fortran::parser::ElsewhereStmt &stmt) {
2458     implicitIterSpace.append(nullptr);
2459   }
2460   void genFIR(const Fortran::parser::EndWhereStmt &) {
2461     implicitIterSpace.shrinkStack();
2462   }
2463 
2464   void genFIR(const Fortran::parser::WhereStmt &stmt) {
2465     Fortran::lower::StatementContext stmtCtx;
2466     const auto &assign = std::get<Fortran::parser::AssignmentStmt>(stmt.t);
2467     implicitIterSpace.growStack();
2468     implicitIterSpace.append(Fortran::semantics::GetExpr(
2469         std::get<Fortran::parser::LogicalExpr>(stmt.t)));
2470     genAssignment(*assign.typedAssignment->v);
2471     implicitIterSpace.shrinkStack();
2472   }
2473 
2474   void genFIR(const Fortran::parser::PointerAssignmentStmt &stmt) {
2475     genAssignment(*stmt.typedAssignment->v);
2476   }
2477 
2478   void genFIR(const Fortran::parser::AssignmentStmt &stmt) {
2479     genAssignment(*stmt.typedAssignment->v);
2480   }
2481 
2482   void genFIR(const Fortran::parser::SyncAllStmt &stmt) {
2483     genSyncAllStatement(*this, stmt);
2484   }
2485 
2486   void genFIR(const Fortran::parser::SyncImagesStmt &stmt) {
2487     genSyncImagesStatement(*this, stmt);
2488   }
2489 
2490   void genFIR(const Fortran::parser::SyncMemoryStmt &stmt) {
2491     genSyncMemoryStatement(*this, stmt);
2492   }
2493 
2494   void genFIR(const Fortran::parser::SyncTeamStmt &stmt) {
2495     genSyncTeamStatement(*this, stmt);
2496   }
2497 
2498   void genFIR(const Fortran::parser::UnlockStmt &stmt) {
2499     genUnlockStatement(*this, stmt);
2500   }
2501 
2502   void genFIR(const Fortran::parser::AssignStmt &stmt) {
2503     const Fortran::semantics::Symbol &symbol =
2504         *std::get<Fortran::parser::Name>(stmt.t).symbol;
2505     mlir::Location loc = toLocation();
2506     mlir::Value labelValue = builder->createIntegerConstant(
2507         loc, genType(symbol), std::get<Fortran::parser::Label>(stmt.t));
2508     builder->create<fir::StoreOp>(loc, labelValue, getSymbolAddress(symbol));
2509   }
2510 
2511   void genFIR(const Fortran::parser::FormatStmt &) {
2512     // do nothing.
2513 
2514     // FORMAT statements have no semantics. They may be lowered if used by a
2515     // data transfer statement.
2516   }
2517 
2518   void genFIR(const Fortran::parser::PauseStmt &stmt) {
2519     genPauseStatement(*this, stmt);
2520   }
2521 
2522   // call FAIL IMAGE in runtime
2523   void genFIR(const Fortran::parser::FailImageStmt &stmt) {
2524     genFailImageStatement(*this);
2525   }
2526 
2527   // call STOP, ERROR STOP in runtime
2528   void genFIR(const Fortran::parser::StopStmt &stmt) {
2529     genStopStatement(*this, stmt);
2530   }
2531 
2532   void genFIR(const Fortran::parser::ReturnStmt &stmt) {
2533     Fortran::lower::pft::FunctionLikeUnit *funit =
2534         getEval().getOwningProcedure();
2535     assert(funit && "not inside main program, function or subroutine");
2536     if (funit->isMainProgram()) {
2537       genExitRoutine();
2538       return;
2539     }
2540     mlir::Location loc = toLocation();
2541     if (stmt.v) {
2542       // Alternate return statement - If this is a subroutine where some
2543       // alternate entries have alternate returns, but the active entry point
2544       // does not, ignore the alternate return value.  Otherwise, assign it
2545       // to the compiler-generated result variable.
2546       const Fortran::semantics::Symbol &symbol = funit->getSubprogramSymbol();
2547       if (Fortran::semantics::HasAlternateReturns(symbol)) {
2548         Fortran::lower::StatementContext stmtCtx;
2549         const Fortran::lower::SomeExpr *expr =
2550             Fortran::semantics::GetExpr(*stmt.v);
2551         assert(expr && "missing alternate return expression");
2552         mlir::Value altReturnIndex = builder->createConvert(
2553             loc, builder->getIndexType(), createFIRExpr(loc, expr, stmtCtx));
2554         builder->create<fir::StoreOp>(loc, altReturnIndex,
2555                                       getAltReturnResult(symbol));
2556       }
2557     }
2558     // Branch to the last block of the SUBROUTINE, which has the actual return.
2559     if (!funit->finalBlock) {
2560       mlir::OpBuilder::InsertPoint insPt = builder->saveInsertionPoint();
2561       funit->finalBlock = builder->createBlock(&builder->getRegion());
2562       builder->restoreInsertionPoint(insPt);
2563     }
2564     builder->create<mlir::cf::BranchOp>(loc, funit->finalBlock);
2565   }
2566 
2567   void genFIR(const Fortran::parser::CycleStmt &) {
2568     genFIRBranch(getEval().controlSuccessor->block);
2569   }
2570   void genFIR(const Fortran::parser::ExitStmt &) {
2571     genFIRBranch(getEval().controlSuccessor->block);
2572   }
2573   void genFIR(const Fortran::parser::GotoStmt &) {
2574     genFIRBranch(getEval().controlSuccessor->block);
2575   }
2576 
2577   // Nop statements - No code, or code is generated at the construct level.
2578   void genFIR(const Fortran::parser::AssociateStmt &) {}       // nop
2579   void genFIR(const Fortran::parser::CaseStmt &) {}            // nop
2580   void genFIR(const Fortran::parser::ContinueStmt &) {}        // nop
2581   void genFIR(const Fortran::parser::ElseIfStmt &) {}          // nop
2582   void genFIR(const Fortran::parser::ElseStmt &) {}            // nop
2583   void genFIR(const Fortran::parser::EndAssociateStmt &) {}    // nop
2584   void genFIR(const Fortran::parser::EndDoStmt &) {}           // nop
2585   void genFIR(const Fortran::parser::EndFunctionStmt &) {}     // nop
2586   void genFIR(const Fortran::parser::EndIfStmt &) {}           // nop
2587   void genFIR(const Fortran::parser::EndMpSubprogramStmt &) {} // nop
2588   void genFIR(const Fortran::parser::EndSelectStmt &) {}       // nop
2589   void genFIR(const Fortran::parser::EndSubroutineStmt &) {}   // nop
2590   void genFIR(const Fortran::parser::EntryStmt &) {}           // nop
2591   void genFIR(const Fortran::parser::IfStmt &) {}              // nop
2592   void genFIR(const Fortran::parser::IfThenStmt &) {}          // nop
2593   void genFIR(const Fortran::parser::NonLabelDoStmt &) {}      // nop
2594   void genFIR(const Fortran::parser::OmpEndLoopDirective &) {} // nop
2595 
2596   void genFIR(const Fortran::parser::NamelistStmt &) {
2597     TODO(toLocation(), "NamelistStmt lowering");
2598   }
2599 
2600   /// Generate FIR for the Evaluation `eval`.
2601   void genFIR(Fortran::lower::pft::Evaluation &eval,
2602               bool unstructuredContext = true) {
2603     if (unstructuredContext) {
2604       // When transitioning from unstructured to structured code,
2605       // the structured code could be a target that starts a new block.
2606       maybeStartBlock(eval.isConstruct() && eval.lowerAsStructured()
2607                           ? eval.getFirstNestedEvaluation().block
2608                           : eval.block);
2609     }
2610 
2611     setCurrentEval(eval);
2612     setCurrentPosition(eval.position);
2613     eval.visit([&](const auto &stmt) { genFIR(stmt); });
2614 
2615     if (unstructuredContext && blockIsUnterminated()) {
2616       // Exit from an unstructured IF or SELECT construct block.
2617       Fortran::lower::pft::Evaluation *successor{};
2618       if (eval.isActionStmt())
2619         successor = eval.controlSuccessor;
2620       else if (eval.isConstruct() &&
2621                eval.getLastNestedEvaluation()
2622                    .lexicalSuccessor->isIntermediateConstructStmt())
2623         successor = eval.constructExit;
2624       if (successor && successor->block)
2625         genFIRBranch(successor->block);
2626     }
2627   }
2628 
2629   /// Map mlir function block arguments to the corresponding Fortran dummy
2630   /// variables. When the result is passed as a hidden argument, the Fortran
2631   /// result is also mapped. The symbol map is used to hold this mapping.
2632   void mapDummiesAndResults(Fortran::lower::pft::FunctionLikeUnit &funit,
2633                             const Fortran::lower::CalleeInterface &callee) {
2634     assert(builder && "require a builder object at this point");
2635     using PassBy = Fortran::lower::CalleeInterface::PassEntityBy;
2636     auto mapPassedEntity = [&](const auto arg) {
2637       if (arg.passBy == PassBy::AddressAndLength) {
2638         // TODO: now that fir call has some attributes regarding character
2639         // return, PassBy::AddressAndLength should be retired.
2640         mlir::Location loc = toLocation();
2641         fir::factory::CharacterExprHelper charHelp{*builder, loc};
2642         mlir::Value box =
2643             charHelp.createEmboxChar(arg.firArgument, arg.firLength);
2644         addSymbol(arg.entity->get(), box);
2645       } else {
2646         if (arg.entity.has_value()) {
2647           addSymbol(arg.entity->get(), arg.firArgument);
2648         } else {
2649           assert(funit.parentHasHostAssoc());
2650           funit.parentHostAssoc().internalProcedureBindings(*this,
2651                                                             localSymbols);
2652         }
2653       }
2654     };
2655     for (const Fortran::lower::CalleeInterface::PassedEntity &arg :
2656          callee.getPassedArguments())
2657       mapPassedEntity(arg);
2658     if (std::optional<Fortran::lower::CalleeInterface::PassedEntity>
2659             passedResult = callee.getPassedResult()) {
2660       mapPassedEntity(*passedResult);
2661       // FIXME: need to make sure things are OK here. addSymbol may not be OK
2662       if (funit.primaryResult &&
2663           passedResult->entity->get() != *funit.primaryResult)
2664         addSymbol(*funit.primaryResult,
2665                   getSymbolAddress(passedResult->entity->get()));
2666     }
2667   }
2668 
2669   /// Instantiate variable \p var and add it to the symbol map.
2670   /// See ConvertVariable.cpp.
2671   void instantiateVar(const Fortran::lower::pft::Variable &var,
2672                       Fortran::lower::AggregateStoreMap &storeMap) {
2673     Fortran::lower::instantiateVariable(*this, var, localSymbols, storeMap);
2674     if (var.hasSymbol() &&
2675         var.getSymbol().test(
2676             Fortran::semantics::Symbol::Flag::OmpThreadprivate))
2677       Fortran::lower::genThreadprivateOp(*this, var);
2678   }
2679 
2680   /// Prepare to translate a new function
2681   void startNewFunction(Fortran::lower::pft::FunctionLikeUnit &funit) {
2682     assert(!builder && "expected nullptr");
2683     Fortran::lower::CalleeInterface callee(funit, *this);
2684     mlir::func::FuncOp func = callee.addEntryBlockAndMapArguments();
2685     builder = new fir::FirOpBuilder(func, bridge.getKindMap());
2686     assert(builder && "FirOpBuilder did not instantiate");
2687     builder->setInsertionPointToStart(&func.front());
2688     func.setVisibility(mlir::SymbolTable::Visibility::Public);
2689 
2690     mapDummiesAndResults(funit, callee);
2691 
2692     // Note: not storing Variable references because getOrderedSymbolTable
2693     // below returns a temporary.
2694     llvm::SmallVector<Fortran::lower::pft::Variable> deferredFuncResultList;
2695 
2696     // Backup actual argument for entry character results
2697     // with different lengths. It needs to be added to the non
2698     // primary results symbol before mapSymbolAttributes is called.
2699     Fortran::lower::SymbolBox resultArg;
2700     if (std::optional<Fortran::lower::CalleeInterface::PassedEntity>
2701             passedResult = callee.getPassedResult())
2702       resultArg = lookupSymbol(passedResult->entity->get());
2703 
2704     Fortran::lower::AggregateStoreMap storeMap;
2705     // The front-end is currently not adding module variables referenced
2706     // in a module procedure as host associated. As a result we need to
2707     // instantiate all module variables here if this is a module procedure.
2708     // It is likely that the front-end behavior should change here.
2709     // This also applies to internal procedures inside module procedures.
2710     if (auto *module = Fortran::lower::pft::getAncestor<
2711             Fortran::lower::pft::ModuleLikeUnit>(funit))
2712       for (const Fortran::lower::pft::Variable &var :
2713            module->getOrderedSymbolTable())
2714         instantiateVar(var, storeMap);
2715 
2716     mlir::Value primaryFuncResultStorage;
2717     for (const Fortran::lower::pft::Variable &var :
2718          funit.getOrderedSymbolTable()) {
2719       // Always instantiate aggregate storage blocks.
2720       if (var.isAggregateStore()) {
2721         instantiateVar(var, storeMap);
2722         continue;
2723       }
2724       const Fortran::semantics::Symbol &sym = var.getSymbol();
2725       if (funit.parentHasHostAssoc()) {
2726         // Never instantitate host associated variables, as they are already
2727         // instantiated from an argument tuple. Instead, just bind the symbol to
2728         // the reference to the host variable, which must be in the map.
2729         const Fortran::semantics::Symbol &ultimate = sym.GetUltimate();
2730         if (funit.parentHostAssoc().isAssociated(ultimate)) {
2731           Fortran::lower::SymbolBox hostBox =
2732               localSymbols.lookupSymbol(ultimate);
2733           assert(hostBox && "host association is not in map");
2734           localSymbols.addSymbol(sym, hostBox.toExtendedValue());
2735           continue;
2736         }
2737       }
2738       if (!sym.IsFuncResult() || !funit.primaryResult) {
2739         instantiateVar(var, storeMap);
2740       } else if (&sym == funit.primaryResult) {
2741         instantiateVar(var, storeMap);
2742         primaryFuncResultStorage = getSymbolAddress(sym);
2743       } else {
2744         deferredFuncResultList.push_back(var);
2745       }
2746     }
2747 
2748     // TODO: should use same mechanism as equivalence?
2749     // One blocking point is character entry returns that need special handling
2750     // since they are not locally allocated but come as argument. CHARACTER(*)
2751     // is not something that fits well with equivalence lowering.
2752     for (const Fortran::lower::pft::Variable &altResult :
2753          deferredFuncResultList) {
2754       if (std::optional<Fortran::lower::CalleeInterface::PassedEntity>
2755               passedResult = callee.getPassedResult())
2756         addSymbol(altResult.getSymbol(), resultArg.getAddr());
2757       Fortran::lower::StatementContext stmtCtx;
2758       Fortran::lower::mapSymbolAttributes(*this, altResult, localSymbols,
2759                                           stmtCtx, primaryFuncResultStorage);
2760     }
2761 
2762     // If this is a host procedure with host associations, then create the tuple
2763     // of pointers for passing to the internal procedures.
2764     if (!funit.getHostAssoc().empty())
2765       funit.getHostAssoc().hostProcedureBindings(*this, localSymbols);
2766 
2767     // Create most function blocks in advance.
2768     createEmptyBlocks(funit.evaluationList);
2769 
2770     // Reinstate entry block as the current insertion point.
2771     builder->setInsertionPointToEnd(&func.front());
2772 
2773     if (callee.hasAlternateReturns()) {
2774       // Create a local temp to hold the alternate return index.
2775       // Give it an integer index type and the subroutine name (for dumps).
2776       // Attach it to the subroutine symbol in the localSymbols map.
2777       // Initialize it to zero, the "fallthrough" alternate return value.
2778       const Fortran::semantics::Symbol &symbol = funit.getSubprogramSymbol();
2779       mlir::Location loc = toLocation();
2780       mlir::Type idxTy = builder->getIndexType();
2781       mlir::Value altResult =
2782           builder->createTemporary(loc, idxTy, toStringRef(symbol.name()));
2783       addSymbol(symbol, altResult);
2784       mlir::Value zero = builder->createIntegerConstant(loc, idxTy, 0);
2785       builder->create<fir::StoreOp>(loc, zero, altResult);
2786     }
2787 
2788     if (Fortran::lower::pft::Evaluation *alternateEntryEval =
2789             funit.getEntryEval())
2790       genFIRBranch(alternateEntryEval->lexicalSuccessor->block);
2791   }
2792 
2793   /// Create global blocks for the current function.  This eliminates the
2794   /// distinction between forward and backward targets when generating
2795   /// branches.  A block is "global" if it can be the target of a GOTO or
2796   /// other source code branch.  A block that can only be targeted by a
2797   /// compiler generated branch is "local".  For example, a DO loop preheader
2798   /// block containing loop initialization code is global.  A loop header
2799   /// block, which is the target of the loop back edge, is local.  Blocks
2800   /// belong to a region.  Any block within a nested region must be replaced
2801   /// with a block belonging to that region.  Branches may not cross region
2802   /// boundaries.
2803   void createEmptyBlocks(
2804       std::list<Fortran::lower::pft::Evaluation> &evaluationList) {
2805     mlir::Region *region = &builder->getRegion();
2806     for (Fortran::lower::pft::Evaluation &eval : evaluationList) {
2807       if (eval.isNewBlock)
2808         eval.block = builder->createBlock(region);
2809       if (eval.isConstruct() || eval.isDirective()) {
2810         if (eval.lowerAsUnstructured()) {
2811           createEmptyBlocks(eval.getNestedEvaluations());
2812         } else if (eval.hasNestedEvaluations()) {
2813           // A structured construct that is a target starts a new block.
2814           Fortran::lower::pft::Evaluation &constructStmt =
2815               eval.getFirstNestedEvaluation();
2816           if (constructStmt.isNewBlock)
2817             constructStmt.block = builder->createBlock(region);
2818         }
2819       }
2820     }
2821   }
2822 
2823   /// Return the predicate: "current block does not have a terminator branch".
2824   bool blockIsUnterminated() {
2825     mlir::Block *currentBlock = builder->getBlock();
2826     return currentBlock->empty() ||
2827            !currentBlock->back().hasTrait<mlir::OpTrait::IsTerminator>();
2828   }
2829 
2830   /// Unconditionally switch code insertion to a new block.
2831   void startBlock(mlir::Block *newBlock) {
2832     assert(newBlock && "missing block");
2833     // Default termination for the current block is a fallthrough branch to
2834     // the new block.
2835     if (blockIsUnterminated())
2836       genFIRBranch(newBlock);
2837     // Some blocks may be re/started more than once, and might not be empty.
2838     // If the new block already has (only) a terminator, set the insertion
2839     // point to the start of the block.  Otherwise set it to the end.
2840     builder->setInsertionPointToStart(newBlock);
2841     if (blockIsUnterminated())
2842       builder->setInsertionPointToEnd(newBlock);
2843   }
2844 
2845   /// Conditionally switch code insertion to a new block.
2846   void maybeStartBlock(mlir::Block *newBlock) {
2847     if (newBlock)
2848       startBlock(newBlock);
2849   }
2850 
2851   /// Emit return and cleanup after the function has been translated.
2852   void endNewFunction(Fortran::lower::pft::FunctionLikeUnit &funit) {
2853     setCurrentPosition(Fortran::lower::pft::stmtSourceLoc(funit.endStmt));
2854     if (funit.isMainProgram())
2855       genExitRoutine();
2856     else
2857       genFIRProcedureExit(funit, funit.getSubprogramSymbol());
2858     funit.finalBlock = nullptr;
2859     LLVM_DEBUG(llvm::dbgs() << "*** Lowering result:\n\n"
2860                             << *builder->getFunction() << '\n');
2861     // FIXME: Simplification should happen in a normal pass, not here.
2862     mlir::IRRewriter rewriter(*builder);
2863     (void)mlir::simplifyRegions(rewriter,
2864                                 {builder->getRegion()}); // remove dead code
2865     delete builder;
2866     builder = nullptr;
2867     hostAssocTuple = mlir::Value{};
2868     localSymbols.clear();
2869   }
2870 
2871   /// Helper to generate GlobalOps when the builder is not positioned in any
2872   /// region block. This is required because the FirOpBuilder assumes it is
2873   /// always positioned inside a region block when creating globals, the easiest
2874   /// way comply is to create a dummy function and to throw it afterwards.
2875   void createGlobalOutsideOfFunctionLowering(
2876       const std::function<void()> &createGlobals) {
2877     // FIXME: get rid of the bogus function context and instantiate the
2878     // globals directly into the module.
2879     mlir::MLIRContext *context = &getMLIRContext();
2880     mlir::func::FuncOp func = fir::FirOpBuilder::createFunction(
2881         mlir::UnknownLoc::get(context), getModuleOp(),
2882         fir::NameUniquer::doGenerated("Sham"),
2883         mlir::FunctionType::get(context, llvm::None, llvm::None));
2884     func.addEntryBlock();
2885     builder = new fir::FirOpBuilder(func, bridge.getKindMap());
2886     createGlobals();
2887     if (mlir::Region *region = func.getCallableRegion())
2888       region->dropAllReferences();
2889     func.erase();
2890     delete builder;
2891     builder = nullptr;
2892     localSymbols.clear();
2893   }
2894   /// Instantiate the data from a BLOCK DATA unit.
2895   void lowerBlockData(Fortran::lower::pft::BlockDataUnit &bdunit) {
2896     createGlobalOutsideOfFunctionLowering([&]() {
2897       Fortran::lower::AggregateStoreMap fakeMap;
2898       for (const auto &[_, sym] : bdunit.symTab) {
2899         if (sym->has<Fortran::semantics::ObjectEntityDetails>()) {
2900           Fortran::lower::pft::Variable var(*sym, true);
2901           instantiateVar(var, fakeMap);
2902         }
2903       }
2904     });
2905   }
2906 
2907   /// Create fir::Global for all the common blocks that appear in the program.
2908   void
2909   lowerCommonBlocks(const Fortran::semantics::CommonBlockList &commonBlocks) {
2910     createGlobalOutsideOfFunctionLowering(
2911         [&]() { Fortran::lower::defineCommonBlocks(*this, commonBlocks); });
2912   }
2913 
2914   /// Lower a procedure (nest).
2915   void lowerFunc(Fortran::lower::pft::FunctionLikeUnit &funit) {
2916     if (!funit.isMainProgram()) {
2917       const Fortran::semantics::Symbol &procSymbol =
2918           funit.getSubprogramSymbol();
2919       if (procSymbol.owner().IsSubmodule())
2920         TODO(toLocation(), "support for submodules");
2921       if (Fortran::semantics::IsSeparateModuleProcedureInterface(&procSymbol))
2922         TODO(toLocation(), "separate module procedure");
2923     }
2924     setCurrentPosition(funit.getStartingSourceLoc());
2925     for (int entryIndex = 0, last = funit.entryPointList.size();
2926          entryIndex < last; ++entryIndex) {
2927       funit.setActiveEntry(entryIndex);
2928       startNewFunction(funit); // the entry point for lowering this procedure
2929       for (Fortran::lower::pft::Evaluation &eval : funit.evaluationList)
2930         genFIR(eval);
2931       endNewFunction(funit);
2932     }
2933     funit.setActiveEntry(0);
2934     for (Fortran::lower::pft::FunctionLikeUnit &f : funit.nestedFunctions)
2935       lowerFunc(f); // internal procedure
2936   }
2937 
2938   /// Lower module variable definitions to fir::globalOp and OpenMP/OpenACC
2939   /// declarative construct.
2940   void lowerModuleDeclScope(Fortran::lower::pft::ModuleLikeUnit &mod) {
2941     setCurrentPosition(mod.getStartingSourceLoc());
2942     createGlobalOutsideOfFunctionLowering([&]() {
2943       for (const Fortran::lower::pft::Variable &var :
2944            mod.getOrderedSymbolTable()) {
2945         // Only define the variables owned by this module.
2946         const Fortran::semantics::Scope *owningScope = var.getOwningScope();
2947         if (!owningScope || mod.getScope() == *owningScope)
2948           Fortran::lower::defineModuleVariable(*this, var);
2949       }
2950       for (auto &eval : mod.evaluationList)
2951         genFIR(eval);
2952     });
2953   }
2954 
2955   /// Lower functions contained in a module.
2956   void lowerMod(Fortran::lower::pft::ModuleLikeUnit &mod) {
2957     for (Fortran::lower::pft::FunctionLikeUnit &f : mod.nestedFunctions)
2958       lowerFunc(f);
2959   }
2960 
2961   void setCurrentPosition(const Fortran::parser::CharBlock &position) {
2962     if (position != Fortran::parser::CharBlock{})
2963       currentPosition = position;
2964   }
2965 
2966   /// Set current position at the location of \p parseTreeNode. Note that the
2967   /// position is updated automatically when visiting statements, but not when
2968   /// entering higher level nodes like constructs or procedures. This helper is
2969   /// intended to cover the latter cases.
2970   template <typename A>
2971   void setCurrentPositionAt(const A &parseTreeNode) {
2972     setCurrentPosition(Fortran::parser::FindSourceLocation(parseTreeNode));
2973   }
2974 
2975   //===--------------------------------------------------------------------===//
2976   // Utility methods
2977   //===--------------------------------------------------------------------===//
2978 
2979   /// Convert a parser CharBlock to a Location
2980   mlir::Location toLocation(const Fortran::parser::CharBlock &cb) {
2981     return genLocation(cb);
2982   }
2983 
2984   mlir::Location toLocation() { return toLocation(currentPosition); }
2985   void setCurrentEval(Fortran::lower::pft::Evaluation &eval) {
2986     evalPtr = &eval;
2987   }
2988   Fortran::lower::pft::Evaluation &getEval() {
2989     assert(evalPtr);
2990     return *evalPtr;
2991   }
2992 
2993   std::optional<Fortran::evaluate::Shape>
2994   getShape(const Fortran::lower::SomeExpr &expr) {
2995     return Fortran::evaluate::GetShape(foldingContext, expr);
2996   }
2997 
2998   //===--------------------------------------------------------------------===//
2999   // Analysis on a nested explicit iteration space.
3000   //===--------------------------------------------------------------------===//
3001 
3002   void analyzeExplicitSpace(const Fortran::parser::ConcurrentHeader &header) {
3003     explicitIterSpace.pushLevel();
3004     for (const Fortran::parser::ConcurrentControl &ctrl :
3005          std::get<std::list<Fortran::parser::ConcurrentControl>>(header.t)) {
3006       const Fortran::semantics::Symbol *ctrlVar =
3007           std::get<Fortran::parser::Name>(ctrl.t).symbol;
3008       explicitIterSpace.addSymbol(ctrlVar);
3009     }
3010     if (const auto &mask =
3011             std::get<std::optional<Fortran::parser::ScalarLogicalExpr>>(
3012                 header.t);
3013         mask.has_value())
3014       analyzeExplicitSpace(*Fortran::semantics::GetExpr(*mask));
3015   }
3016   template <bool LHS = false, typename A>
3017   void analyzeExplicitSpace(const Fortran::evaluate::Expr<A> &e) {
3018     explicitIterSpace.exprBase(&e, LHS);
3019   }
3020   void analyzeExplicitSpace(const Fortran::evaluate::Assignment *assign) {
3021     auto analyzeAssign = [&](const Fortran::lower::SomeExpr &lhs,
3022                              const Fortran::lower::SomeExpr &rhs) {
3023       analyzeExplicitSpace</*LHS=*/true>(lhs);
3024       analyzeExplicitSpace(rhs);
3025     };
3026     std::visit(
3027         Fortran::common::visitors{
3028             [&](const Fortran::evaluate::ProcedureRef &procRef) {
3029               // Ensure the procRef expressions are the one being visited.
3030               assert(procRef.arguments().size() == 2);
3031               const Fortran::lower::SomeExpr *lhs =
3032                   procRef.arguments()[0].value().UnwrapExpr();
3033               const Fortran::lower::SomeExpr *rhs =
3034                   procRef.arguments()[1].value().UnwrapExpr();
3035               assert(lhs && rhs &&
3036                      "user defined assignment arguments must be expressions");
3037               analyzeAssign(*lhs, *rhs);
3038             },
3039             [&](const auto &) { analyzeAssign(assign->lhs, assign->rhs); }},
3040         assign->u);
3041     explicitIterSpace.endAssign();
3042   }
3043   void analyzeExplicitSpace(const Fortran::parser::ForallAssignmentStmt &stmt) {
3044     std::visit([&](const auto &s) { analyzeExplicitSpace(s); }, stmt.u);
3045   }
3046   void analyzeExplicitSpace(const Fortran::parser::AssignmentStmt &s) {
3047     analyzeExplicitSpace(s.typedAssignment->v.operator->());
3048   }
3049   void analyzeExplicitSpace(const Fortran::parser::PointerAssignmentStmt &s) {
3050     analyzeExplicitSpace(s.typedAssignment->v.operator->());
3051   }
3052   void analyzeExplicitSpace(const Fortran::parser::WhereConstruct &c) {
3053     analyzeExplicitSpace(
3054         std::get<
3055             Fortran::parser::Statement<Fortran::parser::WhereConstructStmt>>(
3056             c.t)
3057             .statement);
3058     for (const Fortran::parser::WhereBodyConstruct &body :
3059          std::get<std::list<Fortran::parser::WhereBodyConstruct>>(c.t))
3060       analyzeExplicitSpace(body);
3061     for (const Fortran::parser::WhereConstruct::MaskedElsewhere &e :
3062          std::get<std::list<Fortran::parser::WhereConstruct::MaskedElsewhere>>(
3063              c.t))
3064       analyzeExplicitSpace(e);
3065     if (const auto &e =
3066             std::get<std::optional<Fortran::parser::WhereConstruct::Elsewhere>>(
3067                 c.t);
3068         e.has_value())
3069       analyzeExplicitSpace(e.operator->());
3070   }
3071   void analyzeExplicitSpace(const Fortran::parser::WhereConstructStmt &ws) {
3072     const Fortran::lower::SomeExpr *exp = Fortran::semantics::GetExpr(
3073         std::get<Fortran::parser::LogicalExpr>(ws.t));
3074     addMaskVariable(exp);
3075     analyzeExplicitSpace(*exp);
3076   }
3077   void analyzeExplicitSpace(
3078       const Fortran::parser::WhereConstruct::MaskedElsewhere &ew) {
3079     analyzeExplicitSpace(
3080         std::get<
3081             Fortran::parser::Statement<Fortran::parser::MaskedElsewhereStmt>>(
3082             ew.t)
3083             .statement);
3084     for (const Fortran::parser::WhereBodyConstruct &e :
3085          std::get<std::list<Fortran::parser::WhereBodyConstruct>>(ew.t))
3086       analyzeExplicitSpace(e);
3087   }
3088   void analyzeExplicitSpace(const Fortran::parser::WhereBodyConstruct &body) {
3089     std::visit(Fortran::common::visitors{
3090                    [&](const Fortran::common::Indirection<
3091                        Fortran::parser::WhereConstruct> &wc) {
3092                      analyzeExplicitSpace(wc.value());
3093                    },
3094                    [&](const auto &s) { analyzeExplicitSpace(s.statement); }},
3095                body.u);
3096   }
3097   void analyzeExplicitSpace(const Fortran::parser::MaskedElsewhereStmt &stmt) {
3098     const Fortran::lower::SomeExpr *exp = Fortran::semantics::GetExpr(
3099         std::get<Fortran::parser::LogicalExpr>(stmt.t));
3100     addMaskVariable(exp);
3101     analyzeExplicitSpace(*exp);
3102   }
3103   void
3104   analyzeExplicitSpace(const Fortran::parser::WhereConstruct::Elsewhere *ew) {
3105     for (const Fortran::parser::WhereBodyConstruct &e :
3106          std::get<std::list<Fortran::parser::WhereBodyConstruct>>(ew->t))
3107       analyzeExplicitSpace(e);
3108   }
3109   void analyzeExplicitSpace(const Fortran::parser::WhereStmt &stmt) {
3110     const Fortran::lower::SomeExpr *exp = Fortran::semantics::GetExpr(
3111         std::get<Fortran::parser::LogicalExpr>(stmt.t));
3112     addMaskVariable(exp);
3113     analyzeExplicitSpace(*exp);
3114     const std::optional<Fortran::evaluate::Assignment> &assign =
3115         std::get<Fortran::parser::AssignmentStmt>(stmt.t).typedAssignment->v;
3116     assert(assign.has_value() && "WHERE has no statement");
3117     analyzeExplicitSpace(assign.operator->());
3118   }
3119   void analyzeExplicitSpace(const Fortran::parser::ForallStmt &forall) {
3120     analyzeExplicitSpace(
3121         std::get<
3122             Fortran::common::Indirection<Fortran::parser::ConcurrentHeader>>(
3123             forall.t)
3124             .value());
3125     analyzeExplicitSpace(std::get<Fortran::parser::UnlabeledStatement<
3126                              Fortran::parser::ForallAssignmentStmt>>(forall.t)
3127                              .statement);
3128     analyzeExplicitSpacePop();
3129   }
3130   void
3131   analyzeExplicitSpace(const Fortran::parser::ForallConstructStmt &forall) {
3132     analyzeExplicitSpace(
3133         std::get<
3134             Fortran::common::Indirection<Fortran::parser::ConcurrentHeader>>(
3135             forall.t)
3136             .value());
3137   }
3138   void analyzeExplicitSpace(const Fortran::parser::ForallConstruct &forall) {
3139     analyzeExplicitSpace(
3140         std::get<
3141             Fortran::parser::Statement<Fortran::parser::ForallConstructStmt>>(
3142             forall.t)
3143             .statement);
3144     for (const Fortran::parser::ForallBodyConstruct &s :
3145          std::get<std::list<Fortran::parser::ForallBodyConstruct>>(forall.t)) {
3146       std::visit(Fortran::common::visitors{
3147                      [&](const Fortran::common::Indirection<
3148                          Fortran::parser::ForallConstruct> &b) {
3149                        analyzeExplicitSpace(b.value());
3150                      },
3151                      [&](const Fortran::parser::WhereConstruct &w) {
3152                        analyzeExplicitSpace(w);
3153                      },
3154                      [&](const auto &b) { analyzeExplicitSpace(b.statement); }},
3155                  s.u);
3156     }
3157     analyzeExplicitSpacePop();
3158   }
3159 
3160   void analyzeExplicitSpacePop() { explicitIterSpace.popLevel(); }
3161 
3162   void addMaskVariable(Fortran::lower::FrontEndExpr exp) {
3163     // Note: use i8 to store bool values. This avoids round-down behavior found
3164     // with sequences of i1. That is, an array of i1 will be truncated in size
3165     // and be too small. For example, a buffer of type fir.array<7xi1> will have
3166     // 0 size.
3167     mlir::Type i64Ty = builder->getIntegerType(64);
3168     mlir::TupleType ty = fir::factory::getRaggedArrayHeaderType(*builder);
3169     mlir::Type buffTy = ty.getType(1);
3170     mlir::Type shTy = ty.getType(2);
3171     mlir::Location loc = toLocation();
3172     mlir::Value hdr = builder->createTemporary(loc, ty);
3173     // FIXME: Is there a way to create a `zeroinitializer` in LLVM-IR dialect?
3174     // For now, explicitly set lazy ragged header to all zeros.
3175     // auto nilTup = builder->createNullConstant(loc, ty);
3176     // builder->create<fir::StoreOp>(loc, nilTup, hdr);
3177     mlir::Type i32Ty = builder->getIntegerType(32);
3178     mlir::Value zero = builder->createIntegerConstant(loc, i32Ty, 0);
3179     mlir::Value zero64 = builder->createIntegerConstant(loc, i64Ty, 0);
3180     mlir::Value flags = builder->create<fir::CoordinateOp>(
3181         loc, builder->getRefType(i64Ty), hdr, zero);
3182     builder->create<fir::StoreOp>(loc, zero64, flags);
3183     mlir::Value one = builder->createIntegerConstant(loc, i32Ty, 1);
3184     mlir::Value nullPtr1 = builder->createNullConstant(loc, buffTy);
3185     mlir::Value var = builder->create<fir::CoordinateOp>(
3186         loc, builder->getRefType(buffTy), hdr, one);
3187     builder->create<fir::StoreOp>(loc, nullPtr1, var);
3188     mlir::Value two = builder->createIntegerConstant(loc, i32Ty, 2);
3189     mlir::Value nullPtr2 = builder->createNullConstant(loc, shTy);
3190     mlir::Value shape = builder->create<fir::CoordinateOp>(
3191         loc, builder->getRefType(shTy), hdr, two);
3192     builder->create<fir::StoreOp>(loc, nullPtr2, shape);
3193     implicitIterSpace.addMaskVariable(exp, var, shape, hdr);
3194     explicitIterSpace.outermostContext().attachCleanup(
3195         [builder = this->builder, hdr, loc]() {
3196           fir::runtime::genRaggedArrayDeallocate(loc, *builder, hdr);
3197         });
3198   }
3199 
3200   void createRuntimeTypeInfoGlobals() {}
3201 
3202   //===--------------------------------------------------------------------===//
3203 
3204   Fortran::lower::LoweringBridge &bridge;
3205   Fortran::evaluate::FoldingContext foldingContext;
3206   fir::FirOpBuilder *builder = nullptr;
3207   Fortran::lower::pft::Evaluation *evalPtr = nullptr;
3208   Fortran::lower::SymMap localSymbols;
3209   Fortran::parser::CharBlock currentPosition;
3210   RuntimeTypeInfoConverter runtimeTypeInfoConverter;
3211 
3212   /// WHERE statement/construct mask expression stack.
3213   Fortran::lower::ImplicitIterSpace implicitIterSpace;
3214 
3215   /// FORALL context
3216   Fortran::lower::ExplicitIterSpace explicitIterSpace;
3217 
3218   /// Tuple of host assoicated variables.
3219   mlir::Value hostAssocTuple;
3220 };
3221 
3222 } // namespace
3223 
3224 Fortran::evaluate::FoldingContext
3225 Fortran::lower::LoweringBridge::createFoldingContext() const {
3226   return {getDefaultKinds(), getIntrinsicTable(), getTargetCharacteristics()};
3227 }
3228 
3229 void Fortran::lower::LoweringBridge::lower(
3230     const Fortran::parser::Program &prg,
3231     const Fortran::semantics::SemanticsContext &semanticsContext) {
3232   std::unique_ptr<Fortran::lower::pft::Program> pft =
3233       Fortran::lower::createPFT(prg, semanticsContext);
3234   if (dumpBeforeFir)
3235     Fortran::lower::dumpPFT(llvm::errs(), *pft);
3236   FirConverter converter{*this};
3237   converter.run(*pft);
3238 }
3239 
3240 void Fortran::lower::LoweringBridge::parseSourceFile(llvm::SourceMgr &srcMgr) {
3241   mlir::OwningOpRef<mlir::ModuleOp> owningRef =
3242       mlir::parseSourceFile<mlir::ModuleOp>(srcMgr, &context);
3243   module.reset(new mlir::ModuleOp(owningRef.get().getOperation()));
3244   owningRef.release();
3245 }
3246 
3247 Fortran::lower::LoweringBridge::LoweringBridge(
3248     mlir::MLIRContext &context,
3249     const Fortran::common::IntrinsicTypeDefaultKinds &defaultKinds,
3250     const Fortran::evaluate::IntrinsicProcTable &intrinsics,
3251     const Fortran::evaluate::TargetCharacteristics &targetCharacteristics,
3252     const Fortran::parser::AllCookedSources &cooked, llvm::StringRef triple,
3253     fir::KindMapping &kindMap)
3254     : defaultKinds{defaultKinds}, intrinsics{intrinsics},
3255       targetCharacteristics{targetCharacteristics}, cooked{&cooked},
3256       context{context}, kindMap{kindMap} {
3257   // Register the diagnostic handler.
3258   context.getDiagEngine().registerHandler([](mlir::Diagnostic &diag) {
3259     llvm::raw_ostream &os = llvm::errs();
3260     switch (diag.getSeverity()) {
3261     case mlir::DiagnosticSeverity::Error:
3262       os << "error: ";
3263       break;
3264     case mlir::DiagnosticSeverity::Remark:
3265       os << "info: ";
3266       break;
3267     case mlir::DiagnosticSeverity::Warning:
3268       os << "warning: ";
3269       break;
3270     default:
3271       break;
3272     }
3273     if (!diag.getLocation().isa<mlir::UnknownLoc>())
3274       os << diag.getLocation() << ": ";
3275     os << diag << '\n';
3276     os.flush();
3277     return mlir::success();
3278   });
3279 
3280   // Create the module and attach the attributes.
3281   module = std::make_unique<mlir::ModuleOp>(
3282       mlir::ModuleOp::create(mlir::UnknownLoc::get(&context)));
3283   assert(module.get() && "module was not created");
3284   fir::setTargetTriple(*module.get(), triple);
3285   fir::setKindMapping(*module.get(), kindMap);
3286 }
3287