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