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