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