xref: /llvm-project/flang/lib/Lower/Bridge.cpp (revision e811cb00e533e9737db689e35ee6cb0d5af536cc)
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 
15 #include "flang/Common/Version.h"
16 #include "flang/Lower/Allocatable.h"
17 #include "flang/Lower/CallInterface.h"
18 #include "flang/Lower/Coarray.h"
19 #include "flang/Lower/ConvertCall.h"
20 #include "flang/Lower/ConvertExpr.h"
21 #include "flang/Lower/ConvertExprToHLFIR.h"
22 #include "flang/Lower/ConvertType.h"
23 #include "flang/Lower/ConvertVariable.h"
24 #include "flang/Lower/Cuda.h"
25 #include "flang/Lower/DirectivesCommon.h"
26 #include "flang/Lower/HostAssociations.h"
27 #include "flang/Lower/IO.h"
28 #include "flang/Lower/IterationSpace.h"
29 #include "flang/Lower/Mangler.h"
30 #include "flang/Lower/OpenACC.h"
31 #include "flang/Lower/OpenMP.h"
32 #include "flang/Lower/PFTBuilder.h"
33 #include "flang/Lower/Runtime.h"
34 #include "flang/Lower/StatementContext.h"
35 #include "flang/Lower/Support/Utils.h"
36 #include "flang/Optimizer/Builder/BoxValue.h"
37 #include "flang/Optimizer/Builder/CUFCommon.h"
38 #include "flang/Optimizer/Builder/Character.h"
39 #include "flang/Optimizer/Builder/FIRBuilder.h"
40 #include "flang/Optimizer/Builder/Runtime/Assign.h"
41 #include "flang/Optimizer/Builder/Runtime/Character.h"
42 #include "flang/Optimizer/Builder/Runtime/Derived.h"
43 #include "flang/Optimizer/Builder/Runtime/EnvironmentDefaults.h"
44 #include "flang/Optimizer/Builder/Runtime/Exceptions.h"
45 #include "flang/Optimizer/Builder/Runtime/Main.h"
46 #include "flang/Optimizer/Builder/Runtime/Ragged.h"
47 #include "flang/Optimizer/Builder/Runtime/Stop.h"
48 #include "flang/Optimizer/Builder/Todo.h"
49 #include "flang/Optimizer/Dialect/CUF/Attributes/CUFAttr.h"
50 #include "flang/Optimizer/Dialect/CUF/CUFOps.h"
51 #include "flang/Optimizer/Dialect/FIRAttr.h"
52 #include "flang/Optimizer/Dialect/FIRDialect.h"
53 #include "flang/Optimizer/Dialect/FIROps.h"
54 #include "flang/Optimizer/Dialect/Support/FIRContext.h"
55 #include "flang/Optimizer/HLFIR/HLFIROps.h"
56 #include "flang/Optimizer/Support/DataLayout.h"
57 #include "flang/Optimizer/Support/FatalError.h"
58 #include "flang/Optimizer/Support/InternalNames.h"
59 #include "flang/Optimizer/Transforms/Passes.h"
60 #include "flang/Parser/parse-tree.h"
61 #include "flang/Runtime/iostat-consts.h"
62 #include "flang/Semantics/runtime-type-info.h"
63 #include "flang/Semantics/symbol.h"
64 #include "flang/Semantics/tools.h"
65 #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
66 #include "mlir/IR/Matchers.h"
67 #include "mlir/IR/PatternMatch.h"
68 #include "mlir/Parser/Parser.h"
69 #include "mlir/Transforms/RegionUtils.h"
70 #include "llvm/ADT/SmallVector.h"
71 #include "llvm/ADT/StringSet.h"
72 #include "llvm/Support/CommandLine.h"
73 #include "llvm/Support/Debug.h"
74 #include "llvm/Support/ErrorHandling.h"
75 #include "llvm/Support/FileSystem.h"
76 #include "llvm/Support/Path.h"
77 #include "llvm/Target/TargetMachine.h"
78 #include <optional>
79 
80 #define DEBUG_TYPE "flang-lower-bridge"
81 
82 static llvm::cl::opt<bool> dumpBeforeFir(
83     "fdebug-dump-pre-fir", llvm::cl::init(false),
84     llvm::cl::desc("dump the Pre-FIR tree prior to FIR generation"));
85 
86 static llvm::cl::opt<bool> forceLoopToExecuteOnce(
87     "always-execute-loop-body", llvm::cl::init(false),
88     llvm::cl::desc("force the body of a loop to execute at least once"));
89 
90 namespace {
91 /// Information for generating a structured or unstructured increment loop.
92 struct IncrementLoopInfo {
93   template <typename T>
94   explicit IncrementLoopInfo(Fortran::semantics::Symbol &sym, const T &lower,
95                              const T &upper, const std::optional<T> &step,
96                              bool isUnordered = false)
97       : loopVariableSym{&sym}, lowerExpr{Fortran::semantics::GetExpr(lower)},
98         upperExpr{Fortran::semantics::GetExpr(upper)},
99         stepExpr{Fortran::semantics::GetExpr(step)}, isUnordered{isUnordered} {}
100 
101   IncrementLoopInfo(IncrementLoopInfo &&) = default;
102   IncrementLoopInfo &operator=(IncrementLoopInfo &&x) = default;
103 
104   bool isStructured() const { return !headerBlock; }
105 
106   mlir::Type getLoopVariableType() const {
107     assert(loopVariable && "must be set");
108     return fir::unwrapRefType(loopVariable.getType());
109   }
110 
111   bool hasLocalitySpecs() const {
112     return !localSymList.empty() || !localInitSymList.empty() ||
113            !reduceSymList.empty() || !sharedSymList.empty();
114   }
115 
116   // Data members common to both structured and unstructured loops.
117   const Fortran::semantics::Symbol *loopVariableSym;
118   const Fortran::lower::SomeExpr *lowerExpr;
119   const Fortran::lower::SomeExpr *upperExpr;
120   const Fortran::lower::SomeExpr *stepExpr;
121   const Fortran::lower::SomeExpr *maskExpr = nullptr;
122   bool isUnordered; // do concurrent, forall
123   llvm::SmallVector<const Fortran::semantics::Symbol *> localSymList;
124   llvm::SmallVector<const Fortran::semantics::Symbol *> localInitSymList;
125   llvm::SmallVector<
126       std::pair<fir::ReduceOperationEnum, const Fortran::semantics::Symbol *>>
127       reduceSymList;
128   llvm::SmallVector<const Fortran::semantics::Symbol *> sharedSymList;
129   mlir::Value loopVariable = nullptr;
130 
131   // Data members for structured loops.
132   fir::DoLoopOp doLoop = nullptr;
133 
134   // Data members for unstructured loops.
135   bool hasRealControl = false;
136   mlir::Value tripVariable = nullptr;
137   mlir::Value stepVariable = nullptr;
138   mlir::Block *headerBlock = nullptr; // loop entry and test block
139   mlir::Block *maskBlock = nullptr;   // concurrent loop mask block
140   mlir::Block *bodyBlock = nullptr;   // first loop body block
141   mlir::Block *exitBlock = nullptr;   // loop exit target block
142 };
143 
144 /// Information to support stack management, object deallocation, and
145 /// object finalization at early and normal construct exits.
146 struct ConstructContext {
147   explicit ConstructContext(Fortran::lower::pft::Evaluation &eval,
148                             Fortran::lower::StatementContext &stmtCtx)
149       : eval{eval}, stmtCtx{stmtCtx} {}
150 
151   Fortran::lower::pft::Evaluation &eval;     // construct eval
152   Fortran::lower::StatementContext &stmtCtx; // construct exit code
153   std::optional<hlfir::Entity> selector;     // construct selector, if any.
154   bool pushedScope = false; // was a scoped pushed for this construct?
155 };
156 
157 /// Helper to gather the lower bounds of array components with non deferred
158 /// shape when they are not all ones. Return an empty array attribute otherwise.
159 static mlir::DenseI64ArrayAttr
160 gatherComponentNonDefaultLowerBounds(mlir::Location loc,
161                                      mlir::MLIRContext *mlirContext,
162                                      const Fortran::semantics::Symbol &sym) {
163   if (Fortran::semantics::IsAllocatableOrObjectPointer(&sym))
164     return {};
165   mlir::DenseI64ArrayAttr lbs_attr;
166   if (const auto *objDetails =
167           sym.detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
168     llvm::SmallVector<std::int64_t> lbs;
169     bool hasNonDefaultLbs = false;
170     for (const Fortran::semantics::ShapeSpec &bounds : objDetails->shape())
171       if (auto lb = bounds.lbound().GetExplicit()) {
172         if (auto constant = Fortran::evaluate::ToInt64(*lb)) {
173           hasNonDefaultLbs |= (*constant != 1);
174           lbs.push_back(*constant);
175         } else {
176           TODO(loc, "generate fir.dt_component for length parametrized derived "
177                     "types");
178         }
179       }
180     if (hasNonDefaultLbs) {
181       assert(static_cast<int>(lbs.size()) == sym.Rank() &&
182              "expected component bounds to be constant or deferred");
183       lbs_attr = mlir::DenseI64ArrayAttr::get(mlirContext, lbs);
184     }
185   }
186   return lbs_attr;
187 }
188 
189 // Helper class to generate name of fir.global containing component explicit
190 // default value for objects, and initial procedure target for procedure pointer
191 // components.
192 static mlir::FlatSymbolRefAttr gatherComponentInit(
193     mlir::Location loc, Fortran::lower::AbstractConverter &converter,
194     const Fortran::semantics::Symbol &sym, fir::RecordType derivedType) {
195   mlir::MLIRContext *mlirContext = &converter.getMLIRContext();
196   // Return procedure target mangled name for procedure pointer components.
197   if (const auto *procPtr =
198           sym.detailsIf<Fortran::semantics::ProcEntityDetails>()) {
199     if (std::optional<const Fortran::semantics::Symbol *> maybeInitSym =
200             procPtr->init()) {
201       // So far, do not make distinction between p => NULL() and p without init,
202       // f18 always initialize pointers to NULL anyway.
203       if (!*maybeInitSym)
204         return {};
205       return mlir::FlatSymbolRefAttr::get(mlirContext,
206                                           converter.mangleName(**maybeInitSym));
207     }
208   }
209 
210   const auto *objDetails =
211       sym.detailsIf<Fortran::semantics::ObjectEntityDetails>();
212   if (!objDetails || !objDetails->init().has_value())
213     return {};
214   // Object component initial value. Semantic package component object default
215   // value into compiler generated symbols that are lowered as read-only
216   // fir.global. Get the name of this global.
217   std::string name = fir::NameUniquer::getComponentInitName(
218       derivedType.getName(), toStringRef(sym.name()));
219   return mlir::FlatSymbolRefAttr::get(mlirContext, name);
220 }
221 
222 /// Helper class to generate the runtime type info global data and the
223 /// fir.type_info operations that contain the dipatch tables (if any).
224 /// The type info global data is required to describe the derived type to the
225 /// runtime so that it can operate over it.
226 /// It must be ensured these operations will be generated for every derived type
227 /// lowered in the current translated unit. However, these operations
228 /// cannot be generated before FuncOp have been created for functions since the
229 /// initializers may take their address (e.g for type bound procedures). This
230 /// class allows registering all the required type info while it is not
231 /// possible to create GlobalOp/TypeInfoOp, and to generate this data afte
232 /// function lowering.
233 class TypeInfoConverter {
234   /// Store the location and symbols of derived type info to be generated.
235   /// The location of the derived type instantiation is also stored because
236   /// runtime type descriptor symbols are compiler generated and cannot be
237   /// mapped to user code on their own.
238   struct TypeInfo {
239     Fortran::semantics::SymbolRef symbol;
240     const Fortran::semantics::DerivedTypeSpec &typeSpec;
241     fir::RecordType type;
242     mlir::Location loc;
243   };
244 
245 public:
246   void registerTypeInfo(Fortran::lower::AbstractConverter &converter,
247                         mlir::Location loc,
248                         Fortran::semantics::SymbolRef typeInfoSym,
249                         const Fortran::semantics::DerivedTypeSpec &typeSpec,
250                         fir::RecordType type) {
251     if (seen.contains(typeInfoSym))
252       return;
253     seen.insert(typeInfoSym);
254     currentTypeInfoStack->emplace_back(
255         TypeInfo{typeInfoSym, typeSpec, type, loc});
256     return;
257   }
258 
259   void createTypeInfo(Fortran::lower::AbstractConverter &converter) {
260     while (!registeredTypeInfoA.empty()) {
261       currentTypeInfoStack = &registeredTypeInfoB;
262       for (const TypeInfo &info : registeredTypeInfoA)
263         createTypeInfoOpAndGlobal(converter, info);
264       registeredTypeInfoA.clear();
265       currentTypeInfoStack = &registeredTypeInfoA;
266       for (const TypeInfo &info : registeredTypeInfoB)
267         createTypeInfoOpAndGlobal(converter, info);
268       registeredTypeInfoB.clear();
269     }
270   }
271 
272 private:
273   void createTypeInfoOpAndGlobal(Fortran::lower::AbstractConverter &converter,
274                                  const TypeInfo &info) {
275     Fortran::lower::createRuntimeTypeInfoGlobal(converter, info.symbol.get());
276     createTypeInfoOp(converter, info);
277   }
278 
279   void createTypeInfoOp(Fortran::lower::AbstractConverter &converter,
280                         const TypeInfo &info) {
281     fir::RecordType parentType{};
282     if (const Fortran::semantics::DerivedTypeSpec *parent =
283             Fortran::evaluate::GetParentTypeSpec(info.typeSpec))
284       parentType = mlir::cast<fir::RecordType>(converter.genType(*parent));
285 
286     fir::FirOpBuilder &builder = converter.getFirOpBuilder();
287     fir::TypeInfoOp dt;
288     mlir::OpBuilder::InsertPoint insertPointIfCreated;
289     std::tie(dt, insertPointIfCreated) =
290         builder.createTypeInfoOp(info.loc, info.type, parentType);
291     if (!insertPointIfCreated.isSet())
292       return; // fir.type_info was already built in a previous call.
293 
294     // Set init, destroy, and nofinal attributes.
295     if (!info.typeSpec.HasDefaultInitialization(/*ignoreAllocatable=*/false,
296                                                 /*ignorePointer=*/false))
297       dt->setAttr(dt.getNoInitAttrName(), builder.getUnitAttr());
298     if (!info.typeSpec.HasDestruction())
299       dt->setAttr(dt.getNoDestroyAttrName(), builder.getUnitAttr());
300     if (!Fortran::semantics::MayRequireFinalization(info.typeSpec))
301       dt->setAttr(dt.getNoFinalAttrName(), builder.getUnitAttr());
302 
303     const Fortran::semantics::Scope &derivedScope =
304         DEREF(info.typeSpec.GetScope());
305 
306     // Fill binding table region if the derived type has bindings.
307     Fortran::semantics::SymbolVector bindings =
308         Fortran::semantics::CollectBindings(derivedScope);
309     if (!bindings.empty()) {
310       builder.createBlock(&dt.getDispatchTable());
311       for (const Fortran::semantics::SymbolRef &binding : bindings) {
312         const auto &details =
313             binding.get().get<Fortran::semantics::ProcBindingDetails>();
314         std::string tbpName = binding.get().name().ToString();
315         if (details.numPrivatesNotOverridden() > 0)
316           tbpName += "."s + std::to_string(details.numPrivatesNotOverridden());
317         std::string bindingName = converter.mangleName(details.symbol());
318         builder.create<fir::DTEntryOp>(
319             info.loc, mlir::StringAttr::get(builder.getContext(), tbpName),
320             mlir::SymbolRefAttr::get(builder.getContext(), bindingName));
321       }
322       builder.create<fir::FirEndOp>(info.loc);
323     }
324     // Gather info about components that is not reflected in fir.type and may be
325     // needed later: component initial values and array component non default
326     // lower bounds.
327     mlir::Block *componentInfo = nullptr;
328     for (const auto &componentName :
329          info.typeSpec.typeSymbol()
330              .get<Fortran::semantics::DerivedTypeDetails>()
331              .componentNames()) {
332       auto scopeIter = derivedScope.find(componentName);
333       assert(scopeIter != derivedScope.cend() &&
334              "failed to find derived type component symbol");
335       const Fortran::semantics::Symbol &component = scopeIter->second.get();
336       mlir::FlatSymbolRefAttr init_val =
337           gatherComponentInit(info.loc, converter, component, info.type);
338       mlir::DenseI64ArrayAttr lbs = gatherComponentNonDefaultLowerBounds(
339           info.loc, builder.getContext(), component);
340       if (init_val || lbs) {
341         if (!componentInfo)
342           componentInfo = builder.createBlock(&dt.getComponentInfo());
343         auto compName = mlir::StringAttr::get(builder.getContext(),
344                                               toStringRef(component.name()));
345         builder.create<fir::DTComponentOp>(info.loc, compName, lbs, init_val);
346       }
347     }
348     if (componentInfo)
349       builder.create<fir::FirEndOp>(info.loc);
350     builder.restoreInsertionPoint(insertPointIfCreated);
351   }
352 
353   /// Store the front-end data that will be required to generate the type info
354   /// for the derived types that have been converted to fir.type<>. There are
355   /// two stacks since the type info may visit new types, so the new types must
356   /// be added to a new stack.
357   llvm::SmallVector<TypeInfo> registeredTypeInfoA;
358   llvm::SmallVector<TypeInfo> registeredTypeInfoB;
359   llvm::SmallVector<TypeInfo> *currentTypeInfoStack = &registeredTypeInfoA;
360   /// Track symbols symbols processed during and after the registration
361   /// to avoid infinite loops between type conversions and global variable
362   /// creation.
363   llvm::SmallSetVector<Fortran::semantics::SymbolRef, 32> seen;
364 };
365 
366 using IncrementLoopNestInfo = llvm::SmallVector<IncrementLoopInfo, 8>;
367 } // namespace
368 
369 //===----------------------------------------------------------------------===//
370 // FirConverter
371 //===----------------------------------------------------------------------===//
372 
373 namespace {
374 
375 /// Traverse the pre-FIR tree (PFT) to generate the FIR dialect of MLIR.
376 class FirConverter : public Fortran::lower::AbstractConverter {
377 public:
378   explicit FirConverter(Fortran::lower::LoweringBridge &bridge)
379       : Fortran::lower::AbstractConverter(bridge.getLoweringOptions()),
380         bridge{bridge}, foldingContext{bridge.createFoldingContext()},
381         mlirSymbolTable{bridge.getModule()} {}
382   virtual ~FirConverter() = default;
383 
384   /// Convert the PFT to FIR.
385   void run(Fortran::lower::pft::Program &pft) {
386     // Preliminary translation pass.
387 
388     // Lower common blocks, taking into account initialization and the largest
389     // size of all instances of each common block. This is done before lowering
390     // since the global definition may differ from any one local definition.
391     lowerCommonBlocks(pft.getCommonBlocks());
392 
393     // - Declare all functions that have definitions so that definition
394     //   signatures prevail over call site signatures.
395     // - Define module variables and OpenMP/OpenACC declarative constructs so
396     //   they are available before lowering any function that may use them.
397     bool hasMainProgram = false;
398     const Fortran::semantics::Symbol *globalOmpRequiresSymbol = nullptr;
399     for (Fortran::lower::pft::Program::Units &u : pft.getUnits()) {
400       Fortran::common::visit(
401           Fortran::common::visitors{
402               [&](Fortran::lower::pft::FunctionLikeUnit &f) {
403                 if (f.isMainProgram())
404                   hasMainProgram = true;
405                 declareFunction(f);
406                 if (!globalOmpRequiresSymbol)
407                   globalOmpRequiresSymbol = f.getScope().symbol();
408               },
409               [&](Fortran::lower::pft::ModuleLikeUnit &m) {
410                 lowerModuleDeclScope(m);
411                 for (Fortran::lower::pft::ContainedUnit &unit :
412                      m.containedUnitList)
413                   if (auto *f =
414                           std::get_if<Fortran::lower::pft::FunctionLikeUnit>(
415                               &unit))
416                     declareFunction(*f);
417               },
418               [&](Fortran::lower::pft::BlockDataUnit &b) {
419                 if (!globalOmpRequiresSymbol)
420                   globalOmpRequiresSymbol = b.symTab.symbol();
421               },
422               [&](Fortran::lower::pft::CompilerDirectiveUnit &d) {},
423               [&](Fortran::lower::pft::OpenACCDirectiveUnit &d) {},
424           },
425           u);
426     }
427 
428     // Create definitions of intrinsic module constants.
429     createGlobalOutsideOfFunctionLowering(
430         [&]() { createIntrinsicModuleDefinitions(pft); });
431 
432     // Primary translation pass.
433     for (Fortran::lower::pft::Program::Units &u : pft.getUnits()) {
434       Fortran::common::visit(
435           Fortran::common::visitors{
436               [&](Fortran::lower::pft::FunctionLikeUnit &f) { lowerFunc(f); },
437               [&](Fortran::lower::pft::ModuleLikeUnit &m) { lowerMod(m); },
438               [&](Fortran::lower::pft::BlockDataUnit &b) {},
439               [&](Fortran::lower::pft::CompilerDirectiveUnit &d) {},
440               [&](Fortran::lower::pft::OpenACCDirectiveUnit &d) {
441                 builder = new fir::FirOpBuilder(
442                     bridge.getModule(), bridge.getKindMap(), &mlirSymbolTable);
443                 Fortran::lower::genOpenACCRoutineConstruct(
444                     *this, bridge.getSemanticsContext(), bridge.getModule(),
445                     d.routine, accRoutineInfos);
446                 builder = nullptr;
447               },
448           },
449           u);
450     }
451 
452     // Once all the code has been translated, create global runtime type info
453     // data structures for the derived types that have been processed, as well
454     // as fir.type_info operations for the dispatch tables.
455     createGlobalOutsideOfFunctionLowering(
456         [&]() { typeInfoConverter.createTypeInfo(*this); });
457 
458     // Generate the `main` entry point if necessary
459     if (hasMainProgram)
460       createGlobalOutsideOfFunctionLowering([&]() {
461         fir::runtime::genMain(*builder, toLocation(),
462                               bridge.getEnvironmentDefaults(),
463                               getFoldingContext().languageFeatures().IsEnabled(
464                                   Fortran::common::LanguageFeature::CUDA));
465       });
466 
467     finalizeOpenACCLowering();
468     finalizeOpenMPLowering(globalOmpRequiresSymbol);
469   }
470 
471   /// Declare a function.
472   void declareFunction(Fortran::lower::pft::FunctionLikeUnit &funit) {
473     setCurrentPosition(funit.getStartingSourceLoc());
474     for (int entryIndex = 0, last = funit.entryPointList.size();
475          entryIndex < last; ++entryIndex) {
476       funit.setActiveEntry(entryIndex);
477       // Calling CalleeInterface ctor will build a declaration
478       // mlir::func::FuncOp with no other side effects.
479       // TODO: when doing some compiler profiling on real apps, it may be worth
480       // to check it's better to save the CalleeInterface instead of recomputing
481       // it later when lowering the body. CalleeInterface ctor should be linear
482       // with the number of arguments, so it is not awful to do it that way for
483       // now, but the linear coefficient might be non negligible. Until
484       // measured, stick to the solution that impacts the code less.
485       Fortran::lower::CalleeInterface{funit, *this};
486     }
487     funit.setActiveEntry(0);
488 
489     // Compute the set of host associated entities from the nested functions.
490     llvm::SetVector<const Fortran::semantics::Symbol *> escapeHost;
491     for (Fortran::lower::pft::ContainedUnit &unit : funit.containedUnitList)
492       if (auto *f = std::get_if<Fortran::lower::pft::FunctionLikeUnit>(&unit))
493         collectHostAssociatedVariables(*f, escapeHost);
494     funit.setHostAssociatedSymbols(escapeHost);
495 
496     // Declare internal procedures
497     for (Fortran::lower::pft::ContainedUnit &unit : funit.containedUnitList)
498       if (auto *f = std::get_if<Fortran::lower::pft::FunctionLikeUnit>(&unit))
499         declareFunction(*f);
500   }
501 
502   /// Get the scope that is defining or using \p sym. The returned scope is not
503   /// the ultimate scope, since this helper does not traverse use association.
504   /// This allows capturing module variables that are referenced in an internal
505   /// procedure but whose use statement is inside the host program.
506   const Fortran::semantics::Scope &
507   getSymbolHostScope(const Fortran::semantics::Symbol &sym) {
508     const Fortran::semantics::Symbol *hostSymbol = &sym;
509     while (const auto *details =
510                hostSymbol->detailsIf<Fortran::semantics::HostAssocDetails>())
511       hostSymbol = &details->symbol();
512     return hostSymbol->owner();
513   }
514 
515   /// Collects the canonical list of all host associated symbols. These bindings
516   /// must be aggregated into a tuple which can then be added to each of the
517   /// internal procedure declarations and passed at each call site.
518   void collectHostAssociatedVariables(
519       Fortran::lower::pft::FunctionLikeUnit &funit,
520       llvm::SetVector<const Fortran::semantics::Symbol *> &escapees) {
521     const Fortran::semantics::Scope *internalScope =
522         funit.getSubprogramSymbol().scope();
523     assert(internalScope && "internal procedures symbol must create a scope");
524     auto addToListIfEscapee = [&](const Fortran::semantics::Symbol &sym) {
525       const Fortran::semantics::Symbol &ultimate = sym.GetUltimate();
526       const auto *namelistDetails =
527           ultimate.detailsIf<Fortran::semantics::NamelistDetails>();
528       if (ultimate.has<Fortran::semantics::ObjectEntityDetails>() ||
529           Fortran::semantics::IsProcedurePointer(ultimate) ||
530           Fortran::semantics::IsDummy(sym) || namelistDetails) {
531         const Fortran::semantics::Scope &symbolScope = getSymbolHostScope(sym);
532         if (symbolScope.kind() ==
533                 Fortran::semantics::Scope::Kind::MainProgram ||
534             symbolScope.kind() == Fortran::semantics::Scope::Kind::Subprogram)
535           if (symbolScope != *internalScope &&
536               symbolScope.Contains(*internalScope)) {
537             if (namelistDetails) {
538               // So far, namelist symbols are processed on the fly in IO and
539               // the related namelist data structure is not added to the symbol
540               // map, so it cannot be passed to the internal procedures.
541               // Instead, all the symbols of the host namelist used in the
542               // internal procedure must be considered as host associated so
543               // that IO lowering can find them when needed.
544               for (const auto &namelistObject : namelistDetails->objects())
545                 escapees.insert(&*namelistObject);
546             } else {
547               escapees.insert(&ultimate);
548             }
549           }
550       }
551     };
552     Fortran::lower::pft::visitAllSymbols(funit, addToListIfEscapee);
553   }
554 
555   //===--------------------------------------------------------------------===//
556   // AbstractConverter overrides
557   //===--------------------------------------------------------------------===//
558 
559   mlir::Value getSymbolAddress(Fortran::lower::SymbolRef sym) override final {
560     return lookupSymbol(sym).getAddr();
561   }
562 
563   fir::ExtendedValue symBoxToExtendedValue(
564       const Fortran::lower::SymbolBox &symBox) override final {
565     return symBox.match(
566         [](const Fortran::lower::SymbolBox::Intrinsic &box)
567             -> fir::ExtendedValue { return box.getAddr(); },
568         [](const Fortran::lower::SymbolBox::None &) -> fir::ExtendedValue {
569           llvm::report_fatal_error("symbol not mapped");
570         },
571         [&](const fir::FortranVariableOpInterface &x) -> fir::ExtendedValue {
572           return hlfir::translateToExtendedValue(getCurrentLocation(),
573                                                  getFirOpBuilder(), x);
574         },
575         [](const auto &box) -> fir::ExtendedValue { return box; });
576   }
577 
578   fir::ExtendedValue
579   getSymbolExtendedValue(const Fortran::semantics::Symbol &sym,
580                          Fortran::lower::SymMap *symMap) override final {
581     Fortran::lower::SymbolBox sb = lookupSymbol(sym, symMap);
582     if (!sb) {
583       LLVM_DEBUG(llvm::dbgs() << "unknown symbol: " << sym << "\nmap: "
584                               << (symMap ? *symMap : localSymbols) << '\n');
585       fir::emitFatalError(getCurrentLocation(),
586                           "symbol is not mapped to any IR value");
587     }
588     return symBoxToExtendedValue(sb);
589   }
590 
591   mlir::Value impliedDoBinding(llvm::StringRef name) override final {
592     mlir::Value val = localSymbols.lookupImpliedDo(name);
593     if (!val)
594       fir::emitFatalError(toLocation(), "ac-do-variable has no binding");
595     return val;
596   }
597 
598   void copySymbolBinding(Fortran::lower::SymbolRef src,
599                          Fortran::lower::SymbolRef target) override final {
600     localSymbols.copySymbolBinding(src, target);
601   }
602 
603   /// Add the symbol binding to the inner-most level of the symbol map and
604   /// return true if it is not already present. Otherwise, return false.
605   bool bindIfNewSymbol(Fortran::lower::SymbolRef sym,
606                        const fir::ExtendedValue &exval) {
607     if (shallowLookupSymbol(sym))
608       return false;
609     bindSymbol(sym, exval);
610     return true;
611   }
612 
613   void bindSymbol(Fortran::lower::SymbolRef sym,
614                   const fir::ExtendedValue &exval) override final {
615     addSymbol(sym, exval, /*forced=*/true);
616   }
617 
618   void
619   overrideExprValues(const Fortran::lower::ExprToValueMap *map) override final {
620     exprValueOverrides = map;
621   }
622 
623   const Fortran::lower::ExprToValueMap *getExprOverrides() override final {
624     return exprValueOverrides;
625   }
626 
627   bool lookupLabelSet(Fortran::lower::SymbolRef sym,
628                       Fortran::lower::pft::LabelSet &labelSet) override final {
629     Fortran::lower::pft::FunctionLikeUnit &owningProc =
630         *getEval().getOwningProcedure();
631     auto iter = owningProc.assignSymbolLabelMap.find(sym);
632     if (iter == owningProc.assignSymbolLabelMap.end())
633       return false;
634     labelSet = iter->second;
635     return true;
636   }
637 
638   Fortran::lower::pft::Evaluation *
639   lookupLabel(Fortran::lower::pft::Label label) override final {
640     Fortran::lower::pft::FunctionLikeUnit &owningProc =
641         *getEval().getOwningProcedure();
642     return owningProc.labelEvaluationMap.lookup(label);
643   }
644 
645   fir::ExtendedValue
646   genExprAddr(const Fortran::lower::SomeExpr &expr,
647               Fortran::lower::StatementContext &context,
648               mlir::Location *locPtr = nullptr) override final {
649     mlir::Location loc = locPtr ? *locPtr : toLocation();
650     if (lowerToHighLevelFIR())
651       return Fortran::lower::convertExprToAddress(loc, *this, expr,
652                                                   localSymbols, context);
653     return Fortran::lower::createSomeExtendedAddress(loc, *this, expr,
654                                                      localSymbols, context);
655   }
656 
657   fir::ExtendedValue
658   genExprValue(const Fortran::lower::SomeExpr &expr,
659                Fortran::lower::StatementContext &context,
660                mlir::Location *locPtr = nullptr) override final {
661     mlir::Location loc = locPtr ? *locPtr : toLocation();
662     if (lowerToHighLevelFIR())
663       return Fortran::lower::convertExprToValue(loc, *this, expr, localSymbols,
664                                                 context);
665     return Fortran::lower::createSomeExtendedExpression(loc, *this, expr,
666                                                         localSymbols, context);
667   }
668 
669   fir::ExtendedValue
670   genExprBox(mlir::Location loc, const Fortran::lower::SomeExpr &expr,
671              Fortran::lower::StatementContext &stmtCtx) override final {
672     if (lowerToHighLevelFIR())
673       return Fortran::lower::convertExprToBox(loc, *this, expr, localSymbols,
674                                               stmtCtx);
675     return Fortran::lower::createBoxValue(loc, *this, expr, localSymbols,
676                                           stmtCtx);
677   }
678 
679   Fortran::evaluate::FoldingContext &getFoldingContext() override final {
680     return foldingContext;
681   }
682 
683   mlir::Type genType(const Fortran::lower::SomeExpr &expr) override final {
684     return Fortran::lower::translateSomeExprToFIRType(*this, expr);
685   }
686   mlir::Type genType(const Fortran::lower::pft::Variable &var) override final {
687     return Fortran::lower::translateVariableToFIRType(*this, var);
688   }
689   mlir::Type genType(Fortran::lower::SymbolRef sym) override final {
690     return Fortran::lower::translateSymbolToFIRType(*this, sym);
691   }
692   mlir::Type
693   genType(Fortran::common::TypeCategory tc, int kind,
694           llvm::ArrayRef<std::int64_t> lenParameters) override final {
695     return Fortran::lower::getFIRType(&getMLIRContext(), tc, kind,
696                                       lenParameters);
697   }
698   mlir::Type
699   genType(const Fortran::semantics::DerivedTypeSpec &tySpec) override final {
700     return Fortran::lower::translateDerivedTypeToFIRType(*this, tySpec);
701   }
702   mlir::Type genType(Fortran::common::TypeCategory tc) override final {
703     return Fortran::lower::getFIRType(
704         &getMLIRContext(), tc, bridge.getDefaultKinds().GetDefaultKind(tc),
705         std::nullopt);
706   }
707 
708   Fortran::lower::TypeConstructionStack &
709   getTypeConstructionStack() override final {
710     return typeConstructionStack;
711   }
712 
713   bool
714   isPresentShallowLookup(const Fortran::semantics::Symbol &sym) override final {
715     return bool(shallowLookupSymbol(sym));
716   }
717 
718   bool createHostAssociateVarClone(const Fortran::semantics::Symbol &sym,
719                                    bool skipDefaultInit) override final {
720     mlir::Location loc = genLocation(sym.name());
721     mlir::Type symType = genType(sym);
722     const auto *details = sym.detailsIf<Fortran::semantics::HostAssocDetails>();
723     assert(details && "No host-association found");
724     const Fortran::semantics::Symbol &hsym = details->symbol();
725     mlir::Type hSymType = genType(hsym.GetUltimate());
726     Fortran::lower::SymbolBox hsb =
727         lookupSymbol(hsym, /*symMap=*/nullptr, /*forceHlfirBase=*/true);
728 
729     auto allocate = [&](llvm::ArrayRef<mlir::Value> shape,
730                         llvm::ArrayRef<mlir::Value> typeParams) -> mlir::Value {
731       mlir::Value allocVal = builder->allocateLocal(
732           loc,
733           Fortran::semantics::IsAllocatableOrObjectPointer(&hsym.GetUltimate())
734               ? hSymType
735               : symType,
736           mangleName(sym), toStringRef(sym.GetUltimate().name()),
737           /*pinned=*/true, shape, typeParams,
738           sym.GetUltimate().attrs().test(Fortran::semantics::Attr::TARGET));
739       return allocVal;
740     };
741 
742     fir::ExtendedValue hexv = symBoxToExtendedValue(hsb);
743     fir::ExtendedValue exv = hexv.match(
744         [&](const fir::BoxValue &box) -> fir::ExtendedValue {
745           const Fortran::semantics::DeclTypeSpec *type = sym.GetType();
746           if (type && type->IsPolymorphic())
747             TODO(loc, "create polymorphic host associated copy");
748           // Create a contiguous temp with the same shape and length as
749           // the original variable described by a fir.box.
750           llvm::SmallVector<mlir::Value> extents =
751               fir::factory::getExtents(loc, *builder, hexv);
752           if (box.isDerivedWithLenParameters())
753             TODO(loc, "get length parameters from derived type BoxValue");
754           if (box.isCharacter()) {
755             mlir::Value len = fir::factory::readCharLen(*builder, loc, box);
756             mlir::Value temp = allocate(extents, {len});
757             return fir::CharArrayBoxValue{temp, len, extents};
758           }
759           return fir::ArrayBoxValue{allocate(extents, {}), extents};
760         },
761         [&](const fir::MutableBoxValue &box) -> fir::ExtendedValue {
762           // Allocate storage for a pointer/allocatble descriptor.
763           // No shape/lengths to be passed to the alloca.
764           return fir::MutableBoxValue(allocate({}, {}), {}, {});
765         },
766         [&](const auto &) -> fir::ExtendedValue {
767           mlir::Value temp =
768               allocate(fir::factory::getExtents(loc, *builder, hexv),
769                        fir::factory::getTypeParams(loc, *builder, hexv));
770           return fir::substBase(hexv, temp);
771         });
772 
773     // Initialise cloned allocatable
774     hexv.match(
775         [&](const fir::MutableBoxValue &box) -> void {
776           const auto new_box = exv.getBoxOf<fir::MutableBoxValue>();
777           if (Fortran::semantics::IsPointer(sym.GetUltimate())) {
778             // Establish the pointer descriptors. The rank and type code/size
779             // at least must be set properly for later inquiry of the pointer
780             // to work, and new pointers are always given disassociated status
781             // by flang for safety, even if this is not required by the
782             // language.
783             auto empty = fir::factory::createUnallocatedBox(
784                 *builder, loc, new_box->getBoxTy(), box.nonDeferredLenParams(),
785                 {});
786             builder->create<fir::StoreOp>(loc, empty, new_box->getAddr());
787             return;
788           }
789           // Copy allocation status of Allocatables, creating new storage if
790           // needed.
791 
792           // allocate if allocated
793           mlir::Value isAllocated =
794               fir::factory::genIsAllocatedOrAssociatedTest(*builder, loc, box);
795           auto if_builder = builder->genIfThenElse(loc, isAllocated);
796           if_builder.genThen([&]() {
797             std::string name = mangleName(sym) + ".alloc";
798             fir::ExtendedValue read = fir::factory::genMutableBoxRead(
799                 *builder, loc, box, /*mayBePolymorphic=*/false);
800             if (auto read_arr_box = read.getBoxOf<fir::ArrayBoxValue>()) {
801               fir::factory::genInlinedAllocation(
802                   *builder, loc, *new_box, read_arr_box->getLBounds(),
803                   read_arr_box->getExtents(),
804                   /*lenParams=*/std::nullopt, name,
805                   /*mustBeHeap=*/true);
806             } else if (auto read_char_arr_box =
807                            read.getBoxOf<fir::CharArrayBoxValue>()) {
808               fir::factory::genInlinedAllocation(
809                   *builder, loc, *new_box, read_char_arr_box->getLBounds(),
810                   read_char_arr_box->getExtents(), read_char_arr_box->getLen(),
811                   name,
812                   /*mustBeHeap=*/true);
813             } else if (auto read_char_box =
814                            read.getBoxOf<fir::CharBoxValue>()) {
815               fir::factory::genInlinedAllocation(*builder, loc, *new_box,
816                                                  /*lbounds=*/std::nullopt,
817                                                  /*extents=*/std::nullopt,
818                                                  read_char_box->getLen(), name,
819                                                  /*mustBeHeap=*/true);
820             } else {
821               fir::factory::genInlinedAllocation(
822                   *builder, loc, *new_box, box.getMutableProperties().lbounds,
823                   box.getMutableProperties().extents,
824                   box.nonDeferredLenParams(), name,
825                   /*mustBeHeap=*/true);
826             }
827           });
828           if_builder.genElse([&]() {
829             // nullify box
830             auto empty = fir::factory::createUnallocatedBox(
831                 *builder, loc, new_box->getBoxTy(),
832                 new_box->nonDeferredLenParams(), {});
833             builder->create<fir::StoreOp>(loc, empty, new_box->getAddr());
834           });
835           if_builder.end();
836         },
837         [&](const auto &) -> void {
838           // Always initialize allocatable component descriptor, even when the
839           // value is later copied from the host (e.g. firstprivate) because the
840           // assignment from the host to the copy will fail if the component
841           // descriptors are not initialized.
842           if (skipDefaultInit && !hlfir::mayHaveAllocatableComponent(hSymType))
843             return;
844           // Initialize local/private derived types with default
845           // initialization (Fortran 2023 section 11.1.7.5 and OpenMP 5.2
846           // section 5.3). Pointer and allocatable components, when allowed,
847           // also need to be established so that flang runtime can later work
848           // with them.
849           if (const Fortran::semantics::DeclTypeSpec *declTypeSpec =
850                   sym.GetType())
851             if (const Fortran::semantics::DerivedTypeSpec *derivedTypeSpec =
852                     declTypeSpec->AsDerived())
853               if (derivedTypeSpec->HasDefaultInitialization(
854                       /*ignoreAllocatable=*/false, /*ignorePointer=*/false)) {
855                 mlir::Value box = builder->createBox(loc, exv);
856                 fir::runtime::genDerivedTypeInitialize(*builder, loc, box);
857               }
858         });
859 
860     return bindIfNewSymbol(sym, exv);
861   }
862 
863   void createHostAssociateVarCloneDealloc(
864       const Fortran::semantics::Symbol &sym) override final {
865     mlir::Location loc = genLocation(sym.name());
866     Fortran::lower::SymbolBox hsb =
867         lookupSymbol(sym, /*symMap=*/nullptr, /*forceHlfirBase=*/true);
868 
869     fir::ExtendedValue hexv = symBoxToExtendedValue(hsb);
870     hexv.match(
871         [&](const fir::MutableBoxValue &new_box) -> void {
872           // Do not process pointers
873           if (Fortran::semantics::IsPointer(sym.GetUltimate())) {
874             return;
875           }
876           // deallocate allocated in createHostAssociateVarClone value
877           Fortran::lower::genDeallocateIfAllocated(*this, new_box, loc);
878         },
879         [&](const auto &) -> void {
880           // Do nothing
881         });
882   }
883 
884   void copyVar(mlir::Location loc, mlir::Value dst, mlir::Value src,
885                fir::FortranVariableFlagsEnum attrs) override final {
886     bool isAllocatable =
887         bitEnumContainsAny(attrs, fir::FortranVariableFlagsEnum::allocatable);
888     bool isPointer =
889         bitEnumContainsAny(attrs, fir::FortranVariableFlagsEnum::pointer);
890 
891     copyVarHLFIR(loc, Fortran::lower::SymbolBox::Intrinsic{dst},
892                  Fortran::lower::SymbolBox::Intrinsic{src}, isAllocatable,
893                  isPointer, Fortran::semantics::Symbol::Flags());
894   }
895 
896   void
897   copyHostAssociateVar(const Fortran::semantics::Symbol &sym,
898                        mlir::OpBuilder::InsertPoint *copyAssignIP = nullptr,
899                        bool hostIsSource = true) override final {
900     // 1) Fetch the original copy of the variable.
901     assert(sym.has<Fortran::semantics::HostAssocDetails>() &&
902            "No host-association found");
903     const Fortran::semantics::Symbol &hsym = sym.GetUltimate();
904     Fortran::lower::SymbolBox hsb = lookupOneLevelUpSymbol(hsym);
905     assert(hsb && "Host symbol box not found");
906 
907     // 2) Fetch the copied one that will mask the original.
908     Fortran::lower::SymbolBox sb = shallowLookupSymbol(sym);
909     assert(sb && "Host-associated symbol box not found");
910     assert(hsb.getAddr() != sb.getAddr() &&
911            "Host and associated symbol boxes are the same");
912 
913     // 3) Perform the assignment.
914     mlir::OpBuilder::InsertionGuard guard(*builder);
915     if (copyAssignIP && copyAssignIP->isSet())
916       builder->restoreInsertionPoint(*copyAssignIP);
917     else
918       builder->setInsertionPointAfter(sb.getAddr().getDefiningOp());
919 
920     Fortran::lower::SymbolBox *lhs_sb, *rhs_sb;
921     if (!hostIsSource) {
922       lhs_sb = &hsb;
923       rhs_sb = &sb;
924     } else {
925       lhs_sb = &sb;
926       rhs_sb = &hsb;
927     }
928 
929     copyVar(sym, *lhs_sb, *rhs_sb, sym.flags());
930   }
931 
932   void genEval(Fortran::lower::pft::Evaluation &eval,
933                bool unstructuredContext) override final {
934     genFIR(eval, unstructuredContext);
935   }
936 
937   //===--------------------------------------------------------------------===//
938   // Utility methods
939   //===--------------------------------------------------------------------===//
940 
941   void collectSymbolSet(
942       Fortran::lower::pft::Evaluation &eval,
943       llvm::SetVector<const Fortran::semantics::Symbol *> &symbolSet,
944       Fortran::semantics::Symbol::Flag flag, bool collectSymbols,
945       bool checkHostAssociatedSymbols) override final {
946     auto addToList = [&](const Fortran::semantics::Symbol &sym) {
947       std::function<void(const Fortran::semantics::Symbol &, bool)>
948           insertSymbols = [&](const Fortran::semantics::Symbol &oriSymbol,
949                               bool collectSymbol) {
950             if (collectSymbol && oriSymbol.test(flag))
951               symbolSet.insert(&oriSymbol);
952             else if (checkHostAssociatedSymbols)
953               if (const auto *details{
954                       oriSymbol
955                           .detailsIf<Fortran::semantics::HostAssocDetails>()})
956                 insertSymbols(details->symbol(), true);
957           };
958       insertSymbols(sym, collectSymbols);
959     };
960     Fortran::lower::pft::visitAllSymbols(eval, addToList);
961   }
962 
963   mlir::Location getCurrentLocation() override final { return toLocation(); }
964 
965   /// Generate a dummy location.
966   mlir::Location genUnknownLocation() override final {
967     // Note: builder may not be instantiated yet
968     return mlir::UnknownLoc::get(&getMLIRContext());
969   }
970 
971   static mlir::Location genLocation(Fortran::parser::SourcePosition pos,
972                                     mlir::MLIRContext &ctx) {
973     llvm::SmallString<256> path(*pos.path);
974     llvm::sys::fs::make_absolute(path);
975     llvm::sys::path::remove_dots(path);
976     return mlir::FileLineColLoc::get(&ctx, path.str(), pos.line, pos.column);
977   }
978 
979   /// Generate a `Location` from the `CharBlock`.
980   mlir::Location
981   genLocation(const Fortran::parser::CharBlock &block) override final {
982     mlir::Location mainLocation = genUnknownLocation();
983     if (const Fortran::parser::AllCookedSources *cooked =
984             bridge.getCookedSource()) {
985       if (std::optional<Fortran::parser::ProvenanceRange> provenance =
986               cooked->GetProvenanceRange(block)) {
987         if (std::optional<Fortran::parser::SourcePosition> filePos =
988                 cooked->allSources().GetSourcePosition(provenance->start()))
989           mainLocation = genLocation(*filePos, getMLIRContext());
990 
991         llvm::SmallVector<mlir::Location> locs;
992         locs.push_back(mainLocation);
993 
994         llvm::SmallVector<fir::LocationKindAttr> locAttrs;
995         locAttrs.push_back(fir::LocationKindAttr::get(&getMLIRContext(),
996                                                       fir::LocationKind::Base));
997 
998         // Gather include location information if any.
999         Fortran::parser::ProvenanceRange *prov = &*provenance;
1000         while (prov) {
1001           if (std::optional<Fortran::parser::ProvenanceRange> include =
1002                   cooked->allSources().GetInclusionInfo(*prov)) {
1003             if (std::optional<Fortran::parser::SourcePosition> incPos =
1004                     cooked->allSources().GetSourcePosition(include->start())) {
1005               locs.push_back(genLocation(*incPos, getMLIRContext()));
1006               locAttrs.push_back(fir::LocationKindAttr::get(
1007                   &getMLIRContext(), fir::LocationKind::Inclusion));
1008             }
1009             prov = &*include;
1010           } else {
1011             prov = nullptr;
1012           }
1013         }
1014         if (locs.size() > 1) {
1015           assert(locs.size() == locAttrs.size() &&
1016                  "expect as many attributes as locations");
1017           return mlir::FusedLocWith<fir::LocationKindArrayAttr>::get(
1018               &getMLIRContext(), locs,
1019               fir::LocationKindArrayAttr::get(&getMLIRContext(), locAttrs));
1020         }
1021       }
1022     }
1023     return mainLocation;
1024   }
1025 
1026   const Fortran::semantics::Scope &getCurrentScope() override final {
1027     return bridge.getSemanticsContext().FindScope(currentPosition);
1028   }
1029 
1030   fir::FirOpBuilder &getFirOpBuilder() override final { return *builder; }
1031 
1032   mlir::ModuleOp getModuleOp() override final { return bridge.getModule(); }
1033 
1034   mlir::MLIRContext &getMLIRContext() override final {
1035     return bridge.getMLIRContext();
1036   }
1037   std::string
1038   mangleName(const Fortran::semantics::Symbol &symbol) override final {
1039     return Fortran::lower::mangle::mangleName(
1040         symbol, scopeBlockIdMap, /*keepExternalInScope=*/false,
1041         getLoweringOptions().getUnderscoring());
1042   }
1043   std::string mangleName(
1044       const Fortran::semantics::DerivedTypeSpec &derivedType) override final {
1045     return Fortran::lower::mangle::mangleName(derivedType, scopeBlockIdMap);
1046   }
1047   std::string mangleName(std::string &name) override final {
1048     return Fortran::lower::mangle::mangleName(name, getCurrentScope(),
1049                                               scopeBlockIdMap);
1050   }
1051   std::string getRecordTypeFieldName(
1052       const Fortran::semantics::Symbol &component) override final {
1053     return Fortran::lower::mangle::getRecordTypeFieldName(component,
1054                                                           scopeBlockIdMap);
1055   }
1056   const fir::KindMapping &getKindMap() override final {
1057     return bridge.getKindMap();
1058   }
1059 
1060   /// Return the current function context, which may be a nested BLOCK context
1061   /// or a full subprogram context.
1062   Fortran::lower::StatementContext &getFctCtx() override final {
1063     if (!activeConstructStack.empty() &&
1064         activeConstructStack.back().eval.isA<Fortran::parser::BlockConstruct>())
1065       return activeConstructStack.back().stmtCtx;
1066     return bridge.fctCtx();
1067   }
1068 
1069   mlir::Value hostAssocTupleValue() override final { return hostAssocTuple; }
1070 
1071   /// Record a binding for the ssa-value of the tuple for this function.
1072   void bindHostAssocTuple(mlir::Value val) override final {
1073     assert(!hostAssocTuple && val);
1074     hostAssocTuple = val;
1075   }
1076 
1077   mlir::Value dummyArgsScopeValue() const override final {
1078     return dummyArgsScope;
1079   }
1080 
1081   bool isRegisteredDummySymbol(
1082       Fortran::semantics::SymbolRef symRef) const override final {
1083     auto *sym = &*symRef;
1084     return registeredDummySymbols.contains(sym);
1085   }
1086 
1087   const Fortran::lower::pft::FunctionLikeUnit *
1088   getCurrentFunctionUnit() const override final {
1089     return currentFunctionUnit;
1090   }
1091 
1092   void registerTypeInfo(mlir::Location loc,
1093                         Fortran::lower::SymbolRef typeInfoSym,
1094                         const Fortran::semantics::DerivedTypeSpec &typeSpec,
1095                         fir::RecordType type) override final {
1096     typeInfoConverter.registerTypeInfo(*this, loc, typeInfoSym, typeSpec, type);
1097   }
1098 
1099   llvm::StringRef
1100   getUniqueLitName(mlir::Location loc,
1101                    std::unique_ptr<Fortran::lower::SomeExpr> expr,
1102                    mlir::Type eleTy) override final {
1103     std::string namePrefix =
1104         getConstantExprManglePrefix(loc, *expr.get(), eleTy);
1105     auto [it, inserted] = literalNamesMap.try_emplace(
1106         expr.get(), namePrefix + std::to_string(uniqueLitId));
1107     const auto &name = it->second;
1108     if (inserted) {
1109       // Keep ownership of the expr key.
1110       literalExprsStorage.push_back(std::move(expr));
1111 
1112       // If we've just added a new name, we have to make sure
1113       // there is no global object with the same name in the module.
1114       fir::GlobalOp global = builder->getNamedGlobal(name);
1115       if (global)
1116         fir::emitFatalError(loc, llvm::Twine("global object with name '") +
1117                                      llvm::Twine(name) +
1118                                      llvm::Twine("' already exists"));
1119       ++uniqueLitId;
1120       return name;
1121     }
1122 
1123     // The name already exists. Verify that the prefix is the same.
1124     if (!llvm::StringRef(name).starts_with(namePrefix))
1125       fir::emitFatalError(loc, llvm::Twine("conflicting prefixes: '") +
1126                                    llvm::Twine(name) +
1127                                    llvm::Twine("' does not start with '") +
1128                                    llvm::Twine(namePrefix) + llvm::Twine("'"));
1129 
1130     return name;
1131   }
1132 
1133 private:
1134   FirConverter() = delete;
1135   FirConverter(const FirConverter &) = delete;
1136   FirConverter &operator=(const FirConverter &) = delete;
1137 
1138   //===--------------------------------------------------------------------===//
1139   // Helper member functions
1140   //===--------------------------------------------------------------------===//
1141 
1142   mlir::Value createFIRExpr(mlir::Location loc,
1143                             const Fortran::lower::SomeExpr *expr,
1144                             Fortran::lower::StatementContext &stmtCtx) {
1145     return fir::getBase(genExprValue(*expr, stmtCtx, &loc));
1146   }
1147 
1148   /// Find the symbol in the local map or return null.
1149   Fortran::lower::SymbolBox
1150   lookupSymbol(const Fortran::semantics::Symbol &sym,
1151                Fortran::lower::SymMap *symMap = nullptr,
1152                bool forceHlfirBase = false) {
1153     symMap = symMap ? symMap : &localSymbols;
1154     if (lowerToHighLevelFIR()) {
1155       if (std::optional<fir::FortranVariableOpInterface> var =
1156               symMap->lookupVariableDefinition(sym)) {
1157         auto exv = hlfir::translateToExtendedValue(toLocation(), *builder, *var,
1158                                                    forceHlfirBase);
1159         return exv.match(
1160             [](mlir::Value x) -> Fortran::lower::SymbolBox {
1161               return Fortran::lower::SymbolBox::Intrinsic{x};
1162             },
1163             [](auto x) -> Fortran::lower::SymbolBox { return x; });
1164       }
1165 
1166       // Entry character result represented as an argument pair
1167       // needs to be represented in the symbol table even before
1168       // we can create DeclareOp for it. The temporary mapping
1169       // is EmboxCharOp that conveys the address and length information.
1170       // After mapSymbolAttributes is done, the mapping is replaced
1171       // with the new DeclareOp, and the following table lookups
1172       // do not reach here.
1173       if (sym.IsFuncResult())
1174         if (const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType())
1175           if (declTy->category() ==
1176               Fortran::semantics::DeclTypeSpec::Category::Character)
1177             return symMap->lookupSymbol(sym);
1178 
1179       // Procedure dummies are not mapped with an hlfir.declare because
1180       // they are not "variable" (cannot be assigned to), and it would
1181       // make hlfir.declare more complex than it needs to to allow this.
1182       // Do a regular lookup.
1183       if (Fortran::semantics::IsProcedure(sym))
1184         return symMap->lookupSymbol(sym);
1185 
1186       // Commonblock names are not variables, but in some lowerings (like
1187       // OpenMP) it is useful to maintain the address of the commonblock in an
1188       // MLIR value and query it. hlfir.declare need not be created for these.
1189       if (sym.detailsIf<Fortran::semantics::CommonBlockDetails>())
1190         return symMap->lookupSymbol(sym);
1191 
1192       // For symbols to be privatized in OMP, the symbol is mapped to an
1193       // instance of `SymbolBox::Intrinsic` (i.e. a direct mapping to an MLIR
1194       // SSA value). This MLIR SSA value is the block argument to the
1195       // `omp.private`'s `alloc` block. If this is the case, we return this
1196       // `SymbolBox::Intrinsic` value.
1197       if (Fortran::lower::SymbolBox v = symMap->lookupSymbol(sym))
1198         return v;
1199 
1200       return {};
1201     }
1202     if (Fortran::lower::SymbolBox v = symMap->lookupSymbol(sym))
1203       return v;
1204     return {};
1205   }
1206 
1207   /// Find the symbol in the inner-most level of the local map or return null.
1208   Fortran::lower::SymbolBox
1209   shallowLookupSymbol(const Fortran::semantics::Symbol &sym) {
1210     if (Fortran::lower::SymbolBox v = localSymbols.shallowLookupSymbol(sym))
1211       return v;
1212     return {};
1213   }
1214 
1215   /// Find the symbol in one level up of symbol map such as for host-association
1216   /// in OpenMP code or return null.
1217   Fortran::lower::SymbolBox
1218   lookupOneLevelUpSymbol(const Fortran::semantics::Symbol &sym) override {
1219     if (Fortran::lower::SymbolBox v = localSymbols.lookupOneLevelUpSymbol(sym))
1220       return v;
1221     return {};
1222   }
1223 
1224   mlir::SymbolTable *getMLIRSymbolTable() override { return &mlirSymbolTable; }
1225 
1226   /// Add the symbol to the local map and return `true`. If the symbol is
1227   /// already in the map and \p forced is `false`, the map is not updated.
1228   /// Instead the value `false` is returned.
1229   bool addSymbol(const Fortran::semantics::SymbolRef sym,
1230                  fir::ExtendedValue val, bool forced = false) {
1231     if (!forced && lookupSymbol(sym))
1232       return false;
1233     if (lowerToHighLevelFIR()) {
1234       Fortran::lower::genDeclareSymbol(*this, localSymbols, sym, val,
1235                                        fir::FortranVariableFlagsEnum::None,
1236                                        forced);
1237     } else {
1238       localSymbols.addSymbol(sym, val, forced);
1239     }
1240     return true;
1241   }
1242 
1243   void copyVar(const Fortran::semantics::Symbol &sym,
1244                const Fortran::lower::SymbolBox &lhs_sb,
1245                const Fortran::lower::SymbolBox &rhs_sb,
1246                Fortran::semantics::Symbol::Flags flags) {
1247     mlir::Location loc = genLocation(sym.name());
1248     if (lowerToHighLevelFIR())
1249       copyVarHLFIR(loc, lhs_sb, rhs_sb, flags);
1250     else
1251       copyVarFIR(loc, sym, lhs_sb, rhs_sb);
1252   }
1253 
1254   void copyVarHLFIR(mlir::Location loc, Fortran::lower::SymbolBox dst,
1255                     Fortran::lower::SymbolBox src,
1256                     Fortran::semantics::Symbol::Flags flags) {
1257     assert(lowerToHighLevelFIR());
1258 
1259     bool isBoxAllocatable = dst.match(
1260         [](const fir::MutableBoxValue &box) { return box.isAllocatable(); },
1261         [](const fir::FortranVariableOpInterface &box) {
1262           return fir::FortranVariableOpInterface(box).isAllocatable();
1263         },
1264         [](const auto &box) { return false; });
1265 
1266     bool isBoxPointer = dst.match(
1267         [](const fir::MutableBoxValue &box) { return box.isPointer(); },
1268         [](const fir::FortranVariableOpInterface &box) {
1269           return fir::FortranVariableOpInterface(box).isPointer();
1270         },
1271         [](const auto &box) { return false; });
1272 
1273     copyVarHLFIR(loc, dst, src, isBoxAllocatable, isBoxPointer, flags);
1274   }
1275 
1276   void copyVarHLFIR(mlir::Location loc, Fortran::lower::SymbolBox dst,
1277                     Fortran::lower::SymbolBox src, bool isAllocatable,
1278                     bool isPointer, Fortran::semantics::Symbol::Flags flags) {
1279     assert(lowerToHighLevelFIR());
1280     hlfir::Entity lhs{dst.getAddr()};
1281     hlfir::Entity rhs{src.getAddr()};
1282 
1283     auto copyData = [&](hlfir::Entity l, hlfir::Entity r) {
1284       // Dereference RHS and load it if trivial scalar.
1285       r = hlfir::loadTrivialScalar(loc, *builder, r);
1286       builder->create<hlfir::AssignOp>(loc, r, l, isAllocatable);
1287     };
1288 
1289     if (isPointer) {
1290       // Set LHS target to the target of RHS (do not copy the RHS
1291       // target data into the LHS target storage).
1292       auto loadVal = builder->create<fir::LoadOp>(loc, rhs);
1293       builder->create<fir::StoreOp>(loc, loadVal, lhs);
1294     } else if (isAllocatable &&
1295                flags.test(Fortran::semantics::Symbol::Flag::OmpCopyIn)) {
1296       // For copyin allocatable variables, RHS must be copied to lhs
1297       // only when rhs is allocated.
1298       hlfir::Entity temp =
1299           hlfir::derefPointersAndAllocatables(loc, *builder, rhs);
1300       mlir::Value addr = hlfir::genVariableRawAddress(loc, *builder, temp);
1301       mlir::Value isAllocated = builder->genIsNotNullAddr(loc, addr);
1302       builder->genIfThenElse(loc, isAllocated)
1303           .genThen([&]() { copyData(lhs, rhs); })
1304           .genElse([&]() {
1305             fir::ExtendedValue hexv = symBoxToExtendedValue(dst);
1306             hexv.match(
1307                 [&](const fir::MutableBoxValue &new_box) -> void {
1308                   // if the allocation status of original list item is
1309                   // unallocated, unallocate the copy if it is allocated, else
1310                   // do nothing.
1311                   Fortran::lower::genDeallocateIfAllocated(*this, new_box, loc);
1312                 },
1313                 [&](const auto &) -> void {});
1314           })
1315           .end();
1316     } else if (isAllocatable &&
1317                flags.test(Fortran::semantics::Symbol::Flag::OmpFirstPrivate)) {
1318       // For firstprivate allocatable variables, RHS must be copied
1319       // only when LHS is allocated.
1320       hlfir::Entity temp =
1321           hlfir::derefPointersAndAllocatables(loc, *builder, lhs);
1322       mlir::Value addr = hlfir::genVariableRawAddress(loc, *builder, temp);
1323       mlir::Value isAllocated = builder->genIsNotNullAddr(loc, addr);
1324       builder->genIfThen(loc, isAllocated)
1325           .genThen([&]() { copyData(lhs, rhs); })
1326           .end();
1327     } else {
1328       copyData(lhs, rhs);
1329     }
1330   }
1331 
1332   void copyVarFIR(mlir::Location loc, const Fortran::semantics::Symbol &sym,
1333                   const Fortran::lower::SymbolBox &lhs_sb,
1334                   const Fortran::lower::SymbolBox &rhs_sb) {
1335     assert(!lowerToHighLevelFIR());
1336     fir::ExtendedValue lhs = symBoxToExtendedValue(lhs_sb);
1337     fir::ExtendedValue rhs = symBoxToExtendedValue(rhs_sb);
1338     mlir::Type symType = genType(sym);
1339     if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(symType)) {
1340       Fortran::lower::StatementContext stmtCtx;
1341       Fortran::lower::createSomeArrayAssignment(*this, lhs, rhs, localSymbols,
1342                                                 stmtCtx);
1343       stmtCtx.finalizeAndReset();
1344     } else if (lhs.getBoxOf<fir::CharBoxValue>()) {
1345       fir::factory::CharacterExprHelper{*builder, loc}.createAssign(lhs, rhs);
1346     } else {
1347       auto loadVal = builder->create<fir::LoadOp>(loc, fir::getBase(rhs));
1348       builder->create<fir::StoreOp>(loc, loadVal, fir::getBase(lhs));
1349     }
1350   }
1351 
1352   /// Map a block argument to a result or dummy symbol. This is not the
1353   /// definitive mapping. The specification expression have not been lowered
1354   /// yet. The final mapping will be done using this pre-mapping in
1355   /// Fortran::lower::mapSymbolAttributes.
1356   bool mapBlockArgToDummyOrResult(const Fortran::semantics::SymbolRef sym,
1357                                   mlir::Value val, bool isResult) {
1358     localSymbols.addSymbol(sym, val);
1359     if (!isResult)
1360       registerDummySymbol(sym);
1361 
1362     return true;
1363   }
1364 
1365   /// Generate the address of loop variable \p sym.
1366   /// If \p sym is not mapped yet, allocate local storage for it.
1367   mlir::Value genLoopVariableAddress(mlir::Location loc,
1368                                      const Fortran::semantics::Symbol &sym,
1369                                      bool isUnordered) {
1370     if (isUnordered || sym.has<Fortran::semantics::HostAssocDetails>() ||
1371         sym.has<Fortran::semantics::UseDetails>()) {
1372       if (!shallowLookupSymbol(sym) &&
1373           !sym.test(Fortran::semantics::Symbol::Flag::OmpShared)) {
1374         // Do concurrent loop variables are not mapped yet since they are local
1375         // to the Do concurrent scope (same for OpenMP loops).
1376         mlir::OpBuilder::InsertPoint insPt = builder->saveInsertionPoint();
1377         builder->setInsertionPointToStart(builder->getAllocaBlock());
1378         mlir::Type tempTy = genType(sym);
1379         mlir::Value temp =
1380             builder->createTemporaryAlloc(loc, tempTy, toStringRef(sym.name()));
1381         bindIfNewSymbol(sym, temp);
1382         builder->restoreInsertionPoint(insPt);
1383       }
1384     }
1385     auto entry = lookupSymbol(sym);
1386     (void)entry;
1387     assert(entry && "loop control variable must already be in map");
1388     Fortran::lower::StatementContext stmtCtx;
1389     return fir::getBase(
1390         genExprAddr(Fortran::evaluate::AsGenericExpr(sym).value(), stmtCtx));
1391   }
1392 
1393   static bool isNumericScalarCategory(Fortran::common::TypeCategory cat) {
1394     return cat == Fortran::common::TypeCategory::Integer ||
1395            cat == Fortran::common::TypeCategory::Real ||
1396            cat == Fortran::common::TypeCategory::Complex ||
1397            cat == Fortran::common::TypeCategory::Logical;
1398   }
1399   static bool isLogicalCategory(Fortran::common::TypeCategory cat) {
1400     return cat == Fortran::common::TypeCategory::Logical;
1401   }
1402   static bool isCharacterCategory(Fortran::common::TypeCategory cat) {
1403     return cat == Fortran::common::TypeCategory::Character;
1404   }
1405   static bool isDerivedCategory(Fortran::common::TypeCategory cat) {
1406     return cat == Fortran::common::TypeCategory::Derived;
1407   }
1408 
1409   /// Insert a new block before \p block. Leave the insertion point unchanged.
1410   mlir::Block *insertBlock(mlir::Block *block) {
1411     mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint();
1412     mlir::Block *newBlock = builder->createBlock(block);
1413     builder->restoreInsertionPoint(insertPt);
1414     return newBlock;
1415   }
1416 
1417   Fortran::lower::pft::Evaluation &evalOfLabel(Fortran::parser::Label label) {
1418     const Fortran::lower::pft::LabelEvalMap &labelEvaluationMap =
1419         getEval().getOwningProcedure()->labelEvaluationMap;
1420     const auto iter = labelEvaluationMap.find(label);
1421     assert(iter != labelEvaluationMap.end() && "label missing from map");
1422     return *iter->second;
1423   }
1424 
1425   void genBranch(mlir::Block *targetBlock) {
1426     assert(targetBlock && "missing unconditional target block");
1427     builder->create<mlir::cf::BranchOp>(toLocation(), targetBlock);
1428   }
1429 
1430   void genConditionalBranch(mlir::Value cond, mlir::Block *trueTarget,
1431                             mlir::Block *falseTarget) {
1432     assert(trueTarget && "missing conditional branch true block");
1433     assert(falseTarget && "missing conditional branch false block");
1434     mlir::Location loc = toLocation();
1435     mlir::Value bcc = builder->createConvert(loc, builder->getI1Type(), cond);
1436     builder->create<mlir::cf::CondBranchOp>(loc, bcc, trueTarget, std::nullopt,
1437                                             falseTarget, std::nullopt);
1438   }
1439   void genConditionalBranch(mlir::Value cond,
1440                             Fortran::lower::pft::Evaluation *trueTarget,
1441                             Fortran::lower::pft::Evaluation *falseTarget) {
1442     genConditionalBranch(cond, trueTarget->block, falseTarget->block);
1443   }
1444   void genConditionalBranch(const Fortran::parser::ScalarLogicalExpr &expr,
1445                             mlir::Block *trueTarget, mlir::Block *falseTarget) {
1446     Fortran::lower::StatementContext stmtCtx;
1447     mlir::Value cond =
1448         createFIRExpr(toLocation(), Fortran::semantics::GetExpr(expr), stmtCtx);
1449     stmtCtx.finalizeAndReset();
1450     genConditionalBranch(cond, trueTarget, falseTarget);
1451   }
1452   void genConditionalBranch(const Fortran::parser::ScalarLogicalExpr &expr,
1453                             Fortran::lower::pft::Evaluation *trueTarget,
1454                             Fortran::lower::pft::Evaluation *falseTarget) {
1455     Fortran::lower::StatementContext stmtCtx;
1456     mlir::Value cond =
1457         createFIRExpr(toLocation(), Fortran::semantics::GetExpr(expr), stmtCtx);
1458     stmtCtx.finalizeAndReset();
1459     genConditionalBranch(cond, trueTarget->block, falseTarget->block);
1460   }
1461 
1462   /// Return the nearest active ancestor construct of \p eval, or nullptr.
1463   Fortran::lower::pft::Evaluation *
1464   getActiveAncestor(const Fortran::lower::pft::Evaluation &eval) {
1465     Fortran::lower::pft::Evaluation *ancestor = eval.parentConstruct;
1466     for (; ancestor; ancestor = ancestor->parentConstruct)
1467       if (ancestor->activeConstruct)
1468         break;
1469     return ancestor;
1470   }
1471 
1472   /// Return the predicate: "a branch to \p targetEval has exit code".
1473   bool hasExitCode(const Fortran::lower::pft::Evaluation &targetEval) {
1474     Fortran::lower::pft::Evaluation *activeAncestor =
1475         getActiveAncestor(targetEval);
1476     for (auto it = activeConstructStack.rbegin(),
1477               rend = activeConstructStack.rend();
1478          it != rend; ++it) {
1479       if (&it->eval == activeAncestor)
1480         break;
1481       if (it->stmtCtx.hasCode())
1482         return true;
1483     }
1484     return false;
1485   }
1486 
1487   /// Generate a branch to \p targetEval after generating on-exit code for
1488   /// any enclosing construct scopes that are exited by taking the branch.
1489   void
1490   genConstructExitBranch(const Fortran::lower::pft::Evaluation &targetEval) {
1491     Fortran::lower::pft::Evaluation *activeAncestor =
1492         getActiveAncestor(targetEval);
1493     for (auto it = activeConstructStack.rbegin(),
1494               rend = activeConstructStack.rend();
1495          it != rend; ++it) {
1496       if (&it->eval == activeAncestor)
1497         break;
1498       it->stmtCtx.finalizeAndKeep();
1499     }
1500     genBranch(targetEval.block);
1501   }
1502 
1503   /// A construct contains nested evaluations. Some of these evaluations
1504   /// may start a new basic block, others will add code to an existing
1505   /// block.
1506   /// Collect the list of nested evaluations that are last in their block,
1507   /// organize them into two sets:
1508   /// 1. Exiting evaluations: they may need a branch exiting from their
1509   ///    parent construct,
1510   /// 2. Fall-through evaluations: they will continue to the following
1511   ///    evaluation. They may still need a branch, but they do not exit
1512   ///    the construct. They appear in cases where the following evaluation
1513   ///    is a target of some branch.
1514   void collectFinalEvaluations(
1515       Fortran::lower::pft::Evaluation &construct,
1516       llvm::SmallVector<Fortran::lower::pft::Evaluation *> &exits,
1517       llvm::SmallVector<Fortran::lower::pft::Evaluation *> &fallThroughs) {
1518     Fortran::lower::pft::EvaluationList &nested =
1519         construct.getNestedEvaluations();
1520     if (nested.empty())
1521       return;
1522 
1523     Fortran::lower::pft::Evaluation *exit = construct.constructExit;
1524     Fortran::lower::pft::Evaluation *previous = &nested.front();
1525 
1526     for (auto it = ++nested.begin(), end = nested.end(); it != end;
1527          previous = &*it++) {
1528       if (it->block == nullptr)
1529         continue;
1530       // "*it" starts a new block, check what to do with "previous"
1531       if (it->isIntermediateConstructStmt() && previous != exit)
1532         exits.push_back(previous);
1533       else if (previous->lexicalSuccessor && previous->lexicalSuccessor->block)
1534         fallThroughs.push_back(previous);
1535     }
1536     if (previous != exit)
1537       exits.push_back(previous);
1538   }
1539 
1540   /// Generate a SelectOp or branch sequence that compares \p selector against
1541   /// values in \p valueList and targets corresponding labels in \p labelList.
1542   /// If no value matches the selector, branch to \p defaultEval.
1543   ///
1544   /// Three cases require special processing.
1545   ///
1546   /// An empty \p valueList indicates an ArithmeticIfStmt context that requires
1547   /// two comparisons against 0 or 0.0. The selector may have either INTEGER
1548   /// or REAL type.
1549   ///
1550   /// A nonpositive \p valuelist value indicates an IO statement context
1551   /// (0 for ERR, -1 for END, -2 for EOR). An ERR branch must be taken for
1552   /// any positive (IOSTAT) value. A missing (zero) label requires a branch
1553   /// to \p defaultEval for that value.
1554   ///
1555   /// A non-null \p errorBlock indicates an AssignedGotoStmt context that
1556   /// must always branch to an explicit target. There is no valid defaultEval
1557   /// in this case. Generate a branch to \p errorBlock for an AssignedGotoStmt
1558   /// that violates this program requirement.
1559   ///
1560   /// If this is not an ArithmeticIfStmt and no targets have exit code,
1561   /// generate a SelectOp. Otherwise, for each target, if it has exit code,
1562   /// branch to a new block, insert exit code, and then branch to the target.
1563   /// Otherwise, branch directly to the target.
1564   void genMultiwayBranch(mlir::Value selector,
1565                          llvm::SmallVector<int64_t> valueList,
1566                          llvm::SmallVector<Fortran::parser::Label> labelList,
1567                          const Fortran::lower::pft::Evaluation &defaultEval,
1568                          mlir::Block *errorBlock = nullptr) {
1569     bool inArithmeticIfContext = valueList.empty();
1570     assert(((inArithmeticIfContext && labelList.size() == 2) ||
1571             (valueList.size() && labelList.size() == valueList.size())) &&
1572            "mismatched multiway branch targets");
1573     mlir::Block *defaultBlock = errorBlock ? errorBlock : defaultEval.block;
1574     bool defaultHasExitCode = !errorBlock && hasExitCode(defaultEval);
1575     bool hasAnyExitCode = defaultHasExitCode;
1576     if (!hasAnyExitCode)
1577       for (auto label : labelList)
1578         if (label && hasExitCode(evalOfLabel(label))) {
1579           hasAnyExitCode = true;
1580           break;
1581         }
1582     mlir::Location loc = toLocation();
1583     size_t branchCount = labelList.size();
1584     if (!inArithmeticIfContext && !hasAnyExitCode &&
1585         !getEval().forceAsUnstructured()) { // from -no-structured-fir option
1586       // Generate a SelectOp.
1587       llvm::SmallVector<mlir::Block *> blockList;
1588       for (auto label : labelList) {
1589         mlir::Block *block =
1590             label ? evalOfLabel(label).block : defaultEval.block;
1591         assert(block && "missing multiway branch block");
1592         blockList.push_back(block);
1593       }
1594       blockList.push_back(defaultBlock);
1595       if (valueList[branchCount - 1] == 0) // Swap IO ERR and default blocks.
1596         std::swap(blockList[branchCount - 1], blockList[branchCount]);
1597       builder->create<fir::SelectOp>(loc, selector, valueList, blockList);
1598       return;
1599     }
1600     mlir::Type selectorType = selector.getType();
1601     bool realSelector = mlir::isa<mlir::FloatType>(selectorType);
1602     assert((inArithmeticIfContext || !realSelector) && "invalid selector type");
1603     mlir::Value zero;
1604     if (inArithmeticIfContext)
1605       zero =
1606           realSelector
1607               ? builder->create<mlir::arith::ConstantOp>(
1608                     loc, selectorType, builder->getFloatAttr(selectorType, 0.0))
1609               : builder->createIntegerConstant(loc, selectorType, 0);
1610     for (auto label : llvm::enumerate(labelList)) {
1611       mlir::Value cond;
1612       if (realSelector) // inArithmeticIfContext
1613         cond = builder->create<mlir::arith::CmpFOp>(
1614             loc,
1615             label.index() == 0 ? mlir::arith::CmpFPredicate::OLT
1616                                : mlir::arith::CmpFPredicate::OGT,
1617             selector, zero);
1618       else if (inArithmeticIfContext) // INTEGER selector
1619         cond = builder->create<mlir::arith::CmpIOp>(
1620             loc,
1621             label.index() == 0 ? mlir::arith::CmpIPredicate::slt
1622                                : mlir::arith::CmpIPredicate::sgt,
1623             selector, zero);
1624       else // A value of 0 is an IO ERR branch: invert comparison.
1625         cond = builder->create<mlir::arith::CmpIOp>(
1626             loc,
1627             valueList[label.index()] == 0 ? mlir::arith::CmpIPredicate::ne
1628                                           : mlir::arith::CmpIPredicate::eq,
1629             selector,
1630             builder->createIntegerConstant(loc, selectorType,
1631                                            valueList[label.index()]));
1632       // Branch to a new block with exit code and then to the target, or branch
1633       // directly to the target. defaultBlock is the "else" target.
1634       bool lastBranch = label.index() == branchCount - 1;
1635       mlir::Block *nextBlock =
1636           lastBranch && !defaultHasExitCode
1637               ? defaultBlock
1638               : builder->getBlock()->splitBlock(builder->getInsertionPoint());
1639       const Fortran::lower::pft::Evaluation &targetEval =
1640           label.value() ? evalOfLabel(label.value()) : defaultEval;
1641       if (hasExitCode(targetEval)) {
1642         mlir::Block *jumpBlock =
1643             builder->getBlock()->splitBlock(builder->getInsertionPoint());
1644         genConditionalBranch(cond, jumpBlock, nextBlock);
1645         startBlock(jumpBlock);
1646         genConstructExitBranch(targetEval);
1647       } else {
1648         genConditionalBranch(cond, targetEval.block, nextBlock);
1649       }
1650       if (!lastBranch) {
1651         startBlock(nextBlock);
1652       } else if (defaultHasExitCode) {
1653         startBlock(nextBlock);
1654         genConstructExitBranch(defaultEval);
1655       }
1656     }
1657   }
1658 
1659   void pushActiveConstruct(Fortran::lower::pft::Evaluation &eval,
1660                            Fortran::lower::StatementContext &stmtCtx) {
1661     activeConstructStack.push_back(ConstructContext{eval, stmtCtx});
1662     eval.activeConstruct = true;
1663   }
1664   void popActiveConstruct() {
1665     assert(!activeConstructStack.empty() && "invalid active construct stack");
1666     activeConstructStack.back().eval.activeConstruct = false;
1667     if (activeConstructStack.back().pushedScope)
1668       localSymbols.popScope();
1669     activeConstructStack.pop_back();
1670   }
1671 
1672   //===--------------------------------------------------------------------===//
1673   // Termination of symbolically referenced execution units
1674   //===--------------------------------------------------------------------===//
1675 
1676   /// Exit of a routine
1677   ///
1678   /// Generate the cleanup block before the routine exits
1679   void genExitRoutine(bool earlyReturn, mlir::ValueRange retval = {}) {
1680     if (blockIsUnterminated()) {
1681       bridge.openAccCtx().finalizeAndKeep();
1682       bridge.fctCtx().finalizeAndKeep();
1683       builder->create<mlir::func::ReturnOp>(toLocation(), retval);
1684     }
1685     if (!earlyReturn) {
1686       bridge.openAccCtx().pop();
1687       bridge.fctCtx().pop();
1688     }
1689   }
1690 
1691   /// END of procedure-like constructs
1692   ///
1693   /// Generate the cleanup block before the procedure exits
1694   void genReturnSymbol(const Fortran::semantics::Symbol &functionSymbol) {
1695     const Fortran::semantics::Symbol &resultSym =
1696         functionSymbol.get<Fortran::semantics::SubprogramDetails>().result();
1697     Fortran::lower::SymbolBox resultSymBox = lookupSymbol(resultSym);
1698     mlir::Location loc = toLocation();
1699     if (!resultSymBox) {
1700       mlir::emitError(loc, "internal error when processing function return");
1701       return;
1702     }
1703     mlir::Value resultVal = resultSymBox.match(
1704         [&](const fir::CharBoxValue &x) -> mlir::Value {
1705           if (Fortran::semantics::IsBindCProcedure(functionSymbol))
1706             return builder->create<fir::LoadOp>(loc, x.getBuffer());
1707           return fir::factory::CharacterExprHelper{*builder, loc}
1708               .createEmboxChar(x.getBuffer(), x.getLen());
1709         },
1710         [&](const fir::MutableBoxValue &x) -> mlir::Value {
1711           mlir::Value resultRef = resultSymBox.getAddr();
1712           mlir::Value load = builder->create<fir::LoadOp>(loc, resultRef);
1713           unsigned rank = x.rank();
1714           if (x.isAllocatable() && rank > 0) {
1715             // ALLOCATABLE array result must have default lower bounds.
1716             // At the call site the result box of a function reference
1717             // might be considered having default lower bounds, but
1718             // the runtime box should probably comply with this assumption
1719             // as well. If the result box has proper lbounds in runtime,
1720             // this may improve the debugging experience of Fortran apps.
1721             // We may consider removing this, if the overhead of setting
1722             // default lower bounds is too big.
1723             mlir::Value one =
1724                 builder->createIntegerConstant(loc, builder->getIndexType(), 1);
1725             llvm::SmallVector<mlir::Value> lbounds{rank, one};
1726             auto shiftTy = fir::ShiftType::get(builder->getContext(), rank);
1727             mlir::Value shiftOp =
1728                 builder->create<fir::ShiftOp>(loc, shiftTy, lbounds);
1729             load = builder->create<fir::ReboxOp>(
1730                 loc, load.getType(), load, shiftOp, /*slice=*/mlir::Value{});
1731           }
1732           return load;
1733         },
1734         [&](const auto &) -> mlir::Value {
1735           mlir::Value resultRef = resultSymBox.getAddr();
1736           mlir::Type resultType = genType(resultSym);
1737           mlir::Type resultRefType = builder->getRefType(resultType);
1738           // A function with multiple entry points returning different types
1739           // tags all result variables with one of the largest types to allow
1740           // them to share the same storage. Convert this to the actual type.
1741           if (resultRef.getType() != resultRefType)
1742             resultRef = builder->createConvert(loc, resultRefType, resultRef);
1743           return builder->create<fir::LoadOp>(loc, resultRef);
1744         });
1745     genExitRoutine(false, resultVal);
1746   }
1747 
1748   /// Get the return value of a call to \p symbol, which is a subroutine entry
1749   /// point that has alternative return specifiers.
1750   const mlir::Value
1751   getAltReturnResult(const Fortran::semantics::Symbol &symbol) {
1752     assert(Fortran::semantics::HasAlternateReturns(symbol) &&
1753            "subroutine does not have alternate returns");
1754     return getSymbolAddress(symbol);
1755   }
1756 
1757   void genFIRProcedureExit(Fortran::lower::pft::FunctionLikeUnit &funit,
1758                            const Fortran::semantics::Symbol &symbol) {
1759     if (mlir::Block *finalBlock = funit.finalBlock) {
1760       // The current block must end with a terminator.
1761       if (blockIsUnterminated())
1762         builder->create<mlir::cf::BranchOp>(toLocation(), finalBlock);
1763       // Set insertion point to final block.
1764       builder->setInsertionPoint(finalBlock, finalBlock->end());
1765     }
1766     if (Fortran::semantics::IsFunction(symbol)) {
1767       genReturnSymbol(symbol);
1768     } else if (Fortran::semantics::HasAlternateReturns(symbol)) {
1769       mlir::Value retval = builder->create<fir::LoadOp>(
1770           toLocation(), getAltReturnResult(symbol));
1771       genExitRoutine(false, retval);
1772     } else {
1773       genExitRoutine(false);
1774     }
1775   }
1776 
1777   //
1778   // Statements that have control-flow semantics
1779   //
1780 
1781   /// Generate an If[Then]Stmt condition or its negation.
1782   template <typename A>
1783   mlir::Value genIfCondition(const A *stmt, bool negate = false) {
1784     mlir::Location loc = toLocation();
1785     Fortran::lower::StatementContext stmtCtx;
1786     mlir::Value condExpr = createFIRExpr(
1787         loc,
1788         Fortran::semantics::GetExpr(
1789             std::get<Fortran::parser::ScalarLogicalExpr>(stmt->t)),
1790         stmtCtx);
1791     stmtCtx.finalizeAndReset();
1792     mlir::Value cond =
1793         builder->createConvert(loc, builder->getI1Type(), condExpr);
1794     if (negate)
1795       cond = builder->create<mlir::arith::XOrIOp>(
1796           loc, cond, builder->createIntegerConstant(loc, cond.getType(), 1));
1797     return cond;
1798   }
1799 
1800   mlir::func::FuncOp getFunc(llvm::StringRef name, mlir::FunctionType ty) {
1801     if (mlir::func::FuncOp func = builder->getNamedFunction(name)) {
1802       assert(func.getFunctionType() == ty);
1803       return func;
1804     }
1805     return builder->createFunction(toLocation(), name, ty);
1806   }
1807 
1808   /// Lowering of CALL statement
1809   void genFIR(const Fortran::parser::CallStmt &stmt) {
1810     Fortran::lower::StatementContext stmtCtx;
1811     Fortran::lower::pft::Evaluation &eval = getEval();
1812     setCurrentPosition(stmt.source);
1813     assert(stmt.typedCall && "Call was not analyzed");
1814     mlir::Value res{};
1815     if (lowerToHighLevelFIR()) {
1816       std::optional<mlir::Type> resultType;
1817       if (stmt.typedCall->hasAlternateReturns())
1818         resultType = builder->getIndexType();
1819       auto hlfirRes = Fortran::lower::convertCallToHLFIR(
1820           toLocation(), *this, *stmt.typedCall, resultType, localSymbols,
1821           stmtCtx);
1822       if (hlfirRes)
1823         res = *hlfirRes;
1824     } else {
1825       // Call statement lowering shares code with function call lowering.
1826       res = Fortran::lower::createSubroutineCall(
1827           *this, *stmt.typedCall, explicitIterSpace, implicitIterSpace,
1828           localSymbols, stmtCtx, /*isUserDefAssignment=*/false);
1829     }
1830     stmtCtx.finalizeAndReset();
1831     if (!res)
1832       return; // "Normal" subroutine call.
1833     // Call with alternate return specifiers.
1834     // The call returns an index that selects an alternate return branch target.
1835     llvm::SmallVector<int64_t> indexList;
1836     llvm::SmallVector<Fortran::parser::Label> labelList;
1837     int64_t index = 0;
1838     for (const Fortran::parser::ActualArgSpec &arg :
1839          std::get<std::list<Fortran::parser::ActualArgSpec>>(stmt.call.t)) {
1840       const auto &actual = std::get<Fortran::parser::ActualArg>(arg.t);
1841       if (const auto *altReturn =
1842               std::get_if<Fortran::parser::AltReturnSpec>(&actual.u)) {
1843         indexList.push_back(++index);
1844         labelList.push_back(altReturn->v);
1845       }
1846     }
1847     genMultiwayBranch(res, indexList, labelList, eval.nonNopSuccessor());
1848   }
1849 
1850   void genFIR(const Fortran::parser::ComputedGotoStmt &stmt) {
1851     Fortran::lower::StatementContext stmtCtx;
1852     Fortran::lower::pft::Evaluation &eval = getEval();
1853     mlir::Value selectExpr =
1854         createFIRExpr(toLocation(),
1855                       Fortran::semantics::GetExpr(
1856                           std::get<Fortran::parser::ScalarIntExpr>(stmt.t)),
1857                       stmtCtx);
1858     stmtCtx.finalizeAndReset();
1859     llvm::SmallVector<int64_t> indexList;
1860     llvm::SmallVector<Fortran::parser::Label> labelList;
1861     int64_t index = 0;
1862     for (Fortran::parser::Label label :
1863          std::get<std::list<Fortran::parser::Label>>(stmt.t)) {
1864       indexList.push_back(++index);
1865       labelList.push_back(label);
1866     }
1867     genMultiwayBranch(selectExpr, indexList, labelList, eval.nonNopSuccessor());
1868   }
1869 
1870   void genFIR(const Fortran::parser::ArithmeticIfStmt &stmt) {
1871     Fortran::lower::StatementContext stmtCtx;
1872     mlir::Value expr = createFIRExpr(
1873         toLocation(),
1874         Fortran::semantics::GetExpr(std::get<Fortran::parser::Expr>(stmt.t)),
1875         stmtCtx);
1876     stmtCtx.finalizeAndReset();
1877     // Raise an exception if REAL expr is a NaN.
1878     if (mlir::isa<mlir::FloatType>(expr.getType()))
1879       expr = builder->create<mlir::arith::AddFOp>(toLocation(), expr, expr);
1880     // An empty valueList indicates to genMultiwayBranch that the branch is
1881     // an ArithmeticIfStmt that has two branches on value 0 or 0.0.
1882     llvm::SmallVector<int64_t> valueList;
1883     llvm::SmallVector<Fortran::parser::Label> labelList;
1884     labelList.push_back(std::get<1>(stmt.t));
1885     labelList.push_back(std::get<3>(stmt.t));
1886     const Fortran::lower::pft::LabelEvalMap &labelEvaluationMap =
1887         getEval().getOwningProcedure()->labelEvaluationMap;
1888     const auto iter = labelEvaluationMap.find(std::get<2>(stmt.t));
1889     assert(iter != labelEvaluationMap.end() && "label missing from map");
1890     genMultiwayBranch(expr, valueList, labelList, *iter->second);
1891   }
1892 
1893   void genFIR(const Fortran::parser::AssignedGotoStmt &stmt) {
1894     // See Fortran 90 Clause 8.2.4.
1895     // Relax the requirement that the GOTO variable must have a value in the
1896     // label list when a list is present, and allow a branch to any non-format
1897     // target that has an ASSIGN statement for the variable.
1898     mlir::Location loc = toLocation();
1899     Fortran::lower::pft::Evaluation &eval = getEval();
1900     Fortran::lower::pft::FunctionLikeUnit &owningProc =
1901         *eval.getOwningProcedure();
1902     const Fortran::lower::pft::SymbolLabelMap &symbolLabelMap =
1903         owningProc.assignSymbolLabelMap;
1904     const Fortran::lower::pft::LabelEvalMap &labelEvalMap =
1905         owningProc.labelEvaluationMap;
1906     const Fortran::semantics::Symbol &symbol =
1907         *std::get<Fortran::parser::Name>(stmt.t).symbol;
1908     auto labelSetIter = symbolLabelMap.find(symbol);
1909     llvm::SmallVector<int64_t> valueList;
1910     llvm::SmallVector<Fortran::parser::Label> labelList;
1911     if (labelSetIter != symbolLabelMap.end()) {
1912       for (auto &label : labelSetIter->second) {
1913         const auto evalIter = labelEvalMap.find(label);
1914         assert(evalIter != labelEvalMap.end() && "assigned goto label missing");
1915         if (evalIter->second->block) { // non-format statement
1916           valueList.push_back(label);  // label as an integer
1917           labelList.push_back(label);
1918         }
1919       }
1920     }
1921     if (!labelList.empty()) {
1922       auto selectExpr =
1923           builder->create<fir::LoadOp>(loc, getSymbolAddress(symbol));
1924       // Add a default error target in case the goto is nonconforming.
1925       mlir::Block *errorBlock =
1926           builder->getBlock()->splitBlock(builder->getInsertionPoint());
1927       genMultiwayBranch(selectExpr, valueList, labelList,
1928                         eval.nonNopSuccessor(), errorBlock);
1929       startBlock(errorBlock);
1930     }
1931     fir::runtime::genReportFatalUserError(
1932         *builder, loc,
1933         "Assigned GOTO variable '" + symbol.name().ToString() +
1934             "' does not have a valid target label value");
1935     builder->create<fir::UnreachableOp>(loc);
1936   }
1937 
1938   fir::ReduceOperationEnum
1939   getReduceOperationEnum(const Fortran::parser::ReductionOperator &rOpr) {
1940     switch (rOpr.v) {
1941     case Fortran::parser::ReductionOperator::Operator::Plus:
1942       return fir::ReduceOperationEnum::Add;
1943     case Fortran::parser::ReductionOperator::Operator::Multiply:
1944       return fir::ReduceOperationEnum::Multiply;
1945     case Fortran::parser::ReductionOperator::Operator::And:
1946       return fir::ReduceOperationEnum::AND;
1947     case Fortran::parser::ReductionOperator::Operator::Or:
1948       return fir::ReduceOperationEnum::OR;
1949     case Fortran::parser::ReductionOperator::Operator::Eqv:
1950       return fir::ReduceOperationEnum::EQV;
1951     case Fortran::parser::ReductionOperator::Operator::Neqv:
1952       return fir::ReduceOperationEnum::NEQV;
1953     case Fortran::parser::ReductionOperator::Operator::Max:
1954       return fir::ReduceOperationEnum::MAX;
1955     case Fortran::parser::ReductionOperator::Operator::Min:
1956       return fir::ReduceOperationEnum::MIN;
1957     case Fortran::parser::ReductionOperator::Operator::Iand:
1958       return fir::ReduceOperationEnum::IAND;
1959     case Fortran::parser::ReductionOperator::Operator::Ior:
1960       return fir::ReduceOperationEnum::IOR;
1961     case Fortran::parser::ReductionOperator::Operator::Ieor:
1962       return fir::ReduceOperationEnum::EIOR;
1963     }
1964     llvm_unreachable("illegal reduction operator");
1965   }
1966 
1967   /// Collect DO CONCURRENT or FORALL loop control information.
1968   IncrementLoopNestInfo getConcurrentControl(
1969       const Fortran::parser::ConcurrentHeader &header,
1970       const std::list<Fortran::parser::LocalitySpec> &localityList = {}) {
1971     IncrementLoopNestInfo incrementLoopNestInfo;
1972     for (const Fortran::parser::ConcurrentControl &control :
1973          std::get<std::list<Fortran::parser::ConcurrentControl>>(header.t))
1974       incrementLoopNestInfo.emplace_back(
1975           *std::get<0>(control.t).symbol, std::get<1>(control.t),
1976           std::get<2>(control.t), std::get<3>(control.t), /*isUnordered=*/true);
1977     IncrementLoopInfo &info = incrementLoopNestInfo.back();
1978     info.maskExpr = Fortran::semantics::GetExpr(
1979         std::get<std::optional<Fortran::parser::ScalarLogicalExpr>>(header.t));
1980     for (const Fortran::parser::LocalitySpec &x : localityList) {
1981       if (const auto *localList =
1982               std::get_if<Fortran::parser::LocalitySpec::Local>(&x.u))
1983         for (const Fortran::parser::Name &x : localList->v)
1984           info.localSymList.push_back(x.symbol);
1985       if (const auto *localInitList =
1986               std::get_if<Fortran::parser::LocalitySpec::LocalInit>(&x.u))
1987         for (const Fortran::parser::Name &x : localInitList->v)
1988           info.localInitSymList.push_back(x.symbol);
1989       for (IncrementLoopInfo &info : incrementLoopNestInfo) {
1990         if (const auto *reduceList =
1991                 std::get_if<Fortran::parser::LocalitySpec::Reduce>(&x.u)) {
1992           fir::ReduceOperationEnum reduce_operation = getReduceOperationEnum(
1993               std::get<Fortran::parser::ReductionOperator>(reduceList->t));
1994           for (const Fortran::parser::Name &x :
1995                std::get<std::list<Fortran::parser::Name>>(reduceList->t)) {
1996             info.reduceSymList.push_back(
1997                 std::make_pair(reduce_operation, x.symbol));
1998           }
1999         }
2000       }
2001       if (const auto *sharedList =
2002               std::get_if<Fortran::parser::LocalitySpec::Shared>(&x.u))
2003         for (const Fortran::parser::Name &x : sharedList->v)
2004           info.sharedSymList.push_back(x.symbol);
2005     }
2006     return incrementLoopNestInfo;
2007   }
2008 
2009   /// Create DO CONCURRENT construct symbol bindings and generate LOCAL_INIT
2010   /// assignments.
2011   void handleLocalitySpecs(const IncrementLoopInfo &info) {
2012     Fortran::semantics::SemanticsContext &semanticsContext =
2013         bridge.getSemanticsContext();
2014     for (const Fortran::semantics::Symbol *sym : info.localSymList)
2015       createHostAssociateVarClone(*sym, /*skipDefaultInit=*/false);
2016     for (const Fortran::semantics::Symbol *sym : info.localInitSymList) {
2017       createHostAssociateVarClone(*sym, /*skipDefaultInit=*/true);
2018       const auto *hostDetails =
2019           sym->detailsIf<Fortran::semantics::HostAssocDetails>();
2020       assert(hostDetails && "missing locality spec host symbol");
2021       const Fortran::semantics::Symbol *hostSym = &hostDetails->symbol();
2022       Fortran::evaluate::ExpressionAnalyzer ea{semanticsContext};
2023       Fortran::evaluate::Assignment assign{
2024           ea.Designate(Fortran::evaluate::DataRef{*sym}).value(),
2025           ea.Designate(Fortran::evaluate::DataRef{*hostSym}).value()};
2026       if (Fortran::semantics::IsPointer(*sym))
2027         assign.u = Fortran::evaluate::Assignment::BoundsSpec{};
2028       genAssignment(assign);
2029     }
2030     for (const Fortran::semantics::Symbol *sym : info.sharedSymList) {
2031       const auto *hostDetails =
2032           sym->detailsIf<Fortran::semantics::HostAssocDetails>();
2033       copySymbolBinding(hostDetails->symbol(), *sym);
2034     }
2035     // Note that allocatable, types with ultimate components, and type
2036     // requiring finalization are forbidden in LOCAL/LOCAL_INIT (F2023 C1130),
2037     // so no clean-up needs to be generated for these entities.
2038   }
2039 
2040   /// Generate FIR for a DO construct. There are six variants:
2041   ///  - unstructured infinite and while loops
2042   ///  - structured and unstructured increment loops
2043   ///  - structured and unstructured concurrent loops
2044   void genFIR(const Fortran::parser::DoConstruct &doConstruct) {
2045     setCurrentPositionAt(doConstruct);
2046     // Collect loop nest information.
2047     // Generate begin loop code directly for infinite and while loops.
2048     Fortran::lower::pft::Evaluation &eval = getEval();
2049     bool unstructuredContext = eval.lowerAsUnstructured();
2050     Fortran::lower::pft::Evaluation &doStmtEval =
2051         eval.getFirstNestedEvaluation();
2052     auto *doStmt = doStmtEval.getIf<Fortran::parser::NonLabelDoStmt>();
2053     const auto &loopControl =
2054         std::get<std::optional<Fortran::parser::LoopControl>>(doStmt->t);
2055     mlir::Block *preheaderBlock = doStmtEval.block;
2056     mlir::Block *beginBlock =
2057         preheaderBlock ? preheaderBlock : builder->getBlock();
2058     auto createNextBeginBlock = [&]() {
2059       // Step beginBlock through unstructured preheader, header, and mask
2060       // blocks, created in outermost to innermost order.
2061       return beginBlock = beginBlock->splitBlock(beginBlock->end());
2062     };
2063     mlir::Block *headerBlock =
2064         unstructuredContext ? createNextBeginBlock() : nullptr;
2065     mlir::Block *bodyBlock = doStmtEval.lexicalSuccessor->block;
2066     mlir::Block *exitBlock = doStmtEval.parentConstruct->constructExit->block;
2067     IncrementLoopNestInfo incrementLoopNestInfo;
2068     const Fortran::parser::ScalarLogicalExpr *whileCondition = nullptr;
2069     bool infiniteLoop = !loopControl.has_value();
2070     if (infiniteLoop) {
2071       assert(unstructuredContext && "infinite loop must be unstructured");
2072       startBlock(headerBlock);
2073     } else if ((whileCondition =
2074                     std::get_if<Fortran::parser::ScalarLogicalExpr>(
2075                         &loopControl->u))) {
2076       assert(unstructuredContext && "while loop must be unstructured");
2077       maybeStartBlock(preheaderBlock); // no block or empty block
2078       startBlock(headerBlock);
2079       genConditionalBranch(*whileCondition, bodyBlock, exitBlock);
2080     } else if (const auto *bounds =
2081                    std::get_if<Fortran::parser::LoopControl::Bounds>(
2082                        &loopControl->u)) {
2083       // Non-concurrent increment loop.
2084       IncrementLoopInfo &info = incrementLoopNestInfo.emplace_back(
2085           *bounds->name.thing.symbol, bounds->lower, bounds->upper,
2086           bounds->step);
2087       if (unstructuredContext) {
2088         maybeStartBlock(preheaderBlock);
2089         info.hasRealControl = info.loopVariableSym->GetType()->IsNumeric(
2090             Fortran::common::TypeCategory::Real);
2091         info.headerBlock = headerBlock;
2092         info.bodyBlock = bodyBlock;
2093         info.exitBlock = exitBlock;
2094       }
2095     } else {
2096       const auto *concurrent =
2097           std::get_if<Fortran::parser::LoopControl::Concurrent>(
2098               &loopControl->u);
2099       assert(concurrent && "invalid DO loop variant");
2100       incrementLoopNestInfo = getConcurrentControl(
2101           std::get<Fortran::parser::ConcurrentHeader>(concurrent->t),
2102           std::get<std::list<Fortran::parser::LocalitySpec>>(concurrent->t));
2103       if (unstructuredContext) {
2104         maybeStartBlock(preheaderBlock);
2105         for (IncrementLoopInfo &info : incrementLoopNestInfo) {
2106           // The original loop body provides the body and latch blocks of the
2107           // innermost dimension. The (first) body block of a non-innermost
2108           // dimension is the preheader block of the immediately enclosed
2109           // dimension. The latch block of a non-innermost dimension is the
2110           // exit block of the immediately enclosed dimension.
2111           auto createNextExitBlock = [&]() {
2112             // Create unstructured loop exit blocks, outermost to innermost.
2113             return exitBlock = insertBlock(exitBlock);
2114           };
2115           bool isInnermost = &info == &incrementLoopNestInfo.back();
2116           bool isOutermost = &info == &incrementLoopNestInfo.front();
2117           info.headerBlock = isOutermost ? headerBlock : createNextBeginBlock();
2118           info.bodyBlock = isInnermost ? bodyBlock : createNextBeginBlock();
2119           info.exitBlock = isOutermost ? exitBlock : createNextExitBlock();
2120           if (info.maskExpr)
2121             info.maskBlock = createNextBeginBlock();
2122         }
2123       }
2124     }
2125 
2126     // Increment loop begin code. (Infinite/while code was already generated.)
2127     if (!infiniteLoop && !whileCondition)
2128       genFIRIncrementLoopBegin(incrementLoopNestInfo, doStmtEval.dirs);
2129 
2130     // Loop body code.
2131     auto iter = eval.getNestedEvaluations().begin();
2132     for (auto end = --eval.getNestedEvaluations().end(); iter != end; ++iter)
2133       genFIR(*iter, unstructuredContext);
2134 
2135     // An EndDoStmt in unstructured code may start a new block.
2136     Fortran::lower::pft::Evaluation &endDoEval = *iter;
2137     assert(endDoEval.getIf<Fortran::parser::EndDoStmt>() && "no enddo stmt");
2138     if (unstructuredContext)
2139       maybeStartBlock(endDoEval.block);
2140 
2141     // Loop end code.
2142     if (infiniteLoop || whileCondition)
2143       genBranch(headerBlock);
2144     else
2145       genFIRIncrementLoopEnd(incrementLoopNestInfo);
2146 
2147     // This call may generate a branch in some contexts.
2148     genFIR(endDoEval, unstructuredContext);
2149   }
2150 
2151   /// Generate FIR to evaluate loop control values (lower, upper and step).
2152   mlir::Value genControlValue(const Fortran::lower::SomeExpr *expr,
2153                               const IncrementLoopInfo &info,
2154                               bool *isConst = nullptr) {
2155     mlir::Location loc = toLocation();
2156     mlir::Type controlType = info.isStructured() ? builder->getIndexType()
2157                                                  : info.getLoopVariableType();
2158     Fortran::lower::StatementContext stmtCtx;
2159     if (expr) {
2160       if (isConst)
2161         *isConst = Fortran::evaluate::IsConstantExpr(*expr);
2162       return builder->createConvert(loc, controlType,
2163                                     createFIRExpr(loc, expr, stmtCtx));
2164     }
2165 
2166     if (isConst)
2167       *isConst = true;
2168     if (info.hasRealControl)
2169       return builder->createRealConstant(loc, controlType, 1u);
2170     return builder->createIntegerConstant(loc, controlType, 1); // step
2171   }
2172 
2173   void addLoopAnnotationAttr(
2174       IncrementLoopInfo &info,
2175       llvm::SmallVectorImpl<const Fortran::parser::CompilerDirective *> &dirs) {
2176     mlir::BoolAttr f = mlir::BoolAttr::get(builder->getContext(), false);
2177     mlir::BoolAttr t = mlir::BoolAttr::get(builder->getContext(), true);
2178     mlir::LLVM::LoopVectorizeAttr va;
2179     mlir::LLVM::LoopUnrollAttr ua;
2180     bool has_attrs = false;
2181     for (const auto *dir : dirs) {
2182       Fortran::common::visit(
2183           Fortran::common::visitors{
2184               [&](const Fortran::parser::CompilerDirective::VectorAlways &) {
2185                 va = mlir::LLVM::LoopVectorizeAttr::get(builder->getContext(),
2186                                                         /*disable=*/f, {}, {},
2187                                                         {}, {}, {}, {});
2188                 has_attrs = true;
2189               },
2190               [&](const Fortran::parser::CompilerDirective::Unroll &u) {
2191                 mlir::IntegerAttr countAttr;
2192                 if (u.v.has_value()) {
2193                   countAttr = builder->getIntegerAttr(builder->getI64Type(),
2194                                                       u.v.value());
2195                 }
2196                 ua = mlir::LLVM::LoopUnrollAttr::get(
2197                     builder->getContext(), /*disable=*/f, /*count*/ countAttr,
2198                     {}, /*full*/ u.v.has_value() ? f : t, {}, {}, {});
2199                 has_attrs = true;
2200               },
2201               [&](const auto &) {}},
2202           dir->u);
2203     }
2204     mlir::LLVM::LoopAnnotationAttr la = mlir::LLVM::LoopAnnotationAttr::get(
2205         builder->getContext(), {}, /*vectorize=*/va, {}, /*unroll*/ ua, {}, {},
2206         {}, {}, {}, {}, {}, {}, {}, {}, {});
2207     if (has_attrs)
2208       info.doLoop.setLoopAnnotationAttr(la);
2209   }
2210 
2211   /// Generate FIR to begin a structured or unstructured increment loop nest.
2212   void genFIRIncrementLoopBegin(
2213       IncrementLoopNestInfo &incrementLoopNestInfo,
2214       llvm::SmallVectorImpl<const Fortran::parser::CompilerDirective *> &dirs) {
2215     assert(!incrementLoopNestInfo.empty() && "empty loop nest");
2216     mlir::Location loc = toLocation();
2217     mlir::Operation *boundsAndStepIP = nullptr;
2218     mlir::arith::IntegerOverflowFlags iofBackup{};
2219 
2220     for (IncrementLoopInfo &info : incrementLoopNestInfo) {
2221       mlir::Value lowerValue;
2222       mlir::Value upperValue;
2223       mlir::Value stepValue;
2224 
2225       {
2226         mlir::OpBuilder::InsertionGuard guard(*builder);
2227 
2228         // Set the IP before the first loop in the nest so that all nest bounds
2229         // and step values are created outside the nest.
2230         if (boundsAndStepIP)
2231           builder->setInsertionPointAfter(boundsAndStepIP);
2232 
2233         info.loopVariable = genLoopVariableAddress(loc, *info.loopVariableSym,
2234                                                    info.isUnordered);
2235         if (!getLoweringOptions().getIntegerWrapAround()) {
2236           iofBackup = builder->getIntegerOverflowFlags();
2237           builder->setIntegerOverflowFlags(
2238               mlir::arith::IntegerOverflowFlags::nsw);
2239         }
2240         lowerValue = genControlValue(info.lowerExpr, info);
2241         upperValue = genControlValue(info.upperExpr, info);
2242         bool isConst = true;
2243         stepValue = genControlValue(info.stepExpr, info,
2244                                     info.isStructured() ? nullptr : &isConst);
2245         if (!getLoweringOptions().getIntegerWrapAround())
2246           builder->setIntegerOverflowFlags(iofBackup);
2247         boundsAndStepIP = stepValue.getDefiningOp();
2248 
2249         // Use a temp variable for unstructured loops with non-const step.
2250         if (!isConst) {
2251           info.stepVariable =
2252               builder->createTemporary(loc, stepValue.getType());
2253           boundsAndStepIP =
2254               builder->create<fir::StoreOp>(loc, stepValue, info.stepVariable);
2255         }
2256       }
2257 
2258       // Structured loop - generate fir.do_loop.
2259       if (info.isStructured()) {
2260         mlir::Type loopVarType = info.getLoopVariableType();
2261         mlir::Value loopValue;
2262         if (info.isUnordered) {
2263           llvm::SmallVector<mlir::Value> reduceOperands;
2264           llvm::SmallVector<mlir::Attribute> reduceAttrs;
2265           // Create DO CONCURRENT reduce operands and attributes
2266           for (const auto &reduceSym : info.reduceSymList) {
2267             const fir::ReduceOperationEnum reduce_operation = reduceSym.first;
2268             const Fortran::semantics::Symbol *sym = reduceSym.second;
2269             fir::ExtendedValue exv = getSymbolExtendedValue(*sym, nullptr);
2270             reduceOperands.push_back(fir::getBase(exv));
2271             auto reduce_attr =
2272                 fir::ReduceAttr::get(builder->getContext(), reduce_operation);
2273             reduceAttrs.push_back(reduce_attr);
2274           }
2275           // The loop variable value is explicitly updated.
2276           info.doLoop = builder->create<fir::DoLoopOp>(
2277               loc, lowerValue, upperValue, stepValue, /*unordered=*/true,
2278               /*finalCountValue=*/false, /*iterArgs=*/std::nullopt,
2279               llvm::ArrayRef<mlir::Value>(reduceOperands), reduceAttrs);
2280           builder->setInsertionPointToStart(info.doLoop.getBody());
2281           loopValue = builder->createConvert(loc, loopVarType,
2282                                              info.doLoop.getInductionVar());
2283         } else {
2284           // The loop variable is a doLoop op argument.
2285           info.doLoop = builder->create<fir::DoLoopOp>(
2286               loc, lowerValue, upperValue, stepValue, /*unordered=*/false,
2287               /*finalCountValue=*/true,
2288               builder->createConvert(loc, loopVarType, lowerValue));
2289           builder->setInsertionPointToStart(info.doLoop.getBody());
2290           loopValue = info.doLoop.getRegionIterArgs()[0];
2291         }
2292         // Update the loop variable value in case it has non-index references.
2293         builder->create<fir::StoreOp>(loc, loopValue, info.loopVariable);
2294         if (info.maskExpr) {
2295           Fortran::lower::StatementContext stmtCtx;
2296           mlir::Value maskCond = createFIRExpr(loc, info.maskExpr, stmtCtx);
2297           stmtCtx.finalizeAndReset();
2298           mlir::Value maskCondCast =
2299               builder->createConvert(loc, builder->getI1Type(), maskCond);
2300           auto ifOp = builder->create<fir::IfOp>(loc, maskCondCast,
2301                                                  /*withElseRegion=*/false);
2302           builder->setInsertionPointToStart(&ifOp.getThenRegion().front());
2303         }
2304         if (info.hasLocalitySpecs())
2305           handleLocalitySpecs(info);
2306 
2307         addLoopAnnotationAttr(info, dirs);
2308         continue;
2309       }
2310 
2311       // Unstructured loop preheader - initialize tripVariable and loopVariable.
2312       mlir::Value tripCount;
2313       if (info.hasRealControl) {
2314         auto diff1 =
2315             builder->create<mlir::arith::SubFOp>(loc, upperValue, lowerValue);
2316         auto diff2 =
2317             builder->create<mlir::arith::AddFOp>(loc, diff1, stepValue);
2318         tripCount = builder->create<mlir::arith::DivFOp>(loc, diff2, stepValue);
2319         tripCount =
2320             builder->createConvert(loc, builder->getIndexType(), tripCount);
2321       } else {
2322         auto diff1 =
2323             builder->create<mlir::arith::SubIOp>(loc, upperValue, lowerValue);
2324         auto diff2 =
2325             builder->create<mlir::arith::AddIOp>(loc, diff1, stepValue);
2326         tripCount =
2327             builder->create<mlir::arith::DivSIOp>(loc, diff2, stepValue);
2328       }
2329       if (forceLoopToExecuteOnce) { // minimum tripCount is 1
2330         mlir::Value one =
2331             builder->createIntegerConstant(loc, tripCount.getType(), 1);
2332         auto cond = builder->create<mlir::arith::CmpIOp>(
2333             loc, mlir::arith::CmpIPredicate::slt, tripCount, one);
2334         tripCount =
2335             builder->create<mlir::arith::SelectOp>(loc, cond, one, tripCount);
2336       }
2337       info.tripVariable = builder->createTemporary(loc, tripCount.getType());
2338       builder->create<fir::StoreOp>(loc, tripCount, info.tripVariable);
2339       builder->create<fir::StoreOp>(loc, lowerValue, info.loopVariable);
2340 
2341       // Unstructured loop header - generate loop condition and mask.
2342       // Note - Currently there is no way to tag a loop as a concurrent loop.
2343       startBlock(info.headerBlock);
2344       tripCount = builder->create<fir::LoadOp>(loc, info.tripVariable);
2345       mlir::Value zero =
2346           builder->createIntegerConstant(loc, tripCount.getType(), 0);
2347       auto cond = builder->create<mlir::arith::CmpIOp>(
2348           loc, mlir::arith::CmpIPredicate::sgt, tripCount, zero);
2349       if (info.maskExpr) {
2350         genConditionalBranch(cond, info.maskBlock, info.exitBlock);
2351         startBlock(info.maskBlock);
2352         mlir::Block *latchBlock = getEval().getLastNestedEvaluation().block;
2353         assert(latchBlock && "missing masked concurrent loop latch block");
2354         Fortran::lower::StatementContext stmtCtx;
2355         mlir::Value maskCond = createFIRExpr(loc, info.maskExpr, stmtCtx);
2356         stmtCtx.finalizeAndReset();
2357         genConditionalBranch(maskCond, info.bodyBlock, latchBlock);
2358       } else {
2359         genConditionalBranch(cond, info.bodyBlock, info.exitBlock);
2360         if (&info != &incrementLoopNestInfo.back()) // not innermost
2361           startBlock(info.bodyBlock); // preheader block of enclosed dimension
2362       }
2363       if (info.hasLocalitySpecs()) {
2364         mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint();
2365         builder->setInsertionPointToStart(info.bodyBlock);
2366         handleLocalitySpecs(info);
2367         builder->restoreInsertionPoint(insertPt);
2368       }
2369     }
2370   }
2371 
2372   /// Generate FIR to end a structured or unstructured increment loop nest.
2373   void genFIRIncrementLoopEnd(IncrementLoopNestInfo &incrementLoopNestInfo) {
2374     assert(!incrementLoopNestInfo.empty() && "empty loop nest");
2375     mlir::Location loc = toLocation();
2376     mlir::arith::IntegerOverflowFlags flags{};
2377     if (!getLoweringOptions().getIntegerWrapAround())
2378       flags = bitEnumSet(flags, mlir::arith::IntegerOverflowFlags::nsw);
2379     auto iofAttr = mlir::arith::IntegerOverflowFlagsAttr::get(
2380         builder->getContext(), flags);
2381     for (auto it = incrementLoopNestInfo.rbegin(),
2382               rend = incrementLoopNestInfo.rend();
2383          it != rend; ++it) {
2384       IncrementLoopInfo &info = *it;
2385       if (info.isStructured()) {
2386         // End fir.do_loop.
2387         if (info.isUnordered) {
2388           builder->setInsertionPointAfter(info.doLoop);
2389           continue;
2390         }
2391         // Decrement tripVariable.
2392         builder->setInsertionPointToEnd(info.doLoop.getBody());
2393         llvm::SmallVector<mlir::Value, 2> results;
2394         results.push_back(builder->create<mlir::arith::AddIOp>(
2395             loc, info.doLoop.getInductionVar(), info.doLoop.getStep(),
2396             iofAttr));
2397         // Step loopVariable to help optimizations such as vectorization.
2398         // Induction variable elimination will clean up as necessary.
2399         mlir::Value step = builder->createConvert(
2400             loc, info.getLoopVariableType(), info.doLoop.getStep());
2401         mlir::Value loopVar =
2402             builder->create<fir::LoadOp>(loc, info.loopVariable);
2403         results.push_back(
2404             builder->create<mlir::arith::AddIOp>(loc, loopVar, step, iofAttr));
2405         builder->create<fir::ResultOp>(loc, results);
2406         builder->setInsertionPointAfter(info.doLoop);
2407         // The loop control variable may be used after the loop.
2408         builder->create<fir::StoreOp>(loc, info.doLoop.getResult(1),
2409                                       info.loopVariable);
2410         continue;
2411       }
2412 
2413       // Unstructured loop - decrement tripVariable and step loopVariable.
2414       mlir::Value tripCount =
2415           builder->create<fir::LoadOp>(loc, info.tripVariable);
2416       mlir::Value one =
2417           builder->createIntegerConstant(loc, tripCount.getType(), 1);
2418       tripCount = builder->create<mlir::arith::SubIOp>(loc, tripCount, one);
2419       builder->create<fir::StoreOp>(loc, tripCount, info.tripVariable);
2420       mlir::Value value = builder->create<fir::LoadOp>(loc, info.loopVariable);
2421       mlir::Value step;
2422       if (info.stepVariable)
2423         step = builder->create<fir::LoadOp>(loc, info.stepVariable);
2424       else
2425         step = genControlValue(info.stepExpr, info);
2426       if (info.hasRealControl)
2427         value = builder->create<mlir::arith::AddFOp>(loc, value, step);
2428       else
2429         value = builder->create<mlir::arith::AddIOp>(loc, value, step, iofAttr);
2430       builder->create<fir::StoreOp>(loc, value, info.loopVariable);
2431 
2432       genBranch(info.headerBlock);
2433       if (&info != &incrementLoopNestInfo.front()) // not outermost
2434         startBlock(info.exitBlock); // latch block of enclosing dimension
2435     }
2436   }
2437 
2438   /// Generate structured or unstructured FIR for an IF construct.
2439   /// The initial statement may be either an IfStmt or an IfThenStmt.
2440   void genFIR(const Fortran::parser::IfConstruct &) {
2441     Fortran::lower::pft::Evaluation &eval = getEval();
2442 
2443     // Structured fir.if nest.
2444     if (eval.lowerAsStructured()) {
2445       fir::IfOp topIfOp, currentIfOp;
2446       for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations()) {
2447         auto genIfOp = [&](mlir::Value cond) {
2448           Fortran::lower::pft::Evaluation &succ = *e.controlSuccessor;
2449           bool hasElse = succ.isA<Fortran::parser::ElseIfStmt>() ||
2450                          succ.isA<Fortran::parser::ElseStmt>();
2451           auto ifOp = builder->create<fir::IfOp>(toLocation(), cond,
2452                                                  /*withElseRegion=*/hasElse);
2453           builder->setInsertionPointToStart(&ifOp.getThenRegion().front());
2454           return ifOp;
2455         };
2456         setCurrentPosition(e.position);
2457         if (auto *s = e.getIf<Fortran::parser::IfThenStmt>()) {
2458           topIfOp = currentIfOp = genIfOp(genIfCondition(s, e.negateCondition));
2459         } else if (auto *s = e.getIf<Fortran::parser::IfStmt>()) {
2460           topIfOp = currentIfOp = genIfOp(genIfCondition(s, e.negateCondition));
2461         } else if (auto *s = e.getIf<Fortran::parser::ElseIfStmt>()) {
2462           builder->setInsertionPointToStart(
2463               &currentIfOp.getElseRegion().front());
2464           currentIfOp = genIfOp(genIfCondition(s));
2465         } else if (e.isA<Fortran::parser::ElseStmt>()) {
2466           builder->setInsertionPointToStart(
2467               &currentIfOp.getElseRegion().front());
2468         } else if (e.isA<Fortran::parser::EndIfStmt>()) {
2469           builder->setInsertionPointAfter(topIfOp);
2470           genFIR(e, /*unstructuredContext=*/false); // may generate branch
2471         } else {
2472           genFIR(e, /*unstructuredContext=*/false);
2473         }
2474       }
2475       return;
2476     }
2477 
2478     // Unstructured branch sequence.
2479     llvm::SmallVector<Fortran::lower::pft::Evaluation *> exits, fallThroughs;
2480     collectFinalEvaluations(eval, exits, fallThroughs);
2481 
2482     for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations()) {
2483       auto genIfBranch = [&](mlir::Value cond) {
2484         if (e.lexicalSuccessor == e.controlSuccessor) // empty block -> exit
2485           genConditionalBranch(cond, e.parentConstruct->constructExit,
2486                                e.controlSuccessor);
2487         else // non-empty block
2488           genConditionalBranch(cond, e.lexicalSuccessor, e.controlSuccessor);
2489       };
2490       setCurrentPosition(e.position);
2491       if (auto *s = e.getIf<Fortran::parser::IfThenStmt>()) {
2492         maybeStartBlock(e.block);
2493         genIfBranch(genIfCondition(s, e.negateCondition));
2494       } else if (auto *s = e.getIf<Fortran::parser::IfStmt>()) {
2495         maybeStartBlock(e.block);
2496         genIfBranch(genIfCondition(s, e.negateCondition));
2497       } else if (auto *s = e.getIf<Fortran::parser::ElseIfStmt>()) {
2498         startBlock(e.block);
2499         genIfBranch(genIfCondition(s));
2500       } else {
2501         genFIR(e);
2502         if (blockIsUnterminated()) {
2503           if (llvm::is_contained(exits, &e))
2504             genConstructExitBranch(*eval.constructExit);
2505           else if (llvm::is_contained(fallThroughs, &e))
2506             genBranch(e.lexicalSuccessor->block);
2507         }
2508       }
2509     }
2510   }
2511 
2512   void genCaseOrRankConstruct() {
2513     Fortran::lower::pft::Evaluation &eval = getEval();
2514     Fortran::lower::StatementContext stmtCtx;
2515     pushActiveConstruct(eval, stmtCtx);
2516 
2517     llvm::SmallVector<Fortran::lower::pft::Evaluation *> exits, fallThroughs;
2518     collectFinalEvaluations(eval, exits, fallThroughs);
2519 
2520     for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations()) {
2521       if (e.getIf<Fortran::parser::EndSelectStmt>())
2522         maybeStartBlock(e.block);
2523       else
2524         genFIR(e);
2525       if (blockIsUnterminated()) {
2526         if (llvm::is_contained(exits, &e))
2527           genConstructExitBranch(*eval.constructExit);
2528         else if (llvm::is_contained(fallThroughs, &e))
2529           genBranch(e.lexicalSuccessor->block);
2530       }
2531     }
2532     popActiveConstruct();
2533   }
2534   void genFIR(const Fortran::parser::CaseConstruct &) {
2535     genCaseOrRankConstruct();
2536   }
2537 
2538   template <typename A>
2539   void genNestedStatement(const Fortran::parser::Statement<A> &stmt) {
2540     setCurrentPosition(stmt.source);
2541     genFIR(stmt.statement);
2542   }
2543 
2544   /// Force the binding of an explicit symbol. This is used to bind and re-bind
2545   /// a concurrent control symbol to its value.
2546   void forceControlVariableBinding(const Fortran::semantics::Symbol *sym,
2547                                    mlir::Value inducVar) {
2548     mlir::Location loc = toLocation();
2549     assert(sym && "There must be a symbol to bind");
2550     mlir::Type toTy = genType(*sym);
2551     // FIXME: this should be a "per iteration" temporary.
2552     mlir::Value tmp =
2553         builder->createTemporary(loc, toTy, toStringRef(sym->name()),
2554                                  llvm::ArrayRef<mlir::NamedAttribute>{
2555                                      fir::getAdaptToByRefAttr(*builder)});
2556     mlir::Value cast = builder->createConvert(loc, toTy, inducVar);
2557     builder->create<fir::StoreOp>(loc, cast, tmp);
2558     addSymbol(*sym, tmp, /*force=*/true);
2559   }
2560 
2561   /// Process a concurrent header for a FORALL. (Concurrent headers for DO
2562   /// CONCURRENT loops are lowered elsewhere.)
2563   void genFIR(const Fortran::parser::ConcurrentHeader &header) {
2564     llvm::SmallVector<mlir::Value> lows;
2565     llvm::SmallVector<mlir::Value> highs;
2566     llvm::SmallVector<mlir::Value> steps;
2567     if (explicitIterSpace.isOutermostForall()) {
2568       // For the outermost forall, we evaluate the bounds expressions once.
2569       // Contrastingly, if this forall is nested, the bounds expressions are
2570       // assumed to be pure, possibly dependent on outer concurrent control
2571       // variables, possibly variant with respect to arguments, and will be
2572       // re-evaluated.
2573       mlir::Location loc = toLocation();
2574       mlir::Type idxTy = builder->getIndexType();
2575       Fortran::lower::StatementContext &stmtCtx =
2576           explicitIterSpace.stmtContext();
2577       auto lowerExpr = [&](auto &e) {
2578         return fir::getBase(genExprValue(e, stmtCtx));
2579       };
2580       for (const Fortran::parser::ConcurrentControl &ctrl :
2581            std::get<std::list<Fortran::parser::ConcurrentControl>>(header.t)) {
2582         const Fortran::lower::SomeExpr *lo =
2583             Fortran::semantics::GetExpr(std::get<1>(ctrl.t));
2584         const Fortran::lower::SomeExpr *hi =
2585             Fortran::semantics::GetExpr(std::get<2>(ctrl.t));
2586         auto &optStep =
2587             std::get<std::optional<Fortran::parser::ScalarIntExpr>>(ctrl.t);
2588         lows.push_back(builder->createConvert(loc, idxTy, lowerExpr(*lo)));
2589         highs.push_back(builder->createConvert(loc, idxTy, lowerExpr(*hi)));
2590         steps.push_back(
2591             optStep.has_value()
2592                 ? builder->createConvert(
2593                       loc, idxTy,
2594                       lowerExpr(*Fortran::semantics::GetExpr(*optStep)))
2595                 : builder->createIntegerConstant(loc, idxTy, 1));
2596       }
2597     }
2598     auto lambda = [&, lows, highs, steps]() {
2599       // Create our iteration space from the header spec.
2600       mlir::Location loc = toLocation();
2601       mlir::Type idxTy = builder->getIndexType();
2602       llvm::SmallVector<fir::DoLoopOp> loops;
2603       Fortran::lower::StatementContext &stmtCtx =
2604           explicitIterSpace.stmtContext();
2605       auto lowerExpr = [&](auto &e) {
2606         return fir::getBase(genExprValue(e, stmtCtx));
2607       };
2608       const bool outermost = !lows.empty();
2609       std::size_t headerIndex = 0;
2610       for (const Fortran::parser::ConcurrentControl &ctrl :
2611            std::get<std::list<Fortran::parser::ConcurrentControl>>(header.t)) {
2612         const Fortran::semantics::Symbol *ctrlVar =
2613             std::get<Fortran::parser::Name>(ctrl.t).symbol;
2614         mlir::Value lb;
2615         mlir::Value ub;
2616         mlir::Value by;
2617         if (outermost) {
2618           assert(headerIndex < lows.size());
2619           if (headerIndex == 0)
2620             explicitIterSpace.resetInnerArgs();
2621           lb = lows[headerIndex];
2622           ub = highs[headerIndex];
2623           by = steps[headerIndex++];
2624         } else {
2625           const Fortran::lower::SomeExpr *lo =
2626               Fortran::semantics::GetExpr(std::get<1>(ctrl.t));
2627           const Fortran::lower::SomeExpr *hi =
2628               Fortran::semantics::GetExpr(std::get<2>(ctrl.t));
2629           auto &optStep =
2630               std::get<std::optional<Fortran::parser::ScalarIntExpr>>(ctrl.t);
2631           lb = builder->createConvert(loc, idxTy, lowerExpr(*lo));
2632           ub = builder->createConvert(loc, idxTy, lowerExpr(*hi));
2633           by = optStep.has_value()
2634                    ? builder->createConvert(
2635                          loc, idxTy,
2636                          lowerExpr(*Fortran::semantics::GetExpr(*optStep)))
2637                    : builder->createIntegerConstant(loc, idxTy, 1);
2638         }
2639         auto lp = builder->create<fir::DoLoopOp>(
2640             loc, lb, ub, by, /*unordered=*/true,
2641             /*finalCount=*/false, explicitIterSpace.getInnerArgs());
2642         if ((!loops.empty() || !outermost) && !lp.getRegionIterArgs().empty())
2643           builder->create<fir::ResultOp>(loc, lp.getResults());
2644         explicitIterSpace.setInnerArgs(lp.getRegionIterArgs());
2645         builder->setInsertionPointToStart(lp.getBody());
2646         forceControlVariableBinding(ctrlVar, lp.getInductionVar());
2647         loops.push_back(lp);
2648       }
2649       if (outermost)
2650         explicitIterSpace.setOuterLoop(loops[0]);
2651       explicitIterSpace.appendLoops(loops);
2652       if (const auto &mask =
2653               std::get<std::optional<Fortran::parser::ScalarLogicalExpr>>(
2654                   header.t);
2655           mask.has_value()) {
2656         mlir::Type i1Ty = builder->getI1Type();
2657         fir::ExtendedValue maskExv =
2658             genExprValue(*Fortran::semantics::GetExpr(mask.value()), stmtCtx);
2659         mlir::Value cond =
2660             builder->createConvert(loc, i1Ty, fir::getBase(maskExv));
2661         auto ifOp = builder->create<fir::IfOp>(
2662             loc, explicitIterSpace.innerArgTypes(), cond,
2663             /*withElseRegion=*/true);
2664         builder->create<fir::ResultOp>(loc, ifOp.getResults());
2665         builder->setInsertionPointToStart(&ifOp.getElseRegion().front());
2666         builder->create<fir::ResultOp>(loc, explicitIterSpace.getInnerArgs());
2667         builder->setInsertionPointToStart(&ifOp.getThenRegion().front());
2668       }
2669     };
2670     // Push the lambda to gen the loop nest context.
2671     explicitIterSpace.pushLoopNest(lambda);
2672   }
2673 
2674   void genFIR(const Fortran::parser::ForallAssignmentStmt &stmt) {
2675     Fortran::common::visit([&](const auto &x) { genFIR(x); }, stmt.u);
2676   }
2677 
2678   void genFIR(const Fortran::parser::EndForallStmt &) {
2679     if (!lowerToHighLevelFIR())
2680       cleanupExplicitSpace();
2681   }
2682 
2683   template <typename A>
2684   void prepareExplicitSpace(const A &forall) {
2685     if (!explicitIterSpace.isActive())
2686       analyzeExplicitSpace(forall);
2687     localSymbols.pushScope();
2688     explicitIterSpace.enter();
2689   }
2690 
2691   /// Cleanup all the FORALL context information when we exit.
2692   void cleanupExplicitSpace() {
2693     explicitIterSpace.leave();
2694     localSymbols.popScope();
2695   }
2696 
2697   /// Generate FIR for a FORALL statement.
2698   void genFIR(const Fortran::parser::ForallStmt &stmt) {
2699     const auto &concurrentHeader =
2700         std::get<
2701             Fortran::common::Indirection<Fortran::parser::ConcurrentHeader>>(
2702             stmt.t)
2703             .value();
2704     if (lowerToHighLevelFIR()) {
2705       mlir::OpBuilder::InsertionGuard guard(*builder);
2706       Fortran::lower::SymMapScope scope(localSymbols);
2707       genForallNest(concurrentHeader);
2708       genFIR(std::get<Fortran::parser::UnlabeledStatement<
2709                  Fortran::parser::ForallAssignmentStmt>>(stmt.t)
2710                  .statement);
2711       return;
2712     }
2713     prepareExplicitSpace(stmt);
2714     genFIR(concurrentHeader);
2715     genFIR(std::get<Fortran::parser::UnlabeledStatement<
2716                Fortran::parser::ForallAssignmentStmt>>(stmt.t)
2717                .statement);
2718     cleanupExplicitSpace();
2719   }
2720 
2721   /// Generate FIR for a FORALL construct.
2722   void genFIR(const Fortran::parser::ForallConstruct &forall) {
2723     mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint();
2724     if (lowerToHighLevelFIR())
2725       localSymbols.pushScope();
2726     else
2727       prepareExplicitSpace(forall);
2728     genNestedStatement(
2729         std::get<
2730             Fortran::parser::Statement<Fortran::parser::ForallConstructStmt>>(
2731             forall.t));
2732     for (const Fortran::parser::ForallBodyConstruct &s :
2733          std::get<std::list<Fortran::parser::ForallBodyConstruct>>(forall.t)) {
2734       Fortran::common::visit(
2735           Fortran::common::visitors{
2736               [&](const Fortran::parser::WhereConstruct &b) { genFIR(b); },
2737               [&](const Fortran::common::Indirection<
2738                   Fortran::parser::ForallConstruct> &b) { genFIR(b.value()); },
2739               [&](const auto &b) { genNestedStatement(b); }},
2740           s.u);
2741     }
2742     genNestedStatement(
2743         std::get<Fortran::parser::Statement<Fortran::parser::EndForallStmt>>(
2744             forall.t));
2745     if (lowerToHighLevelFIR()) {
2746       localSymbols.popScope();
2747       builder->restoreInsertionPoint(insertPt);
2748     }
2749   }
2750 
2751   /// Lower the concurrent header specification.
2752   void genFIR(const Fortran::parser::ForallConstructStmt &stmt) {
2753     const auto &concurrentHeader =
2754         std::get<
2755             Fortran::common::Indirection<Fortran::parser::ConcurrentHeader>>(
2756             stmt.t)
2757             .value();
2758     if (lowerToHighLevelFIR())
2759       genForallNest(concurrentHeader);
2760     else
2761       genFIR(concurrentHeader);
2762   }
2763 
2764   /// Generate hlfir.forall and hlfir.forall_mask nest given a Forall
2765   /// concurrent header
2766   void genForallNest(const Fortran::parser::ConcurrentHeader &header) {
2767     mlir::Location loc = getCurrentLocation();
2768     const bool isOutterForall = !isInsideHlfirForallOrWhere();
2769     hlfir::ForallOp outerForall;
2770     auto evaluateControl = [&](const auto &parserExpr, mlir::Region &region,
2771                                bool isMask = false) {
2772       if (region.empty())
2773         builder->createBlock(&region);
2774       Fortran::lower::StatementContext localStmtCtx;
2775       const Fortran::semantics::SomeExpr *anlalyzedExpr =
2776           Fortran::semantics::GetExpr(parserExpr);
2777       assert(anlalyzedExpr && "expression semantics failed");
2778       // Generate the controls of outer forall outside of the hlfir.forall
2779       // region. They do not depend on any previous forall indices (C1123) and
2780       // no assignment has been made yet that could modify their value. This
2781       // will simplify hlfir.forall analysis because the SSA integer value
2782       // yielded will obviously not depend on any variable modified by the
2783       // forall when produced outside of it.
2784       // This is not done for the mask because it may (and in usual code, does)
2785       // depend on the forall indices that have just been defined as
2786       // hlfir.forall block arguments.
2787       mlir::OpBuilder::InsertPoint innerInsertionPoint;
2788       if (outerForall && !isMask) {
2789         innerInsertionPoint = builder->saveInsertionPoint();
2790         builder->setInsertionPoint(outerForall);
2791       }
2792       mlir::Value exprVal =
2793           fir::getBase(genExprValue(*anlalyzedExpr, localStmtCtx, &loc));
2794       localStmtCtx.finalizeAndPop();
2795       if (isMask)
2796         exprVal = builder->createConvert(loc, builder->getI1Type(), exprVal);
2797       if (innerInsertionPoint.isSet())
2798         builder->restoreInsertionPoint(innerInsertionPoint);
2799       builder->create<hlfir::YieldOp>(loc, exprVal);
2800     };
2801     for (const Fortran::parser::ConcurrentControl &control :
2802          std::get<std::list<Fortran::parser::ConcurrentControl>>(header.t)) {
2803       auto forallOp = builder->create<hlfir::ForallOp>(loc);
2804       if (isOutterForall && !outerForall)
2805         outerForall = forallOp;
2806       evaluateControl(std::get<1>(control.t), forallOp.getLbRegion());
2807       evaluateControl(std::get<2>(control.t), forallOp.getUbRegion());
2808       if (const auto &optionalStep =
2809               std::get<std::optional<Fortran::parser::ScalarIntExpr>>(
2810                   control.t))
2811         evaluateControl(*optionalStep, forallOp.getStepRegion());
2812       // Create block argument and map it to a symbol via an hlfir.forall_index
2813       // op (symbols must be mapped to in memory values).
2814       const Fortran::semantics::Symbol *controlVar =
2815           std::get<Fortran::parser::Name>(control.t).symbol;
2816       assert(controlVar && "symbol analysis failed");
2817       mlir::Type controlVarType = genType(*controlVar);
2818       mlir::Block *forallBody = builder->createBlock(&forallOp.getBody(), {},
2819                                                      {controlVarType}, {loc});
2820       auto forallIndex = builder->create<hlfir::ForallIndexOp>(
2821           loc, fir::ReferenceType::get(controlVarType),
2822           forallBody->getArguments()[0],
2823           builder->getStringAttr(controlVar->name().ToString()));
2824       localSymbols.addVariableDefinition(*controlVar, forallIndex,
2825                                          /*force=*/true);
2826       auto end = builder->create<fir::FirEndOp>(loc);
2827       builder->setInsertionPoint(end);
2828     }
2829 
2830     if (const auto &maskExpr =
2831             std::get<std::optional<Fortran::parser::ScalarLogicalExpr>>(
2832                 header.t)) {
2833       // Create hlfir.forall_mask and set insertion point in its body.
2834       auto forallMaskOp = builder->create<hlfir::ForallMaskOp>(loc);
2835       evaluateControl(*maskExpr, forallMaskOp.getMaskRegion(), /*isMask=*/true);
2836       builder->createBlock(&forallMaskOp.getBody());
2837       auto end = builder->create<fir::FirEndOp>(loc);
2838       builder->setInsertionPoint(end);
2839     }
2840   }
2841 
2842   void attachDirectiveToLoop(const Fortran::parser::CompilerDirective &dir,
2843                              Fortran::lower::pft::Evaluation *e) {
2844     while (e->isDirective())
2845       e = e->lexicalSuccessor;
2846 
2847     if (e->isA<Fortran::parser::NonLabelDoStmt>())
2848       e->dirs.push_back(&dir);
2849   }
2850 
2851   void genFIR(const Fortran::parser::CompilerDirective &dir) {
2852     Fortran::lower::pft::Evaluation &eval = getEval();
2853 
2854     Fortran::common::visit(
2855         Fortran::common::visitors{
2856             [&](const Fortran::parser::CompilerDirective::VectorAlways &) {
2857               attachDirectiveToLoop(dir, &eval);
2858             },
2859             [&](const Fortran::parser::CompilerDirective::Unroll &) {
2860               attachDirectiveToLoop(dir, &eval);
2861             },
2862             [&](const auto &) {}},
2863         dir.u);
2864   }
2865 
2866   void genFIR(const Fortran::parser::OpenACCConstruct &acc) {
2867     mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint();
2868     localSymbols.pushScope();
2869     mlir::Value exitCond = genOpenACCConstruct(
2870         *this, bridge.getSemanticsContext(), getEval(), acc);
2871 
2872     const Fortran::parser::OpenACCLoopConstruct *accLoop =
2873         std::get_if<Fortran::parser::OpenACCLoopConstruct>(&acc.u);
2874     const Fortran::parser::OpenACCCombinedConstruct *accCombined =
2875         std::get_if<Fortran::parser::OpenACCCombinedConstruct>(&acc.u);
2876 
2877     Fortran::lower::pft::Evaluation *curEval = &getEval();
2878 
2879     if (accLoop || accCombined) {
2880       int64_t collapseValue;
2881       if (accLoop) {
2882         const Fortran::parser::AccBeginLoopDirective &beginLoopDir =
2883             std::get<Fortran::parser::AccBeginLoopDirective>(accLoop->t);
2884         const Fortran::parser::AccClauseList &clauseList =
2885             std::get<Fortran::parser::AccClauseList>(beginLoopDir.t);
2886         collapseValue = Fortran::lower::getCollapseValue(clauseList);
2887       } else if (accCombined) {
2888         const Fortran::parser::AccBeginCombinedDirective &beginCombinedDir =
2889             std::get<Fortran::parser::AccBeginCombinedDirective>(
2890                 accCombined->t);
2891         const Fortran::parser::AccClauseList &clauseList =
2892             std::get<Fortran::parser::AccClauseList>(beginCombinedDir.t);
2893         collapseValue = Fortran::lower::getCollapseValue(clauseList);
2894       }
2895 
2896       if (curEval->lowerAsStructured()) {
2897         curEval = &curEval->getFirstNestedEvaluation();
2898         for (int64_t i = 1; i < collapseValue; i++)
2899           curEval = &*std::next(curEval->getNestedEvaluations().begin());
2900       }
2901     }
2902 
2903     for (Fortran::lower::pft::Evaluation &e : curEval->getNestedEvaluations())
2904       genFIR(e);
2905     localSymbols.popScope();
2906     builder->restoreInsertionPoint(insertPt);
2907 
2908     if (accLoop && exitCond) {
2909       Fortran::lower::pft::FunctionLikeUnit *funit =
2910           getEval().getOwningProcedure();
2911       assert(funit && "not inside main program, function or subroutine");
2912       mlir::Block *continueBlock =
2913           builder->getBlock()->splitBlock(builder->getBlock()->end());
2914       builder->create<mlir::cf::CondBranchOp>(toLocation(), exitCond,
2915                                               funit->finalBlock, continueBlock);
2916       builder->setInsertionPointToEnd(continueBlock);
2917     }
2918   }
2919 
2920   void genFIR(const Fortran::parser::OpenACCDeclarativeConstruct &accDecl) {
2921     genOpenACCDeclarativeConstruct(*this, bridge.getSemanticsContext(),
2922                                    bridge.openAccCtx(), accDecl,
2923                                    accRoutineInfos);
2924     for (Fortran::lower::pft::Evaluation &e : getEval().getNestedEvaluations())
2925       genFIR(e);
2926   }
2927 
2928   void genFIR(const Fortran::parser::OpenACCRoutineConstruct &acc) {
2929     // Handled by genFIR(const Fortran::parser::OpenACCDeclarativeConstruct &)
2930   }
2931 
2932   void genFIR(const Fortran::parser::CUFKernelDoConstruct &kernel) {
2933     Fortran::lower::SymMapScope scope(localSymbols);
2934     const Fortran::parser::CUFKernelDoConstruct::Directive &dir =
2935         std::get<Fortran::parser::CUFKernelDoConstruct::Directive>(kernel.t);
2936 
2937     mlir::Location loc = genLocation(dir.source);
2938 
2939     Fortran::lower::StatementContext stmtCtx;
2940 
2941     unsigned nestedLoops = 1;
2942 
2943     const auto &nLoops =
2944         std::get<std::optional<Fortran::parser::ScalarIntConstantExpr>>(dir.t);
2945     if (nLoops)
2946       nestedLoops = *Fortran::semantics::GetIntValue(*nLoops);
2947 
2948     mlir::IntegerAttr n;
2949     if (nestedLoops > 1)
2950       n = builder->getIntegerAttr(builder->getI64Type(), nestedLoops);
2951 
2952     const auto &launchConfig = std::get<std::optional<
2953         Fortran::parser::CUFKernelDoConstruct::LaunchConfiguration>>(dir.t);
2954 
2955     const std::list<Fortran::parser::CUFReduction> &cufreds =
2956         std::get<2>(dir.t);
2957 
2958     llvm::SmallVector<mlir::Value> reduceOperands;
2959     llvm::SmallVector<mlir::Attribute> reduceAttrs;
2960 
2961     for (const Fortran::parser::CUFReduction &cufred : cufreds) {
2962       fir::ReduceOperationEnum redOpEnum = getReduceOperationEnum(
2963           std::get<Fortran::parser::ReductionOperator>(cufred.t));
2964       const std::list<Fortran::parser::Scalar<Fortran::parser::Variable>>
2965           &scalarvars = std::get<1>(cufred.t);
2966       for (const Fortran::parser::Scalar<Fortran::parser::Variable> &scalarvar :
2967            scalarvars) {
2968         auto reduce_attr =
2969             fir::ReduceAttr::get(builder->getContext(), redOpEnum);
2970         reduceAttrs.push_back(reduce_attr);
2971         const Fortran::parser::Variable &var = scalarvar.thing;
2972         if (const auto *iDesignator = std::get_if<
2973                 Fortran::common::Indirection<Fortran::parser::Designator>>(
2974                 &var.u)) {
2975           const Fortran::parser::Designator &designator = iDesignator->value();
2976           if (const auto *name =
2977                   Fortran::semantics::getDesignatorNameIfDataRef(designator)) {
2978             auto val = getSymbolAddress(*name->symbol);
2979             reduceOperands.push_back(val);
2980           }
2981         }
2982       }
2983     }
2984 
2985     auto isOnlyStars =
2986         [&](const std::list<Fortran::parser::CUFKernelDoConstruct::StarOrExpr>
2987                 &list) -> bool {
2988       for (const Fortran::parser::CUFKernelDoConstruct::StarOrExpr &expr :
2989            list) {
2990         if (expr.v)
2991           return false;
2992       }
2993       return true;
2994     };
2995 
2996     mlir::Value zero =
2997         builder->createIntegerConstant(loc, builder->getI32Type(), 0);
2998 
2999     llvm::SmallVector<mlir::Value> gridValues;
3000     llvm::SmallVector<mlir::Value> blockValues;
3001     mlir::Value streamValue;
3002 
3003     if (launchConfig) {
3004       const std::list<Fortran::parser::CUFKernelDoConstruct::StarOrExpr> &grid =
3005           std::get<0>(launchConfig->t);
3006       const std::list<Fortran::parser::CUFKernelDoConstruct::StarOrExpr>
3007           &block = std::get<1>(launchConfig->t);
3008       const std::optional<Fortran::parser::ScalarIntExpr> &stream =
3009           std::get<2>(launchConfig->t);
3010       if (!isOnlyStars(grid)) {
3011         for (const Fortran::parser::CUFKernelDoConstruct::StarOrExpr &expr :
3012              grid) {
3013           if (expr.v) {
3014             gridValues.push_back(fir::getBase(
3015                 genExprValue(*Fortran::semantics::GetExpr(*expr.v), stmtCtx)));
3016           } else {
3017             gridValues.push_back(zero);
3018           }
3019         }
3020       }
3021       if (!isOnlyStars(block)) {
3022         for (const Fortran::parser::CUFKernelDoConstruct::StarOrExpr &expr :
3023              block) {
3024           if (expr.v) {
3025             blockValues.push_back(fir::getBase(
3026                 genExprValue(*Fortran::semantics::GetExpr(*expr.v), stmtCtx)));
3027           } else {
3028             blockValues.push_back(zero);
3029           }
3030         }
3031       }
3032 
3033       if (stream)
3034         streamValue = builder->createConvert(
3035             loc, builder->getI32Type(),
3036             fir::getBase(
3037                 genExprValue(*Fortran::semantics::GetExpr(*stream), stmtCtx)));
3038     }
3039 
3040     const auto &outerDoConstruct =
3041         std::get<std::optional<Fortran::parser::DoConstruct>>(kernel.t);
3042 
3043     llvm::SmallVector<mlir::Location> locs;
3044     locs.push_back(loc);
3045     llvm::SmallVector<mlir::Value> lbs, ubs, steps;
3046 
3047     mlir::Type idxTy = builder->getIndexType();
3048 
3049     llvm::SmallVector<mlir::Type> ivTypes;
3050     llvm::SmallVector<mlir::Location> ivLocs;
3051     llvm::SmallVector<mlir::Value> ivValues;
3052     Fortran::lower::pft::Evaluation *loopEval =
3053         &getEval().getFirstNestedEvaluation();
3054     for (unsigned i = 0; i < nestedLoops; ++i) {
3055       const Fortran::parser::LoopControl *loopControl;
3056       mlir::Location crtLoc = loc;
3057       if (i == 0) {
3058         loopControl = &*outerDoConstruct->GetLoopControl();
3059         crtLoc =
3060             genLocation(Fortran::parser::FindSourceLocation(outerDoConstruct));
3061       } else {
3062         auto *doCons = loopEval->getIf<Fortran::parser::DoConstruct>();
3063         assert(doCons && "expect do construct");
3064         loopControl = &*doCons->GetLoopControl();
3065         crtLoc = genLocation(Fortran::parser::FindSourceLocation(*doCons));
3066       }
3067 
3068       locs.push_back(crtLoc);
3069 
3070       const Fortran::parser::LoopControl::Bounds *bounds =
3071           std::get_if<Fortran::parser::LoopControl::Bounds>(&loopControl->u);
3072       assert(bounds && "Expected bounds on the loop construct");
3073 
3074       Fortran::semantics::Symbol &ivSym =
3075           bounds->name.thing.symbol->GetUltimate();
3076       ivValues.push_back(getSymbolAddress(ivSym));
3077 
3078       lbs.push_back(builder->createConvert(
3079           crtLoc, idxTy,
3080           fir::getBase(genExprValue(*Fortran::semantics::GetExpr(bounds->lower),
3081                                     stmtCtx))));
3082       ubs.push_back(builder->createConvert(
3083           crtLoc, idxTy,
3084           fir::getBase(genExprValue(*Fortran::semantics::GetExpr(bounds->upper),
3085                                     stmtCtx))));
3086       if (bounds->step)
3087         steps.push_back(builder->createConvert(
3088             crtLoc, idxTy,
3089             fir::getBase(genExprValue(
3090                 *Fortran::semantics::GetExpr(bounds->step), stmtCtx))));
3091       else // If `step` is not present, assume it is `1`.
3092         steps.push_back(builder->createIntegerConstant(loc, idxTy, 1));
3093 
3094       ivTypes.push_back(idxTy);
3095       ivLocs.push_back(crtLoc);
3096       if (i < nestedLoops - 1)
3097         loopEval = &*std::next(loopEval->getNestedEvaluations().begin());
3098     }
3099 
3100     auto op = builder->create<cuf::KernelOp>(
3101         loc, gridValues, blockValues, streamValue, lbs, ubs, steps, n,
3102         mlir::ValueRange(reduceOperands), builder->getArrayAttr(reduceAttrs));
3103     builder->createBlock(&op.getRegion(), op.getRegion().end(), ivTypes,
3104                          ivLocs);
3105     mlir::Block &b = op.getRegion().back();
3106     builder->setInsertionPointToStart(&b);
3107 
3108     Fortran::lower::pft::Evaluation *crtEval = &getEval();
3109     if (crtEval->lowerAsUnstructured())
3110       Fortran::lower::createEmptyRegionBlocks<fir::FirEndOp>(
3111           *builder, crtEval->getNestedEvaluations());
3112     builder->setInsertionPointToStart(&b);
3113 
3114     for (auto [arg, value] : llvm::zip(
3115              op.getLoopRegions().front()->front().getArguments(), ivValues)) {
3116       mlir::Value convArg =
3117           builder->createConvert(loc, fir::unwrapRefType(value.getType()), arg);
3118       builder->create<fir::StoreOp>(loc, convArg, value);
3119     }
3120 
3121     if (crtEval->lowerAsStructured()) {
3122       crtEval = &crtEval->getFirstNestedEvaluation();
3123       for (int64_t i = 1; i < nestedLoops; i++)
3124         crtEval = &*std::next(crtEval->getNestedEvaluations().begin());
3125     }
3126 
3127     // Generate loop body
3128     for (Fortran::lower::pft::Evaluation &e : crtEval->getNestedEvaluations())
3129       genFIR(e);
3130 
3131     builder->create<fir::FirEndOp>(loc);
3132     builder->setInsertionPointAfter(op);
3133   }
3134 
3135   void genFIR(const Fortran::parser::OpenMPConstruct &omp) {
3136     mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint();
3137     genOpenMPConstruct(*this, localSymbols, bridge.getSemanticsContext(),
3138                        getEval(), omp);
3139     builder->restoreInsertionPoint(insertPt);
3140 
3141     // Register if a target region was found
3142     ompDeviceCodeFound =
3143         ompDeviceCodeFound || Fortran::lower::isOpenMPTargetConstruct(omp);
3144   }
3145 
3146   void genFIR(const Fortran::parser::OpenMPDeclarativeConstruct &ompDecl) {
3147     mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint();
3148     // Register if a declare target construct intended for a target device was
3149     // found
3150     ompDeviceCodeFound =
3151         ompDeviceCodeFound ||
3152         Fortran::lower::isOpenMPDeviceDeclareTarget(
3153             *this, bridge.getSemanticsContext(), getEval(), ompDecl);
3154     Fortran::lower::gatherOpenMPDeferredDeclareTargets(
3155         *this, bridge.getSemanticsContext(), getEval(), ompDecl,
3156         ompDeferredDeclareTarget);
3157     genOpenMPDeclarativeConstruct(
3158         *this, localSymbols, bridge.getSemanticsContext(), getEval(), ompDecl);
3159     builder->restoreInsertionPoint(insertPt);
3160   }
3161 
3162   /// Generate FIR for a SELECT CASE statement.
3163   /// The selector may have CHARACTER, INTEGER, UNSIGNED, or LOGICAL type.
3164   void genFIR(const Fortran::parser::SelectCaseStmt &stmt) {
3165     Fortran::lower::pft::Evaluation &eval = getEval();
3166     Fortran::lower::pft::Evaluation *parentConstruct = eval.parentConstruct;
3167     assert(!activeConstructStack.empty() &&
3168            &activeConstructStack.back().eval == parentConstruct &&
3169            "select case construct is not active");
3170     Fortran::lower::StatementContext &stmtCtx =
3171         activeConstructStack.back().stmtCtx;
3172     const Fortran::lower::SomeExpr *expr = Fortran::semantics::GetExpr(
3173         std::get<Fortran::parser::Scalar<Fortran::parser::Expr>>(stmt.t));
3174     bool isCharSelector = isCharacterCategory(expr->GetType()->category());
3175     bool isLogicalSelector = isLogicalCategory(expr->GetType()->category());
3176     mlir::MLIRContext *context = builder->getContext();
3177     mlir::Location loc = toLocation();
3178     auto charValue = [&](const Fortran::lower::SomeExpr *expr) {
3179       fir::ExtendedValue exv = genExprAddr(*expr, stmtCtx, &loc);
3180       return exv.match(
3181           [&](const fir::CharBoxValue &cbv) {
3182             return fir::factory::CharacterExprHelper{*builder, loc}
3183                 .createEmboxChar(cbv.getAddr(), cbv.getLen());
3184           },
3185           [&](auto) {
3186             fir::emitFatalError(loc, "not a character");
3187             return mlir::Value{};
3188           });
3189     };
3190     mlir::Value selector;
3191     if (isCharSelector) {
3192       selector = charValue(expr);
3193     } else {
3194       selector = createFIRExpr(loc, expr, stmtCtx);
3195       if (isLogicalSelector)
3196         selector = builder->createConvert(loc, builder->getI1Type(), selector);
3197     }
3198     mlir::Type selectType = selector.getType();
3199     if (selectType.isUnsignedInteger())
3200       selectType = mlir::IntegerType::get(
3201           builder->getContext(), selectType.getIntOrFloatBitWidth(),
3202           mlir::IntegerType::SignednessSemantics::Signless);
3203     llvm::SmallVector<mlir::Attribute> attrList;
3204     llvm::SmallVector<mlir::Value> valueList;
3205     llvm::SmallVector<mlir::Block *> blockList;
3206     mlir::Block *defaultBlock = parentConstruct->constructExit->block;
3207     using CaseValue = Fortran::parser::Scalar<Fortran::parser::ConstantExpr>;
3208     auto addValue = [&](const CaseValue &caseValue) {
3209       const Fortran::lower::SomeExpr *expr =
3210           Fortran::semantics::GetExpr(caseValue.thing);
3211       if (isCharSelector)
3212         valueList.push_back(charValue(expr));
3213       else if (isLogicalSelector)
3214         valueList.push_back(builder->createConvert(
3215             loc, selectType, createFIRExpr(toLocation(), expr, stmtCtx)));
3216       else {
3217         valueList.push_back(builder->createIntegerConstant(
3218             loc, selectType, *Fortran::evaluate::ToInt64(*expr)));
3219       }
3220     };
3221     for (Fortran::lower::pft::Evaluation *e = eval.controlSuccessor; e;
3222          e = e->controlSuccessor) {
3223       const auto &caseStmt = e->getIf<Fortran::parser::CaseStmt>();
3224       assert(e->block && "missing CaseStmt block");
3225       const auto &caseSelector =
3226           std::get<Fortran::parser::CaseSelector>(caseStmt->t);
3227       const auto *caseValueRangeList =
3228           std::get_if<std::list<Fortran::parser::CaseValueRange>>(
3229               &caseSelector.u);
3230       if (!caseValueRangeList) {
3231         defaultBlock = e->block;
3232         continue;
3233       }
3234       for (const Fortran::parser::CaseValueRange &caseValueRange :
3235            *caseValueRangeList) {
3236         blockList.push_back(e->block);
3237         if (const auto *caseValue = std::get_if<CaseValue>(&caseValueRange.u)) {
3238           attrList.push_back(fir::PointIntervalAttr::get(context));
3239           addValue(*caseValue);
3240           continue;
3241         }
3242         const auto &caseRange =
3243             std::get<Fortran::parser::CaseValueRange::Range>(caseValueRange.u);
3244         if (caseRange.lower && caseRange.upper) {
3245           attrList.push_back(fir::ClosedIntervalAttr::get(context));
3246           addValue(*caseRange.lower);
3247           addValue(*caseRange.upper);
3248         } else if (caseRange.lower) {
3249           attrList.push_back(fir::LowerBoundAttr::get(context));
3250           addValue(*caseRange.lower);
3251         } else {
3252           attrList.push_back(fir::UpperBoundAttr::get(context));
3253           addValue(*caseRange.upper);
3254         }
3255       }
3256     }
3257     // Skip a logical default block that can never be referenced.
3258     if (isLogicalSelector && attrList.size() == 2)
3259       defaultBlock = parentConstruct->constructExit->block;
3260     attrList.push_back(mlir::UnitAttr::get(context));
3261     blockList.push_back(defaultBlock);
3262 
3263     // Generate a fir::SelectCaseOp. Explicit branch code is better for the
3264     // LOGICAL type. The CHARACTER type does not have downstream SelectOp
3265     // support. The -no-structured-fir option can be used to force generation
3266     // of INTEGER type branch code.
3267     if (!isLogicalSelector && !isCharSelector &&
3268         !getEval().forceAsUnstructured()) {
3269       // The selector is in an ssa register. Any temps that may have been
3270       // generated while evaluating it can be cleaned up now.
3271       stmtCtx.finalizeAndReset();
3272       builder->create<fir::SelectCaseOp>(loc, selector, attrList, valueList,
3273                                          blockList);
3274       return;
3275     }
3276 
3277     // Generate a sequence of case value comparisons and branches.
3278     auto caseValue = valueList.begin();
3279     auto caseBlock = blockList.begin();
3280     for (mlir::Attribute attr : attrList) {
3281       if (mlir::isa<mlir::UnitAttr>(attr)) {
3282         genBranch(*caseBlock++);
3283         break;
3284       }
3285       auto genCond = [&](mlir::Value rhs,
3286                          mlir::arith::CmpIPredicate pred) -> mlir::Value {
3287         if (!isCharSelector)
3288           return builder->create<mlir::arith::CmpIOp>(loc, pred, selector, rhs);
3289         fir::factory::CharacterExprHelper charHelper{*builder, loc};
3290         std::pair<mlir::Value, mlir::Value> lhsVal =
3291             charHelper.createUnboxChar(selector);
3292         std::pair<mlir::Value, mlir::Value> rhsVal =
3293             charHelper.createUnboxChar(rhs);
3294         return fir::runtime::genCharCompare(*builder, loc, pred, lhsVal.first,
3295                                             lhsVal.second, rhsVal.first,
3296                                             rhsVal.second);
3297       };
3298       mlir::Block *newBlock = insertBlock(*caseBlock);
3299       if (mlir::isa<fir::ClosedIntervalAttr>(attr)) {
3300         mlir::Block *newBlock2 = insertBlock(*caseBlock);
3301         mlir::Value cond =
3302             genCond(*caseValue++, mlir::arith::CmpIPredicate::sge);
3303         genConditionalBranch(cond, newBlock, newBlock2);
3304         builder->setInsertionPointToEnd(newBlock);
3305         mlir::Value cond2 =
3306             genCond(*caseValue++, mlir::arith::CmpIPredicate::sle);
3307         genConditionalBranch(cond2, *caseBlock++, newBlock2);
3308         builder->setInsertionPointToEnd(newBlock2);
3309         continue;
3310       }
3311       mlir::arith::CmpIPredicate pred;
3312       if (mlir::isa<fir::PointIntervalAttr>(attr)) {
3313         pred = mlir::arith::CmpIPredicate::eq;
3314       } else if (mlir::isa<fir::LowerBoundAttr>(attr)) {
3315         pred = mlir::arith::CmpIPredicate::sge;
3316       } else {
3317         assert(mlir::isa<fir::UpperBoundAttr>(attr) && "unexpected predicate");
3318         pred = mlir::arith::CmpIPredicate::sle;
3319       }
3320       mlir::Value cond = genCond(*caseValue++, pred);
3321       genConditionalBranch(cond, *caseBlock++, newBlock);
3322       builder->setInsertionPointToEnd(newBlock);
3323     }
3324     assert(caseValue == valueList.end() && caseBlock == blockList.end() &&
3325            "select case list mismatch");
3326   }
3327 
3328   fir::ExtendedValue
3329   genAssociateSelector(const Fortran::lower::SomeExpr &selector,
3330                        Fortran::lower::StatementContext &stmtCtx) {
3331     if (lowerToHighLevelFIR())
3332       return genExprAddr(selector, stmtCtx);
3333     return Fortran::lower::isArraySectionWithoutVectorSubscript(selector)
3334                ? Fortran::lower::createSomeArrayBox(*this, selector,
3335                                                     localSymbols, stmtCtx)
3336                : genExprAddr(selector, stmtCtx);
3337   }
3338 
3339   void genFIR(const Fortran::parser::AssociateConstruct &) {
3340     Fortran::lower::pft::Evaluation &eval = getEval();
3341     Fortran::lower::StatementContext stmtCtx;
3342     pushActiveConstruct(eval, stmtCtx);
3343     for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations()) {
3344       setCurrentPosition(e.position);
3345       if (auto *stmt = e.getIf<Fortran::parser::AssociateStmt>()) {
3346         if (eval.lowerAsUnstructured())
3347           maybeStartBlock(e.block);
3348         localSymbols.pushScope();
3349         for (const Fortran::parser::Association &assoc :
3350              std::get<std::list<Fortran::parser::Association>>(stmt->t)) {
3351           Fortran::semantics::Symbol &sym =
3352               *std::get<Fortran::parser::Name>(assoc.t).symbol;
3353           const Fortran::lower::SomeExpr &selector =
3354               *sym.get<Fortran::semantics::AssocEntityDetails>().expr();
3355           addSymbol(sym, genAssociateSelector(selector, stmtCtx));
3356         }
3357       } else if (e.getIf<Fortran::parser::EndAssociateStmt>()) {
3358         if (eval.lowerAsUnstructured())
3359           maybeStartBlock(e.block);
3360         localSymbols.popScope();
3361       } else {
3362         genFIR(e);
3363       }
3364     }
3365     popActiveConstruct();
3366   }
3367 
3368   void genFIR(const Fortran::parser::BlockConstruct &blockConstruct) {
3369     Fortran::lower::pft::Evaluation &eval = getEval();
3370     Fortran::lower::StatementContext stmtCtx;
3371     pushActiveConstruct(eval, stmtCtx);
3372     for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations()) {
3373       setCurrentPosition(e.position);
3374       if (e.getIf<Fortran::parser::BlockStmt>()) {
3375         if (eval.lowerAsUnstructured())
3376           maybeStartBlock(e.block);
3377         const Fortran::parser::CharBlock &endPosition =
3378             eval.getLastNestedEvaluation().position;
3379         localSymbols.pushScope();
3380         mlir::Value stackPtr = builder->genStackSave(toLocation());
3381         mlir::Location endLoc = genLocation(endPosition);
3382         stmtCtx.attachCleanup(
3383             [=]() { builder->genStackRestore(endLoc, stackPtr); });
3384         Fortran::semantics::Scope &scope =
3385             bridge.getSemanticsContext().FindScope(endPosition);
3386         scopeBlockIdMap.try_emplace(&scope, ++blockId);
3387         Fortran::lower::AggregateStoreMap storeMap;
3388         for (const Fortran::lower::pft::Variable &var :
3389              Fortran::lower::pft::getScopeVariableList(scope)) {
3390           // Do no instantiate again variables from the block host
3391           // that appears in specification of block variables.
3392           if (!var.hasSymbol() || !lookupSymbol(var.getSymbol()))
3393             instantiateVar(var, storeMap);
3394         }
3395       } else if (e.getIf<Fortran::parser::EndBlockStmt>()) {
3396         if (eval.lowerAsUnstructured())
3397           maybeStartBlock(e.block);
3398         localSymbols.popScope();
3399       } else {
3400         genFIR(e);
3401       }
3402     }
3403     popActiveConstruct();
3404   }
3405 
3406   void genFIR(const Fortran::parser::ChangeTeamConstruct &construct) {
3407     TODO(toLocation(), "coarray: ChangeTeamConstruct");
3408   }
3409   void genFIR(const Fortran::parser::ChangeTeamStmt &stmt) {
3410     TODO(toLocation(), "coarray: ChangeTeamStmt");
3411   }
3412   void genFIR(const Fortran::parser::EndChangeTeamStmt &stmt) {
3413     TODO(toLocation(), "coarray: EndChangeTeamStmt");
3414   }
3415 
3416   void genFIR(const Fortran::parser::CriticalConstruct &criticalConstruct) {
3417     setCurrentPositionAt(criticalConstruct);
3418     TODO(toLocation(), "coarray: CriticalConstruct");
3419   }
3420   void genFIR(const Fortran::parser::CriticalStmt &) {
3421     TODO(toLocation(), "coarray: CriticalStmt");
3422   }
3423   void genFIR(const Fortran::parser::EndCriticalStmt &) {
3424     TODO(toLocation(), "coarray: EndCriticalStmt");
3425   }
3426 
3427   void genFIR(const Fortran::parser::SelectRankConstruct &selectRankConstruct) {
3428     setCurrentPositionAt(selectRankConstruct);
3429     genCaseOrRankConstruct();
3430   }
3431 
3432   void genFIR(const Fortran::parser::SelectRankStmt &selectRankStmt) {
3433     // Generate a fir.select_case with the selector rank. The RANK(*) case,
3434     // if any, is handles with a conditional branch before the fir.select_case.
3435     mlir::Type rankType = builder->getIntegerType(8);
3436     mlir::MLIRContext *context = builder->getContext();
3437     mlir::Location loc = toLocation();
3438     // Build block list for fir.select_case, and identify RANK(*) block, if any.
3439     // Default block must be placed last in the fir.select_case block list.
3440     mlir::Block *rankStarBlock = nullptr;
3441     Fortran::lower::pft::Evaluation &eval = getEval();
3442     mlir::Block *defaultBlock = eval.parentConstruct->constructExit->block;
3443     llvm::SmallVector<mlir::Attribute> attrList;
3444     llvm::SmallVector<mlir::Value> valueList;
3445     llvm::SmallVector<mlir::Block *> blockList;
3446     for (Fortran::lower::pft::Evaluation *e = eval.controlSuccessor; e;
3447          e = e->controlSuccessor) {
3448       if (const auto *rankCaseStmt =
3449               e->getIf<Fortran::parser::SelectRankCaseStmt>()) {
3450         const auto &rank = std::get<Fortran::parser::SelectRankCaseStmt::Rank>(
3451             rankCaseStmt->t);
3452         assert(e->block && "missing SelectRankCaseStmt block");
3453         Fortran::common::visit(
3454             Fortran::common::visitors{
3455                 [&](const Fortran::parser::ScalarIntConstantExpr &rankExpr) {
3456                   blockList.emplace_back(e->block);
3457                   attrList.emplace_back(fir::PointIntervalAttr::get(context));
3458                   std::optional<std::int64_t> rankCst =
3459                       Fortran::evaluate::ToInt64(
3460                           Fortran::semantics::GetExpr(rankExpr));
3461                   assert(rankCst.has_value() &&
3462                          "rank expr must be constant integer");
3463                   valueList.emplace_back(
3464                       builder->createIntegerConstant(loc, rankType, *rankCst));
3465                 },
3466                 [&](const Fortran::parser::Star &) {
3467                   rankStarBlock = e->block;
3468                 },
3469                 [&](const Fortran::parser::Default &) {
3470                   defaultBlock = e->block;
3471                 }},
3472             rank.u);
3473       }
3474     }
3475     attrList.push_back(mlir::UnitAttr::get(context));
3476     blockList.push_back(defaultBlock);
3477 
3478     // Lower selector.
3479     assert(!activeConstructStack.empty() && "must be inside construct");
3480     assert(!activeConstructStack.back().selector &&
3481            "selector should not yet be set");
3482     Fortran::lower::StatementContext &stmtCtx =
3483         activeConstructStack.back().stmtCtx;
3484     const Fortran::lower::SomeExpr *selectorExpr = Fortran::common::visit(
3485         [](const auto &x) { return Fortran::semantics::GetExpr(x); },
3486         std::get<Fortran::parser::Selector>(selectRankStmt.t).u);
3487     assert(selectorExpr && "failed to retrieve selector expr");
3488     hlfir::Entity selector = Fortran::lower::convertExprToHLFIR(
3489         loc, *this, *selectorExpr, localSymbols, stmtCtx);
3490     activeConstructStack.back().selector = selector;
3491 
3492     // Deal with assumed-size first. They must fall into RANK(*) if present, or
3493     // the default case (F'2023 11.1.10.2.). The selector cannot be an
3494     // assumed-size if it is allocatable or pointer, so the check is skipped.
3495     if (!Fortran::evaluate::IsAllocatableOrPointerObject(*selectorExpr)) {
3496       mlir::Value isAssumedSize = builder->create<fir::IsAssumedSizeOp>(
3497           loc, builder->getI1Type(), selector);
3498       // Create new block to hold the fir.select_case for the non assumed-size
3499       // cases.
3500       mlir::Block *selectCaseBlock = insertBlock(blockList[0]);
3501       mlir::Block *assumedSizeBlock =
3502           rankStarBlock ? rankStarBlock : defaultBlock;
3503       builder->create<mlir::cf::CondBranchOp>(loc, isAssumedSize,
3504                                               assumedSizeBlock, std::nullopt,
3505                                               selectCaseBlock, std::nullopt);
3506       startBlock(selectCaseBlock);
3507     }
3508     // Create fir.select_case for the other rank cases.
3509     mlir::Value rank = builder->create<fir::BoxRankOp>(loc, rankType, selector);
3510     stmtCtx.finalizeAndReset();
3511     builder->create<fir::SelectCaseOp>(loc, rank, attrList, valueList,
3512                                        blockList);
3513   }
3514 
3515   // Get associating entity symbol inside case statement scope.
3516   static const Fortran::semantics::Symbol &
3517   getAssociatingEntitySymbol(const Fortran::semantics::Scope &scope) {
3518     const Fortran::semantics::Symbol *assocSym = nullptr;
3519     for (const auto &sym : scope.GetSymbols()) {
3520       if (sym->has<Fortran::semantics::AssocEntityDetails>()) {
3521         assert(!assocSym &&
3522                "expect only one associating entity symbol in this scope");
3523         assocSym = &*sym;
3524       }
3525     }
3526     assert(assocSym && "should contain associating entity symbol");
3527     return *assocSym;
3528   }
3529 
3530   void genFIR(const Fortran::parser::SelectRankCaseStmt &stmt) {
3531     assert(!activeConstructStack.empty() &&
3532            "must be inside select rank construct");
3533     // Pop previous associating entity mapping, if any, and push scope for new
3534     // mapping.
3535     if (activeConstructStack.back().pushedScope)
3536       localSymbols.popScope();
3537     localSymbols.pushScope();
3538     activeConstructStack.back().pushedScope = true;
3539     const Fortran::semantics::Symbol &assocEntitySymbol =
3540         getAssociatingEntitySymbol(
3541             bridge.getSemanticsContext().FindScope(getEval().position));
3542     const auto &details =
3543         assocEntitySymbol.get<Fortran::semantics::AssocEntityDetails>();
3544     assert(!activeConstructStack.empty() &&
3545            activeConstructStack.back().selector.has_value() &&
3546            "selector must have been created");
3547     // Get lowered value for the selector.
3548     hlfir::Entity selector = *activeConstructStack.back().selector;
3549     assert(selector.isVariable() && "assumed-rank selector are variables");
3550     // Cook selector mlir::Value according to rank case and map it to
3551     // associating entity symbol.
3552     Fortran::lower::StatementContext stmtCtx;
3553     mlir::Location loc = toLocation();
3554     if (details.IsAssumedRank()) {
3555       fir::ExtendedValue selectorExv = Fortran::lower::translateToExtendedValue(
3556           loc, *builder, selector, stmtCtx);
3557       addSymbol(assocEntitySymbol, selectorExv);
3558     } else if (details.IsAssumedSize()) {
3559       // Create rank-1 assumed-size from descriptor. Assumed-size are contiguous
3560       // so a new entity can be built from scratch using the base address, type
3561       // parameters and dynamic type. The selector cannot be a
3562       // POINTER/ALLOCATBLE as per F'2023 C1160.
3563       fir::ExtendedValue newExv;
3564       llvm::SmallVector assumeSizeExtents{
3565           builder->createMinusOneInteger(loc, builder->getIndexType())};
3566       mlir::Value baseAddr =
3567           hlfir::genVariableRawAddress(loc, *builder, selector);
3568       mlir::Type eleType =
3569           fir::unwrapSequenceType(fir::unwrapRefType(baseAddr.getType()));
3570       mlir::Type rank1Type =
3571           fir::ReferenceType::get(builder->getVarLenSeqTy(eleType, 1));
3572       baseAddr = builder->createConvert(loc, rank1Type, baseAddr);
3573       if (selector.isCharacter()) {
3574         mlir::Value len = hlfir::genCharLength(loc, *builder, selector);
3575         newExv = fir::CharArrayBoxValue{baseAddr, len, assumeSizeExtents};
3576       } else if (selector.isDerivedWithLengthParameters()) {
3577         TODO(loc, "RANK(*) with parameterized derived type selector");
3578       } else if (selector.isPolymorphic()) {
3579         TODO(loc, "RANK(*) with polymorphic selector");
3580       } else {
3581         // Simple intrinsic or derived type.
3582         newExv = fir::ArrayBoxValue{baseAddr, assumeSizeExtents};
3583       }
3584       addSymbol(assocEntitySymbol, newExv);
3585     } else {
3586       int rank = details.rank().value();
3587       auto boxTy =
3588           mlir::cast<fir::BaseBoxType>(fir::unwrapRefType(selector.getType()));
3589       mlir::Type newBoxType = boxTy.getBoxTypeWithNewShape(rank);
3590       if (fir::isa_ref_type(selector.getType()))
3591         newBoxType = fir::ReferenceType::get(newBoxType);
3592       // Give rank info to value via cast, and get rid of the box if not needed
3593       // (simple scalars, contiguous arrays... This is done by
3594       // translateVariableToExtendedValue).
3595       hlfir::Entity rankedBox{
3596           builder->createConvert(loc, newBoxType, selector)};
3597       bool isSimplyContiguous = Fortran::evaluate::IsSimplyContiguous(
3598           assocEntitySymbol, getFoldingContext());
3599       fir::ExtendedValue newExv = Fortran::lower::translateToExtendedValue(
3600           loc, *builder, rankedBox, stmtCtx, isSimplyContiguous);
3601 
3602       // Non deferred length parameters of character allocatable/pointer
3603       // MutableBoxValue should be properly set before binding it to a symbol in
3604       // order to get correct assignment semantics.
3605       if (const fir::MutableBoxValue *mutableBox =
3606               newExv.getBoxOf<fir::MutableBoxValue>()) {
3607         if (selector.isCharacter()) {
3608           auto dynamicType =
3609               Fortran::evaluate::DynamicType::From(assocEntitySymbol);
3610           if (!dynamicType.value().HasDeferredTypeParameter()) {
3611             llvm::SmallVector<mlir::Value> lengthParams;
3612             hlfir::genLengthParameters(loc, *builder, selector, lengthParams);
3613             newExv = fir::MutableBoxValue{rankedBox, lengthParams,
3614                                           mutableBox->getMutableProperties()};
3615           }
3616         }
3617       }
3618       addSymbol(assocEntitySymbol, newExv);
3619     }
3620     // Statements inside rank case are lowered by SelectRankConstruct visit.
3621   }
3622 
3623   void genFIR(const Fortran::parser::SelectTypeConstruct &selectTypeConstruct) {
3624     mlir::MLIRContext *context = builder->getContext();
3625     Fortran::lower::StatementContext stmtCtx;
3626     fir::ExtendedValue selector;
3627     llvm::SmallVector<mlir::Attribute> attrList;
3628     llvm::SmallVector<mlir::Block *> blockList;
3629     unsigned typeGuardIdx = 0;
3630     std::size_t defaultAttrPos = std::numeric_limits<size_t>::max();
3631     bool hasLocalScope = false;
3632     llvm::SmallVector<const Fortran::semantics::Scope *> typeCaseScopes;
3633 
3634     const auto &typeCaseList =
3635         std::get<std::list<Fortran::parser::SelectTypeConstruct::TypeCase>>(
3636             selectTypeConstruct.t);
3637     for (const auto &typeCase : typeCaseList) {
3638       const auto &stmt =
3639           std::get<Fortran::parser::Statement<Fortran::parser::TypeGuardStmt>>(
3640               typeCase.t);
3641       const Fortran::semantics::Scope &scope =
3642           bridge.getSemanticsContext().FindScope(stmt.source);
3643       typeCaseScopes.push_back(&scope);
3644     }
3645 
3646     pushActiveConstruct(getEval(), stmtCtx);
3647     llvm::SmallVector<Fortran::lower::pft::Evaluation *> exits, fallThroughs;
3648     collectFinalEvaluations(getEval(), exits, fallThroughs);
3649     Fortran::lower::pft::Evaluation &constructExit = *getEval().constructExit;
3650 
3651     for (Fortran::lower::pft::Evaluation &eval :
3652          getEval().getNestedEvaluations()) {
3653       setCurrentPosition(eval.position);
3654       mlir::Location loc = toLocation();
3655       if (auto *selectTypeStmt =
3656               eval.getIf<Fortran::parser::SelectTypeStmt>()) {
3657         // A genFIR(SelectTypeStmt) call would have unwanted side effects.
3658         maybeStartBlock(eval.block);
3659         // Retrieve the selector
3660         const auto &s = std::get<Fortran::parser::Selector>(selectTypeStmt->t);
3661         if (const auto *v = std::get_if<Fortran::parser::Variable>(&s.u))
3662           selector = genExprBox(loc, *Fortran::semantics::GetExpr(*v), stmtCtx);
3663         else if (const auto *e = std::get_if<Fortran::parser::Expr>(&s.u))
3664           selector = genExprBox(loc, *Fortran::semantics::GetExpr(*e), stmtCtx);
3665 
3666         // Going through the controlSuccessor first to create the
3667         // fir.select_type operation.
3668         mlir::Block *defaultBlock = eval.parentConstruct->constructExit->block;
3669         for (Fortran::lower::pft::Evaluation *e = eval.controlSuccessor; e;
3670              e = e->controlSuccessor) {
3671           const auto &typeGuardStmt =
3672               e->getIf<Fortran::parser::TypeGuardStmt>();
3673           const auto &guard =
3674               std::get<Fortran::parser::TypeGuardStmt::Guard>(typeGuardStmt->t);
3675           assert(e->block && "missing TypeGuardStmt block");
3676           // CLASS DEFAULT
3677           if (std::holds_alternative<Fortran::parser::Default>(guard.u)) {
3678             defaultBlock = e->block;
3679             // Keep track of the actual position of the CLASS DEFAULT type guard
3680             // in the SELECT TYPE construct.
3681             defaultAttrPos = attrList.size();
3682             continue;
3683           }
3684 
3685           blockList.push_back(e->block);
3686           if (const auto *typeSpec =
3687                   std::get_if<Fortran::parser::TypeSpec>(&guard.u)) {
3688             // TYPE IS
3689             mlir::Type ty;
3690             if (std::holds_alternative<Fortran::parser::IntrinsicTypeSpec>(
3691                     typeSpec->u)) {
3692               const Fortran::semantics::IntrinsicTypeSpec *intrinsic =
3693                   typeSpec->declTypeSpec->AsIntrinsic();
3694               int kind =
3695                   Fortran::evaluate::ToInt64(intrinsic->kind()).value_or(kind);
3696               llvm::SmallVector<Fortran::lower::LenParameterTy> params;
3697               ty = genType(intrinsic->category(), kind, params);
3698             } else {
3699               const Fortran::semantics::DerivedTypeSpec *derived =
3700                   typeSpec->declTypeSpec->AsDerived();
3701               ty = genType(*derived);
3702             }
3703             attrList.push_back(fir::ExactTypeAttr::get(ty));
3704           } else if (const auto *derived =
3705                          std::get_if<Fortran::parser::DerivedTypeSpec>(
3706                              &guard.u)) {
3707             // CLASS IS
3708             assert(derived->derivedTypeSpec && "derived type spec is null");
3709             mlir::Type ty = genType(*(derived->derivedTypeSpec));
3710             attrList.push_back(fir::SubclassAttr::get(ty));
3711           }
3712         }
3713         attrList.push_back(mlir::UnitAttr::get(context));
3714         blockList.push_back(defaultBlock);
3715         builder->create<fir::SelectTypeOp>(loc, fir::getBase(selector),
3716                                            attrList, blockList);
3717 
3718         // If the actual position of CLASS DEFAULT type guard is not the last
3719         // one, it needs to be put back at its correct position for the rest of
3720         // the processing. TypeGuardStmt are processed in the same order they
3721         // appear in the Fortran code.
3722         if (defaultAttrPos < attrList.size() - 1) {
3723           auto attrIt = attrList.begin();
3724           attrIt = attrIt + defaultAttrPos;
3725           auto blockIt = blockList.begin();
3726           blockIt = blockIt + defaultAttrPos;
3727           attrList.insert(attrIt, mlir::UnitAttr::get(context));
3728           blockList.insert(blockIt, defaultBlock);
3729           attrList.pop_back();
3730           blockList.pop_back();
3731         }
3732       } else if (auto *typeGuardStmt =
3733                      eval.getIf<Fortran::parser::TypeGuardStmt>()) {
3734         // Map the type guard local symbol for the selector to a more precise
3735         // typed entity in the TypeGuardStmt when necessary.
3736         genFIR(eval);
3737         const auto &guard =
3738             std::get<Fortran::parser::TypeGuardStmt::Guard>(typeGuardStmt->t);
3739         if (hasLocalScope)
3740           localSymbols.popScope();
3741         localSymbols.pushScope();
3742         hasLocalScope = true;
3743         assert(attrList.size() >= typeGuardIdx &&
3744                "TypeGuard attribute missing");
3745         mlir::Attribute typeGuardAttr = attrList[typeGuardIdx];
3746         mlir::Block *typeGuardBlock = blockList[typeGuardIdx];
3747         mlir::OpBuilder::InsertPoint crtInsPt = builder->saveInsertionPoint();
3748         builder->setInsertionPointToStart(typeGuardBlock);
3749 
3750         auto addAssocEntitySymbol = [&](fir::ExtendedValue exv) {
3751           for (auto &symbol : typeCaseScopes[typeGuardIdx]->GetSymbols()) {
3752             if (symbol->GetUltimate()
3753                     .detailsIf<Fortran::semantics::AssocEntityDetails>()) {
3754               addSymbol(symbol, exv);
3755               break;
3756             }
3757           }
3758         };
3759 
3760         mlir::Type baseTy = fir::getBase(selector).getType();
3761         bool isPointer = fir::isPointerType(baseTy);
3762         bool isAllocatable = fir::isAllocatableType(baseTy);
3763         bool isArray =
3764             mlir::isa<fir::SequenceType>(fir::dyn_cast_ptrOrBoxEleTy(baseTy));
3765         const fir::BoxValue *selectorBox = selector.getBoxOf<fir::BoxValue>();
3766         if (std::holds_alternative<Fortran::parser::Default>(guard.u)) {
3767           // CLASS DEFAULT
3768           addAssocEntitySymbol(selector);
3769         } else if (const auto *typeSpec =
3770                        std::get_if<Fortran::parser::TypeSpec>(&guard.u)) {
3771           // TYPE IS
3772           fir::ExactTypeAttr attr =
3773               mlir::dyn_cast<fir::ExactTypeAttr>(typeGuardAttr);
3774           mlir::Value exactValue;
3775           mlir::Type addrTy = attr.getType();
3776           if (isArray) {
3777             auto seqTy = mlir::dyn_cast<fir::SequenceType>(
3778                 fir::dyn_cast_ptrOrBoxEleTy(baseTy));
3779             addrTy = fir::SequenceType::get(seqTy.getShape(), attr.getType());
3780           }
3781           if (isPointer)
3782             addrTy = fir::PointerType::get(addrTy);
3783           if (isAllocatable)
3784             addrTy = fir::HeapType::get(addrTy);
3785           if (std::holds_alternative<Fortran::parser::IntrinsicTypeSpec>(
3786                   typeSpec->u)) {
3787             mlir::Type refTy = fir::ReferenceType::get(addrTy);
3788             if (isPointer || isAllocatable)
3789               refTy = addrTy;
3790             exactValue = builder->create<fir::BoxAddrOp>(
3791                 loc, refTy, fir::getBase(selector));
3792             const Fortran::semantics::IntrinsicTypeSpec *intrinsic =
3793                 typeSpec->declTypeSpec->AsIntrinsic();
3794             if (isArray) {
3795               mlir::Value exact = builder->create<fir::ConvertOp>(
3796                   loc, fir::BoxType::get(addrTy), fir::getBase(selector));
3797               addAssocEntitySymbol(selectorBox->clone(exact));
3798             } else if (intrinsic->category() ==
3799                        Fortran::common::TypeCategory::Character) {
3800               auto charTy = mlir::dyn_cast<fir::CharacterType>(attr.getType());
3801               mlir::Value charLen =
3802                   fir::factory::CharacterExprHelper(*builder, loc)
3803                       .readLengthFromBox(fir::getBase(selector), charTy);
3804               addAssocEntitySymbol(fir::CharBoxValue(exactValue, charLen));
3805             } else {
3806               addAssocEntitySymbol(exactValue);
3807             }
3808           } else if (std::holds_alternative<Fortran::parser::DerivedTypeSpec>(
3809                          typeSpec->u)) {
3810             exactValue = builder->create<fir::ConvertOp>(
3811                 loc, fir::BoxType::get(addrTy), fir::getBase(selector));
3812             addAssocEntitySymbol(selectorBox->clone(exactValue));
3813           }
3814         } else if (std::holds_alternative<Fortran::parser::DerivedTypeSpec>(
3815                        guard.u)) {
3816           // CLASS IS
3817           fir::SubclassAttr attr =
3818               mlir::dyn_cast<fir::SubclassAttr>(typeGuardAttr);
3819           mlir::Type addrTy = attr.getType();
3820           if (isArray) {
3821             auto seqTy = mlir::dyn_cast<fir::SequenceType>(
3822                 fir::dyn_cast_ptrOrBoxEleTy(baseTy));
3823             addrTy = fir::SequenceType::get(seqTy.getShape(), attr.getType());
3824           }
3825           if (isPointer)
3826             addrTy = fir::PointerType::get(addrTy);
3827           if (isAllocatable)
3828             addrTy = fir::HeapType::get(addrTy);
3829           mlir::Type classTy = fir::ClassType::get(addrTy);
3830           if (classTy == baseTy) {
3831             addAssocEntitySymbol(selector);
3832           } else {
3833             mlir::Value derived = builder->create<fir::ConvertOp>(
3834                 loc, classTy, fir::getBase(selector));
3835             addAssocEntitySymbol(selectorBox->clone(derived));
3836           }
3837         }
3838         builder->restoreInsertionPoint(crtInsPt);
3839         ++typeGuardIdx;
3840       } else if (eval.getIf<Fortran::parser::EndSelectStmt>()) {
3841         maybeStartBlock(eval.block);
3842         if (hasLocalScope)
3843           localSymbols.popScope();
3844       } else {
3845         genFIR(eval);
3846       }
3847       if (blockIsUnterminated()) {
3848         if (llvm::is_contained(exits, &eval))
3849           genConstructExitBranch(constructExit);
3850         else if (llvm::is_contained(fallThroughs, &eval))
3851           genBranch(eval.lexicalSuccessor->block);
3852       }
3853     }
3854     popActiveConstruct();
3855   }
3856 
3857   //===--------------------------------------------------------------------===//
3858   // IO statements (see io.h)
3859   //===--------------------------------------------------------------------===//
3860 
3861   void genFIR(const Fortran::parser::BackspaceStmt &stmt) {
3862     mlir::Value iostat = genBackspaceStatement(*this, stmt);
3863     genIoConditionBranches(getEval(), stmt.v, iostat);
3864   }
3865   void genFIR(const Fortran::parser::CloseStmt &stmt) {
3866     mlir::Value iostat = genCloseStatement(*this, stmt);
3867     genIoConditionBranches(getEval(), stmt.v, iostat);
3868   }
3869   void genFIR(const Fortran::parser::EndfileStmt &stmt) {
3870     mlir::Value iostat = genEndfileStatement(*this, stmt);
3871     genIoConditionBranches(getEval(), stmt.v, iostat);
3872   }
3873   void genFIR(const Fortran::parser::FlushStmt &stmt) {
3874     mlir::Value iostat = genFlushStatement(*this, stmt);
3875     genIoConditionBranches(getEval(), stmt.v, iostat);
3876   }
3877   void genFIR(const Fortran::parser::InquireStmt &stmt) {
3878     mlir::Value iostat = genInquireStatement(*this, stmt);
3879     if (const auto *specs =
3880             std::get_if<std::list<Fortran::parser::InquireSpec>>(&stmt.u))
3881       genIoConditionBranches(getEval(), *specs, iostat);
3882   }
3883   void genFIR(const Fortran::parser::OpenStmt &stmt) {
3884     mlir::Value iostat = genOpenStatement(*this, stmt);
3885     genIoConditionBranches(getEval(), stmt.v, iostat);
3886   }
3887   void genFIR(const Fortran::parser::PrintStmt &stmt) {
3888     genPrintStatement(*this, stmt);
3889   }
3890   void genFIR(const Fortran::parser::ReadStmt &stmt) {
3891     mlir::Value iostat = genReadStatement(*this, stmt);
3892     genIoConditionBranches(getEval(), stmt.controls, iostat);
3893   }
3894   void genFIR(const Fortran::parser::RewindStmt &stmt) {
3895     mlir::Value iostat = genRewindStatement(*this, stmt);
3896     genIoConditionBranches(getEval(), stmt.v, iostat);
3897   }
3898   void genFIR(const Fortran::parser::WaitStmt &stmt) {
3899     mlir::Value iostat = genWaitStatement(*this, stmt);
3900     genIoConditionBranches(getEval(), stmt.v, iostat);
3901   }
3902   void genFIR(const Fortran::parser::WriteStmt &stmt) {
3903     mlir::Value iostat = genWriteStatement(*this, stmt);
3904     genIoConditionBranches(getEval(), stmt.controls, iostat);
3905   }
3906 
3907   template <typename A>
3908   void genIoConditionBranches(Fortran::lower::pft::Evaluation &eval,
3909                               const A &specList, mlir::Value iostat) {
3910     if (!iostat)
3911       return;
3912 
3913     Fortran::parser::Label endLabel{};
3914     Fortran::parser::Label eorLabel{};
3915     Fortran::parser::Label errLabel{};
3916     bool hasIostat{};
3917     for (const auto &spec : specList) {
3918       Fortran::common::visit(
3919           Fortran::common::visitors{
3920               [&](const Fortran::parser::EndLabel &label) {
3921                 endLabel = label.v;
3922               },
3923               [&](const Fortran::parser::EorLabel &label) {
3924                 eorLabel = label.v;
3925               },
3926               [&](const Fortran::parser::ErrLabel &label) {
3927                 errLabel = label.v;
3928               },
3929               [&](const Fortran::parser::StatVariable &) { hasIostat = true; },
3930               [](const auto &) {}},
3931           spec.u);
3932     }
3933     if (!endLabel && !eorLabel && !errLabel)
3934       return;
3935 
3936     // An ERR specifier branch is taken on any positive error value rather than
3937     // some single specific value. If ERR and IOSTAT specifiers are given and
3938     // END and EOR specifiers are allowed, the latter two specifiers must have
3939     // explicit branch targets to allow the ERR branch to be implemented as a
3940     // default/else target. A label=0 target for an absent END or EOR specifier
3941     // indicates that these specifiers have a fallthrough target. END and EOR
3942     // specifiers may appear on READ and WAIT statements.
3943     bool allSpecifiersRequired = errLabel && hasIostat &&
3944                                  (eval.isA<Fortran::parser::ReadStmt>() ||
3945                                   eval.isA<Fortran::parser::WaitStmt>());
3946     mlir::Value selector =
3947         builder->createConvert(toLocation(), builder->getIndexType(), iostat);
3948     llvm::SmallVector<int64_t> valueList;
3949     llvm::SmallVector<Fortran::parser::Label> labelList;
3950     if (eorLabel || allSpecifiersRequired) {
3951       valueList.push_back(Fortran::runtime::io::IostatEor);
3952       labelList.push_back(eorLabel ? eorLabel : 0);
3953     }
3954     if (endLabel || allSpecifiersRequired) {
3955       valueList.push_back(Fortran::runtime::io::IostatEnd);
3956       labelList.push_back(endLabel ? endLabel : 0);
3957     }
3958     if (errLabel) {
3959       // Must be last. Value 0 is interpreted as any positive value, or
3960       // equivalently as any value other than 0, IostatEor, or IostatEnd.
3961       valueList.push_back(0);
3962       labelList.push_back(errLabel);
3963     }
3964     genMultiwayBranch(selector, valueList, labelList, eval.nonNopSuccessor());
3965   }
3966 
3967   //===--------------------------------------------------------------------===//
3968   // Memory allocation and deallocation
3969   //===--------------------------------------------------------------------===//
3970 
3971   void genFIR(const Fortran::parser::AllocateStmt &stmt) {
3972     Fortran::lower::genAllocateStmt(*this, stmt, toLocation());
3973   }
3974 
3975   void genFIR(const Fortran::parser::DeallocateStmt &stmt) {
3976     Fortran::lower::genDeallocateStmt(*this, stmt, toLocation());
3977   }
3978 
3979   /// Nullify pointer object list
3980   ///
3981   /// For each pointer object, reset the pointer to a disassociated status.
3982   /// We do this by setting each pointer to null.
3983   void genFIR(const Fortran::parser::NullifyStmt &stmt) {
3984     mlir::Location loc = toLocation();
3985     for (auto &pointerObject : stmt.v) {
3986       const Fortran::lower::SomeExpr *expr =
3987           Fortran::semantics::GetExpr(pointerObject);
3988       assert(expr);
3989       if (Fortran::evaluate::IsProcedurePointer(*expr)) {
3990         Fortran::lower::StatementContext stmtCtx;
3991         hlfir::Entity pptr = Fortran::lower::convertExprToHLFIR(
3992             loc, *this, *expr, localSymbols, stmtCtx);
3993         auto boxTy{
3994             Fortran::lower::getUntypedBoxProcType(builder->getContext())};
3995         hlfir::Entity nullBoxProc(
3996             fir::factory::createNullBoxProc(*builder, loc, boxTy));
3997         builder->createStoreWithConvert(loc, nullBoxProc, pptr);
3998       } else {
3999         fir::MutableBoxValue box = genExprMutableBox(loc, *expr);
4000         fir::factory::disassociateMutableBox(*builder, loc, box);
4001         cuf::genPointerSync(box.getAddr(), *builder);
4002       }
4003     }
4004   }
4005 
4006   //===--------------------------------------------------------------------===//
4007 
4008   void genFIR(const Fortran::parser::NotifyWaitStmt &stmt) {
4009     genNotifyWaitStatement(*this, stmt);
4010   }
4011 
4012   void genFIR(const Fortran::parser::EventPostStmt &stmt) {
4013     genEventPostStatement(*this, stmt);
4014   }
4015 
4016   void genFIR(const Fortran::parser::EventWaitStmt &stmt) {
4017     genEventWaitStatement(*this, stmt);
4018   }
4019 
4020   void genFIR(const Fortran::parser::FormTeamStmt &stmt) {
4021     genFormTeamStatement(*this, getEval(), stmt);
4022   }
4023 
4024   void genFIR(const Fortran::parser::LockStmt &stmt) {
4025     genLockStatement(*this, stmt);
4026   }
4027 
4028   fir::ExtendedValue
4029   genInitializerExprValue(const Fortran::lower::SomeExpr &expr,
4030                           Fortran::lower::StatementContext &stmtCtx) {
4031     return Fortran::lower::createSomeInitializerExpression(
4032         toLocation(), *this, expr, localSymbols, stmtCtx);
4033   }
4034 
4035   /// Return true if the current context is a conditionalized and implied
4036   /// iteration space.
4037   bool implicitIterationSpace() { return !implicitIterSpace.empty(); }
4038 
4039   /// Return true if context is currently an explicit iteration space. A scalar
4040   /// assignment expression may be contextually within a user-defined iteration
4041   /// space, transforming it into an array expression.
4042   bool explicitIterationSpace() { return explicitIterSpace.isActive(); }
4043 
4044   /// Generate an array assignment.
4045   /// This is an assignment expression with rank > 0. The assignment may or may
4046   /// not be in a WHERE and/or FORALL context.
4047   /// In a FORALL context, the assignment may be a pointer assignment and the \p
4048   /// lbounds and \p ubounds parameters should only be used in such a pointer
4049   /// assignment case. (If both are None then the array assignment cannot be a
4050   /// pointer assignment.)
4051   void genArrayAssignment(
4052       const Fortran::evaluate::Assignment &assign,
4053       Fortran::lower::StatementContext &localStmtCtx,
4054       std::optional<llvm::SmallVector<mlir::Value>> lbounds = std::nullopt,
4055       std::optional<llvm::SmallVector<mlir::Value>> ubounds = std::nullopt) {
4056 
4057     Fortran::lower::StatementContext &stmtCtx =
4058         explicitIterationSpace()
4059             ? explicitIterSpace.stmtContext()
4060             : (implicitIterationSpace() ? implicitIterSpace.stmtContext()
4061                                         : localStmtCtx);
4062     if (Fortran::lower::isWholeAllocatable(assign.lhs)) {
4063       // Assignment to allocatables may require the lhs to be
4064       // deallocated/reallocated. See Fortran 2018 10.2.1.3 p3
4065       Fortran::lower::createAllocatableArrayAssignment(
4066           *this, assign.lhs, assign.rhs, explicitIterSpace, implicitIterSpace,
4067           localSymbols, stmtCtx);
4068       return;
4069     }
4070 
4071     if (lbounds) {
4072       // Array of POINTER entities, with elemental assignment.
4073       if (!Fortran::lower::isWholePointer(assign.lhs))
4074         fir::emitFatalError(toLocation(), "pointer assignment to non-pointer");
4075 
4076       Fortran::lower::createArrayOfPointerAssignment(
4077           *this, assign.lhs, assign.rhs, explicitIterSpace, implicitIterSpace,
4078           *lbounds, ubounds, localSymbols, stmtCtx);
4079       return;
4080     }
4081 
4082     if (!implicitIterationSpace() && !explicitIterationSpace()) {
4083       // No masks and the iteration space is implied by the array, so create a
4084       // simple array assignment.
4085       Fortran::lower::createSomeArrayAssignment(*this, assign.lhs, assign.rhs,
4086                                                 localSymbols, stmtCtx);
4087       return;
4088     }
4089 
4090     // If there is an explicit iteration space, generate an array assignment
4091     // with a user-specified iteration space and possibly with masks. These
4092     // assignments may *appear* to be scalar expressions, but the scalar
4093     // expression is evaluated at all points in the user-defined space much like
4094     // an ordinary array assignment. More specifically, the semantics inside the
4095     // FORALL much more closely resembles that of WHERE than a scalar
4096     // assignment.
4097     // Otherwise, generate a masked array assignment. The iteration space is
4098     // implied by the lhs array expression.
4099     Fortran::lower::createAnyMaskedArrayAssignment(
4100         *this, assign.lhs, assign.rhs, explicitIterSpace, implicitIterSpace,
4101         localSymbols, stmtCtx);
4102   }
4103 
4104 #if !defined(NDEBUG)
4105   static bool isFuncResultDesignator(const Fortran::lower::SomeExpr &expr) {
4106     const Fortran::semantics::Symbol *sym =
4107         Fortran::evaluate::GetFirstSymbol(expr);
4108     return sym && sym->IsFuncResult();
4109   }
4110 #endif
4111 
4112   inline fir::MutableBoxValue
4113   genExprMutableBox(mlir::Location loc,
4114                     const Fortran::lower::SomeExpr &expr) override final {
4115     if (lowerToHighLevelFIR())
4116       return Fortran::lower::convertExprToMutableBox(loc, *this, expr,
4117                                                      localSymbols);
4118     return Fortran::lower::createMutableBox(loc, *this, expr, localSymbols);
4119   }
4120 
4121   // Create the [newRank] array with the lower bounds to be passed to the
4122   // runtime as a descriptor.
4123   mlir::Value createLboundArray(llvm::ArrayRef<mlir::Value> lbounds,
4124                                 mlir::Location loc) {
4125     mlir::Type indexTy = builder->getIndexType();
4126     mlir::Type boundArrayTy = fir::SequenceType::get(
4127         {static_cast<int64_t>(lbounds.size())}, builder->getI64Type());
4128     mlir::Value boundArray = builder->create<fir::AllocaOp>(loc, boundArrayTy);
4129     mlir::Value array = builder->create<fir::UndefOp>(loc, boundArrayTy);
4130     for (unsigned i = 0; i < lbounds.size(); ++i) {
4131       array = builder->create<fir::InsertValueOp>(
4132           loc, boundArrayTy, array, lbounds[i],
4133           builder->getArrayAttr({builder->getIntegerAttr(
4134               builder->getIndexType(), static_cast<int>(i))}));
4135     }
4136     builder->create<fir::StoreOp>(loc, array, boundArray);
4137     mlir::Type boxTy = fir::BoxType::get(boundArrayTy);
4138     mlir::Value ext =
4139         builder->createIntegerConstant(loc, indexTy, lbounds.size());
4140     llvm::SmallVector<mlir::Value> shapes = {ext};
4141     mlir::Value shapeOp = builder->genShape(loc, shapes);
4142     return builder->create<fir::EmboxOp>(loc, boxTy, boundArray, shapeOp);
4143   }
4144 
4145   // Generate pointer assignment with possibly empty bounds-spec. R1035: a
4146   // bounds-spec is a lower bound value.
4147   void genPointerAssignment(
4148       mlir::Location loc, const Fortran::evaluate::Assignment &assign,
4149       const Fortran::evaluate::Assignment::BoundsSpec &lbExprs) {
4150     Fortran::lower::StatementContext stmtCtx;
4151 
4152     if (!lowerToHighLevelFIR() &&
4153         Fortran::evaluate::IsProcedureDesignator(assign.rhs))
4154       TODO(loc, "procedure pointer assignment");
4155     if (Fortran::evaluate::IsProcedurePointer(assign.lhs)) {
4156       hlfir::Entity lhs = Fortran::lower::convertExprToHLFIR(
4157           loc, *this, assign.lhs, localSymbols, stmtCtx);
4158       if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
4159               assign.rhs)) {
4160         // rhs is null(). rhs being null(pptr) is handled in genNull.
4161         auto boxTy{
4162             Fortran::lower::getUntypedBoxProcType(builder->getContext())};
4163         hlfir::Entity rhs(
4164             fir::factory::createNullBoxProc(*builder, loc, boxTy));
4165         builder->createStoreWithConvert(loc, rhs, lhs);
4166         return;
4167       }
4168       hlfir::Entity rhs(getBase(Fortran::lower::convertExprToAddress(
4169           loc, *this, assign.rhs, localSymbols, stmtCtx)));
4170       builder->createStoreWithConvert(loc, rhs, lhs);
4171       return;
4172     }
4173 
4174     std::optional<Fortran::evaluate::DynamicType> lhsType =
4175         assign.lhs.GetType();
4176     // Delegate pointer association to unlimited polymorphic pointer
4177     // to the runtime. element size, type code, attribute and of
4178     // course base_addr might need to be updated.
4179     if (lhsType && lhsType->IsPolymorphic()) {
4180       if (!lowerToHighLevelFIR() && explicitIterationSpace())
4181         TODO(loc, "polymorphic pointer assignment in FORALL");
4182       llvm::SmallVector<mlir::Value> lbounds;
4183       for (const Fortran::evaluate::ExtentExpr &lbExpr : lbExprs)
4184         lbounds.push_back(
4185             fir::getBase(genExprValue(toEvExpr(lbExpr), stmtCtx)));
4186       fir::MutableBoxValue lhsMutableBox = genExprMutableBox(loc, assign.lhs);
4187       if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
4188               assign.rhs)) {
4189         fir::factory::disassociateMutableBox(*builder, loc, lhsMutableBox);
4190         return;
4191       }
4192       mlir::Value lhs = lhsMutableBox.getAddr();
4193       mlir::Value rhs = fir::getBase(genExprBox(loc, assign.rhs, stmtCtx));
4194       if (!lbounds.empty()) {
4195         mlir::Value boundsDesc = createLboundArray(lbounds, loc);
4196         Fortran::lower::genPointerAssociateLowerBounds(*builder, loc, lhs, rhs,
4197                                                        boundsDesc);
4198         return;
4199       }
4200       Fortran::lower::genPointerAssociate(*builder, loc, lhs, rhs);
4201       return;
4202     }
4203 
4204     llvm::SmallVector<mlir::Value> lbounds;
4205     for (const Fortran::evaluate::ExtentExpr &lbExpr : lbExprs)
4206       lbounds.push_back(fir::getBase(genExprValue(toEvExpr(lbExpr), stmtCtx)));
4207     if (!lowerToHighLevelFIR() && explicitIterationSpace()) {
4208       // Pointer assignment in FORALL context. Copy the rhs box value
4209       // into the lhs box variable.
4210       genArrayAssignment(assign, stmtCtx, lbounds);
4211       return;
4212     }
4213     fir::MutableBoxValue lhs = genExprMutableBox(loc, assign.lhs);
4214     Fortran::lower::associateMutableBox(*this, loc, lhs, assign.rhs, lbounds,
4215                                         stmtCtx);
4216   }
4217 
4218   // Create the 2 x newRank array with the bounds to be passed to the runtime as
4219   // a descriptor.
4220   mlir::Value createBoundArray(llvm::ArrayRef<mlir::Value> lbounds,
4221                                llvm::ArrayRef<mlir::Value> ubounds,
4222                                mlir::Location loc) {
4223     assert(lbounds.size() && ubounds.size());
4224     mlir::Type indexTy = builder->getIndexType();
4225     mlir::Type boundArrayTy = fir::SequenceType::get(
4226         {2, static_cast<int64_t>(lbounds.size())}, builder->getI64Type());
4227     mlir::Value boundArray = builder->create<fir::AllocaOp>(loc, boundArrayTy);
4228     mlir::Value array = builder->create<fir::UndefOp>(loc, boundArrayTy);
4229     for (unsigned i = 0; i < lbounds.size(); ++i) {
4230       array = builder->create<fir::InsertValueOp>(
4231           loc, boundArrayTy, array, lbounds[i],
4232           builder->getArrayAttr(
4233               {builder->getIntegerAttr(builder->getIndexType(), 0),
4234                builder->getIntegerAttr(builder->getIndexType(),
4235                                        static_cast<int>(i))}));
4236       array = builder->create<fir::InsertValueOp>(
4237           loc, boundArrayTy, array, ubounds[i],
4238           builder->getArrayAttr(
4239               {builder->getIntegerAttr(builder->getIndexType(), 1),
4240                builder->getIntegerAttr(builder->getIndexType(),
4241                                        static_cast<int>(i))}));
4242     }
4243     builder->create<fir::StoreOp>(loc, array, boundArray);
4244     mlir::Type boxTy = fir::BoxType::get(boundArrayTy);
4245     mlir::Value ext =
4246         builder->createIntegerConstant(loc, indexTy, lbounds.size());
4247     mlir::Value c2 = builder->createIntegerConstant(loc, indexTy, 2);
4248     llvm::SmallVector<mlir::Value> shapes = {c2, ext};
4249     mlir::Value shapeOp = builder->genShape(loc, shapes);
4250     return builder->create<fir::EmboxOp>(loc, boxTy, boundArray, shapeOp);
4251   }
4252 
4253   // Pointer assignment with bounds-remapping. R1036: a bounds-remapping is a
4254   // pair, lower bound and upper bound.
4255   void genPointerAssignment(
4256       mlir::Location loc, const Fortran::evaluate::Assignment &assign,
4257       const Fortran::evaluate::Assignment::BoundsRemapping &boundExprs) {
4258     Fortran::lower::StatementContext stmtCtx;
4259     llvm::SmallVector<mlir::Value> lbounds;
4260     llvm::SmallVector<mlir::Value> ubounds;
4261     for (const std::pair<Fortran::evaluate::ExtentExpr,
4262                          Fortran::evaluate::ExtentExpr> &pair : boundExprs) {
4263       const Fortran::evaluate::ExtentExpr &lbExpr = pair.first;
4264       const Fortran::evaluate::ExtentExpr &ubExpr = pair.second;
4265       lbounds.push_back(fir::getBase(genExprValue(toEvExpr(lbExpr), stmtCtx)));
4266       ubounds.push_back(fir::getBase(genExprValue(toEvExpr(ubExpr), stmtCtx)));
4267     }
4268 
4269     std::optional<Fortran::evaluate::DynamicType> lhsType =
4270         assign.lhs.GetType();
4271     std::optional<Fortran::evaluate::DynamicType> rhsType =
4272         assign.rhs.GetType();
4273     // Polymorphic lhs/rhs need more care. See F2018 10.2.2.3.
4274     if ((lhsType && lhsType->IsPolymorphic()) ||
4275         (rhsType && rhsType->IsPolymorphic())) {
4276       if (!lowerToHighLevelFIR() && explicitIterationSpace())
4277         TODO(loc, "polymorphic pointer assignment in FORALL");
4278 
4279       fir::MutableBoxValue lhsMutableBox = genExprMutableBox(loc, assign.lhs);
4280       if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
4281               assign.rhs)) {
4282         fir::factory::disassociateMutableBox(*builder, loc, lhsMutableBox);
4283         return;
4284       }
4285       mlir::Value lhs = lhsMutableBox.getAddr();
4286       mlir::Value rhs = fir::getBase(genExprBox(loc, assign.rhs, stmtCtx));
4287       mlir::Value boundsDesc = createBoundArray(lbounds, ubounds, loc);
4288       Fortran::lower::genPointerAssociateRemapping(*builder, loc, lhs, rhs,
4289                                                    boundsDesc);
4290       return;
4291     }
4292     if (!lowerToHighLevelFIR() && explicitIterationSpace()) {
4293       // Pointer assignment in FORALL context. Copy the rhs box value
4294       // into the lhs box variable.
4295       genArrayAssignment(assign, stmtCtx, lbounds, ubounds);
4296       return;
4297     }
4298     fir::MutableBoxValue lhs = genExprMutableBox(loc, assign.lhs);
4299     if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
4300             assign.rhs)) {
4301       fir::factory::disassociateMutableBox(*builder, loc, lhs);
4302       return;
4303     }
4304     if (lowerToHighLevelFIR()) {
4305       fir::ExtendedValue rhs = genExprAddr(assign.rhs, stmtCtx);
4306       fir::factory::associateMutableBoxWithRemap(*builder, loc, lhs, rhs,
4307                                                  lbounds, ubounds);
4308       return;
4309     }
4310     // Legacy lowering below.
4311     // Do not generate a temp in case rhs is an array section.
4312     fir::ExtendedValue rhs =
4313         Fortran::lower::isArraySectionWithoutVectorSubscript(assign.rhs)
4314             ? Fortran::lower::createSomeArrayBox(*this, assign.rhs,
4315                                                  localSymbols, stmtCtx)
4316             : genExprAddr(assign.rhs, stmtCtx);
4317     fir::factory::associateMutableBoxWithRemap(*builder, loc, lhs, rhs, lbounds,
4318                                                ubounds);
4319     if (explicitIterationSpace()) {
4320       mlir::ValueRange inners = explicitIterSpace.getInnerArgs();
4321       if (!inners.empty())
4322         builder->create<fir::ResultOp>(loc, inners);
4323     }
4324   }
4325 
4326   /// Given converted LHS and RHS of the assignment, materialize any
4327   /// implicit conversion of the RHS to the LHS type. The front-end
4328   /// usually already makes those explicit, except for non-standard
4329   /// LOGICAL <-> INTEGER, or if the LHS is a whole allocatable
4330   /// (making the conversion explicit in the front-end would prevent
4331   /// propagation of the LHS lower bound in the reallocation).
4332   /// If array temporaries or values are created, the cleanups are
4333   /// added in the statement context.
4334   hlfir::Entity genImplicitConvert(const Fortran::evaluate::Assignment &assign,
4335                                    hlfir::Entity rhs, bool preserveLowerBounds,
4336                                    Fortran::lower::StatementContext &stmtCtx) {
4337     mlir::Location loc = toLocation();
4338     auto &builder = getFirOpBuilder();
4339     mlir::Type toType = genType(assign.lhs);
4340     auto valueAndPair = hlfir::genTypeAndKindConvert(loc, builder, rhs, toType,
4341                                                      preserveLowerBounds);
4342     if (valueAndPair.second)
4343       stmtCtx.attachCleanup(*valueAndPair.second);
4344     return hlfir::Entity{valueAndPair.first};
4345   }
4346 
4347   bool firstDummyIsPointerOrAllocatable(
4348       const Fortran::evaluate::ProcedureRef &userDefinedAssignment) {
4349     using DummyAttr = Fortran::evaluate::characteristics::DummyDataObject::Attr;
4350     if (auto procedure =
4351             Fortran::evaluate::characteristics::Procedure::Characterize(
4352                 userDefinedAssignment.proc(), getFoldingContext(),
4353                 /*emitError=*/false))
4354       if (!procedure->dummyArguments.empty())
4355         if (const auto *dataArg = std::get_if<
4356                 Fortran::evaluate::characteristics::DummyDataObject>(
4357                 &procedure->dummyArguments[0].u))
4358           return dataArg->attrs.test(DummyAttr::Pointer) ||
4359                  dataArg->attrs.test(DummyAttr::Allocatable);
4360     return false;
4361   }
4362 
4363   void genCUDADataTransfer(fir::FirOpBuilder &builder, mlir::Location loc,
4364                            const Fortran::evaluate::Assignment &assign,
4365                            hlfir::Entity &lhs, hlfir::Entity &rhs) {
4366     bool lhsIsDevice = Fortran::evaluate::HasCUDADeviceAttrs(assign.lhs);
4367     bool rhsIsDevice = Fortran::evaluate::HasCUDADeviceAttrs(assign.rhs);
4368 
4369     auto getRefFromValue = [](mlir::Value val) -> mlir::Value {
4370       if (auto loadOp =
4371               mlir::dyn_cast_or_null<fir::LoadOp>(val.getDefiningOp()))
4372         return loadOp.getMemref();
4373       if (!mlir::isa<fir::BaseBoxType>(val.getType()))
4374         return val;
4375       if (auto declOp =
4376               mlir::dyn_cast_or_null<hlfir::DeclareOp>(val.getDefiningOp())) {
4377         if (!declOp.getShape())
4378           return val;
4379         if (mlir::isa<fir::ReferenceType>(declOp.getMemref().getType()))
4380           return declOp.getResults()[1];
4381       }
4382       return val;
4383     };
4384 
4385     auto getShapeFromDecl = [](mlir::Value val) -> mlir::Value {
4386       if (!mlir::isa<fir::BaseBoxType>(val.getType()))
4387         return {};
4388       if (auto declOp =
4389               mlir::dyn_cast_or_null<hlfir::DeclareOp>(val.getDefiningOp()))
4390         return declOp.getShape();
4391       return {};
4392     };
4393 
4394     mlir::Value rhsVal = getRefFromValue(rhs.getBase());
4395     mlir::Value lhsVal = getRefFromValue(lhs.getBase());
4396     // Get shape from the rhs if available otherwise get it from lhs.
4397     mlir::Value shape = getShapeFromDecl(rhs.getBase());
4398     if (!shape)
4399       shape = getShapeFromDecl(lhs.getBase());
4400 
4401     // device = host
4402     if (lhsIsDevice && !rhsIsDevice) {
4403       auto transferKindAttr = cuf::DataTransferKindAttr::get(
4404           builder.getContext(), cuf::DataTransferKind::HostDevice);
4405       if (!rhs.isVariable()) {
4406         mlir::Value base = rhs;
4407         if (auto convertOp =
4408                 mlir::dyn_cast<fir::ConvertOp>(rhs.getDefiningOp()))
4409           base = convertOp.getValue();
4410         // Special case if the rhs is a constant.
4411         if (matchPattern(base.getDefiningOp(), mlir::m_Constant())) {
4412           builder.create<cuf::DataTransferOp>(loc, base, lhsVal, shape,
4413                                               transferKindAttr);
4414         } else {
4415           auto associate = hlfir::genAssociateExpr(
4416               loc, builder, rhs, rhs.getType(), ".cuf_host_tmp");
4417           builder.create<cuf::DataTransferOp>(loc, associate.getBase(), lhsVal,
4418                                               shape, transferKindAttr);
4419           builder.create<hlfir::EndAssociateOp>(loc, associate);
4420         }
4421       } else {
4422         builder.create<cuf::DataTransferOp>(loc, rhsVal, lhsVal, shape,
4423                                             transferKindAttr);
4424       }
4425       return;
4426     }
4427 
4428     // host = device
4429     if (!lhsIsDevice && rhsIsDevice) {
4430       auto transferKindAttr = cuf::DataTransferKindAttr::get(
4431           builder.getContext(), cuf::DataTransferKind::DeviceHost);
4432       builder.create<cuf::DataTransferOp>(loc, rhsVal, lhsVal, shape,
4433                                           transferKindAttr);
4434       return;
4435     }
4436 
4437     // device = device
4438     if (lhsIsDevice && rhsIsDevice) {
4439       assert(rhs.isVariable() && "CUDA Fortran assignment rhs is not legal");
4440       auto transferKindAttr = cuf::DataTransferKindAttr::get(
4441           builder.getContext(), cuf::DataTransferKind::DeviceDevice);
4442       builder.create<cuf::DataTransferOp>(loc, rhsVal, lhsVal, shape,
4443                                           transferKindAttr);
4444       return;
4445     }
4446     llvm_unreachable("Unhandled CUDA data transfer");
4447   }
4448 
4449   llvm::SmallVector<mlir::Value>
4450   genCUDAImplicitDataTransfer(fir::FirOpBuilder &builder, mlir::Location loc,
4451                               const Fortran::evaluate::Assignment &assign) {
4452     llvm::SmallVector<mlir::Value> temps;
4453     localSymbols.pushScope();
4454     auto transferKindAttr = cuf::DataTransferKindAttr::get(
4455         builder.getContext(), cuf::DataTransferKind::DeviceHost);
4456     [[maybe_unused]] unsigned nbDeviceResidentObject = 0;
4457     for (const Fortran::semantics::Symbol &sym :
4458          Fortran::evaluate::CollectSymbols(assign.rhs)) {
4459       if (const auto *details =
4460               sym.GetUltimate()
4461                   .detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
4462         if (details->cudaDataAttr() &&
4463             *details->cudaDataAttr() != Fortran::common::CUDADataAttr::Pinned) {
4464           if (sym.owner().IsDerivedType() && IsAllocatable(sym.GetUltimate()))
4465             TODO(loc, "Device resident allocatable derived-type component");
4466           // TODO: This should probably being checked in semantic and give a
4467           // proper error.
4468           assert(
4469               nbDeviceResidentObject <= 1 &&
4470               "Only one reference to the device resident object is supported");
4471           auto addr = getSymbolAddress(sym);
4472           hlfir::Entity entity{addr};
4473           auto [temp, cleanup] =
4474               hlfir::createTempFromMold(loc, builder, entity);
4475           auto needCleanup = fir::getIntIfConstant(cleanup);
4476           if (needCleanup && *needCleanup) {
4477             if (auto declareOp =
4478                     mlir::dyn_cast<hlfir::DeclareOp>(temp.getDefiningOp()))
4479               temps.push_back(declareOp.getMemref());
4480             else
4481               temps.push_back(temp);
4482           }
4483           addSymbol(sym,
4484                     hlfir::translateToExtendedValue(loc, builder, temp).first,
4485                     /*forced=*/true);
4486           builder.create<cuf::DataTransferOp>(
4487               loc, addr, temp, /*shape=*/mlir::Value{}, transferKindAttr);
4488           ++nbDeviceResidentObject;
4489         }
4490       }
4491     }
4492     return temps;
4493   }
4494 
4495   void genDataAssignment(
4496       const Fortran::evaluate::Assignment &assign,
4497       const Fortran::evaluate::ProcedureRef *userDefinedAssignment) {
4498     mlir::Location loc = getCurrentLocation();
4499     fir::FirOpBuilder &builder = getFirOpBuilder();
4500 
4501     bool isInDeviceContext = Fortran::lower::isCudaDeviceContext(builder);
4502 
4503     bool isCUDATransfer = (Fortran::evaluate::HasCUDADeviceAttrs(assign.lhs) ||
4504                            Fortran::evaluate::HasCUDADeviceAttrs(assign.rhs)) &&
4505                           !isInDeviceContext;
4506     bool hasCUDAImplicitTransfer =
4507         Fortran::evaluate::HasCUDAImplicitTransfer(assign.rhs);
4508     llvm::SmallVector<mlir::Value> implicitTemps;
4509 
4510     if (hasCUDAImplicitTransfer && !isInDeviceContext)
4511       implicitTemps = genCUDAImplicitDataTransfer(builder, loc, assign);
4512 
4513     // Gather some information about the assignment that will impact how it is
4514     // lowered.
4515     const bool isWholeAllocatableAssignment =
4516         !userDefinedAssignment && !isInsideHlfirWhere() &&
4517         Fortran::lower::isWholeAllocatable(assign.lhs) &&
4518         bridge.getLoweringOptions().getReallocateLHS();
4519     const bool isUserDefAssignToPointerOrAllocatable =
4520         userDefinedAssignment &&
4521         firstDummyIsPointerOrAllocatable(*userDefinedAssignment);
4522     std::optional<Fortran::evaluate::DynamicType> lhsType =
4523         assign.lhs.GetType();
4524     const bool keepLhsLengthInAllocatableAssignment =
4525         isWholeAllocatableAssignment && lhsType.has_value() &&
4526         lhsType->category() == Fortran::common::TypeCategory::Character &&
4527         !lhsType->HasDeferredTypeParameter();
4528     const bool lhsHasVectorSubscripts =
4529         Fortran::evaluate::HasVectorSubscript(assign.lhs);
4530 
4531     // Helper to generate the code evaluating the right-hand side.
4532     auto evaluateRhs = [&](Fortran::lower::StatementContext &stmtCtx) {
4533       hlfir::Entity rhs = Fortran::lower::convertExprToHLFIR(
4534           loc, *this, assign.rhs, localSymbols, stmtCtx);
4535       // Load trivial scalar RHS to allow the loads to be hoisted outside of
4536       // loops early if possible. This also dereferences pointer and
4537       // allocatable RHS: the target is being assigned from.
4538       rhs = hlfir::loadTrivialScalar(loc, builder, rhs);
4539       // In intrinsic assignments, the LHS type may not match the RHS type, in
4540       // which case an implicit conversion of the LHS must be done. The
4541       // front-end usually makes it explicit, unless it cannot (whole
4542       // allocatable LHS or Logical<->Integer assignment extension). Recognize
4543       // any type mismatches here and insert explicit scalar convert or
4544       // ElementalOp for array assignment. Preserve the RHS lower bounds on the
4545       // converted entity in case of assignment to whole allocatables so to
4546       // propagate the lower bounds to the LHS in case of reallocation.
4547       if (!userDefinedAssignment)
4548         rhs = genImplicitConvert(assign, rhs, isWholeAllocatableAssignment,
4549                                  stmtCtx);
4550       return rhs;
4551     };
4552 
4553     // Helper to generate the code evaluating the left-hand side.
4554     auto evaluateLhs = [&](Fortran::lower::StatementContext &stmtCtx) {
4555       hlfir::Entity lhs = Fortran::lower::convertExprToHLFIR(
4556           loc, *this, assign.lhs, localSymbols, stmtCtx);
4557       // Dereference pointer LHS: the target is being assigned to.
4558       // Same for allocatables outside of whole allocatable assignments.
4559       if (!isWholeAllocatableAssignment &&
4560           !isUserDefAssignToPointerOrAllocatable)
4561         lhs = hlfir::derefPointersAndAllocatables(loc, builder, lhs);
4562       return lhs;
4563     };
4564 
4565     if (!isInsideHlfirForallOrWhere() && !lhsHasVectorSubscripts &&
4566         !userDefinedAssignment) {
4567       Fortran::lower::StatementContext localStmtCtx;
4568       hlfir::Entity rhs = evaluateRhs(localStmtCtx);
4569       hlfir::Entity lhs = evaluateLhs(localStmtCtx);
4570       if (isCUDATransfer && !hasCUDAImplicitTransfer)
4571         genCUDADataTransfer(builder, loc, assign, lhs, rhs);
4572       else
4573         builder.create<hlfir::AssignOp>(loc, rhs, lhs,
4574                                         isWholeAllocatableAssignment,
4575                                         keepLhsLengthInAllocatableAssignment);
4576       if (hasCUDAImplicitTransfer && !isInDeviceContext) {
4577         localSymbols.popScope();
4578         for (mlir::Value temp : implicitTemps)
4579           builder.create<fir::FreeMemOp>(loc, temp);
4580       }
4581       return;
4582     }
4583     // Assignments inside Forall, Where, or assignments to a vector subscripted
4584     // left-hand side requires using an hlfir.region_assign in HLFIR. The
4585     // right-hand side and left-hand side must be evaluated inside the
4586     // hlfir.region_assign regions.
4587     auto regionAssignOp = builder.create<hlfir::RegionAssignOp>(loc);
4588 
4589     // Lower RHS in its own region.
4590     builder.createBlock(&regionAssignOp.getRhsRegion());
4591     Fortran::lower::StatementContext rhsContext;
4592     hlfir::Entity rhs = evaluateRhs(rhsContext);
4593     auto rhsYieldOp = builder.create<hlfir::YieldOp>(loc, rhs);
4594     Fortran::lower::genCleanUpInRegionIfAny(
4595         loc, builder, rhsYieldOp.getCleanup(), rhsContext);
4596     // Lower LHS in its own region.
4597     builder.createBlock(&regionAssignOp.getLhsRegion());
4598     Fortran::lower::StatementContext lhsContext;
4599     mlir::Value lhsYield = nullptr;
4600     if (!lhsHasVectorSubscripts) {
4601       hlfir::Entity lhs = evaluateLhs(lhsContext);
4602       auto lhsYieldOp = builder.create<hlfir::YieldOp>(loc, lhs);
4603       Fortran::lower::genCleanUpInRegionIfAny(
4604           loc, builder, lhsYieldOp.getCleanup(), lhsContext);
4605       lhsYield = lhs;
4606     } else {
4607       hlfir::ElementalAddrOp elementalAddr =
4608           Fortran::lower::convertVectorSubscriptedExprToElementalAddr(
4609               loc, *this, assign.lhs, localSymbols, lhsContext);
4610       Fortran::lower::genCleanUpInRegionIfAny(
4611           loc, builder, elementalAddr.getCleanup(), lhsContext);
4612       lhsYield = elementalAddr.getYieldOp().getEntity();
4613     }
4614     assert(lhsYield && "must have been set");
4615 
4616     // Add "realloc" flag to hlfir.region_assign.
4617     if (isWholeAllocatableAssignment)
4618       TODO(loc, "assignment to a whole allocatable inside FORALL");
4619 
4620     // Generate the hlfir.region_assign userDefinedAssignment region.
4621     if (userDefinedAssignment) {
4622       mlir::Type rhsType = rhs.getType();
4623       mlir::Type lhsType = lhsYield.getType();
4624       if (userDefinedAssignment->IsElemental()) {
4625         rhsType = hlfir::getEntityElementType(rhs);
4626         lhsType = hlfir::getEntityElementType(hlfir::Entity{lhsYield});
4627       }
4628       builder.createBlock(&regionAssignOp.getUserDefinedAssignment(),
4629                           mlir::Region::iterator{}, {rhsType, lhsType},
4630                           {loc, loc});
4631       auto end = builder.create<fir::FirEndOp>(loc);
4632       builder.setInsertionPoint(end);
4633       hlfir::Entity lhsBlockArg{regionAssignOp.getUserAssignmentLhs()};
4634       hlfir::Entity rhsBlockArg{regionAssignOp.getUserAssignmentRhs()};
4635       Fortran::lower::convertUserDefinedAssignmentToHLFIR(
4636           loc, *this, *userDefinedAssignment, lhsBlockArg, rhsBlockArg,
4637           localSymbols);
4638     }
4639     builder.setInsertionPointAfter(regionAssignOp);
4640   }
4641 
4642   /// Shared for both assignments and pointer assignments.
4643   void genAssignment(const Fortran::evaluate::Assignment &assign) {
4644     mlir::Location loc = toLocation();
4645     if (lowerToHighLevelFIR()) {
4646       Fortran::common::visit(
4647           Fortran::common::visitors{
4648               [&](const Fortran::evaluate::Assignment::Intrinsic &) {
4649                 genDataAssignment(assign, /*userDefinedAssignment=*/nullptr);
4650               },
4651               [&](const Fortran::evaluate::ProcedureRef &procRef) {
4652                 genDataAssignment(assign, /*userDefinedAssignment=*/&procRef);
4653               },
4654               [&](const Fortran::evaluate::Assignment::BoundsSpec &lbExprs) {
4655                 if (isInsideHlfirForallOrWhere())
4656                   TODO(loc, "pointer assignment inside FORALL");
4657                 genPointerAssignment(loc, assign, lbExprs);
4658               },
4659               [&](const Fortran::evaluate::Assignment::BoundsRemapping
4660                       &boundExprs) {
4661                 if (isInsideHlfirForallOrWhere())
4662                   TODO(loc, "pointer assignment inside FORALL");
4663                 genPointerAssignment(loc, assign, boundExprs);
4664               },
4665           },
4666           assign.u);
4667       return;
4668     }
4669     if (explicitIterationSpace()) {
4670       Fortran::lower::createArrayLoads(*this, explicitIterSpace, localSymbols);
4671       explicitIterSpace.genLoopNest();
4672     }
4673     Fortran::lower::StatementContext stmtCtx;
4674     Fortran::common::visit(
4675         Fortran::common::visitors{
4676             // [1] Plain old assignment.
4677             [&](const Fortran::evaluate::Assignment::Intrinsic &) {
4678               const Fortran::semantics::Symbol *sym =
4679                   Fortran::evaluate::GetLastSymbol(assign.lhs);
4680 
4681               if (!sym)
4682                 TODO(loc, "assignment to pointer result of function reference");
4683 
4684               std::optional<Fortran::evaluate::DynamicType> lhsType =
4685                   assign.lhs.GetType();
4686               assert(lhsType && "lhs cannot be typeless");
4687               std::optional<Fortran::evaluate::DynamicType> rhsType =
4688                   assign.rhs.GetType();
4689 
4690               // Assignment to/from polymorphic entities are done with the
4691               // runtime.
4692               if (lhsType->IsPolymorphic() ||
4693                   lhsType->IsUnlimitedPolymorphic() ||
4694                   (rhsType && (rhsType->IsPolymorphic() ||
4695                                rhsType->IsUnlimitedPolymorphic()))) {
4696                 mlir::Value lhs;
4697                 if (Fortran::lower::isWholeAllocatable(assign.lhs))
4698                   lhs = genExprMutableBox(loc, assign.lhs).getAddr();
4699                 else
4700                   lhs = fir::getBase(genExprBox(loc, assign.lhs, stmtCtx));
4701                 mlir::Value rhs =
4702                     fir::getBase(genExprBox(loc, assign.rhs, stmtCtx));
4703                 if ((lhsType->IsPolymorphic() ||
4704                      lhsType->IsUnlimitedPolymorphic()) &&
4705                     Fortran::lower::isWholeAllocatable(assign.lhs))
4706                   fir::runtime::genAssignPolymorphic(*builder, loc, lhs, rhs);
4707                 else
4708                   fir::runtime::genAssign(*builder, loc, lhs, rhs);
4709                 return;
4710               }
4711 
4712               // Note: No ad-hoc handling for pointers is required here. The
4713               // target will be assigned as per 2018 10.2.1.3 p2. genExprAddr
4714               // on a pointer returns the target address and not the address of
4715               // the pointer variable.
4716 
4717               if (assign.lhs.Rank() > 0 || explicitIterationSpace()) {
4718                 if (isDerivedCategory(lhsType->category()) &&
4719                     Fortran::semantics::IsFinalizable(
4720                         lhsType->GetDerivedTypeSpec()))
4721                   TODO(loc, "derived-type finalization with array assignment");
4722                 // Array assignment
4723                 // See Fortran 2018 10.2.1.3 p5, p6, and p7
4724                 genArrayAssignment(assign, stmtCtx);
4725                 return;
4726               }
4727 
4728               // Scalar assignment
4729               const bool isNumericScalar =
4730                   isNumericScalarCategory(lhsType->category());
4731               const bool isVector =
4732                   isDerivedCategory(lhsType->category()) &&
4733                   lhsType->GetDerivedTypeSpec().IsVectorType();
4734               fir::ExtendedValue rhs = (isNumericScalar || isVector)
4735                                            ? genExprValue(assign.rhs, stmtCtx)
4736                                            : genExprAddr(assign.rhs, stmtCtx);
4737               const bool lhsIsWholeAllocatable =
4738                   Fortran::lower::isWholeAllocatable(assign.lhs);
4739               std::optional<fir::factory::MutableBoxReallocation> lhsRealloc;
4740               std::optional<fir::MutableBoxValue> lhsMutableBox;
4741 
4742               // Set flag to know if the LHS needs finalization. Polymorphic,
4743               // unlimited polymorphic assignment will be done with genAssign.
4744               // Assign runtime function performs the finalization.
4745               bool needFinalization = !lhsType->IsPolymorphic() &&
4746                                       !lhsType->IsUnlimitedPolymorphic() &&
4747                                       (isDerivedCategory(lhsType->category()) &&
4748                                        Fortran::semantics::IsFinalizable(
4749                                            lhsType->GetDerivedTypeSpec()));
4750 
4751               auto lhs = [&]() -> fir::ExtendedValue {
4752                 if (lhsIsWholeAllocatable) {
4753                   lhsMutableBox = genExprMutableBox(loc, assign.lhs);
4754                   // Finalize if needed.
4755                   if (needFinalization) {
4756                     mlir::Value isAllocated =
4757                         fir::factory::genIsAllocatedOrAssociatedTest(
4758                             *builder, loc, *lhsMutableBox);
4759                     builder->genIfThen(loc, isAllocated)
4760                         .genThen([&]() {
4761                           fir::runtime::genDerivedTypeDestroy(
4762                               *builder, loc, fir::getBase(*lhsMutableBox));
4763                         })
4764                         .end();
4765                     needFinalization = false;
4766                   }
4767 
4768                   llvm::SmallVector<mlir::Value> lengthParams;
4769                   if (const fir::CharBoxValue *charBox = rhs.getCharBox())
4770                     lengthParams.push_back(charBox->getLen());
4771                   else if (fir::isDerivedWithLenParameters(rhs))
4772                     TODO(loc, "assignment to derived type allocatable with "
4773                               "LEN parameters");
4774                   lhsRealloc = fir::factory::genReallocIfNeeded(
4775                       *builder, loc, *lhsMutableBox,
4776                       /*shape=*/std::nullopt, lengthParams);
4777                   return lhsRealloc->newValue;
4778                 }
4779                 return genExprAddr(assign.lhs, stmtCtx);
4780               }();
4781 
4782               if (isNumericScalar || isVector) {
4783                 // Fortran 2018 10.2.1.3 p8 and p9
4784                 // Conversions should have been inserted by semantic analysis,
4785                 // but they can be incorrect between the rhs and lhs. Correct
4786                 // that here.
4787                 mlir::Value addr = fir::getBase(lhs);
4788                 mlir::Value val = fir::getBase(rhs);
4789                 // A function with multiple entry points returning different
4790                 // types tags all result variables with one of the largest
4791                 // types to allow them to share the same storage. Assignment
4792                 // to a result variable of one of the other types requires
4793                 // conversion to the actual type.
4794                 mlir::Type toTy = genType(assign.lhs);
4795 
4796                 // If Cray pointee, need to handle the address
4797                 // Array is handled in genCoordinateOp.
4798                 if (sym->test(Fortran::semantics::Symbol::Flag::CrayPointee) &&
4799                     sym->Rank() == 0) {
4800                   // get the corresponding Cray pointer
4801 
4802                   const Fortran::semantics::Symbol &ptrSym =
4803                       Fortran::semantics::GetCrayPointer(*sym);
4804                   fir::ExtendedValue ptr =
4805                       getSymbolExtendedValue(ptrSym, nullptr);
4806                   mlir::Value ptrVal = fir::getBase(ptr);
4807                   mlir::Type ptrTy = genType(ptrSym);
4808 
4809                   fir::ExtendedValue pte =
4810                       getSymbolExtendedValue(*sym, nullptr);
4811                   mlir::Value pteVal = fir::getBase(pte);
4812                   mlir::Value cnvrt = Fortran::lower::addCrayPointerInst(
4813                       loc, *builder, ptrVal, ptrTy, pteVal.getType());
4814                   addr = builder->create<fir::LoadOp>(loc, cnvrt);
4815                 }
4816                 mlir::Value cast =
4817                     isVector ? val
4818                              : builder->convertWithSemantics(loc, toTy, val);
4819                 if (fir::dyn_cast_ptrEleTy(addr.getType()) != toTy) {
4820                   assert(isFuncResultDesignator(assign.lhs) && "type mismatch");
4821                   addr = builder->createConvert(
4822                       toLocation(), builder->getRefType(toTy), addr);
4823                 }
4824                 builder->create<fir::StoreOp>(loc, cast, addr);
4825               } else if (isCharacterCategory(lhsType->category())) {
4826                 // Fortran 2018 10.2.1.3 p10 and p11
4827                 fir::factory::CharacterExprHelper{*builder, loc}.createAssign(
4828                     lhs, rhs);
4829               } else if (isDerivedCategory(lhsType->category())) {
4830                 // Handle parent component.
4831                 if (Fortran::lower::isParentComponent(assign.lhs)) {
4832                   if (!mlir::isa<fir::BaseBoxType>(fir::getBase(lhs).getType()))
4833                     lhs = fir::getBase(builder->createBox(loc, lhs));
4834                   lhs = Fortran::lower::updateBoxForParentComponent(*this, lhs,
4835                                                                     assign.lhs);
4836                 }
4837 
4838                 // Fortran 2018 10.2.1.3 p13 and p14
4839                 // Recursively gen an assignment on each element pair.
4840                 fir::factory::genRecordAssignment(*builder, loc, lhs, rhs,
4841                                                   needFinalization);
4842               } else {
4843                 llvm_unreachable("unknown category");
4844               }
4845               if (lhsIsWholeAllocatable) {
4846                 assert(lhsRealloc.has_value());
4847                 fir::factory::finalizeRealloc(*builder, loc, *lhsMutableBox,
4848                                               /*lbounds=*/std::nullopt,
4849                                               /*takeLboundsIfRealloc=*/false,
4850                                               *lhsRealloc);
4851               }
4852             },
4853 
4854             // [2] User defined assignment. If the context is a scalar
4855             // expression then call the procedure.
4856             [&](const Fortran::evaluate::ProcedureRef &procRef) {
4857               Fortran::lower::StatementContext &ctx =
4858                   explicitIterationSpace() ? explicitIterSpace.stmtContext()
4859                                            : stmtCtx;
4860               Fortran::lower::createSubroutineCall(
4861                   *this, procRef, explicitIterSpace, implicitIterSpace,
4862                   localSymbols, ctx, /*isUserDefAssignment=*/true);
4863             },
4864 
4865             [&](const Fortran::evaluate::Assignment::BoundsSpec &lbExprs) {
4866               return genPointerAssignment(loc, assign, lbExprs);
4867             },
4868             [&](const Fortran::evaluate::Assignment::BoundsRemapping
4869                     &boundExprs) {
4870               return genPointerAssignment(loc, assign, boundExprs);
4871             },
4872         },
4873         assign.u);
4874     if (explicitIterationSpace())
4875       Fortran::lower::createArrayMergeStores(*this, explicitIterSpace);
4876   }
4877 
4878   // Is the insertion point of the builder directly or indirectly set
4879   // inside any operation of type "Op"?
4880   template <typename... Op>
4881   bool isInsideOp() const {
4882     mlir::Block *block = builder->getInsertionBlock();
4883     mlir::Operation *op = block ? block->getParentOp() : nullptr;
4884     while (op) {
4885       if (mlir::isa<Op...>(op))
4886         return true;
4887       op = op->getParentOp();
4888     }
4889     return false;
4890   }
4891   bool isInsideHlfirForallOrWhere() const {
4892     return isInsideOp<hlfir::ForallOp, hlfir::WhereOp>();
4893   }
4894   bool isInsideHlfirWhere() const { return isInsideOp<hlfir::WhereOp>(); }
4895 
4896   void genFIR(const Fortran::parser::WhereConstruct &c) {
4897     mlir::Location loc = getCurrentLocation();
4898     hlfir::WhereOp whereOp;
4899 
4900     if (!lowerToHighLevelFIR()) {
4901       implicitIterSpace.growStack();
4902     } else {
4903       whereOp = builder->create<hlfir::WhereOp>(loc);
4904       builder->createBlock(&whereOp.getMaskRegion());
4905     }
4906 
4907     // Lower the where mask. For HLFIR, this is done in the hlfir.where mask
4908     // region.
4909     genNestedStatement(
4910         std::get<
4911             Fortran::parser::Statement<Fortran::parser::WhereConstructStmt>>(
4912             c.t));
4913 
4914     // Lower WHERE body. For HLFIR, this is done in the hlfir.where body
4915     // region.
4916     if (whereOp)
4917       builder->createBlock(&whereOp.getBody());
4918 
4919     for (const auto &body :
4920          std::get<std::list<Fortran::parser::WhereBodyConstruct>>(c.t))
4921       genFIR(body);
4922     for (const auto &e :
4923          std::get<std::list<Fortran::parser::WhereConstruct::MaskedElsewhere>>(
4924              c.t))
4925       genFIR(e);
4926     if (const auto &e =
4927             std::get<std::optional<Fortran::parser::WhereConstruct::Elsewhere>>(
4928                 c.t);
4929         e.has_value())
4930       genFIR(*e);
4931     genNestedStatement(
4932         std::get<Fortran::parser::Statement<Fortran::parser::EndWhereStmt>>(
4933             c.t));
4934 
4935     if (whereOp) {
4936       // For HLFIR, create fir.end terminator in the last hlfir.elsewhere, or
4937       // in the hlfir.where if it had no elsewhere.
4938       builder->create<fir::FirEndOp>(loc);
4939       builder->setInsertionPointAfter(whereOp);
4940     }
4941   }
4942   void genFIR(const Fortran::parser::WhereBodyConstruct &body) {
4943     Fortran::common::visit(
4944         Fortran::common::visitors{
4945             [&](const Fortran::parser::Statement<
4946                 Fortran::parser::AssignmentStmt> &stmt) {
4947               genNestedStatement(stmt);
4948             },
4949             [&](const Fortran::parser::Statement<Fortran::parser::WhereStmt>
4950                     &stmt) { genNestedStatement(stmt); },
4951             [&](const Fortran::common::Indirection<
4952                 Fortran::parser::WhereConstruct> &c) { genFIR(c.value()); },
4953         },
4954         body.u);
4955   }
4956 
4957   /// Lower a Where or Elsewhere mask into an hlfir mask region.
4958   void lowerWhereMaskToHlfir(mlir::Location loc,
4959                              const Fortran::semantics::SomeExpr *maskExpr) {
4960     assert(maskExpr && "mask semantic analysis failed");
4961     Fortran::lower::StatementContext maskContext;
4962     hlfir::Entity mask = Fortran::lower::convertExprToHLFIR(
4963         loc, *this, *maskExpr, localSymbols, maskContext);
4964     mask = hlfir::loadTrivialScalar(loc, *builder, mask);
4965     auto yieldOp = builder->create<hlfir::YieldOp>(loc, mask);
4966     Fortran::lower::genCleanUpInRegionIfAny(loc, *builder, yieldOp.getCleanup(),
4967                                             maskContext);
4968   }
4969   void genFIR(const Fortran::parser::WhereConstructStmt &stmt) {
4970     const Fortran::semantics::SomeExpr *maskExpr = Fortran::semantics::GetExpr(
4971         std::get<Fortran::parser::LogicalExpr>(stmt.t));
4972     if (lowerToHighLevelFIR())
4973       lowerWhereMaskToHlfir(getCurrentLocation(), maskExpr);
4974     else
4975       implicitIterSpace.append(maskExpr);
4976   }
4977   void genFIR(const Fortran::parser::WhereConstruct::MaskedElsewhere &ew) {
4978     mlir::Location loc = getCurrentLocation();
4979     hlfir::ElseWhereOp elsewhereOp;
4980     if (lowerToHighLevelFIR()) {
4981       elsewhereOp = builder->create<hlfir::ElseWhereOp>(loc);
4982       // Lower mask in the mask region.
4983       builder->createBlock(&elsewhereOp.getMaskRegion());
4984     }
4985     genNestedStatement(
4986         std::get<
4987             Fortran::parser::Statement<Fortran::parser::MaskedElsewhereStmt>>(
4988             ew.t));
4989 
4990     // For HLFIR, lower the body in the hlfir.elsewhere body region.
4991     if (elsewhereOp)
4992       builder->createBlock(&elsewhereOp.getBody());
4993 
4994     for (const auto &body :
4995          std::get<std::list<Fortran::parser::WhereBodyConstruct>>(ew.t))
4996       genFIR(body);
4997   }
4998   void genFIR(const Fortran::parser::MaskedElsewhereStmt &stmt) {
4999     const auto *maskExpr = Fortran::semantics::GetExpr(
5000         std::get<Fortran::parser::LogicalExpr>(stmt.t));
5001     if (lowerToHighLevelFIR())
5002       lowerWhereMaskToHlfir(getCurrentLocation(), maskExpr);
5003     else
5004       implicitIterSpace.append(maskExpr);
5005   }
5006   void genFIR(const Fortran::parser::WhereConstruct::Elsewhere &ew) {
5007     if (lowerToHighLevelFIR()) {
5008       auto elsewhereOp =
5009           builder->create<hlfir::ElseWhereOp>(getCurrentLocation());
5010       builder->createBlock(&elsewhereOp.getBody());
5011     }
5012     genNestedStatement(
5013         std::get<Fortran::parser::Statement<Fortran::parser::ElsewhereStmt>>(
5014             ew.t));
5015     for (const auto &body :
5016          std::get<std::list<Fortran::parser::WhereBodyConstruct>>(ew.t))
5017       genFIR(body);
5018   }
5019   void genFIR(const Fortran::parser::ElsewhereStmt &stmt) {
5020     if (!lowerToHighLevelFIR())
5021       implicitIterSpace.append(nullptr);
5022   }
5023   void genFIR(const Fortran::parser::EndWhereStmt &) {
5024     if (!lowerToHighLevelFIR())
5025       implicitIterSpace.shrinkStack();
5026   }
5027 
5028   void genFIR(const Fortran::parser::WhereStmt &stmt) {
5029     Fortran::lower::StatementContext stmtCtx;
5030     const auto &assign = std::get<Fortran::parser::AssignmentStmt>(stmt.t);
5031     const auto *mask = Fortran::semantics::GetExpr(
5032         std::get<Fortran::parser::LogicalExpr>(stmt.t));
5033     if (lowerToHighLevelFIR()) {
5034       mlir::Location loc = getCurrentLocation();
5035       auto whereOp = builder->create<hlfir::WhereOp>(loc);
5036       builder->createBlock(&whereOp.getMaskRegion());
5037       lowerWhereMaskToHlfir(loc, mask);
5038       builder->createBlock(&whereOp.getBody());
5039       genAssignment(*assign.typedAssignment->v);
5040       builder->create<fir::FirEndOp>(loc);
5041       builder->setInsertionPointAfter(whereOp);
5042       return;
5043     }
5044     implicitIterSpace.growStack();
5045     implicitIterSpace.append(mask);
5046     genAssignment(*assign.typedAssignment->v);
5047     implicitIterSpace.shrinkStack();
5048   }
5049 
5050   void genFIR(const Fortran::parser::PointerAssignmentStmt &stmt) {
5051     genAssignment(*stmt.typedAssignment->v);
5052   }
5053 
5054   void genFIR(const Fortran::parser::AssignmentStmt &stmt) {
5055     genAssignment(*stmt.typedAssignment->v);
5056   }
5057 
5058   void genFIR(const Fortran::parser::SyncAllStmt &stmt) {
5059     genSyncAllStatement(*this, stmt);
5060   }
5061 
5062   void genFIR(const Fortran::parser::SyncImagesStmt &stmt) {
5063     genSyncImagesStatement(*this, stmt);
5064   }
5065 
5066   void genFIR(const Fortran::parser::SyncMemoryStmt &stmt) {
5067     genSyncMemoryStatement(*this, stmt);
5068   }
5069 
5070   void genFIR(const Fortran::parser::SyncTeamStmt &stmt) {
5071     genSyncTeamStatement(*this, stmt);
5072   }
5073 
5074   void genFIR(const Fortran::parser::UnlockStmt &stmt) {
5075     genUnlockStatement(*this, stmt);
5076   }
5077 
5078   void genFIR(const Fortran::parser::AssignStmt &stmt) {
5079     const Fortran::semantics::Symbol &symbol =
5080         *std::get<Fortran::parser::Name>(stmt.t).symbol;
5081     mlir::Location loc = toLocation();
5082     mlir::Value labelValue = builder->createIntegerConstant(
5083         loc, genType(symbol), std::get<Fortran::parser::Label>(stmt.t));
5084     builder->create<fir::StoreOp>(loc, labelValue, getSymbolAddress(symbol));
5085   }
5086 
5087   void genFIR(const Fortran::parser::FormatStmt &) {
5088     // do nothing.
5089 
5090     // FORMAT statements have no semantics. They may be lowered if used by a
5091     // data transfer statement.
5092   }
5093 
5094   void genFIR(const Fortran::parser::PauseStmt &stmt) {
5095     genPauseStatement(*this, stmt);
5096   }
5097 
5098   // call FAIL IMAGE in runtime
5099   void genFIR(const Fortran::parser::FailImageStmt &stmt) {
5100     genFailImageStatement(*this);
5101   }
5102 
5103   // call STOP, ERROR STOP in runtime
5104   void genFIR(const Fortran::parser::StopStmt &stmt) {
5105     genStopStatement(*this, stmt);
5106   }
5107 
5108   void genFIR(const Fortran::parser::ReturnStmt &stmt) {
5109     Fortran::lower::pft::FunctionLikeUnit *funit =
5110         getEval().getOwningProcedure();
5111     assert(funit && "not inside main program, function or subroutine");
5112     for (auto it = activeConstructStack.rbegin(),
5113               rend = activeConstructStack.rend();
5114          it != rend; ++it) {
5115       it->stmtCtx.finalizeAndKeep();
5116     }
5117     if (funit->isMainProgram()) {
5118       genExitRoutine(true);
5119       return;
5120     }
5121     mlir::Location loc = toLocation();
5122     if (stmt.v) {
5123       // Alternate return statement - If this is a subroutine where some
5124       // alternate entries have alternate returns, but the active entry point
5125       // does not, ignore the alternate return value. Otherwise, assign it
5126       // to the compiler-generated result variable.
5127       const Fortran::semantics::Symbol &symbol = funit->getSubprogramSymbol();
5128       if (Fortran::semantics::HasAlternateReturns(symbol)) {
5129         Fortran::lower::StatementContext stmtCtx;
5130         const Fortran::lower::SomeExpr *expr =
5131             Fortran::semantics::GetExpr(*stmt.v);
5132         assert(expr && "missing alternate return expression");
5133         mlir::Value altReturnIndex = builder->createConvert(
5134             loc, builder->getIndexType(), createFIRExpr(loc, expr, stmtCtx));
5135         builder->create<fir::StoreOp>(loc, altReturnIndex,
5136                                       getAltReturnResult(symbol));
5137       }
5138     }
5139     // Branch to the last block of the SUBROUTINE, which has the actual return.
5140     if (!funit->finalBlock) {
5141       mlir::OpBuilder::InsertPoint insPt = builder->saveInsertionPoint();
5142       Fortran::lower::setInsertionPointAfterOpenACCLoopIfInside(*builder);
5143       funit->finalBlock = builder->createBlock(&builder->getRegion());
5144       builder->restoreInsertionPoint(insPt);
5145     }
5146 
5147     if (Fortran::lower::isInOpenACCLoop(*builder))
5148       Fortran::lower::genEarlyReturnInOpenACCLoop(*builder, loc);
5149     else
5150       builder->create<mlir::cf::BranchOp>(loc, funit->finalBlock);
5151   }
5152 
5153   void genFIR(const Fortran::parser::CycleStmt &) {
5154     genConstructExitBranch(*getEval().controlSuccessor);
5155   }
5156   void genFIR(const Fortran::parser::ExitStmt &) {
5157     genConstructExitBranch(*getEval().controlSuccessor);
5158   }
5159   void genFIR(const Fortran::parser::GotoStmt &) {
5160     genConstructExitBranch(*getEval().controlSuccessor);
5161   }
5162 
5163   // Nop statements - No code, or code is generated at the construct level.
5164   // But note that the genFIR call immediately below that wraps one of these
5165   // calls does block management, possibly starting a new block, and possibly
5166   // generating a branch to end a block. So these calls may still be required
5167   // for that functionality.
5168   void genFIR(const Fortran::parser::AssociateStmt &) {}       // nop
5169   void genFIR(const Fortran::parser::BlockStmt &) {}           // nop
5170   void genFIR(const Fortran::parser::CaseStmt &) {}            // nop
5171   void genFIR(const Fortran::parser::ContinueStmt &) {}        // nop
5172   void genFIR(const Fortran::parser::ElseIfStmt &) {}          // nop
5173   void genFIR(const Fortran::parser::ElseStmt &) {}            // nop
5174   void genFIR(const Fortran::parser::EndAssociateStmt &) {}    // nop
5175   void genFIR(const Fortran::parser::EndBlockStmt &) {}        // nop
5176   void genFIR(const Fortran::parser::EndDoStmt &) {}           // nop
5177   void genFIR(const Fortran::parser::EndFunctionStmt &) {}     // nop
5178   void genFIR(const Fortran::parser::EndIfStmt &) {}           // nop
5179   void genFIR(const Fortran::parser::EndMpSubprogramStmt &) {} // nop
5180   void genFIR(const Fortran::parser::EndProgramStmt &) {}      // nop
5181   void genFIR(const Fortran::parser::EndSelectStmt &) {}       // nop
5182   void genFIR(const Fortran::parser::EndSubroutineStmt &) {}   // nop
5183   void genFIR(const Fortran::parser::EntryStmt &) {}           // nop
5184   void genFIR(const Fortran::parser::IfStmt &) {}              // nop
5185   void genFIR(const Fortran::parser::IfThenStmt &) {}          // nop
5186   void genFIR(const Fortran::parser::NonLabelDoStmt &) {}      // nop
5187   void genFIR(const Fortran::parser::OmpEndLoopDirective &) {} // nop
5188   void genFIR(const Fortran::parser::SelectTypeStmt &) {}      // nop
5189   void genFIR(const Fortran::parser::TypeGuardStmt &) {}       // nop
5190 
5191   /// Generate FIR for Evaluation \p eval.
5192   void genFIR(Fortran::lower::pft::Evaluation &eval,
5193               bool unstructuredContext = true) {
5194     // Start a new unstructured block when applicable. When transitioning
5195     // from unstructured to structured code, unstructuredContext is true,
5196     // which accounts for the possibility that the structured code could be
5197     // a target that starts a new block.
5198     if (unstructuredContext)
5199       maybeStartBlock(eval.isConstruct() && eval.lowerAsStructured()
5200                           ? eval.getFirstNestedEvaluation().block
5201                           : eval.block);
5202 
5203     // Generate evaluation specific code. Even nop calls should usually reach
5204     // here in case they start a new block or require generation of a generic
5205     // end-of-block branch. An alternative is to add special case code
5206     // elsewhere, such as in the genFIR code for a parent construct.
5207     setCurrentEval(eval);
5208     setCurrentPosition(eval.position);
5209     eval.visit([&](const auto &stmt) { genFIR(stmt); });
5210   }
5211 
5212   /// Map mlir function block arguments to the corresponding Fortran dummy
5213   /// variables. When the result is passed as a hidden argument, the Fortran
5214   /// result is also mapped. The symbol map is used to hold this mapping.
5215   void mapDummiesAndResults(Fortran::lower::pft::FunctionLikeUnit &funit,
5216                             const Fortran::lower::CalleeInterface &callee) {
5217     assert(builder && "require a builder object at this point");
5218     using PassBy = Fortran::lower::CalleeInterface::PassEntityBy;
5219     auto mapPassedEntity = [&](const auto arg, bool isResult = false) {
5220       if (arg.passBy == PassBy::AddressAndLength) {
5221         if (callee.characterize().IsBindC())
5222           return;
5223         // TODO: now that fir call has some attributes regarding character
5224         // return, PassBy::AddressAndLength should be retired.
5225         mlir::Location loc = toLocation();
5226         fir::factory::CharacterExprHelper charHelp{*builder, loc};
5227         mlir::Value box =
5228             charHelp.createEmboxChar(arg.firArgument, arg.firLength);
5229         mapBlockArgToDummyOrResult(arg.entity->get(), box, isResult);
5230       } else {
5231         if (arg.entity.has_value()) {
5232           mapBlockArgToDummyOrResult(arg.entity->get(), arg.firArgument,
5233                                      isResult);
5234         } else {
5235           assert(funit.parentHasTupleHostAssoc() && "expect tuple argument");
5236         }
5237       }
5238     };
5239     for (const Fortran::lower::CalleeInterface::PassedEntity &arg :
5240          callee.getPassedArguments())
5241       mapPassedEntity(arg);
5242     if (lowerToHighLevelFIR() && !callee.getPassedArguments().empty()) {
5243       mlir::Value scopeOp = builder->create<fir::DummyScopeOp>(toLocation());
5244       setDummyArgsScope(scopeOp);
5245     }
5246     if (std::optional<Fortran::lower::CalleeInterface::PassedEntity>
5247             passedResult = callee.getPassedResult()) {
5248       mapPassedEntity(*passedResult, /*isResult=*/true);
5249       // FIXME: need to make sure things are OK here. addSymbol may not be OK
5250       if (funit.primaryResult &&
5251           passedResult->entity->get() != *funit.primaryResult)
5252         mapBlockArgToDummyOrResult(
5253             *funit.primaryResult, getSymbolAddress(passedResult->entity->get()),
5254             /*isResult=*/true);
5255     }
5256   }
5257 
5258   /// Instantiate variable \p var and add it to the symbol map.
5259   /// See ConvertVariable.cpp.
5260   void instantiateVar(const Fortran::lower::pft::Variable &var,
5261                       Fortran::lower::AggregateStoreMap &storeMap) {
5262     Fortran::lower::instantiateVariable(*this, var, localSymbols, storeMap);
5263     if (var.hasSymbol())
5264       genOpenMPSymbolProperties(*this, var);
5265   }
5266 
5267   /// Where applicable, save the exception state and halting, rounding, and
5268   /// underflow modes at function entry, and restore them at function exits.
5269   void manageFPEnvironment(Fortran::lower::pft::FunctionLikeUnit &funit) {
5270     mlir::Location loc = toLocation();
5271     mlir::Location endLoc =
5272         toLocation(Fortran::lower::pft::stmtSourceLoc(funit.endStmt));
5273     if (funit.hasIeeeAccess) {
5274       // Subject to F18 Clause 17.1p3, 17.3p3 states: If a flag is signaling
5275       // on entry to a procedure [...], the processor will set it to quiet
5276       // on entry and restore it to signaling on return. If a flag signals
5277       // during execution of a procedure, the processor shall not set it to
5278       // quiet on return.
5279       mlir::func::FuncOp testExcept = fir::factory::getFetestexcept(*builder);
5280       mlir::func::FuncOp clearExcept = fir::factory::getFeclearexcept(*builder);
5281       mlir::func::FuncOp raiseExcept = fir::factory::getFeraiseexcept(*builder);
5282       mlir::Value ones = builder->createIntegerConstant(
5283           loc, testExcept.getFunctionType().getInput(0), -1);
5284       mlir::Value exceptSet =
5285           builder->create<fir::CallOp>(loc, testExcept, ones).getResult(0);
5286       builder->create<fir::CallOp>(loc, clearExcept, exceptSet);
5287       bridge.fctCtx().attachCleanup([=]() {
5288         builder->create<fir::CallOp>(endLoc, raiseExcept, exceptSet);
5289       });
5290     }
5291     if (funit.mayModifyHaltingMode) {
5292       // F18 Clause 17.6p1: In a procedure [...], the processor shall not
5293       // change the halting mode on entry, and on return shall ensure that
5294       // the halting mode is the same as it was on entry.
5295       mlir::func::FuncOp getExcept = fir::factory::getFegetexcept(*builder);
5296       mlir::func::FuncOp disableExcept =
5297           fir::factory::getFedisableexcept(*builder);
5298       mlir::func::FuncOp enableExcept =
5299           fir::factory::getFeenableexcept(*builder);
5300       mlir::Value exceptSet =
5301           builder->create<fir::CallOp>(loc, getExcept).getResult(0);
5302       mlir::Value ones = builder->createIntegerConstant(
5303           loc, disableExcept.getFunctionType().getInput(0), -1);
5304       bridge.fctCtx().attachCleanup([=]() {
5305         builder->create<fir::CallOp>(endLoc, disableExcept, ones);
5306         builder->create<fir::CallOp>(endLoc, enableExcept, exceptSet);
5307       });
5308     }
5309     if (funit.mayModifyRoundingMode) {
5310       // F18 Clause 17.4p5: In a procedure [...], the processor shall not
5311       // change the rounding modes on entry, and on return shall ensure that
5312       // the rounding modes are the same as they were on entry.
5313       mlir::func::FuncOp getRounding =
5314           fir::factory::getLlvmGetRounding(*builder);
5315       mlir::func::FuncOp setRounding =
5316           fir::factory::getLlvmSetRounding(*builder);
5317       mlir::Value roundingMode =
5318           builder->create<fir::CallOp>(loc, getRounding).getResult(0);
5319       bridge.fctCtx().attachCleanup([=]() {
5320         builder->create<fir::CallOp>(endLoc, setRounding, roundingMode);
5321       });
5322     }
5323     if ((funit.mayModifyUnderflowMode) &&
5324         (bridge.getTargetCharacteristics().hasSubnormalFlushingControl(
5325             /*any=*/true))) {
5326       // F18 Clause 17.5p2: In a procedure [...], the processor shall not
5327       // change the underflow mode on entry, and on return shall ensure that
5328       // the underflow mode is the same as it was on entry.
5329       mlir::Value underflowMode =
5330           fir::runtime::genGetUnderflowMode(*builder, loc);
5331       bridge.fctCtx().attachCleanup([=]() {
5332         fir::runtime::genSetUnderflowMode(*builder, loc, {underflowMode});
5333       });
5334     }
5335   }
5336 
5337   /// Start translation of a function.
5338   void startNewFunction(Fortran::lower::pft::FunctionLikeUnit &funit) {
5339     assert(!builder && "expected nullptr");
5340     bridge.fctCtx().pushScope();
5341     bridge.openAccCtx().pushScope();
5342     const Fortran::semantics::Scope &scope = funit.getScope();
5343     LLVM_DEBUG(llvm::dbgs() << "\n[bridge - startNewFunction]";
5344                if (auto *sym = scope.symbol()) llvm::dbgs() << " " << *sym;
5345                llvm::dbgs() << "\n");
5346     Fortran::lower::CalleeInterface callee(funit, *this);
5347     mlir::func::FuncOp func = callee.addEntryBlockAndMapArguments();
5348     builder =
5349         new fir::FirOpBuilder(func, bridge.getKindMap(), &mlirSymbolTable);
5350     assert(builder && "FirOpBuilder did not instantiate");
5351     builder->setFastMathFlags(bridge.getLoweringOptions().getMathOptions());
5352     builder->setInsertionPointToStart(&func.front());
5353     if (funit.parent.isA<Fortran::lower::pft::FunctionLikeUnit>()) {
5354       // Give internal linkage to internal functions. There are no name clash
5355       // risks, but giving global linkage to internal procedure will break the
5356       // static link register in shared libraries because of the system calls.
5357       // Also, it should be possible to eliminate the procedure code if all the
5358       // uses have been inlined.
5359       fir::factory::setInternalLinkage(func);
5360     } else {
5361       func.setVisibility(mlir::SymbolTable::Visibility::Public);
5362     }
5363     assert(blockId == 0 && "invalid blockId");
5364     assert(activeConstructStack.empty() && "invalid construct stack state");
5365 
5366     // Manage floating point exception, halting mode, and rounding mode
5367     // settings at function entry and exit.
5368     if (!funit.isMainProgram())
5369       manageFPEnvironment(funit);
5370 
5371     mapDummiesAndResults(funit, callee);
5372 
5373     // Map host associated symbols from parent procedure if any.
5374     if (funit.parentHasHostAssoc())
5375       funit.parentHostAssoc().internalProcedureBindings(*this, localSymbols);
5376 
5377     // Non-primary results of a function with multiple entry points.
5378     // These result values share storage with the primary result.
5379     llvm::SmallVector<Fortran::lower::pft::Variable> deferredFuncResultList;
5380 
5381     // Backup actual argument for entry character results with different
5382     // lengths. It needs to be added to the non-primary results symbol before
5383     // mapSymbolAttributes is called.
5384     Fortran::lower::SymbolBox resultArg;
5385     if (std::optional<Fortran::lower::CalleeInterface::PassedEntity>
5386             passedResult = callee.getPassedResult())
5387       resultArg = lookupSymbol(passedResult->entity->get());
5388 
5389     Fortran::lower::AggregateStoreMap storeMap;
5390 
5391     // Map all containing submodule and module equivalences and variables, in
5392     // case they are referenced. It might be better to limit this to variables
5393     // that are actually referenced, although that is more complicated when
5394     // there are equivalenced variables.
5395     auto &scopeVariableListMap =
5396         Fortran::lower::pft::getScopeVariableListMap(funit);
5397     for (auto *scp = &scope.parent(); !scp->IsGlobal(); scp = &scp->parent())
5398       if (scp->kind() == Fortran::semantics::Scope::Kind::Module)
5399         for (const auto &var : Fortran::lower::pft::getScopeVariableList(
5400                  *scp, scopeVariableListMap))
5401           if (!var.isRuntimeTypeInfoData())
5402             instantiateVar(var, storeMap);
5403 
5404     // Map function equivalences and variables.
5405     mlir::Value primaryFuncResultStorage;
5406     for (const Fortran::lower::pft::Variable &var :
5407          Fortran::lower::pft::getScopeVariableList(scope)) {
5408       // Always instantiate aggregate storage blocks.
5409       if (var.isAggregateStore()) {
5410         instantiateVar(var, storeMap);
5411         continue;
5412       }
5413       const Fortran::semantics::Symbol &sym = var.getSymbol();
5414       if (funit.parentHasHostAssoc()) {
5415         // Never instantiate host associated variables, as they are already
5416         // instantiated from an argument tuple. Instead, just bind the symbol
5417         // to the host variable, which must be in the map.
5418         const Fortran::semantics::Symbol &ultimate = sym.GetUltimate();
5419         if (funit.parentHostAssoc().isAssociated(ultimate)) {
5420           copySymbolBinding(ultimate, sym);
5421           continue;
5422         }
5423       }
5424       if (!sym.IsFuncResult() || !funit.primaryResult) {
5425         instantiateVar(var, storeMap);
5426       } else if (&sym == funit.primaryResult) {
5427         instantiateVar(var, storeMap);
5428         primaryFuncResultStorage = getSymbolAddress(sym);
5429       } else {
5430         deferredFuncResultList.push_back(var);
5431       }
5432     }
5433 
5434     // TODO: should use same mechanism as equivalence?
5435     // One blocking point is character entry returns that need special handling
5436     // since they are not locally allocated but come as argument. CHARACTER(*)
5437     // is not something that fits well with equivalence lowering.
5438     for (const Fortran::lower::pft::Variable &altResult :
5439          deferredFuncResultList) {
5440       Fortran::lower::StatementContext stmtCtx;
5441       if (std::optional<Fortran::lower::CalleeInterface::PassedEntity>
5442               passedResult = callee.getPassedResult()) {
5443         mapBlockArgToDummyOrResult(altResult.getSymbol(), resultArg.getAddr(),
5444                                    /*isResult=*/true);
5445         Fortran::lower::mapSymbolAttributes(*this, altResult, localSymbols,
5446                                             stmtCtx);
5447       } else {
5448         // catch cases where the allocation for the function result storage type
5449         // doesn't match the type of this symbol
5450         mlir::Value preAlloc = primaryFuncResultStorage;
5451         mlir::Type resTy = primaryFuncResultStorage.getType();
5452         mlir::Type symTy = genType(altResult);
5453         mlir::Type wrappedSymTy = fir::ReferenceType::get(symTy);
5454         if (resTy != wrappedSymTy) {
5455           // check size of the pointed to type so we can't overflow by writing
5456           // double precision to a single precision allocation, etc
5457           LLVM_ATTRIBUTE_UNUSED auto getBitWidth = [this](mlir::Type ty) {
5458             // 15.6.2.6.3: differering result types should be integer, real,
5459             // complex or logical
5460             if (auto cmplx = mlir::dyn_cast_or_null<mlir::ComplexType>(ty))
5461               return 2 * cmplx.getElementType().getIntOrFloatBitWidth();
5462             if (auto logical = mlir::dyn_cast_or_null<fir::LogicalType>(ty)) {
5463               fir::KindTy kind = logical.getFKind();
5464               return builder->getKindMap().getLogicalBitsize(kind);
5465             }
5466             return ty.getIntOrFloatBitWidth();
5467           };
5468           assert(getBitWidth(fir::unwrapRefType(resTy)) >= getBitWidth(symTy));
5469 
5470           // convert the storage to the symbol type so that the hlfir.declare
5471           // gets the correct type for this symbol
5472           preAlloc = builder->create<fir::ConvertOp>(getCurrentLocation(),
5473                                                      wrappedSymTy, preAlloc);
5474         }
5475 
5476         Fortran::lower::mapSymbolAttributes(*this, altResult, localSymbols,
5477                                             stmtCtx, preAlloc);
5478       }
5479     }
5480 
5481     // If this is a host procedure with host associations, then create the tuple
5482     // of pointers for passing to the internal procedures.
5483     if (!funit.getHostAssoc().empty())
5484       funit.getHostAssoc().hostProcedureBindings(*this, localSymbols);
5485 
5486     // Unregister all dummy symbols, so that their cloning (e.g. for OpenMP
5487     // privatization) does not create the cloned hlfir.declare operations
5488     // with dummy_scope operands.
5489     resetRegisteredDummySymbols();
5490 
5491     // Create most function blocks in advance.
5492     createEmptyBlocks(funit.evaluationList);
5493 
5494     // Reinstate entry block as the current insertion point.
5495     builder->setInsertionPointToEnd(&func.front());
5496 
5497     if (callee.hasAlternateReturns()) {
5498       // Create a local temp to hold the alternate return index.
5499       // Give it an integer index type and the subroutine name (for dumps).
5500       // Attach it to the subroutine symbol in the localSymbols map.
5501       // Initialize it to zero, the "fallthrough" alternate return value.
5502       const Fortran::semantics::Symbol &symbol = funit.getSubprogramSymbol();
5503       mlir::Location loc = toLocation();
5504       mlir::Type idxTy = builder->getIndexType();
5505       mlir::Value altResult =
5506           builder->createTemporary(loc, idxTy, toStringRef(symbol.name()));
5507       addSymbol(symbol, altResult);
5508       mlir::Value zero = builder->createIntegerConstant(loc, idxTy, 0);
5509       builder->create<fir::StoreOp>(loc, zero, altResult);
5510     }
5511 
5512     if (Fortran::lower::pft::Evaluation *alternateEntryEval =
5513             funit.getEntryEval())
5514       genBranch(alternateEntryEval->lexicalSuccessor->block);
5515   }
5516 
5517   /// Create global blocks for the current function. This eliminates the
5518   /// distinction between forward and backward targets when generating
5519   /// branches. A block is "global" if it can be the target of a GOTO or
5520   /// other source code branch. A block that can only be targeted by a
5521   /// compiler generated branch is "local". For example, a DO loop preheader
5522   /// block containing loop initialization code is global. A loop header
5523   /// block, which is the target of the loop back edge, is local. Blocks
5524   /// belong to a region. Any block within a nested region must be replaced
5525   /// with a block belonging to that region. Branches may not cross region
5526   /// boundaries.
5527   void createEmptyBlocks(
5528       std::list<Fortran::lower::pft::Evaluation> &evaluationList) {
5529     mlir::Region *region = &builder->getRegion();
5530     for (Fortran::lower::pft::Evaluation &eval : evaluationList) {
5531       if (eval.isNewBlock)
5532         eval.block = builder->createBlock(region);
5533       if (eval.isConstruct() || eval.isDirective()) {
5534         if (eval.lowerAsUnstructured()) {
5535           createEmptyBlocks(eval.getNestedEvaluations());
5536         } else if (eval.hasNestedEvaluations()) {
5537           // A structured construct that is a target starts a new block.
5538           Fortran::lower::pft::Evaluation &constructStmt =
5539               eval.getFirstNestedEvaluation();
5540           if (constructStmt.isNewBlock)
5541             constructStmt.block = builder->createBlock(region);
5542         }
5543       }
5544     }
5545   }
5546 
5547   /// Return the predicate: "current block does not have a terminator branch".
5548   bool blockIsUnterminated() {
5549     mlir::Block *currentBlock = builder->getBlock();
5550     return currentBlock->empty() ||
5551            !currentBlock->back().hasTrait<mlir::OpTrait::IsTerminator>();
5552   }
5553 
5554   /// Unconditionally switch code insertion to a new block.
5555   void startBlock(mlir::Block *newBlock) {
5556     assert(newBlock && "missing block");
5557     // Default termination for the current block is a fallthrough branch to
5558     // the new block.
5559     if (blockIsUnterminated())
5560       genBranch(newBlock);
5561     // Some blocks may be re/started more than once, and might not be empty.
5562     // If the new block already has (only) a terminator, set the insertion
5563     // point to the start of the block. Otherwise set it to the end.
5564     builder->setInsertionPointToStart(newBlock);
5565     if (blockIsUnterminated())
5566       builder->setInsertionPointToEnd(newBlock);
5567   }
5568 
5569   /// Conditionally switch code insertion to a new block.
5570   void maybeStartBlock(mlir::Block *newBlock) {
5571     if (newBlock)
5572       startBlock(newBlock);
5573   }
5574 
5575   void eraseDeadCodeAndBlocks(mlir::RewriterBase &rewriter,
5576                               llvm::MutableArrayRef<mlir::Region> regions) {
5577     // WARNING: Do not add passes that can do folding or code motion here
5578     // because they might cross omp.target region boundaries, which can result
5579     // in incorrect code. Optimization passes like these must be added after
5580     // OMP early outlining has been done.
5581     (void)mlir::eraseUnreachableBlocks(rewriter, regions);
5582     (void)mlir::runRegionDCE(rewriter, regions);
5583   }
5584 
5585   /// Finish translation of a function.
5586   void endNewFunction(Fortran::lower::pft::FunctionLikeUnit &funit) {
5587     setCurrentPosition(Fortran::lower::pft::stmtSourceLoc(funit.endStmt));
5588     if (funit.isMainProgram()) {
5589       genExitRoutine(false);
5590     } else {
5591       genFIRProcedureExit(funit, funit.getSubprogramSymbol());
5592     }
5593     funit.finalBlock = nullptr;
5594     LLVM_DEBUG(llvm::dbgs() << "\n[bridge - endNewFunction";
5595                if (auto *sym = funit.scope->symbol()) llvm::dbgs()
5596                << " " << sym->name();
5597                llvm::dbgs() << "] generated IR:\n\n"
5598                             << *builder->getFunction() << '\n');
5599     // Eliminate dead code as a prerequisite to calling other IR passes.
5600     // FIXME: This simplification should happen in a normal pass, not here.
5601     mlir::IRRewriter rewriter(*builder);
5602     (void)eraseDeadCodeAndBlocks(rewriter, {builder->getRegion()});
5603     delete builder;
5604     builder = nullptr;
5605     hostAssocTuple = mlir::Value{};
5606     localSymbols.clear();
5607     blockId = 0;
5608     dummyArgsScope = mlir::Value{};
5609     resetRegisteredDummySymbols();
5610   }
5611 
5612   /// Helper to generate GlobalOps when the builder is not positioned in any
5613   /// region block. This is required because the FirOpBuilder assumes it is
5614   /// always positioned inside a region block when creating globals, the easiest
5615   /// way comply is to create a dummy function and to throw it afterwards.
5616   void createGlobalOutsideOfFunctionLowering(
5617       const std::function<void()> &createGlobals) {
5618     // FIXME: get rid of the bogus function context and instantiate the
5619     // globals directly into the module.
5620     mlir::MLIRContext *context = &getMLIRContext();
5621     mlir::SymbolTable *symbolTable = getMLIRSymbolTable();
5622     mlir::func::FuncOp func = fir::FirOpBuilder::createFunction(
5623         mlir::UnknownLoc::get(context), getModuleOp(),
5624         fir::NameUniquer::doGenerated("Sham"),
5625         mlir::FunctionType::get(context, std::nullopt, std::nullopt),
5626         symbolTable);
5627     func.addEntryBlock();
5628     builder = new fir::FirOpBuilder(func, bridge.getKindMap(), symbolTable);
5629     assert(builder && "FirOpBuilder did not instantiate");
5630     builder->setFastMathFlags(bridge.getLoweringOptions().getMathOptions());
5631     createGlobals();
5632     if (mlir::Region *region = func.getCallableRegion())
5633       region->dropAllReferences();
5634     func.erase();
5635     delete builder;
5636     builder = nullptr;
5637     localSymbols.clear();
5638     resetRegisteredDummySymbols();
5639   }
5640 
5641   /// Instantiate the data from a BLOCK DATA unit.
5642   void lowerBlockData(Fortran::lower::pft::BlockDataUnit &bdunit) {
5643     createGlobalOutsideOfFunctionLowering([&]() {
5644       Fortran::lower::AggregateStoreMap fakeMap;
5645       for (const auto &[_, sym] : bdunit.symTab) {
5646         if (sym->has<Fortran::semantics::ObjectEntityDetails>()) {
5647           Fortran::lower::pft::Variable var(*sym, true);
5648           instantiateVar(var, fakeMap);
5649         }
5650       }
5651     });
5652   }
5653 
5654   /// Create fir::Global for all the common blocks that appear in the program.
5655   void
5656   lowerCommonBlocks(const Fortran::semantics::CommonBlockList &commonBlocks) {
5657     createGlobalOutsideOfFunctionLowering(
5658         [&]() { Fortran::lower::defineCommonBlocks(*this, commonBlocks); });
5659   }
5660 
5661   /// Create intrinsic module array constant definitions.
5662   void createIntrinsicModuleDefinitions(Fortran::lower::pft::Program &pft) {
5663     // The intrinsic module scope, if present, is the first scope.
5664     const Fortran::semantics::Scope *intrinsicModuleScope = nullptr;
5665     for (Fortran::lower::pft::Program::Units &u : pft.getUnits()) {
5666       Fortran::common::visit(
5667           Fortran::common::visitors{
5668               [&](Fortran::lower::pft::FunctionLikeUnit &f) {
5669                 intrinsicModuleScope = &f.getScope().parent();
5670               },
5671               [&](Fortran::lower::pft::ModuleLikeUnit &m) {
5672                 intrinsicModuleScope = &m.getScope().parent();
5673               },
5674               [&](Fortran::lower::pft::BlockDataUnit &b) {},
5675               [&](Fortran::lower::pft::CompilerDirectiveUnit &d) {},
5676               [&](Fortran::lower::pft::OpenACCDirectiveUnit &d) {},
5677           },
5678           u);
5679       if (intrinsicModuleScope) {
5680         while (!intrinsicModuleScope->IsGlobal())
5681           intrinsicModuleScope = &intrinsicModuleScope->parent();
5682         intrinsicModuleScope = &intrinsicModuleScope->children().front();
5683         break;
5684       }
5685     }
5686     if (!intrinsicModuleScope || !intrinsicModuleScope->IsIntrinsicModules())
5687       return;
5688     for (const auto &scope : intrinsicModuleScope->children()) {
5689       llvm::StringRef modName = toStringRef(scope.symbol()->name());
5690       if (modName != "__fortran_ieee_exceptions")
5691         continue;
5692       for (auto &var : Fortran::lower::pft::getScopeVariableList(scope)) {
5693         const Fortran::semantics::Symbol &sym = var.getSymbol();
5694         if (sym.test(Fortran::semantics::Symbol::Flag::CompilerCreated))
5695           continue;
5696         const auto *object =
5697             sym.detailsIf<Fortran::semantics::ObjectEntityDetails>();
5698         if (object && object->IsArray() && object->init())
5699           Fortran::lower::createIntrinsicModuleGlobal(*this, var);
5700       }
5701     }
5702   }
5703 
5704   /// Lower a procedure (nest).
5705   void lowerFunc(Fortran::lower::pft::FunctionLikeUnit &funit) {
5706     setCurrentPosition(funit.getStartingSourceLoc());
5707     setCurrentFunctionUnit(&funit);
5708     for (int entryIndex = 0, last = funit.entryPointList.size();
5709          entryIndex < last; ++entryIndex) {
5710       funit.setActiveEntry(entryIndex);
5711       startNewFunction(funit); // the entry point for lowering this procedure
5712       for (Fortran::lower::pft::Evaluation &eval : funit.evaluationList)
5713         genFIR(eval);
5714       endNewFunction(funit);
5715     }
5716     funit.setActiveEntry(0);
5717     setCurrentFunctionUnit(nullptr);
5718     for (Fortran::lower::pft::ContainedUnit &unit : funit.containedUnitList)
5719       if (auto *f = std::get_if<Fortran::lower::pft::FunctionLikeUnit>(&unit))
5720         lowerFunc(*f); // internal procedure
5721   }
5722 
5723   /// Lower module variable definitions to fir::globalOp and OpenMP/OpenACC
5724   /// declarative construct.
5725   void lowerModuleDeclScope(Fortran::lower::pft::ModuleLikeUnit &mod) {
5726     setCurrentPosition(mod.getStartingSourceLoc());
5727     createGlobalOutsideOfFunctionLowering([&]() {
5728       auto &scopeVariableListMap =
5729           Fortran::lower::pft::getScopeVariableListMap(mod);
5730       for (const auto &var : Fortran::lower::pft::getScopeVariableList(
5731                mod.getScope(), scopeVariableListMap)) {
5732         // Only define the variables owned by this module.
5733         const Fortran::semantics::Scope *owningScope = var.getOwningScope();
5734         if (!owningScope || mod.getScope() == *owningScope)
5735           Fortran::lower::defineModuleVariable(*this, var);
5736       }
5737       for (auto &eval : mod.evaluationList)
5738         genFIR(eval);
5739     });
5740   }
5741 
5742   /// Lower functions contained in a module.
5743   void lowerMod(Fortran::lower::pft::ModuleLikeUnit &mod) {
5744     for (Fortran::lower::pft::ContainedUnit &unit : mod.containedUnitList)
5745       if (auto *f = std::get_if<Fortran::lower::pft::FunctionLikeUnit>(&unit))
5746         lowerFunc(*f);
5747   }
5748 
5749   void setCurrentPosition(const Fortran::parser::CharBlock &position) {
5750     if (position != Fortran::parser::CharBlock{})
5751       currentPosition = position;
5752   }
5753 
5754   /// Set current position at the location of \p parseTreeNode. Note that the
5755   /// position is updated automatically when visiting statements, but not when
5756   /// entering higher level nodes like constructs or procedures. This helper is
5757   /// intended to cover the latter cases.
5758   template <typename A>
5759   void setCurrentPositionAt(const A &parseTreeNode) {
5760     setCurrentPosition(Fortran::parser::FindSourceLocation(parseTreeNode));
5761   }
5762 
5763   //===--------------------------------------------------------------------===//
5764   // Utility methods
5765   //===--------------------------------------------------------------------===//
5766 
5767   /// Convert a parser CharBlock to a Location
5768   mlir::Location toLocation(const Fortran::parser::CharBlock &cb) {
5769     return genLocation(cb);
5770   }
5771 
5772   mlir::Location toLocation() { return toLocation(currentPosition); }
5773   void setCurrentEval(Fortran::lower::pft::Evaluation &eval) {
5774     evalPtr = &eval;
5775   }
5776   Fortran::lower::pft::Evaluation &getEval() {
5777     assert(evalPtr);
5778     return *evalPtr;
5779   }
5780 
5781   std::optional<Fortran::evaluate::Shape>
5782   getShape(const Fortran::lower::SomeExpr &expr) {
5783     return Fortran::evaluate::GetShape(foldingContext, expr);
5784   }
5785 
5786   //===--------------------------------------------------------------------===//
5787   // Analysis on a nested explicit iteration space.
5788   //===--------------------------------------------------------------------===//
5789 
5790   void analyzeExplicitSpace(const Fortran::parser::ConcurrentHeader &header) {
5791     explicitIterSpace.pushLevel();
5792     for (const Fortran::parser::ConcurrentControl &ctrl :
5793          std::get<std::list<Fortran::parser::ConcurrentControl>>(header.t)) {
5794       const Fortran::semantics::Symbol *ctrlVar =
5795           std::get<Fortran::parser::Name>(ctrl.t).symbol;
5796       explicitIterSpace.addSymbol(ctrlVar);
5797     }
5798     if (const auto &mask =
5799             std::get<std::optional<Fortran::parser::ScalarLogicalExpr>>(
5800                 header.t);
5801         mask.has_value())
5802       analyzeExplicitSpace(*Fortran::semantics::GetExpr(*mask));
5803   }
5804   template <bool LHS = false, typename A>
5805   void analyzeExplicitSpace(const Fortran::evaluate::Expr<A> &e) {
5806     explicitIterSpace.exprBase(&e, LHS);
5807   }
5808   void analyzeExplicitSpace(const Fortran::evaluate::Assignment *assign) {
5809     auto analyzeAssign = [&](const Fortran::lower::SomeExpr &lhs,
5810                              const Fortran::lower::SomeExpr &rhs) {
5811       analyzeExplicitSpace</*LHS=*/true>(lhs);
5812       analyzeExplicitSpace(rhs);
5813     };
5814     Fortran::common::visit(
5815         Fortran::common::visitors{
5816             [&](const Fortran::evaluate::ProcedureRef &procRef) {
5817               // Ensure the procRef expressions are the one being visited.
5818               assert(procRef.arguments().size() == 2);
5819               const Fortran::lower::SomeExpr *lhs =
5820                   procRef.arguments()[0].value().UnwrapExpr();
5821               const Fortran::lower::SomeExpr *rhs =
5822                   procRef.arguments()[1].value().UnwrapExpr();
5823               assert(lhs && rhs &&
5824                      "user defined assignment arguments must be expressions");
5825               analyzeAssign(*lhs, *rhs);
5826             },
5827             [&](const auto &) { analyzeAssign(assign->lhs, assign->rhs); }},
5828         assign->u);
5829     explicitIterSpace.endAssign();
5830   }
5831   void analyzeExplicitSpace(const Fortran::parser::ForallAssignmentStmt &stmt) {
5832     Fortran::common::visit([&](const auto &s) { analyzeExplicitSpace(s); },
5833                            stmt.u);
5834   }
5835   void analyzeExplicitSpace(const Fortran::parser::AssignmentStmt &s) {
5836     analyzeExplicitSpace(s.typedAssignment->v.operator->());
5837   }
5838   void analyzeExplicitSpace(const Fortran::parser::PointerAssignmentStmt &s) {
5839     analyzeExplicitSpace(s.typedAssignment->v.operator->());
5840   }
5841   void analyzeExplicitSpace(const Fortran::parser::WhereConstruct &c) {
5842     analyzeExplicitSpace(
5843         std::get<
5844             Fortran::parser::Statement<Fortran::parser::WhereConstructStmt>>(
5845             c.t)
5846             .statement);
5847     for (const Fortran::parser::WhereBodyConstruct &body :
5848          std::get<std::list<Fortran::parser::WhereBodyConstruct>>(c.t))
5849       analyzeExplicitSpace(body);
5850     for (const Fortran::parser::WhereConstruct::MaskedElsewhere &e :
5851          std::get<std::list<Fortran::parser::WhereConstruct::MaskedElsewhere>>(
5852              c.t))
5853       analyzeExplicitSpace(e);
5854     if (const auto &e =
5855             std::get<std::optional<Fortran::parser::WhereConstruct::Elsewhere>>(
5856                 c.t);
5857         e.has_value())
5858       analyzeExplicitSpace(e.operator->());
5859   }
5860   void analyzeExplicitSpace(const Fortran::parser::WhereConstructStmt &ws) {
5861     const Fortran::lower::SomeExpr *exp = Fortran::semantics::GetExpr(
5862         std::get<Fortran::parser::LogicalExpr>(ws.t));
5863     addMaskVariable(exp);
5864     analyzeExplicitSpace(*exp);
5865   }
5866   void analyzeExplicitSpace(
5867       const Fortran::parser::WhereConstruct::MaskedElsewhere &ew) {
5868     analyzeExplicitSpace(
5869         std::get<
5870             Fortran::parser::Statement<Fortran::parser::MaskedElsewhereStmt>>(
5871             ew.t)
5872             .statement);
5873     for (const Fortran::parser::WhereBodyConstruct &e :
5874          std::get<std::list<Fortran::parser::WhereBodyConstruct>>(ew.t))
5875       analyzeExplicitSpace(e);
5876   }
5877   void analyzeExplicitSpace(const Fortran::parser::WhereBodyConstruct &body) {
5878     Fortran::common::visit(
5879         Fortran::common::visitors{
5880             [&](const Fortran::common::Indirection<
5881                 Fortran::parser::WhereConstruct> &wc) {
5882               analyzeExplicitSpace(wc.value());
5883             },
5884             [&](const auto &s) { analyzeExplicitSpace(s.statement); }},
5885         body.u);
5886   }
5887   void analyzeExplicitSpace(const Fortran::parser::MaskedElsewhereStmt &stmt) {
5888     const Fortran::lower::SomeExpr *exp = Fortran::semantics::GetExpr(
5889         std::get<Fortran::parser::LogicalExpr>(stmt.t));
5890     addMaskVariable(exp);
5891     analyzeExplicitSpace(*exp);
5892   }
5893   void
5894   analyzeExplicitSpace(const Fortran::parser::WhereConstruct::Elsewhere *ew) {
5895     for (const Fortran::parser::WhereBodyConstruct &e :
5896          std::get<std::list<Fortran::parser::WhereBodyConstruct>>(ew->t))
5897       analyzeExplicitSpace(e);
5898   }
5899   void analyzeExplicitSpace(const Fortran::parser::WhereStmt &stmt) {
5900     const Fortran::lower::SomeExpr *exp = Fortran::semantics::GetExpr(
5901         std::get<Fortran::parser::LogicalExpr>(stmt.t));
5902     addMaskVariable(exp);
5903     analyzeExplicitSpace(*exp);
5904     const std::optional<Fortran::evaluate::Assignment> &assign =
5905         std::get<Fortran::parser::AssignmentStmt>(stmt.t).typedAssignment->v;
5906     assert(assign.has_value() && "WHERE has no statement");
5907     analyzeExplicitSpace(assign.operator->());
5908   }
5909   void analyzeExplicitSpace(const Fortran::parser::ForallStmt &forall) {
5910     analyzeExplicitSpace(
5911         std::get<
5912             Fortran::common::Indirection<Fortran::parser::ConcurrentHeader>>(
5913             forall.t)
5914             .value());
5915     analyzeExplicitSpace(std::get<Fortran::parser::UnlabeledStatement<
5916                              Fortran::parser::ForallAssignmentStmt>>(forall.t)
5917                              .statement);
5918     analyzeExplicitSpacePop();
5919   }
5920   void
5921   analyzeExplicitSpace(const Fortran::parser::ForallConstructStmt &forall) {
5922     analyzeExplicitSpace(
5923         std::get<
5924             Fortran::common::Indirection<Fortran::parser::ConcurrentHeader>>(
5925             forall.t)
5926             .value());
5927   }
5928   void analyzeExplicitSpace(const Fortran::parser::ForallConstruct &forall) {
5929     analyzeExplicitSpace(
5930         std::get<
5931             Fortran::parser::Statement<Fortran::parser::ForallConstructStmt>>(
5932             forall.t)
5933             .statement);
5934     for (const Fortran::parser::ForallBodyConstruct &s :
5935          std::get<std::list<Fortran::parser::ForallBodyConstruct>>(forall.t)) {
5936       Fortran::common::visit(
5937           Fortran::common::visitors{
5938               [&](const Fortran::common::Indirection<
5939                   Fortran::parser::ForallConstruct> &b) {
5940                 analyzeExplicitSpace(b.value());
5941               },
5942               [&](const Fortran::parser::WhereConstruct &w) {
5943                 analyzeExplicitSpace(w);
5944               },
5945               [&](const auto &b) { analyzeExplicitSpace(b.statement); }},
5946           s.u);
5947     }
5948     analyzeExplicitSpacePop();
5949   }
5950 
5951   void analyzeExplicitSpacePop() { explicitIterSpace.popLevel(); }
5952 
5953   void addMaskVariable(Fortran::lower::FrontEndExpr exp) {
5954     // Note: use i8 to store bool values. This avoids round-down behavior found
5955     // with sequences of i1. That is, an array of i1 will be truncated in size
5956     // and be too small. For example, a buffer of type fir.array<7xi1> will have
5957     // 0 size.
5958     mlir::Type i64Ty = builder->getIntegerType(64);
5959     mlir::TupleType ty = fir::factory::getRaggedArrayHeaderType(*builder);
5960     mlir::Type buffTy = ty.getType(1);
5961     mlir::Type shTy = ty.getType(2);
5962     mlir::Location loc = toLocation();
5963     mlir::Value hdr = builder->createTemporary(loc, ty);
5964     // FIXME: Is there a way to create a `zeroinitializer` in LLVM-IR dialect?
5965     // For now, explicitly set lazy ragged header to all zeros.
5966     // auto nilTup = builder->createNullConstant(loc, ty);
5967     // builder->create<fir::StoreOp>(loc, nilTup, hdr);
5968     mlir::Type i32Ty = builder->getIntegerType(32);
5969     mlir::Value zero = builder->createIntegerConstant(loc, i32Ty, 0);
5970     mlir::Value zero64 = builder->createIntegerConstant(loc, i64Ty, 0);
5971     mlir::Value flags = builder->create<fir::CoordinateOp>(
5972         loc, builder->getRefType(i64Ty), hdr, zero);
5973     builder->create<fir::StoreOp>(loc, zero64, flags);
5974     mlir::Value one = builder->createIntegerConstant(loc, i32Ty, 1);
5975     mlir::Value nullPtr1 = builder->createNullConstant(loc, buffTy);
5976     mlir::Value var = builder->create<fir::CoordinateOp>(
5977         loc, builder->getRefType(buffTy), hdr, one);
5978     builder->create<fir::StoreOp>(loc, nullPtr1, var);
5979     mlir::Value two = builder->createIntegerConstant(loc, i32Ty, 2);
5980     mlir::Value nullPtr2 = builder->createNullConstant(loc, shTy);
5981     mlir::Value shape = builder->create<fir::CoordinateOp>(
5982         loc, builder->getRefType(shTy), hdr, two);
5983     builder->create<fir::StoreOp>(loc, nullPtr2, shape);
5984     implicitIterSpace.addMaskVariable(exp, var, shape, hdr);
5985     explicitIterSpace.outermostContext().attachCleanup(
5986         [builder = this->builder, hdr, loc]() {
5987           fir::runtime::genRaggedArrayDeallocate(loc, *builder, hdr);
5988         });
5989   }
5990 
5991   void createRuntimeTypeInfoGlobals() {}
5992 
5993   bool lowerToHighLevelFIR() const {
5994     return bridge.getLoweringOptions().getLowerToHighLevelFIR();
5995   }
5996 
5997   // Returns the mangling prefix for the given constant expression.
5998   std::string getConstantExprManglePrefix(mlir::Location loc,
5999                                           const Fortran::lower::SomeExpr &expr,
6000                                           mlir::Type eleTy) {
6001     return Fortran::common::visit(
6002         [&](const auto &x) -> std::string {
6003           using T = std::decay_t<decltype(x)>;
6004           if constexpr (Fortran::common::HasMember<
6005                             T, Fortran::lower::CategoryExpression>) {
6006             if constexpr (T::Result::category ==
6007                           Fortran::common::TypeCategory::Derived) {
6008               if (const auto *constant =
6009                       std::get_if<Fortran::evaluate::Constant<
6010                           Fortran::evaluate::SomeDerived>>(&x.u))
6011                 return Fortran::lower::mangle::mangleArrayLiteral(eleTy,
6012                                                                   *constant);
6013               fir::emitFatalError(loc,
6014                                   "non a constant derived type expression");
6015             } else {
6016               return Fortran::common::visit(
6017                   [&](const auto &someKind) -> std::string {
6018                     using T = std::decay_t<decltype(someKind)>;
6019                     using TK = Fortran::evaluate::Type<T::Result::category,
6020                                                        T::Result::kind>;
6021                     if (const auto *constant =
6022                             std::get_if<Fortran::evaluate::Constant<TK>>(
6023                                 &someKind.u)) {
6024                       return Fortran::lower::mangle::mangleArrayLiteral(
6025                           nullptr, *constant);
6026                     }
6027                     fir::emitFatalError(
6028                         loc, "not a Fortran::evaluate::Constant<T> expression");
6029                     return {};
6030                   },
6031                   x.u);
6032             }
6033           } else {
6034             fir::emitFatalError(loc, "unexpected expression");
6035           }
6036         },
6037         expr.u);
6038   }
6039 
6040   /// Performing OpenACC lowering action that were deferred to the end of
6041   /// lowering.
6042   void finalizeOpenACCLowering() {
6043     Fortran::lower::finalizeOpenACCRoutineAttachment(getModuleOp(),
6044                                                      accRoutineInfos);
6045   }
6046 
6047   /// Performing OpenMP lowering actions that were deferred to the end of
6048   /// lowering.
6049   void finalizeOpenMPLowering(
6050       const Fortran::semantics::Symbol *globalOmpRequiresSymbol) {
6051     if (!ompDeferredDeclareTarget.empty()) {
6052       bool deferredDeviceFuncFound =
6053           Fortran::lower::markOpenMPDeferredDeclareTargetFunctions(
6054               getModuleOp().getOperation(), ompDeferredDeclareTarget, *this);
6055       ompDeviceCodeFound = ompDeviceCodeFound || deferredDeviceFuncFound;
6056     }
6057 
6058     // Set the module attribute related to OpenMP requires directives
6059     if (ompDeviceCodeFound)
6060       Fortran::lower::genOpenMPRequires(getModuleOp().getOperation(),
6061                                         globalOmpRequiresSymbol);
6062   }
6063 
6064   /// Record fir.dummy_scope operation for this function.
6065   /// It will be used to set dummy_scope operand of the hlfir.declare
6066   /// operations.
6067   void setDummyArgsScope(mlir::Value val) {
6068     assert(!dummyArgsScope && val);
6069     dummyArgsScope = val;
6070   }
6071 
6072   /// Record the given symbol as a dummy argument of this function.
6073   void registerDummySymbol(Fortran::semantics::SymbolRef symRef) {
6074     auto *sym = &*symRef;
6075     registeredDummySymbols.insert(sym);
6076   }
6077 
6078   /// Reset all registered dummy symbols.
6079   void resetRegisteredDummySymbols() { registeredDummySymbols.clear(); }
6080 
6081   void setCurrentFunctionUnit(Fortran::lower::pft::FunctionLikeUnit *unit) {
6082     currentFunctionUnit = unit;
6083   }
6084 
6085   //===--------------------------------------------------------------------===//
6086 
6087   Fortran::lower::LoweringBridge &bridge;
6088   Fortran::evaluate::FoldingContext foldingContext;
6089   fir::FirOpBuilder *builder = nullptr;
6090   Fortran::lower::pft::Evaluation *evalPtr = nullptr;
6091   Fortran::lower::pft::FunctionLikeUnit *currentFunctionUnit = nullptr;
6092   Fortran::lower::SymMap localSymbols;
6093   Fortran::parser::CharBlock currentPosition;
6094   TypeInfoConverter typeInfoConverter;
6095 
6096   // Stack to manage object deallocation and finalization at construct exits.
6097   llvm::SmallVector<ConstructContext> activeConstructStack;
6098 
6099   /// BLOCK name mangling component map
6100   int blockId = 0;
6101   Fortran::lower::mangle::ScopeBlockIdMap scopeBlockIdMap;
6102 
6103   /// FORALL statement/construct context
6104   Fortran::lower::ExplicitIterSpace explicitIterSpace;
6105 
6106   /// WHERE statement/construct mask expression stack
6107   Fortran::lower::ImplicitIterSpace implicitIterSpace;
6108 
6109   /// Tuple of host associated variables
6110   mlir::Value hostAssocTuple;
6111 
6112   /// Value of fir.dummy_scope operation for this function.
6113   mlir::Value dummyArgsScope;
6114 
6115   /// A set of dummy argument symbols for this function.
6116   /// The set is only preserved during the instatiation
6117   /// of variables for this function.
6118   llvm::SmallPtrSet<const Fortran::semantics::Symbol *, 16>
6119       registeredDummySymbols;
6120 
6121   /// A map of unique names for constant expressions.
6122   /// The names are used for representing the constant expressions
6123   /// with global constant initialized objects.
6124   /// The names are usually prefixed by a mangling string based
6125   /// on the element type of the constant expression, but the element
6126   /// type is not used as a key into the map (so the assumption is that
6127   /// the equivalent constant expressions are prefixed using the same
6128   /// element type).
6129   llvm::DenseMap<const Fortran::lower::SomeExpr *, std::string> literalNamesMap;
6130 
6131   /// Storage for Constant expressions used as keys for literalNamesMap.
6132   llvm::SmallVector<std::unique_ptr<Fortran::lower::SomeExpr>>
6133       literalExprsStorage;
6134 
6135   /// A counter for uniquing names in `literalNamesMap`.
6136   std::uint64_t uniqueLitId = 0;
6137 
6138   /// Deferred OpenACC routine attachment.
6139   Fortran::lower::AccRoutineInfoMappingList accRoutineInfos;
6140 
6141   /// Whether an OpenMP target region or declare target function/subroutine
6142   /// intended for device offloading has been detected
6143   bool ompDeviceCodeFound = false;
6144 
6145   /// Keeps track of symbols defined as declare target that could not be
6146   /// processed at the time of lowering the declare target construct, such
6147   /// as certain cases where interfaces are declared but not defined within
6148   /// a module.
6149   llvm::SmallVector<Fortran::lower::OMPDeferredDeclareTargetInfo>
6150       ompDeferredDeclareTarget;
6151 
6152   const Fortran::lower::ExprToValueMap *exprValueOverrides{nullptr};
6153 
6154   /// Stack of derived type under construction to avoid infinite loops when
6155   /// dealing with recursive derived types. This is held in the bridge because
6156   /// the state needs to be maintained between data and function type lowering
6157   /// utilities to deal with procedure pointer components whose arguments have
6158   /// the type of the containing derived type.
6159   Fortran::lower::TypeConstructionStack typeConstructionStack;
6160   /// MLIR symbol table of the fir.global/func.func operations. Note that it is
6161   /// not guaranteed to contain all operations of the ModuleOp with Symbol
6162   /// attribute since mlirSymbolTable must pro-actively be maintained when
6163   /// new Symbol operations are created.
6164   mlir::SymbolTable mlirSymbolTable;
6165 };
6166 
6167 } // namespace
6168 
6169 Fortran::evaluate::FoldingContext
6170 Fortran::lower::LoweringBridge::createFoldingContext() {
6171   return {getDefaultKinds(), getIntrinsicTable(), getTargetCharacteristics(),
6172           getLanguageFeatures(), tempNames};
6173 }
6174 
6175 void Fortran::lower::LoweringBridge::lower(
6176     const Fortran::parser::Program &prg,
6177     const Fortran::semantics::SemanticsContext &semanticsContext) {
6178   std::unique_ptr<Fortran::lower::pft::Program> pft =
6179       Fortran::lower::createPFT(prg, semanticsContext);
6180   if (dumpBeforeFir)
6181     Fortran::lower::dumpPFT(llvm::errs(), *pft);
6182   FirConverter converter{*this};
6183   converter.run(*pft);
6184 }
6185 
6186 void Fortran::lower::LoweringBridge::parseSourceFile(llvm::SourceMgr &srcMgr) {
6187   module = mlir::parseSourceFile<mlir::ModuleOp>(srcMgr, &context);
6188 }
6189 
6190 Fortran::lower::LoweringBridge::LoweringBridge(
6191     mlir::MLIRContext &context,
6192     Fortran::semantics::SemanticsContext &semanticsContext,
6193     const Fortran::common::IntrinsicTypeDefaultKinds &defaultKinds,
6194     const Fortran::evaluate::IntrinsicProcTable &intrinsics,
6195     const Fortran::evaluate::TargetCharacteristics &targetCharacteristics,
6196     const Fortran::parser::AllCookedSources &cooked, llvm::StringRef triple,
6197     fir::KindMapping &kindMap,
6198     const Fortran::lower::LoweringOptions &loweringOptions,
6199     const std::vector<Fortran::lower::EnvironmentDefault> &envDefaults,
6200     const Fortran::common::LanguageFeatureControl &languageFeatures,
6201     const llvm::TargetMachine &targetMachine,
6202     const Fortran::frontend::TargetOptions &targetOpts,
6203     const Fortran::frontend::CodeGenOptions &cgOpts)
6204     : semanticsContext{semanticsContext}, defaultKinds{defaultKinds},
6205       intrinsics{intrinsics}, targetCharacteristics{targetCharacteristics},
6206       cooked{&cooked}, context{context}, kindMap{kindMap},
6207       loweringOptions{loweringOptions}, envDefaults{envDefaults},
6208       languageFeatures{languageFeatures} {
6209   // Register the diagnostic handler.
6210   context.getDiagEngine().registerHandler([](mlir::Diagnostic &diag) {
6211     llvm::raw_ostream &os = llvm::errs();
6212     switch (diag.getSeverity()) {
6213     case mlir::DiagnosticSeverity::Error:
6214       os << "error: ";
6215       break;
6216     case mlir::DiagnosticSeverity::Remark:
6217       os << "info: ";
6218       break;
6219     case mlir::DiagnosticSeverity::Warning:
6220       os << "warning: ";
6221       break;
6222     default:
6223       break;
6224     }
6225     if (!mlir::isa<mlir::UnknownLoc>(diag.getLocation()))
6226       os << diag.getLocation() << ": ";
6227     os << diag << '\n';
6228     os.flush();
6229     return mlir::success();
6230   });
6231 
6232   auto getPathLocation = [&semanticsContext, &context]() -> mlir::Location {
6233     std::optional<std::string> path;
6234     const auto &allSources{semanticsContext.allCookedSources().allSources()};
6235     if (auto initial{allSources.GetFirstFileProvenance()};
6236         initial && !initial->empty()) {
6237       if (const auto *sourceFile{allSources.GetSourceFile(initial->start())}) {
6238         path = sourceFile->path();
6239       }
6240     }
6241 
6242     if (path.has_value()) {
6243       llvm::SmallString<256> curPath(*path);
6244       llvm::sys::fs::make_absolute(curPath);
6245       llvm::sys::path::remove_dots(curPath);
6246       return mlir::FileLineColLoc::get(&context, curPath.str(), /*line=*/0,
6247                                        /*col=*/0);
6248     } else {
6249       return mlir::UnknownLoc::get(&context);
6250     }
6251   };
6252 
6253   // Create the module and attach the attributes.
6254   module = mlir::OwningOpRef<mlir::ModuleOp>(
6255       mlir::ModuleOp::create(getPathLocation()));
6256   assert(*module && "module was not created");
6257   fir::setTargetTriple(*module, triple);
6258   fir::setKindMapping(*module, kindMap);
6259   fir::setTargetCPU(*module, targetMachine.getTargetCPU());
6260   fir::setTuneCPU(*module, targetOpts.cpuToTuneFor);
6261   fir::setTargetFeatures(*module, targetMachine.getTargetFeatureString());
6262   fir::support::setMLIRDataLayout(*module, targetMachine.createDataLayout());
6263   fir::setIdent(*module, Fortran::common::getFlangFullVersion());
6264   if (cgOpts.RecordCommandLine)
6265     fir::setCommandline(*module, *cgOpts.RecordCommandLine);
6266 }
6267 
6268 void Fortran::lower::genCleanUpInRegionIfAny(
6269     mlir::Location loc, fir::FirOpBuilder &builder, mlir::Region &region,
6270     Fortran::lower::StatementContext &context) {
6271   if (!context.hasCode())
6272     return;
6273   mlir::OpBuilder::InsertPoint insertPt = builder.saveInsertionPoint();
6274   if (region.empty())
6275     builder.createBlock(&region);
6276   else
6277     builder.setInsertionPointToEnd(&region.front());
6278   context.finalizeAndPop();
6279   hlfir::YieldOp::ensureTerminator(region, builder, loc);
6280   builder.restoreInsertionPoint(insertPt);
6281 }
6282