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/CallInterface.h" 16 #include "flang/Lower/ConvertExpr.h" 17 #include "flang/Lower/ConvertType.h" 18 #include "flang/Lower/ConvertVariable.h" 19 #include "flang/Lower/Mangler.h" 20 #include "flang/Lower/PFTBuilder.h" 21 #include "flang/Lower/Runtime.h" 22 #include "flang/Lower/SymbolMap.h" 23 #include "flang/Lower/Todo.h" 24 #include "flang/Optimizer/Support/FIRContext.h" 25 #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h" 26 #include "mlir/IR/PatternMatch.h" 27 #include "mlir/Transforms/RegionUtils.h" 28 #include "llvm/Support/CommandLine.h" 29 #include "llvm/Support/Debug.h" 30 31 #define DEBUG_TYPE "flang-lower-bridge" 32 33 static llvm::cl::opt<bool> dumpBeforeFir( 34 "fdebug-dump-pre-fir", llvm::cl::init(false), 35 llvm::cl::desc("dump the Pre-FIR tree prior to FIR generation")); 36 37 //===----------------------------------------------------------------------===// 38 // FirConverter 39 //===----------------------------------------------------------------------===// 40 41 namespace { 42 43 /// Traverse the pre-FIR tree (PFT) to generate the FIR dialect of MLIR. 44 class FirConverter : public Fortran::lower::AbstractConverter { 45 public: 46 explicit FirConverter(Fortran::lower::LoweringBridge &bridge) 47 : bridge{bridge}, foldingContext{bridge.createFoldingContext()} {} 48 virtual ~FirConverter() = default; 49 50 /// Convert the PFT to FIR. 51 void run(Fortran::lower::pft::Program &pft) { 52 // Primary translation pass. 53 for (Fortran::lower::pft::Program::Units &u : pft.getUnits()) { 54 std::visit( 55 Fortran::common::visitors{ 56 [&](Fortran::lower::pft::FunctionLikeUnit &f) { lowerFunc(f); }, 57 [&](Fortran::lower::pft::ModuleLikeUnit &m) {}, 58 [&](Fortran::lower::pft::BlockDataUnit &b) {}, 59 [&](Fortran::lower::pft::CompilerDirectiveUnit &d) { 60 setCurrentPosition( 61 d.get<Fortran::parser::CompilerDirective>().source); 62 mlir::emitWarning(toLocation(), 63 "ignoring all compiler directives"); 64 }, 65 }, 66 u); 67 } 68 } 69 70 //===--------------------------------------------------------------------===// 71 // AbstractConverter overrides 72 //===--------------------------------------------------------------------===// 73 74 mlir::Value getSymbolAddress(Fortran::lower::SymbolRef sym) override final { 75 return lookupSymbol(sym).getAddr(); 76 } 77 78 fir::ExtendedValue genExprAddr(const Fortran::lower::SomeExpr &expr, 79 mlir::Location *loc = nullptr) override final { 80 TODO_NOLOC("Not implemented genExprAddr. Needed for more complex " 81 "expression lowering"); 82 } 83 fir::ExtendedValue 84 genExprValue(const Fortran::lower::SomeExpr &expr, 85 mlir::Location *loc = nullptr) override final { 86 return createSomeExtendedExpression(loc ? *loc : toLocation(), *this, expr, 87 localSymbols); 88 } 89 90 Fortran::evaluate::FoldingContext &getFoldingContext() override final { 91 return foldingContext; 92 } 93 94 mlir::Type genType(const Fortran::evaluate::DataRef &) override final { 95 TODO_NOLOC("Not implemented genType DataRef. Needed for more complex " 96 "expression lowering"); 97 } 98 mlir::Type genType(const Fortran::lower::SomeExpr &) override final { 99 TODO_NOLOC("Not implemented genType SomeExpr. Needed for more complex " 100 "expression lowering"); 101 } 102 mlir::Type genType(Fortran::lower::SymbolRef) override final { 103 TODO_NOLOC("Not implemented genType SymbolRef. Needed for more complex " 104 "expression lowering"); 105 } 106 mlir::Type genType(Fortran::common::TypeCategory tc) override final { 107 TODO_NOLOC("Not implemented genType TypeCategory. Needed for more complex " 108 "expression lowering"); 109 } 110 mlir::Type genType(Fortran::common::TypeCategory tc, 111 int kind) override final { 112 return Fortran::lower::getFIRType(&getMLIRContext(), tc, kind); 113 } 114 mlir::Type genType(const Fortran::lower::pft::Variable &var) override final { 115 return Fortran::lower::translateVariableToFIRType(*this, var); 116 } 117 118 void setCurrentPosition(const Fortran::parser::CharBlock &position) { 119 if (position != Fortran::parser::CharBlock{}) 120 currentPosition = position; 121 } 122 123 //===--------------------------------------------------------------------===// 124 // Utility methods 125 //===--------------------------------------------------------------------===// 126 127 /// Convert a parser CharBlock to a Location 128 mlir::Location toLocation(const Fortran::parser::CharBlock &cb) { 129 return genLocation(cb); 130 } 131 132 mlir::Location toLocation() { return toLocation(currentPosition); } 133 void setCurrentEval(Fortran::lower::pft::Evaluation &eval) { 134 evalPtr = &eval; 135 } 136 Fortran::lower::pft::Evaluation &getEval() { 137 assert(evalPtr && "current evaluation not set"); 138 return *evalPtr; 139 } 140 141 mlir::Location getCurrentLocation() override final { return toLocation(); } 142 143 /// Generate a dummy location. 144 mlir::Location genUnknownLocation() override final { 145 // Note: builder may not be instantiated yet 146 return mlir::UnknownLoc::get(&getMLIRContext()); 147 } 148 149 /// Generate a `Location` from the `CharBlock`. 150 mlir::Location 151 genLocation(const Fortran::parser::CharBlock &block) override final { 152 if (const Fortran::parser::AllCookedSources *cooked = 153 bridge.getCookedSource()) { 154 if (std::optional<std::pair<Fortran::parser::SourcePosition, 155 Fortran::parser::SourcePosition>> 156 loc = cooked->GetSourcePositionRange(block)) { 157 // loc is a pair (begin, end); use the beginning position 158 Fortran::parser::SourcePosition &filePos = loc->first; 159 return mlir::FileLineColLoc::get(&getMLIRContext(), filePos.file.path(), 160 filePos.line, filePos.column); 161 } 162 } 163 return genUnknownLocation(); 164 } 165 166 fir::FirOpBuilder &getFirOpBuilder() override final { return *builder; } 167 168 mlir::ModuleOp &getModuleOp() override final { return bridge.getModule(); } 169 170 mlir::MLIRContext &getMLIRContext() override final { 171 return bridge.getMLIRContext(); 172 } 173 std::string 174 mangleName(const Fortran::semantics::Symbol &symbol) override final { 175 return Fortran::lower::mangle::mangleName(symbol); 176 } 177 178 const fir::KindMapping &getKindMap() override final { 179 return bridge.getKindMap(); 180 } 181 182 /// Return the predicate: "current block does not have a terminator branch". 183 bool blockIsUnterminated() { 184 mlir::Block *currentBlock = builder->getBlock(); 185 return currentBlock->empty() || 186 !currentBlock->back().hasTrait<mlir::OpTrait::IsTerminator>(); 187 } 188 189 /// Unconditionally switch code insertion to a new block. 190 void startBlock(mlir::Block *newBlock) { 191 assert(newBlock && "missing block"); 192 // Default termination for the current block is a fallthrough branch to 193 // the new block. 194 if (blockIsUnterminated()) 195 genFIRBranch(newBlock); 196 // Some blocks may be re/started more than once, and might not be empty. 197 // If the new block already has (only) a terminator, set the insertion 198 // point to the start of the block. Otherwise set it to the end. 199 // Note that setting the insertion point causes the subsequent function 200 // call to check the existence of terminator in the newBlock. 201 builder->setInsertionPointToStart(newBlock); 202 if (blockIsUnterminated()) 203 builder->setInsertionPointToEnd(newBlock); 204 } 205 206 /// Conditionally switch code insertion to a new block. 207 void maybeStartBlock(mlir::Block *newBlock) { 208 if (newBlock) 209 startBlock(newBlock); 210 } 211 212 /// Emit return and cleanup after the function has been translated. 213 void endNewFunction(Fortran::lower::pft::FunctionLikeUnit &funit) { 214 setCurrentPosition(Fortran::lower::pft::stmtSourceLoc(funit.endStmt)); 215 if (funit.isMainProgram()) 216 genExitRoutine(); 217 else 218 genFIRProcedureExit(funit, funit.getSubprogramSymbol()); 219 funit.finalBlock = nullptr; 220 LLVM_DEBUG(llvm::dbgs() << "*** Lowering result:\n\n" 221 << *builder->getFunction() << '\n'); 222 // FIXME: Simplification should happen in a normal pass, not here. 223 mlir::IRRewriter rewriter(*builder); 224 (void)mlir::simplifyRegions(rewriter, 225 {builder->getRegion()}); // remove dead code 226 delete builder; 227 builder = nullptr; 228 localSymbols.clear(); 229 } 230 231 /// Instantiate variable \p var and add it to the symbol map. 232 /// See ConvertVariable.cpp. 233 void instantiateVar(const Fortran::lower::pft::Variable &var) { 234 Fortran::lower::instantiateVariable(*this, var, localSymbols); 235 } 236 237 /// Prepare to translate a new function 238 void startNewFunction(Fortran::lower::pft::FunctionLikeUnit &funit) { 239 assert(!builder && "expected nullptr"); 240 Fortran::lower::CalleeInterface callee(funit, *this); 241 mlir::FuncOp func = callee.addEntryBlockAndMapArguments(); 242 func.setVisibility(mlir::SymbolTable::Visibility::Public); 243 builder = new fir::FirOpBuilder(func, bridge.getKindMap()); 244 assert(builder && "FirOpBuilder did not instantiate"); 245 builder->setInsertionPointToStart(&func.front()); 246 247 for (const Fortran::lower::pft::Variable &var : 248 funit.getOrderedSymbolTable()) { 249 const Fortran::semantics::Symbol &sym = var.getSymbol(); 250 if (!sym.IsFuncResult() || !funit.primaryResult) 251 instantiateVar(var); 252 } 253 254 // Create most function blocks in advance. 255 createEmptyGlobalBlocks(funit.evaluationList); 256 257 // Reinstate entry block as the current insertion point. 258 builder->setInsertionPointToEnd(&func.front()); 259 } 260 261 /// Create global blocks for the current function. This eliminates the 262 /// distinction between forward and backward targets when generating 263 /// branches. A block is "global" if it can be the target of a GOTO or 264 /// other source code branch. A block that can only be targeted by a 265 /// compiler generated branch is "local". For example, a DO loop preheader 266 /// block containing loop initialization code is global. A loop header 267 /// block, which is the target of the loop back edge, is local. Blocks 268 /// belong to a region. Any block within a nested region must be replaced 269 /// with a block belonging to that region. Branches may not cross region 270 /// boundaries. 271 void createEmptyGlobalBlocks( 272 std::list<Fortran::lower::pft::Evaluation> &evaluationList) { 273 mlir::Region *region = &builder->getRegion(); 274 for (Fortran::lower::pft::Evaluation &eval : evaluationList) { 275 if (eval.isNewBlock) 276 eval.block = builder->createBlock(region); 277 if (eval.isConstruct() || eval.isDirective()) { 278 if (eval.lowerAsUnstructured()) { 279 createEmptyGlobalBlocks(eval.getNestedEvaluations()); 280 } else if (eval.hasNestedEvaluations()) { 281 TODO(toLocation(), "Constructs with nested evaluations"); 282 } 283 } 284 } 285 } 286 287 /// Lower a procedure (nest). 288 void lowerFunc(Fortran::lower::pft::FunctionLikeUnit &funit) { 289 setCurrentPosition(funit.getStartingSourceLoc()); 290 for (int entryIndex = 0, last = funit.entryPointList.size(); 291 entryIndex < last; ++entryIndex) { 292 funit.setActiveEntry(entryIndex); 293 startNewFunction(funit); // the entry point for lowering this procedure 294 for (Fortran::lower::pft::Evaluation &eval : funit.evaluationList) 295 genFIR(eval); 296 endNewFunction(funit); 297 } 298 funit.setActiveEntry(0); 299 for (Fortran::lower::pft::FunctionLikeUnit &f : funit.nestedFunctions) 300 lowerFunc(f); // internal procedure 301 } 302 303 private: 304 FirConverter() = delete; 305 FirConverter(const FirConverter &) = delete; 306 FirConverter &operator=(const FirConverter &) = delete; 307 308 //===--------------------------------------------------------------------===// 309 // Helper member functions 310 //===--------------------------------------------------------------------===// 311 312 /// Find the symbol in the local map or return null. 313 Fortran::lower::SymbolBox 314 lookupSymbol(const Fortran::semantics::Symbol &sym) { 315 if (Fortran::lower::SymbolBox v = localSymbols.lookupSymbol(sym)) 316 return v; 317 return {}; 318 } 319 320 void genFIRBranch(mlir::Block *targetBlock) { 321 assert(targetBlock && "missing unconditional target block"); 322 builder->create<cf::BranchOp>(toLocation(), targetBlock); 323 } 324 325 //===--------------------------------------------------------------------===// 326 // Termination of symbolically referenced execution units 327 //===--------------------------------------------------------------------===// 328 329 /// END of program 330 /// 331 /// Generate the cleanup block before the program exits 332 void genExitRoutine() { 333 if (blockIsUnterminated()) 334 builder->create<mlir::ReturnOp>(toLocation()); 335 } 336 void genFIR(const Fortran::parser::EndProgramStmt &) { genExitRoutine(); } 337 338 void genFIRProcedureExit(Fortran::lower::pft::FunctionLikeUnit &funit, 339 const Fortran::semantics::Symbol &symbol) { 340 if (mlir::Block *finalBlock = funit.finalBlock) { 341 // The current block must end with a terminator. 342 if (blockIsUnterminated()) 343 builder->create<mlir::cf::BranchOp>(toLocation(), finalBlock); 344 // Set insertion point to final block. 345 builder->setInsertionPoint(finalBlock, finalBlock->end()); 346 } 347 if (Fortran::semantics::IsFunction(symbol)) { 348 TODO(toLocation(), "Function lowering"); 349 } else { 350 genExitRoutine(); 351 } 352 } 353 354 void genFIR(const Fortran::parser::CallStmt &stmt) { 355 TODO(toLocation(), "CallStmt lowering"); 356 } 357 358 void genFIR(const Fortran::parser::ComputedGotoStmt &stmt) { 359 TODO(toLocation(), "ComputedGotoStmt lowering"); 360 } 361 362 void genFIR(const Fortran::parser::ArithmeticIfStmt &stmt) { 363 TODO(toLocation(), "ArithmeticIfStmt lowering"); 364 } 365 366 void genFIR(const Fortran::parser::AssignedGotoStmt &stmt) { 367 TODO(toLocation(), "AssignedGotoStmt lowering"); 368 } 369 370 void genFIR(const Fortran::parser::DoConstruct &doConstruct) { 371 TODO(toLocation(), "DoConstruct lowering"); 372 } 373 374 void genFIR(const Fortran::parser::IfConstruct &) { 375 TODO(toLocation(), "IfConstruct lowering"); 376 } 377 378 void genFIR(const Fortran::parser::CaseConstruct &) { 379 TODO(toLocation(), "CaseConstruct lowering"); 380 } 381 382 void genFIR(const Fortran::parser::ConcurrentHeader &header) { 383 TODO(toLocation(), "ConcurrentHeader lowering"); 384 } 385 386 void genFIR(const Fortran::parser::ForallAssignmentStmt &stmt) { 387 TODO(toLocation(), "ForallAssignmentStmt lowering"); 388 } 389 390 void genFIR(const Fortran::parser::EndForallStmt &) { 391 TODO(toLocation(), "EndForallStmt lowering"); 392 } 393 394 void genFIR(const Fortran::parser::ForallStmt &) { 395 TODO(toLocation(), "ForallStmt lowering"); 396 } 397 398 void genFIR(const Fortran::parser::ForallConstruct &) { 399 TODO(toLocation(), "ForallConstruct lowering"); 400 } 401 402 void genFIR(const Fortran::parser::ForallConstructStmt &) { 403 TODO(toLocation(), "ForallConstructStmt lowering"); 404 } 405 406 void genFIR(const Fortran::parser::CompilerDirective &) { 407 TODO(toLocation(), "CompilerDirective lowering"); 408 } 409 410 void genFIR(const Fortran::parser::OpenACCConstruct &) { 411 TODO(toLocation(), "OpenACCConstruct lowering"); 412 } 413 414 void genFIR(const Fortran::parser::OpenACCDeclarativeConstruct &) { 415 TODO(toLocation(), "OpenACCDeclarativeConstruct lowering"); 416 } 417 418 void genFIR(const Fortran::parser::OpenMPConstruct &) { 419 TODO(toLocation(), "OpenMPConstruct lowering"); 420 } 421 422 void genFIR(const Fortran::parser::OpenMPDeclarativeConstruct &) { 423 TODO(toLocation(), "OpenMPDeclarativeConstruct lowering"); 424 } 425 426 void genFIR(const Fortran::parser::SelectCaseStmt &) { 427 TODO(toLocation(), "SelectCaseStmt lowering"); 428 } 429 430 void genFIR(const Fortran::parser::AssociateConstruct &) { 431 TODO(toLocation(), "AssociateConstruct lowering"); 432 } 433 434 void genFIR(const Fortran::parser::BlockConstruct &blockConstruct) { 435 TODO(toLocation(), "BlockConstruct lowering"); 436 } 437 438 void genFIR(const Fortran::parser::BlockStmt &) { 439 TODO(toLocation(), "BlockStmt lowering"); 440 } 441 442 void genFIR(const Fortran::parser::EndBlockStmt &) { 443 TODO(toLocation(), "EndBlockStmt lowering"); 444 } 445 446 void genFIR(const Fortran::parser::ChangeTeamConstruct &construct) { 447 TODO(toLocation(), "ChangeTeamConstruct lowering"); 448 } 449 450 void genFIR(const Fortran::parser::ChangeTeamStmt &stmt) { 451 TODO(toLocation(), "ChangeTeamStmt lowering"); 452 } 453 454 void genFIR(const Fortran::parser::EndChangeTeamStmt &stmt) { 455 TODO(toLocation(), "EndChangeTeamStmt lowering"); 456 } 457 458 void genFIR(const Fortran::parser::CriticalConstruct &criticalConstruct) { 459 TODO(toLocation(), "CriticalConstruct lowering"); 460 } 461 462 void genFIR(const Fortran::parser::CriticalStmt &) { 463 TODO(toLocation(), "CriticalStmt lowering"); 464 } 465 466 void genFIR(const Fortran::parser::EndCriticalStmt &) { 467 TODO(toLocation(), "EndCriticalStmt lowering"); 468 } 469 470 void genFIR(const Fortran::parser::SelectRankConstruct &selectRankConstruct) { 471 TODO(toLocation(), "SelectRankConstruct lowering"); 472 } 473 474 void genFIR(const Fortran::parser::SelectRankStmt &) { 475 TODO(toLocation(), "SelectRankStmt lowering"); 476 } 477 478 void genFIR(const Fortran::parser::SelectRankCaseStmt &) { 479 TODO(toLocation(), "SelectRankCaseStmt lowering"); 480 } 481 482 void genFIR(const Fortran::parser::SelectTypeConstruct &selectTypeConstruct) { 483 TODO(toLocation(), "SelectTypeConstruct lowering"); 484 } 485 486 void genFIR(const Fortran::parser::SelectTypeStmt &) { 487 TODO(toLocation(), "SelectTypeStmt lowering"); 488 } 489 490 void genFIR(const Fortran::parser::TypeGuardStmt &) { 491 TODO(toLocation(), "TypeGuardStmt lowering"); 492 } 493 494 //===--------------------------------------------------------------------===// 495 // IO statements (see io.h) 496 //===--------------------------------------------------------------------===// 497 498 void genFIR(const Fortran::parser::BackspaceStmt &stmt) { 499 TODO(toLocation(), "BackspaceStmt lowering"); 500 } 501 502 void genFIR(const Fortran::parser::CloseStmt &stmt) { 503 TODO(toLocation(), "CloseStmt lowering"); 504 } 505 506 void genFIR(const Fortran::parser::EndfileStmt &stmt) { 507 TODO(toLocation(), "EndfileStmt lowering"); 508 } 509 510 void genFIR(const Fortran::parser::FlushStmt &stmt) { 511 TODO(toLocation(), "FlushStmt lowering"); 512 } 513 514 void genFIR(const Fortran::parser::InquireStmt &stmt) { 515 TODO(toLocation(), "InquireStmt lowering"); 516 } 517 518 void genFIR(const Fortran::parser::OpenStmt &stmt) { 519 TODO(toLocation(), "OpenStmt lowering"); 520 } 521 522 void genFIR(const Fortran::parser::PrintStmt &stmt) { 523 TODO(toLocation(), "PrintStmt lowering"); 524 } 525 526 void genFIR(const Fortran::parser::ReadStmt &stmt) { 527 TODO(toLocation(), "ReadStmt lowering"); 528 } 529 530 void genFIR(const Fortran::parser::RewindStmt &stmt) { 531 TODO(toLocation(), "RewindStmt lowering"); 532 } 533 534 void genFIR(const Fortran::parser::WaitStmt &stmt) { 535 TODO(toLocation(), "WaitStmt lowering"); 536 } 537 538 void genFIR(const Fortran::parser::WriteStmt &stmt) { 539 TODO(toLocation(), "WriteStmt lowering"); 540 } 541 542 //===--------------------------------------------------------------------===// 543 // Memory allocation and deallocation 544 //===--------------------------------------------------------------------===// 545 546 void genFIR(const Fortran::parser::AllocateStmt &stmt) { 547 TODO(toLocation(), "AllocateStmt lowering"); 548 } 549 550 void genFIR(const Fortran::parser::DeallocateStmt &stmt) { 551 TODO(toLocation(), "DeallocateStmt lowering"); 552 } 553 554 void genFIR(const Fortran::parser::NullifyStmt &stmt) { 555 TODO(toLocation(), "NullifyStmt lowering"); 556 } 557 558 //===--------------------------------------------------------------------===// 559 560 void genFIR(const Fortran::parser::EventPostStmt &stmt) { 561 TODO(toLocation(), "EventPostStmt lowering"); 562 } 563 564 void genFIR(const Fortran::parser::EventWaitStmt &stmt) { 565 TODO(toLocation(), "EventWaitStmt lowering"); 566 } 567 568 void genFIR(const Fortran::parser::FormTeamStmt &stmt) { 569 TODO(toLocation(), "FormTeamStmt lowering"); 570 } 571 572 void genFIR(const Fortran::parser::LockStmt &stmt) { 573 TODO(toLocation(), "LockStmt lowering"); 574 } 575 576 void genFIR(const Fortran::parser::WhereConstruct &c) { 577 TODO(toLocation(), "WhereConstruct lowering"); 578 } 579 580 void genFIR(const Fortran::parser::WhereBodyConstruct &body) { 581 TODO(toLocation(), "WhereBodyConstruct lowering"); 582 } 583 584 void genFIR(const Fortran::parser::WhereConstructStmt &stmt) { 585 TODO(toLocation(), "WhereConstructStmt lowering"); 586 } 587 588 void genFIR(const Fortran::parser::WhereConstruct::MaskedElsewhere &ew) { 589 TODO(toLocation(), "MaskedElsewhere lowering"); 590 } 591 592 void genFIR(const Fortran::parser::MaskedElsewhereStmt &stmt) { 593 TODO(toLocation(), "MaskedElsewhereStmt lowering"); 594 } 595 596 void genFIR(const Fortran::parser::WhereConstruct::Elsewhere &ew) { 597 TODO(toLocation(), "Elsewhere lowering"); 598 } 599 600 void genFIR(const Fortran::parser::ElsewhereStmt &stmt) { 601 TODO(toLocation(), "ElsewhereStmt lowering"); 602 } 603 604 void genFIR(const Fortran::parser::EndWhereStmt &) { 605 TODO(toLocation(), "EndWhereStmt lowering"); 606 } 607 608 void genFIR(const Fortran::parser::WhereStmt &stmt) { 609 TODO(toLocation(), "WhereStmt lowering"); 610 } 611 612 void genFIR(const Fortran::parser::PointerAssignmentStmt &stmt) { 613 TODO(toLocation(), "PointerAssignmentStmt lowering"); 614 } 615 616 void genFIR(const Fortran::parser::AssignmentStmt &stmt) { 617 TODO(toLocation(), "AssignmentStmt lowering"); 618 } 619 620 void genFIR(const Fortran::parser::SyncAllStmt &stmt) { 621 TODO(toLocation(), "SyncAllStmt lowering"); 622 } 623 624 void genFIR(const Fortran::parser::SyncImagesStmt &stmt) { 625 TODO(toLocation(), "SyncImagesStmt lowering"); 626 } 627 628 void genFIR(const Fortran::parser::SyncMemoryStmt &stmt) { 629 TODO(toLocation(), "SyncMemoryStmt lowering"); 630 } 631 632 void genFIR(const Fortran::parser::SyncTeamStmt &stmt) { 633 TODO(toLocation(), "SyncTeamStmt lowering"); 634 } 635 636 void genFIR(const Fortran::parser::UnlockStmt &stmt) { 637 TODO(toLocation(), "UnlockStmt lowering"); 638 } 639 640 void genFIR(const Fortran::parser::AssignStmt &stmt) { 641 TODO(toLocation(), "AssignStmt lowering"); 642 } 643 644 void genFIR(const Fortran::parser::FormatStmt &) { 645 TODO(toLocation(), "FormatStmt lowering"); 646 } 647 648 void genFIR(const Fortran::parser::PauseStmt &stmt) { 649 genPauseStatement(*this, stmt); 650 } 651 652 void genFIR(const Fortran::parser::FailImageStmt &stmt) { 653 TODO(toLocation(), "FailImageStmt lowering"); 654 } 655 656 // call STOP, ERROR STOP in runtime 657 void genFIR(const Fortran::parser::StopStmt &stmt) { 658 genStopStatement(*this, stmt); 659 } 660 661 void genFIR(const Fortran::parser::ReturnStmt &stmt) { 662 Fortran::lower::pft::FunctionLikeUnit *funit = 663 getEval().getOwningProcedure(); 664 assert(funit && "not inside main program, function or subroutine"); 665 if (funit->isMainProgram()) { 666 genExitRoutine(); 667 return; 668 } 669 mlir::Location loc = toLocation(); 670 if (stmt.v) { 671 TODO(loc, "Alternate return statement"); 672 } 673 // Branch to the last block of the SUBROUTINE, which has the actual return. 674 if (!funit->finalBlock) { 675 mlir::OpBuilder::InsertPoint insPt = builder->saveInsertionPoint(); 676 funit->finalBlock = builder->createBlock(&builder->getRegion()); 677 builder->restoreInsertionPoint(insPt); 678 } 679 builder->create<mlir::cf::BranchOp>(loc, funit->finalBlock); 680 } 681 682 void genFIR(const Fortran::parser::CycleStmt &) { 683 TODO(toLocation(), "CycleStmt lowering"); 684 } 685 686 void genFIR(const Fortran::parser::ExitStmt &) { 687 TODO(toLocation(), "ExitStmt lowering"); 688 } 689 690 void genFIR(const Fortran::parser::GotoStmt &) { 691 genFIRBranch(getEval().controlSuccessor->block); 692 } 693 694 void genFIR(const Fortran::parser::AssociateStmt &) { 695 TODO(toLocation(), "AssociateStmt lowering"); 696 } 697 698 void genFIR(const Fortran::parser::CaseStmt &) { 699 TODO(toLocation(), "CaseStmt lowering"); 700 } 701 702 void genFIR(const Fortran::parser::ContinueStmt &) { 703 TODO(toLocation(), "ContinueStmt lowering"); 704 } 705 706 void genFIR(const Fortran::parser::ElseIfStmt &) { 707 TODO(toLocation(), "ElseIfStmt lowering"); 708 } 709 710 void genFIR(const Fortran::parser::ElseStmt &) { 711 TODO(toLocation(), "ElseStmt lowering"); 712 } 713 714 void genFIR(const Fortran::parser::EndAssociateStmt &) { 715 TODO(toLocation(), "EndAssociateStmt lowering"); 716 } 717 718 void genFIR(const Fortran::parser::EndDoStmt &) { 719 TODO(toLocation(), "EndDoStmt lowering"); 720 } 721 722 void genFIR(const Fortran::parser::EndFunctionStmt &) { 723 TODO(toLocation(), "EndFunctionStmt lowering"); 724 } 725 726 void genFIR(const Fortran::parser::EndIfStmt &) { 727 TODO(toLocation(), "EndIfStmt lowering"); 728 } 729 730 void genFIR(const Fortran::parser::EndMpSubprogramStmt &) { 731 TODO(toLocation(), "EndMpSubprogramStmt lowering"); 732 } 733 734 void genFIR(const Fortran::parser::EndSelectStmt &) { 735 TODO(toLocation(), "EndSelectStmt lowering"); 736 } 737 738 // Nop statements - No code, or code is generated at the construct level. 739 void genFIR(const Fortran::parser::EndSubroutineStmt &) {} // nop 740 741 void genFIR(const Fortran::parser::EntryStmt &) { 742 TODO(toLocation(), "EntryStmt lowering"); 743 } 744 745 void genFIR(const Fortran::parser::IfStmt &) { 746 TODO(toLocation(), "IfStmt lowering"); 747 } 748 749 void genFIR(const Fortran::parser::IfThenStmt &) { 750 TODO(toLocation(), "IfThenStmt lowering"); 751 } 752 753 void genFIR(const Fortran::parser::NonLabelDoStmt &) { 754 TODO(toLocation(), "NonLabelDoStmt lowering"); 755 } 756 757 void genFIR(const Fortran::parser::OmpEndLoopDirective &) { 758 TODO(toLocation(), "OmpEndLoopDirective lowering"); 759 } 760 761 void genFIR(const Fortran::parser::NamelistStmt &) { 762 TODO(toLocation(), "NamelistStmt lowering"); 763 } 764 765 void genFIR(Fortran::lower::pft::Evaluation &eval, 766 bool unstructuredContext = true) { 767 if (unstructuredContext) { 768 // When transitioning from unstructured to structured code, 769 // the structured code could be a target that starts a new block. 770 maybeStartBlock(eval.isConstruct() && eval.lowerAsStructured() 771 ? eval.getFirstNestedEvaluation().block 772 : eval.block); 773 } 774 775 setCurrentEval(eval); 776 setCurrentPosition(eval.position); 777 eval.visit([&](const auto &stmt) { genFIR(stmt); }); 778 } 779 780 //===--------------------------------------------------------------------===// 781 782 Fortran::lower::LoweringBridge &bridge; 783 Fortran::evaluate::FoldingContext foldingContext; 784 fir::FirOpBuilder *builder = nullptr; 785 Fortran::lower::pft::Evaluation *evalPtr = nullptr; 786 Fortran::lower::SymMap localSymbols; 787 Fortran::parser::CharBlock currentPosition; 788 }; 789 790 } // namespace 791 792 Fortran::evaluate::FoldingContext 793 Fortran::lower::LoweringBridge::createFoldingContext() const { 794 return {getDefaultKinds(), getIntrinsicTable()}; 795 } 796 797 void Fortran::lower::LoweringBridge::lower( 798 const Fortran::parser::Program &prg, 799 const Fortran::semantics::SemanticsContext &semanticsContext) { 800 std::unique_ptr<Fortran::lower::pft::Program> pft = 801 Fortran::lower::createPFT(prg, semanticsContext); 802 if (dumpBeforeFir) 803 Fortran::lower::dumpPFT(llvm::errs(), *pft); 804 FirConverter converter{*this}; 805 converter.run(*pft); 806 } 807 808 Fortran::lower::LoweringBridge::LoweringBridge( 809 mlir::MLIRContext &context, 810 const Fortran::common::IntrinsicTypeDefaultKinds &defaultKinds, 811 const Fortran::evaluate::IntrinsicProcTable &intrinsics, 812 const Fortran::parser::AllCookedSources &cooked, llvm::StringRef triple, 813 fir::KindMapping &kindMap) 814 : defaultKinds{defaultKinds}, intrinsics{intrinsics}, cooked{&cooked}, 815 context{context}, kindMap{kindMap} { 816 // Register the diagnostic handler. 817 context.getDiagEngine().registerHandler([](mlir::Diagnostic &diag) { 818 llvm::raw_ostream &os = llvm::errs(); 819 switch (diag.getSeverity()) { 820 case mlir::DiagnosticSeverity::Error: 821 os << "error: "; 822 break; 823 case mlir::DiagnosticSeverity::Remark: 824 os << "info: "; 825 break; 826 case mlir::DiagnosticSeverity::Warning: 827 os << "warning: "; 828 break; 829 default: 830 break; 831 } 832 if (!diag.getLocation().isa<UnknownLoc>()) 833 os << diag.getLocation() << ": "; 834 os << diag << '\n'; 835 os.flush(); 836 return mlir::success(); 837 }); 838 839 // Create the module and attach the attributes. 840 module = std::make_unique<mlir::ModuleOp>( 841 mlir::ModuleOp::create(mlir::UnknownLoc::get(&context))); 842 assert(module.get() && "module was not created"); 843 fir::setTargetTriple(*module.get(), triple); 844 fir::setKindMapping(*module.get(), kindMap); 845 } 846