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