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