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