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