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 sym) override final { 103 return Fortran::lower::translateSymbolToFIRType(*this, sym); 104 } 105 mlir::Type genType(Fortran::common::TypeCategory tc) override final { 106 TODO_NOLOC("Not implemented genType TypeCategory. Needed for more complex " 107 "expression lowering"); 108 } 109 mlir::Type genType(Fortran::common::TypeCategory tc, 110 int kind) override final { 111 return Fortran::lower::getFIRType(&getMLIRContext(), tc, kind); 112 } 113 mlir::Type genType(const Fortran::lower::pft::Variable &var) override final { 114 return Fortran::lower::translateVariableToFIRType(*this, var); 115 } 116 117 void setCurrentPosition(const Fortran::parser::CharBlock &position) { 118 if (position != Fortran::parser::CharBlock{}) 119 currentPosition = position; 120 } 121 122 //===--------------------------------------------------------------------===// 123 // Utility methods 124 //===--------------------------------------------------------------------===// 125 126 /// Convert a parser CharBlock to a Location 127 mlir::Location toLocation(const Fortran::parser::CharBlock &cb) { 128 return genLocation(cb); 129 } 130 131 mlir::Location toLocation() { return toLocation(currentPosition); } 132 void setCurrentEval(Fortran::lower::pft::Evaluation &eval) { 133 evalPtr = &eval; 134 } 135 Fortran::lower::pft::Evaluation &getEval() { 136 assert(evalPtr && "current evaluation not set"); 137 return *evalPtr; 138 } 139 140 mlir::Location getCurrentLocation() override final { return toLocation(); } 141 142 /// Generate a dummy location. 143 mlir::Location genUnknownLocation() override final { 144 // Note: builder may not be instantiated yet 145 return mlir::UnknownLoc::get(&getMLIRContext()); 146 } 147 148 /// Generate a `Location` from the `CharBlock`. 149 mlir::Location 150 genLocation(const Fortran::parser::CharBlock &block) override final { 151 if (const Fortran::parser::AllCookedSources *cooked = 152 bridge.getCookedSource()) { 153 if (std::optional<std::pair<Fortran::parser::SourcePosition, 154 Fortran::parser::SourcePosition>> 155 loc = cooked->GetSourcePositionRange(block)) { 156 // loc is a pair (begin, end); use the beginning position 157 Fortran::parser::SourcePosition &filePos = loc->first; 158 return mlir::FileLineColLoc::get(&getMLIRContext(), filePos.file.path(), 159 filePos.line, filePos.column); 160 } 161 } 162 return genUnknownLocation(); 163 } 164 165 fir::FirOpBuilder &getFirOpBuilder() override final { return *builder; } 166 167 mlir::ModuleOp &getModuleOp() override final { return bridge.getModule(); } 168 169 mlir::MLIRContext &getMLIRContext() override final { 170 return bridge.getMLIRContext(); 171 } 172 std::string 173 mangleName(const Fortran::semantics::Symbol &symbol) override final { 174 return Fortran::lower::mangle::mangleName(symbol); 175 } 176 177 const fir::KindMapping &getKindMap() override final { 178 return bridge.getKindMap(); 179 } 180 181 /// Return the predicate: "current block does not have a terminator branch". 182 bool blockIsUnterminated() { 183 mlir::Block *currentBlock = builder->getBlock(); 184 return currentBlock->empty() || 185 !currentBlock->back().hasTrait<mlir::OpTrait::IsTerminator>(); 186 } 187 188 /// Unconditionally switch code insertion to a new block. 189 void startBlock(mlir::Block *newBlock) { 190 assert(newBlock && "missing block"); 191 // Default termination for the current block is a fallthrough branch to 192 // the new block. 193 if (blockIsUnterminated()) 194 genFIRBranch(newBlock); 195 // Some blocks may be re/started more than once, and might not be empty. 196 // If the new block already has (only) a terminator, set the insertion 197 // point to the start of the block. Otherwise set it to the end. 198 // Note that setting the insertion point causes the subsequent function 199 // call to check the existence of terminator in the newBlock. 200 builder->setInsertionPointToStart(newBlock); 201 if (blockIsUnterminated()) 202 builder->setInsertionPointToEnd(newBlock); 203 } 204 205 /// Conditionally switch code insertion to a new block. 206 void maybeStartBlock(mlir::Block *newBlock) { 207 if (newBlock) 208 startBlock(newBlock); 209 } 210 211 /// Emit return and cleanup after the function has been translated. 212 void endNewFunction(Fortran::lower::pft::FunctionLikeUnit &funit) { 213 setCurrentPosition(Fortran::lower::pft::stmtSourceLoc(funit.endStmt)); 214 if (funit.isMainProgram()) 215 genExitRoutine(); 216 else 217 genFIRProcedureExit(funit, funit.getSubprogramSymbol()); 218 funit.finalBlock = nullptr; 219 LLVM_DEBUG(llvm::dbgs() << "*** Lowering result:\n\n" 220 << *builder->getFunction() << '\n'); 221 // FIXME: Simplification should happen in a normal pass, not here. 222 mlir::IRRewriter rewriter(*builder); 223 (void)mlir::simplifyRegions(rewriter, 224 {builder->getRegion()}); // remove dead code 225 delete builder; 226 builder = nullptr; 227 localSymbols.clear(); 228 } 229 230 /// Map mlir function block arguments to the corresponding Fortran dummy 231 /// variables. When the result is passed as a hidden argument, the Fortran 232 /// result is also mapped. The symbol map is used to hold this mapping. 233 void mapDummiesAndResults(Fortran::lower::pft::FunctionLikeUnit &funit, 234 const Fortran::lower::CalleeInterface &callee) { 235 assert(builder && "require a builder object at this point"); 236 using PassBy = Fortran::lower::CalleeInterface::PassEntityBy; 237 auto mapPassedEntity = [&](const auto arg) -> void { 238 if (arg.passBy == PassBy::AddressAndLength) { 239 // // TODO: now that fir call has some attributes regarding character 240 // // return, PassBy::AddressAndLength should be retired. 241 // mlir::Location loc = toLocation(); 242 // fir::factory::CharacterExprHelper charHelp{*builder, loc}; 243 // mlir::Value box = 244 // charHelp.createEmboxChar(arg.firArgument, arg.firLength); 245 // addSymbol(arg.entity->get(), box); 246 } else { 247 if (arg.entity.has_value()) { 248 addSymbol(arg.entity->get(), arg.firArgument); 249 } else { 250 // assert(funit.parentHasHostAssoc()); 251 // funit.parentHostAssoc().internalProcedureBindings(*this, 252 // localSymbols); 253 } 254 } 255 }; 256 for (const Fortran::lower::CalleeInterface::PassedEntity &arg : 257 callee.getPassedArguments()) 258 mapPassedEntity(arg); 259 260 // Allocate local skeleton instances of dummies from other entry points. 261 // Most of these locals will not survive into final generated code, but 262 // some will. It is illegal to reference them at run time if they do. 263 for (const Fortran::semantics::Symbol *arg : 264 funit.nonUniversalDummyArguments) { 265 if (lookupSymbol(*arg)) 266 continue; 267 mlir::Type type = genType(*arg); 268 // TODO: Account for VALUE arguments (and possibly other variants). 269 type = builder->getRefType(type); 270 addSymbol(*arg, builder->create<fir::UndefOp>(toLocation(), type)); 271 } 272 if (std::optional<Fortran::lower::CalleeInterface::PassedEntity> 273 passedResult = callee.getPassedResult()) { 274 mapPassedEntity(*passedResult); 275 // FIXME: need to make sure things are OK here. addSymbol may not be OK 276 if (funit.primaryResult && 277 passedResult->entity->get() != *funit.primaryResult) 278 addSymbol(*funit.primaryResult, 279 getSymbolAddress(passedResult->entity->get())); 280 } 281 } 282 283 /// Instantiate variable \p var and add it to the symbol map. 284 /// See ConvertVariable.cpp. 285 void instantiateVar(const Fortran::lower::pft::Variable &var) { 286 Fortran::lower::instantiateVariable(*this, var, localSymbols); 287 } 288 289 /// Prepare to translate a new function 290 void startNewFunction(Fortran::lower::pft::FunctionLikeUnit &funit) { 291 assert(!builder && "expected nullptr"); 292 Fortran::lower::CalleeInterface callee(funit, *this); 293 mlir::FuncOp func = callee.addEntryBlockAndMapArguments(); 294 func.setVisibility(mlir::SymbolTable::Visibility::Public); 295 builder = new fir::FirOpBuilder(func, bridge.getKindMap()); 296 assert(builder && "FirOpBuilder did not instantiate"); 297 builder->setInsertionPointToStart(&func.front()); 298 299 mapDummiesAndResults(funit, callee); 300 301 for (const Fortran::lower::pft::Variable &var : 302 funit.getOrderedSymbolTable()) { 303 const Fortran::semantics::Symbol &sym = var.getSymbol(); 304 if (!sym.IsFuncResult() || !funit.primaryResult) { 305 instantiateVar(var); 306 } else if (&sym == funit.primaryResult) { 307 instantiateVar(var); 308 } 309 } 310 311 // Create most function blocks in advance. 312 createEmptyGlobalBlocks(funit.evaluationList); 313 314 // Reinstate entry block as the current insertion point. 315 builder->setInsertionPointToEnd(&func.front()); 316 } 317 318 /// Create global blocks for the current function. This eliminates the 319 /// distinction between forward and backward targets when generating 320 /// branches. A block is "global" if it can be the target of a GOTO or 321 /// other source code branch. A block that can only be targeted by a 322 /// compiler generated branch is "local". For example, a DO loop preheader 323 /// block containing loop initialization code is global. A loop header 324 /// block, which is the target of the loop back edge, is local. Blocks 325 /// belong to a region. Any block within a nested region must be replaced 326 /// with a block belonging to that region. Branches may not cross region 327 /// boundaries. 328 void createEmptyGlobalBlocks( 329 std::list<Fortran::lower::pft::Evaluation> &evaluationList) { 330 mlir::Region *region = &builder->getRegion(); 331 for (Fortran::lower::pft::Evaluation &eval : evaluationList) { 332 if (eval.isNewBlock) 333 eval.block = builder->createBlock(region); 334 if (eval.isConstruct() || eval.isDirective()) { 335 if (eval.lowerAsUnstructured()) { 336 createEmptyGlobalBlocks(eval.getNestedEvaluations()); 337 } else if (eval.hasNestedEvaluations()) { 338 TODO(toLocation(), "Constructs with nested evaluations"); 339 } 340 } 341 } 342 } 343 344 /// Lower a procedure (nest). 345 void lowerFunc(Fortran::lower::pft::FunctionLikeUnit &funit) { 346 setCurrentPosition(funit.getStartingSourceLoc()); 347 for (int entryIndex = 0, last = funit.entryPointList.size(); 348 entryIndex < last; ++entryIndex) { 349 funit.setActiveEntry(entryIndex); 350 startNewFunction(funit); // the entry point for lowering this procedure 351 for (Fortran::lower::pft::Evaluation &eval : funit.evaluationList) 352 genFIR(eval); 353 endNewFunction(funit); 354 } 355 funit.setActiveEntry(0); 356 for (Fortran::lower::pft::FunctionLikeUnit &f : funit.nestedFunctions) 357 lowerFunc(f); // internal procedure 358 } 359 360 private: 361 FirConverter() = delete; 362 FirConverter(const FirConverter &) = delete; 363 FirConverter &operator=(const FirConverter &) = delete; 364 365 //===--------------------------------------------------------------------===// 366 // Helper member functions 367 //===--------------------------------------------------------------------===// 368 369 /// Find the symbol in the local map or return null. 370 Fortran::lower::SymbolBox 371 lookupSymbol(const Fortran::semantics::Symbol &sym) { 372 if (Fortran::lower::SymbolBox v = localSymbols.lookupSymbol(sym)) 373 return v; 374 return {}; 375 } 376 377 /// Add the symbol to the local map and return `true`. If the symbol is 378 /// already in the map and \p forced is `false`, the map is not updated. 379 /// Instead the value `false` is returned. 380 bool addSymbol(const Fortran::semantics::SymbolRef sym, mlir::Value val, 381 bool forced = false) { 382 if (!forced && lookupSymbol(sym)) 383 return false; 384 localSymbols.addSymbol(sym, val, forced); 385 return true; 386 } 387 388 void genFIRBranch(mlir::Block *targetBlock) { 389 assert(targetBlock && "missing unconditional target block"); 390 builder->create<cf::BranchOp>(toLocation(), targetBlock); 391 } 392 393 //===--------------------------------------------------------------------===// 394 // Termination of symbolically referenced execution units 395 //===--------------------------------------------------------------------===// 396 397 /// END of program 398 /// 399 /// Generate the cleanup block before the program exits 400 void genExitRoutine() { 401 if (blockIsUnterminated()) 402 builder->create<mlir::ReturnOp>(toLocation()); 403 } 404 void genFIR(const Fortran::parser::EndProgramStmt &) { genExitRoutine(); } 405 406 /// END of procedure-like constructs 407 /// 408 /// Generate the cleanup block before the procedure exits 409 void genReturnSymbol(const Fortran::semantics::Symbol &functionSymbol) { 410 const Fortran::semantics::Symbol &resultSym = 411 functionSymbol.get<Fortran::semantics::SubprogramDetails>().result(); 412 Fortran::lower::SymbolBox resultSymBox = lookupSymbol(resultSym); 413 mlir::Location loc = toLocation(); 414 if (!resultSymBox) { 415 mlir::emitError(loc, "failed lowering function return"); 416 return; 417 } 418 mlir::Value resultVal = resultSymBox.match( 419 [&](const fir::CharBoxValue &x) -> mlir::Value { 420 TODO(loc, "Function return CharBoxValue"); 421 }, 422 [&](const auto &) -> mlir::Value { 423 mlir::Value resultRef = resultSymBox.getAddr(); 424 mlir::Type resultType = genType(resultSym); 425 mlir::Type resultRefType = builder->getRefType(resultType); 426 // A function with multiple entry points returning different types 427 // tags all result variables with one of the largest types to allow 428 // them to share the same storage. Convert this to the actual type. 429 if (resultRef.getType() != resultRefType) 430 TODO(loc, "Convert to actual type"); 431 return builder->create<fir::LoadOp>(loc, resultRef); 432 }); 433 builder->create<mlir::ReturnOp>(loc, resultVal); 434 } 435 436 void genFIRProcedureExit(Fortran::lower::pft::FunctionLikeUnit &funit, 437 const Fortran::semantics::Symbol &symbol) { 438 if (mlir::Block *finalBlock = funit.finalBlock) { 439 // The current block must end with a terminator. 440 if (blockIsUnterminated()) 441 builder->create<mlir::cf::BranchOp>(toLocation(), finalBlock); 442 // Set insertion point to final block. 443 builder->setInsertionPoint(finalBlock, finalBlock->end()); 444 } 445 if (Fortran::semantics::IsFunction(symbol)) { 446 genReturnSymbol(symbol); 447 } else { 448 genExitRoutine(); 449 } 450 } 451 452 void genFIR(const Fortran::parser::CallStmt &stmt) { 453 TODO(toLocation(), "CallStmt lowering"); 454 } 455 456 void genFIR(const Fortran::parser::ComputedGotoStmt &stmt) { 457 TODO(toLocation(), "ComputedGotoStmt lowering"); 458 } 459 460 void genFIR(const Fortran::parser::ArithmeticIfStmt &stmt) { 461 TODO(toLocation(), "ArithmeticIfStmt lowering"); 462 } 463 464 void genFIR(const Fortran::parser::AssignedGotoStmt &stmt) { 465 TODO(toLocation(), "AssignedGotoStmt lowering"); 466 } 467 468 void genFIR(const Fortran::parser::DoConstruct &doConstruct) { 469 TODO(toLocation(), "DoConstruct lowering"); 470 } 471 472 void genFIR(const Fortran::parser::IfConstruct &) { 473 TODO(toLocation(), "IfConstruct lowering"); 474 } 475 476 void genFIR(const Fortran::parser::CaseConstruct &) { 477 TODO(toLocation(), "CaseConstruct lowering"); 478 } 479 480 void genFIR(const Fortran::parser::ConcurrentHeader &header) { 481 TODO(toLocation(), "ConcurrentHeader lowering"); 482 } 483 484 void genFIR(const Fortran::parser::ForallAssignmentStmt &stmt) { 485 TODO(toLocation(), "ForallAssignmentStmt lowering"); 486 } 487 488 void genFIR(const Fortran::parser::EndForallStmt &) { 489 TODO(toLocation(), "EndForallStmt lowering"); 490 } 491 492 void genFIR(const Fortran::parser::ForallStmt &) { 493 TODO(toLocation(), "ForallStmt lowering"); 494 } 495 496 void genFIR(const Fortran::parser::ForallConstruct &) { 497 TODO(toLocation(), "ForallConstruct lowering"); 498 } 499 500 void genFIR(const Fortran::parser::ForallConstructStmt &) { 501 TODO(toLocation(), "ForallConstructStmt lowering"); 502 } 503 504 void genFIR(const Fortran::parser::CompilerDirective &) { 505 TODO(toLocation(), "CompilerDirective lowering"); 506 } 507 508 void genFIR(const Fortran::parser::OpenACCConstruct &) { 509 TODO(toLocation(), "OpenACCConstruct lowering"); 510 } 511 512 void genFIR(const Fortran::parser::OpenACCDeclarativeConstruct &) { 513 TODO(toLocation(), "OpenACCDeclarativeConstruct lowering"); 514 } 515 516 void genFIR(const Fortran::parser::OpenMPConstruct &) { 517 TODO(toLocation(), "OpenMPConstruct lowering"); 518 } 519 520 void genFIR(const Fortran::parser::OpenMPDeclarativeConstruct &) { 521 TODO(toLocation(), "OpenMPDeclarativeConstruct lowering"); 522 } 523 524 void genFIR(const Fortran::parser::SelectCaseStmt &) { 525 TODO(toLocation(), "SelectCaseStmt lowering"); 526 } 527 528 void genFIR(const Fortran::parser::AssociateConstruct &) { 529 TODO(toLocation(), "AssociateConstruct lowering"); 530 } 531 532 void genFIR(const Fortran::parser::BlockConstruct &blockConstruct) { 533 TODO(toLocation(), "BlockConstruct lowering"); 534 } 535 536 void genFIR(const Fortran::parser::BlockStmt &) { 537 TODO(toLocation(), "BlockStmt lowering"); 538 } 539 540 void genFIR(const Fortran::parser::EndBlockStmt &) { 541 TODO(toLocation(), "EndBlockStmt lowering"); 542 } 543 544 void genFIR(const Fortran::parser::ChangeTeamConstruct &construct) { 545 TODO(toLocation(), "ChangeTeamConstruct lowering"); 546 } 547 548 void genFIR(const Fortran::parser::ChangeTeamStmt &stmt) { 549 TODO(toLocation(), "ChangeTeamStmt lowering"); 550 } 551 552 void genFIR(const Fortran::parser::EndChangeTeamStmt &stmt) { 553 TODO(toLocation(), "EndChangeTeamStmt lowering"); 554 } 555 556 void genFIR(const Fortran::parser::CriticalConstruct &criticalConstruct) { 557 TODO(toLocation(), "CriticalConstruct lowering"); 558 } 559 560 void genFIR(const Fortran::parser::CriticalStmt &) { 561 TODO(toLocation(), "CriticalStmt lowering"); 562 } 563 564 void genFIR(const Fortran::parser::EndCriticalStmt &) { 565 TODO(toLocation(), "EndCriticalStmt lowering"); 566 } 567 568 void genFIR(const Fortran::parser::SelectRankConstruct &selectRankConstruct) { 569 TODO(toLocation(), "SelectRankConstruct lowering"); 570 } 571 572 void genFIR(const Fortran::parser::SelectRankStmt &) { 573 TODO(toLocation(), "SelectRankStmt lowering"); 574 } 575 576 void genFIR(const Fortran::parser::SelectRankCaseStmt &) { 577 TODO(toLocation(), "SelectRankCaseStmt lowering"); 578 } 579 580 void genFIR(const Fortran::parser::SelectTypeConstruct &selectTypeConstruct) { 581 TODO(toLocation(), "SelectTypeConstruct lowering"); 582 } 583 584 void genFIR(const Fortran::parser::SelectTypeStmt &) { 585 TODO(toLocation(), "SelectTypeStmt lowering"); 586 } 587 588 void genFIR(const Fortran::parser::TypeGuardStmt &) { 589 TODO(toLocation(), "TypeGuardStmt lowering"); 590 } 591 592 //===--------------------------------------------------------------------===// 593 // IO statements (see io.h) 594 //===--------------------------------------------------------------------===// 595 596 void genFIR(const Fortran::parser::BackspaceStmt &stmt) { 597 TODO(toLocation(), "BackspaceStmt lowering"); 598 } 599 600 void genFIR(const Fortran::parser::CloseStmt &stmt) { 601 TODO(toLocation(), "CloseStmt lowering"); 602 } 603 604 void genFIR(const Fortran::parser::EndfileStmt &stmt) { 605 TODO(toLocation(), "EndfileStmt lowering"); 606 } 607 608 void genFIR(const Fortran::parser::FlushStmt &stmt) { 609 TODO(toLocation(), "FlushStmt lowering"); 610 } 611 612 void genFIR(const Fortran::parser::InquireStmt &stmt) { 613 TODO(toLocation(), "InquireStmt lowering"); 614 } 615 616 void genFIR(const Fortran::parser::OpenStmt &stmt) { 617 TODO(toLocation(), "OpenStmt lowering"); 618 } 619 620 void genFIR(const Fortran::parser::PrintStmt &stmt) { 621 TODO(toLocation(), "PrintStmt lowering"); 622 } 623 624 void genFIR(const Fortran::parser::ReadStmt &stmt) { 625 TODO(toLocation(), "ReadStmt lowering"); 626 } 627 628 void genFIR(const Fortran::parser::RewindStmt &stmt) { 629 TODO(toLocation(), "RewindStmt lowering"); 630 } 631 632 void genFIR(const Fortran::parser::WaitStmt &stmt) { 633 TODO(toLocation(), "WaitStmt lowering"); 634 } 635 636 void genFIR(const Fortran::parser::WriteStmt &stmt) { 637 TODO(toLocation(), "WriteStmt lowering"); 638 } 639 640 //===--------------------------------------------------------------------===// 641 // Memory allocation and deallocation 642 //===--------------------------------------------------------------------===// 643 644 void genFIR(const Fortran::parser::AllocateStmt &stmt) { 645 TODO(toLocation(), "AllocateStmt lowering"); 646 } 647 648 void genFIR(const Fortran::parser::DeallocateStmt &stmt) { 649 TODO(toLocation(), "DeallocateStmt lowering"); 650 } 651 652 void genFIR(const Fortran::parser::NullifyStmt &stmt) { 653 TODO(toLocation(), "NullifyStmt lowering"); 654 } 655 656 //===--------------------------------------------------------------------===// 657 658 void genFIR(const Fortran::parser::EventPostStmt &stmt) { 659 TODO(toLocation(), "EventPostStmt lowering"); 660 } 661 662 void genFIR(const Fortran::parser::EventWaitStmt &stmt) { 663 TODO(toLocation(), "EventWaitStmt lowering"); 664 } 665 666 void genFIR(const Fortran::parser::FormTeamStmt &stmt) { 667 TODO(toLocation(), "FormTeamStmt lowering"); 668 } 669 670 void genFIR(const Fortran::parser::LockStmt &stmt) { 671 TODO(toLocation(), "LockStmt lowering"); 672 } 673 674 void genFIR(const Fortran::parser::WhereConstruct &c) { 675 TODO(toLocation(), "WhereConstruct lowering"); 676 } 677 678 void genFIR(const Fortran::parser::WhereBodyConstruct &body) { 679 TODO(toLocation(), "WhereBodyConstruct lowering"); 680 } 681 682 void genFIR(const Fortran::parser::WhereConstructStmt &stmt) { 683 TODO(toLocation(), "WhereConstructStmt lowering"); 684 } 685 686 void genFIR(const Fortran::parser::WhereConstruct::MaskedElsewhere &ew) { 687 TODO(toLocation(), "MaskedElsewhere lowering"); 688 } 689 690 void genFIR(const Fortran::parser::MaskedElsewhereStmt &stmt) { 691 TODO(toLocation(), "MaskedElsewhereStmt lowering"); 692 } 693 694 void genFIR(const Fortran::parser::WhereConstruct::Elsewhere &ew) { 695 TODO(toLocation(), "Elsewhere lowering"); 696 } 697 698 void genFIR(const Fortran::parser::ElsewhereStmt &stmt) { 699 TODO(toLocation(), "ElsewhereStmt lowering"); 700 } 701 702 void genFIR(const Fortran::parser::EndWhereStmt &) { 703 TODO(toLocation(), "EndWhereStmt lowering"); 704 } 705 706 void genFIR(const Fortran::parser::WhereStmt &stmt) { 707 TODO(toLocation(), "WhereStmt lowering"); 708 } 709 710 void genFIR(const Fortran::parser::PointerAssignmentStmt &stmt) { 711 TODO(toLocation(), "PointerAssignmentStmt lowering"); 712 } 713 714 void genFIR(const Fortran::parser::AssignmentStmt &stmt) { 715 TODO(toLocation(), "AssignmentStmt lowering"); 716 } 717 718 void genFIR(const Fortran::parser::SyncAllStmt &stmt) { 719 TODO(toLocation(), "SyncAllStmt lowering"); 720 } 721 722 void genFIR(const Fortran::parser::SyncImagesStmt &stmt) { 723 TODO(toLocation(), "SyncImagesStmt lowering"); 724 } 725 726 void genFIR(const Fortran::parser::SyncMemoryStmt &stmt) { 727 TODO(toLocation(), "SyncMemoryStmt lowering"); 728 } 729 730 void genFIR(const Fortran::parser::SyncTeamStmt &stmt) { 731 TODO(toLocation(), "SyncTeamStmt lowering"); 732 } 733 734 void genFIR(const Fortran::parser::UnlockStmt &stmt) { 735 TODO(toLocation(), "UnlockStmt lowering"); 736 } 737 738 void genFIR(const Fortran::parser::AssignStmt &stmt) { 739 TODO(toLocation(), "AssignStmt lowering"); 740 } 741 742 void genFIR(const Fortran::parser::FormatStmt &) { 743 TODO(toLocation(), "FormatStmt lowering"); 744 } 745 746 void genFIR(const Fortran::parser::PauseStmt &stmt) { 747 genPauseStatement(*this, stmt); 748 } 749 750 void genFIR(const Fortran::parser::FailImageStmt &stmt) { 751 TODO(toLocation(), "FailImageStmt lowering"); 752 } 753 754 // call STOP, ERROR STOP in runtime 755 void genFIR(const Fortran::parser::StopStmt &stmt) { 756 genStopStatement(*this, stmt); 757 } 758 759 void genFIR(const Fortran::parser::ReturnStmt &stmt) { 760 Fortran::lower::pft::FunctionLikeUnit *funit = 761 getEval().getOwningProcedure(); 762 assert(funit && "not inside main program, function or subroutine"); 763 if (funit->isMainProgram()) { 764 genExitRoutine(); 765 return; 766 } 767 mlir::Location loc = toLocation(); 768 if (stmt.v) { 769 TODO(loc, "Alternate return statement"); 770 } 771 // Branch to the last block of the SUBROUTINE, which has the actual return. 772 if (!funit->finalBlock) { 773 mlir::OpBuilder::InsertPoint insPt = builder->saveInsertionPoint(); 774 funit->finalBlock = builder->createBlock(&builder->getRegion()); 775 builder->restoreInsertionPoint(insPt); 776 } 777 builder->create<mlir::cf::BranchOp>(loc, funit->finalBlock); 778 } 779 780 void genFIR(const Fortran::parser::CycleStmt &) { 781 TODO(toLocation(), "CycleStmt lowering"); 782 } 783 784 void genFIR(const Fortran::parser::ExitStmt &) { 785 TODO(toLocation(), "ExitStmt lowering"); 786 } 787 788 void genFIR(const Fortran::parser::GotoStmt &) { 789 genFIRBranch(getEval().controlSuccessor->block); 790 } 791 792 void genFIR(const Fortran::parser::AssociateStmt &) { 793 TODO(toLocation(), "AssociateStmt lowering"); 794 } 795 796 void genFIR(const Fortran::parser::CaseStmt &) { 797 TODO(toLocation(), "CaseStmt lowering"); 798 } 799 800 void genFIR(const Fortran::parser::ContinueStmt &) { 801 TODO(toLocation(), "ContinueStmt lowering"); 802 } 803 804 void genFIR(const Fortran::parser::ElseIfStmt &) { 805 TODO(toLocation(), "ElseIfStmt lowering"); 806 } 807 808 void genFIR(const Fortran::parser::ElseStmt &) { 809 TODO(toLocation(), "ElseStmt lowering"); 810 } 811 812 void genFIR(const Fortran::parser::EndAssociateStmt &) { 813 TODO(toLocation(), "EndAssociateStmt lowering"); 814 } 815 816 void genFIR(const Fortran::parser::EndDoStmt &) { 817 TODO(toLocation(), "EndDoStmt lowering"); 818 } 819 820 void genFIR(const Fortran::parser::EndIfStmt &) { 821 TODO(toLocation(), "EndIfStmt lowering"); 822 } 823 824 void genFIR(const Fortran::parser::EndMpSubprogramStmt &) { 825 TODO(toLocation(), "EndMpSubprogramStmt lowering"); 826 } 827 828 void genFIR(const Fortran::parser::EndSelectStmt &) { 829 TODO(toLocation(), "EndSelectStmt lowering"); 830 } 831 832 // Nop statements - No code, or code is generated at the construct level. 833 void genFIR(const Fortran::parser::EndFunctionStmt &) {} // nop 834 void genFIR(const Fortran::parser::EndSubroutineStmt &) {} // nop 835 836 void genFIR(const Fortran::parser::EntryStmt &) { 837 TODO(toLocation(), "EntryStmt lowering"); 838 } 839 840 void genFIR(const Fortran::parser::IfStmt &) { 841 TODO(toLocation(), "IfStmt lowering"); 842 } 843 844 void genFIR(const Fortran::parser::IfThenStmt &) { 845 TODO(toLocation(), "IfThenStmt lowering"); 846 } 847 848 void genFIR(const Fortran::parser::NonLabelDoStmt &) { 849 TODO(toLocation(), "NonLabelDoStmt lowering"); 850 } 851 852 void genFIR(const Fortran::parser::OmpEndLoopDirective &) { 853 TODO(toLocation(), "OmpEndLoopDirective lowering"); 854 } 855 856 void genFIR(const Fortran::parser::NamelistStmt &) { 857 TODO(toLocation(), "NamelistStmt lowering"); 858 } 859 860 void genFIR(Fortran::lower::pft::Evaluation &eval, 861 bool unstructuredContext = true) { 862 if (unstructuredContext) { 863 // When transitioning from unstructured to structured code, 864 // the structured code could be a target that starts a new block. 865 maybeStartBlock(eval.isConstruct() && eval.lowerAsStructured() 866 ? eval.getFirstNestedEvaluation().block 867 : eval.block); 868 } 869 870 setCurrentEval(eval); 871 setCurrentPosition(eval.position); 872 eval.visit([&](const auto &stmt) { genFIR(stmt); }); 873 } 874 875 //===--------------------------------------------------------------------===// 876 877 Fortran::lower::LoweringBridge &bridge; 878 Fortran::evaluate::FoldingContext foldingContext; 879 fir::FirOpBuilder *builder = nullptr; 880 Fortran::lower::pft::Evaluation *evalPtr = nullptr; 881 Fortran::lower::SymMap localSymbols; 882 Fortran::parser::CharBlock currentPosition; 883 }; 884 885 } // namespace 886 887 Fortran::evaluate::FoldingContext 888 Fortran::lower::LoweringBridge::createFoldingContext() const { 889 return {getDefaultKinds(), getIntrinsicTable()}; 890 } 891 892 void Fortran::lower::LoweringBridge::lower( 893 const Fortran::parser::Program &prg, 894 const Fortran::semantics::SemanticsContext &semanticsContext) { 895 std::unique_ptr<Fortran::lower::pft::Program> pft = 896 Fortran::lower::createPFT(prg, semanticsContext); 897 if (dumpBeforeFir) 898 Fortran::lower::dumpPFT(llvm::errs(), *pft); 899 FirConverter converter{*this}; 900 converter.run(*pft); 901 } 902 903 Fortran::lower::LoweringBridge::LoweringBridge( 904 mlir::MLIRContext &context, 905 const Fortran::common::IntrinsicTypeDefaultKinds &defaultKinds, 906 const Fortran::evaluate::IntrinsicProcTable &intrinsics, 907 const Fortran::parser::AllCookedSources &cooked, llvm::StringRef triple, 908 fir::KindMapping &kindMap) 909 : defaultKinds{defaultKinds}, intrinsics{intrinsics}, cooked{&cooked}, 910 context{context}, kindMap{kindMap} { 911 // Register the diagnostic handler. 912 context.getDiagEngine().registerHandler([](mlir::Diagnostic &diag) { 913 llvm::raw_ostream &os = llvm::errs(); 914 switch (diag.getSeverity()) { 915 case mlir::DiagnosticSeverity::Error: 916 os << "error: "; 917 break; 918 case mlir::DiagnosticSeverity::Remark: 919 os << "info: "; 920 break; 921 case mlir::DiagnosticSeverity::Warning: 922 os << "warning: "; 923 break; 924 default: 925 break; 926 } 927 if (!diag.getLocation().isa<UnknownLoc>()) 928 os << diag.getLocation() << ": "; 929 os << diag << '\n'; 930 os.flush(); 931 return mlir::success(); 932 }); 933 934 // Create the module and attach the attributes. 935 module = std::make_unique<mlir::ModuleOp>( 936 mlir::ModuleOp::create(mlir::UnknownLoc::get(&context))); 937 assert(module.get() && "module was not created"); 938 fir::setTargetTriple(*module.get(), triple); 939 fir::setKindMapping(*module.get(), kindMap); 940 } 941