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 ¤tIfOp.getElseRegion().front());
1376 currentIfOp = genIfOp(genIfCondition(s));
1377 } else if (e.isA<Fortran::parser::ElseStmt>()) {
1378 builder->setInsertionPointToStart(
1379 ¤tIfOp.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