1 //===--- FrontendActions.cpp ----------------------------------------------===// 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/Frontend/FrontendActions.h" 14 #include "flang/Common/default-kinds.h" 15 #include "flang/Frontend/CompilerInstance.h" 16 #include "flang/Frontend/FrontendOptions.h" 17 #include "flang/Frontend/PreprocessorOptions.h" 18 #include "flang/Lower/Bridge.h" 19 #include "flang/Lower/PFTBuilder.h" 20 #include "flang/Lower/Support/Verifier.h" 21 #include "flang/Optimizer/Support/FIRContext.h" 22 #include "flang/Optimizer/Support/InitFIR.h" 23 #include "flang/Optimizer/Support/KindMapping.h" 24 #include "flang/Optimizer/Support/Utils.h" 25 #include "flang/Parser/dump-parse-tree.h" 26 #include "flang/Parser/parsing.h" 27 #include "flang/Parser/provenance.h" 28 #include "flang/Parser/source.h" 29 #include "flang/Parser/unparse.h" 30 #include "flang/Semantics/runtime-type-info.h" 31 #include "flang/Semantics/semantics.h" 32 #include "flang/Semantics/unparse-with-symbols.h" 33 34 #include "mlir/IR/Dialect.h" 35 #include "mlir/Pass/PassManager.h" 36 #include "mlir/Target/LLVMIR/ModuleTranslation.h" 37 #include "clang/Basic/Diagnostic.h" 38 #include "clang/Basic/DiagnosticFrontend.h" 39 #include "llvm/ADT/StringRef.h" 40 #include "llvm/Analysis/TargetLibraryInfo.h" 41 #include "llvm/Analysis/TargetTransformInfo.h" 42 #include "llvm/Bitcode/BitcodeWriterPass.h" 43 #include "llvm/IR/LegacyPassManager.h" 44 #include "llvm/IRReader/IRReader.h" 45 #include "llvm/MC/TargetRegistry.h" 46 #include "llvm/Passes/PassBuilder.h" 47 #include "llvm/Support/ErrorHandling.h" 48 #include "llvm/Support/SourceMgr.h" 49 #include "llvm/Target/TargetMachine.h" 50 #include <memory> 51 52 using namespace Fortran::frontend; 53 54 //===----------------------------------------------------------------------===// 55 // Custom BeginSourceFileAction 56 //===----------------------------------------------------------------------===// 57 58 bool PrescanAction::beginSourceFileAction() { return runPrescan(); } 59 60 bool PrescanAndParseAction::beginSourceFileAction() { 61 return runPrescan() && runParse(); 62 } 63 64 bool PrescanAndSemaAction::beginSourceFileAction() { 65 return runPrescan() && runParse() && runSemanticChecks() && 66 generateRtTypeTables(); 67 } 68 69 bool PrescanAndSemaDebugAction::beginSourceFileAction() { 70 // This is a "debug" action for development purposes. To facilitate this, the 71 // semantic checks are made to succeed unconditionally to prevent this action 72 // from exiting early (i.e. in the presence of semantic errors). We should 73 // never do this in actions intended for end-users or otherwise regular 74 // compiler workflows! 75 return runPrescan() && runParse() && (runSemanticChecks() || true) && 76 (generateRtTypeTables() || true); 77 } 78 79 bool CodeGenAction::beginSourceFileAction() { 80 llvmCtx = std::make_unique<llvm::LLVMContext>(); 81 82 // If the input is an LLVM file, just parse it and return. 83 if (this->getCurrentInput().getKind().getLanguage() == Language::LLVM_IR) { 84 llvm::SMDiagnostic err; 85 llvmModule = llvm::parseIRFile(getCurrentInput().getFile(), err, *llvmCtx); 86 87 return (nullptr != llvmModule); 88 } 89 90 // Otherwise, generate an MLIR module from the input Fortran source 91 assert(getCurrentInput().getKind().getLanguage() == Language::Fortran && 92 "Invalid input type - expecting a Fortran file"); 93 bool res = runPrescan() && runParse() && runSemanticChecks(); 94 if (!res) 95 return res; 96 97 CompilerInstance &ci = this->getInstance(); 98 99 // Load the MLIR dialects required by Flang 100 mlir::DialectRegistry registry; 101 mlirCtx = std::make_unique<mlir::MLIRContext>(registry); 102 fir::support::registerNonCodegenDialects(registry); 103 fir::support::loadNonCodegenDialects(*mlirCtx); 104 105 // Create a LoweringBridge 106 const common::IntrinsicTypeDefaultKinds &defKinds = 107 ci.getInvocation().getSemanticsContext().defaultKinds(); 108 fir::KindMapping kindMap(mlirCtx.get(), 109 llvm::ArrayRef<fir::KindTy>{fir::fromDefaultKinds(defKinds)}); 110 lower::LoweringBridge lb = Fortran::lower::LoweringBridge::create( 111 *mlirCtx, defKinds, ci.getInvocation().getSemanticsContext().intrinsics(), 112 ci.getParsing().allCooked(), ci.getInvocation().getTargetOpts().triple, 113 kindMap); 114 115 // Create a parse tree and lower it to FIR 116 Fortran::parser::Program &parseTree{*ci.getParsing().parseTree()}; 117 lb.lower(parseTree, ci.getInvocation().getSemanticsContext()); 118 mlirModule = std::make_unique<mlir::ModuleOp>(lb.getModule()); 119 120 // run the default passes. 121 mlir::PassManager pm(mlirCtx.get(), mlir::OpPassManager::Nesting::Implicit); 122 pm.enableVerifier(/*verifyPasses=*/true); 123 pm.addPass(std::make_unique<Fortran::lower::VerifierPass>()); 124 125 if (mlir::failed(pm.run(*mlirModule))) { 126 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 127 clang::DiagnosticsEngine::Error, 128 "verification of lowering to FIR failed"); 129 ci.getDiagnostics().Report(diagID); 130 return false; 131 } 132 133 return true; 134 } 135 136 //===----------------------------------------------------------------------===// 137 // Custom ExecuteAction 138 //===----------------------------------------------------------------------===// 139 void InputOutputTestAction::executeAction() { 140 CompilerInstance &ci = getInstance(); 141 142 // Create a stream for errors 143 std::string buf; 144 llvm::raw_string_ostream errorStream{buf}; 145 146 // Read the input file 147 Fortran::parser::AllSources &allSources{ci.getAllSources()}; 148 std::string path{getCurrentFileOrBufferName()}; 149 const Fortran::parser::SourceFile *sf; 150 if (path == "-") 151 sf = allSources.ReadStandardInput(errorStream); 152 else 153 sf = allSources.Open(path, errorStream, std::optional<std::string>{"."s}); 154 llvm::ArrayRef<char> fileContent = sf->content(); 155 156 // Output file descriptor to receive the contents of the input file. 157 std::unique_ptr<llvm::raw_ostream> os; 158 159 // Copy the contents from the input file to the output file 160 if (!ci.isOutputStreamNull()) { 161 // An output stream (outputStream_) was set earlier 162 ci.writeOutputStream(fileContent.data()); 163 } else { 164 // No pre-set output stream - create an output file 165 os = ci.createDefaultOutputFile( 166 /*binary=*/true, getCurrentFileOrBufferName(), "txt"); 167 if (!os) 168 return; 169 (*os) << fileContent.data(); 170 } 171 } 172 173 void PrintPreprocessedAction::executeAction() { 174 std::string buf; 175 llvm::raw_string_ostream outForPP{buf}; 176 177 // Format or dump the prescanner's output 178 CompilerInstance &ci = this->getInstance(); 179 if (ci.getInvocation().getPreprocessorOpts().noReformat) { 180 ci.getParsing().DumpCookedChars(outForPP); 181 } else { 182 ci.getParsing().EmitPreprocessedSource( 183 outForPP, !ci.getInvocation().getPreprocessorOpts().noLineDirectives); 184 } 185 186 // Print getDiagnostics from the prescanner 187 ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources()); 188 189 // If a pre-defined output stream exists, dump the preprocessed content there 190 if (!ci.isOutputStreamNull()) { 191 // Send the output to the pre-defined output buffer. 192 ci.writeOutputStream(outForPP.str()); 193 return; 194 } 195 196 // Create a file and save the preprocessed output there 197 std::unique_ptr<llvm::raw_pwrite_stream> os{ci.createDefaultOutputFile( 198 /*Binary=*/true, /*InFile=*/getCurrentFileOrBufferName())}; 199 if (!os) { 200 return; 201 } 202 203 (*os) << outForPP.str(); 204 } 205 206 void DebugDumpProvenanceAction::executeAction() { 207 this->getInstance().getParsing().DumpProvenance(llvm::outs()); 208 } 209 210 void ParseSyntaxOnlyAction::executeAction() {} 211 212 void DebugUnparseNoSemaAction::executeAction() { 213 auto &invoc = this->getInstance().getInvocation(); 214 auto &parseTree{getInstance().getParsing().parseTree()}; 215 216 // TODO: Options should come from CompilerInvocation 217 Unparse(llvm::outs(), *parseTree, 218 /*encoding=*/Fortran::parser::Encoding::UTF_8, 219 /*capitalizeKeywords=*/true, /*backslashEscapes=*/false, 220 /*preStatement=*/nullptr, 221 invoc.getUseAnalyzedObjectsForUnparse() ? &invoc.getAsFortran() 222 : nullptr); 223 } 224 225 void DebugUnparseAction::executeAction() { 226 auto &invoc = this->getInstance().getInvocation(); 227 auto &parseTree{getInstance().getParsing().parseTree()}; 228 229 CompilerInstance &ci = this->getInstance(); 230 auto os{ci.createDefaultOutputFile( 231 /*Binary=*/false, /*InFile=*/getCurrentFileOrBufferName())}; 232 233 // TODO: Options should come from CompilerInvocation 234 Unparse(*os, *parseTree, 235 /*encoding=*/Fortran::parser::Encoding::UTF_8, 236 /*capitalizeKeywords=*/true, /*backslashEscapes=*/false, 237 /*preStatement=*/nullptr, 238 invoc.getUseAnalyzedObjectsForUnparse() ? &invoc.getAsFortran() 239 : nullptr); 240 241 // Report fatal semantic errors 242 reportFatalSemanticErrors(); 243 } 244 245 void DebugUnparseWithSymbolsAction::executeAction() { 246 auto &parseTree{*getInstance().getParsing().parseTree()}; 247 248 Fortran::semantics::UnparseWithSymbols( 249 llvm::outs(), parseTree, /*encoding=*/Fortran::parser::Encoding::UTF_8); 250 251 // Report fatal semantic errors 252 reportFatalSemanticErrors(); 253 } 254 255 void DebugDumpSymbolsAction::executeAction() { 256 CompilerInstance &ci = this->getInstance(); 257 258 if (!ci.getRtTyTables().schemata) { 259 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 260 clang::DiagnosticsEngine::Error, 261 "could not find module file for __fortran_type_info"); 262 ci.getDiagnostics().Report(diagID); 263 llvm::errs() << "\n"; 264 return; 265 } 266 267 // Dump symbols 268 ci.getSemantics().DumpSymbols(llvm::outs()); 269 } 270 271 void DebugDumpAllAction::executeAction() { 272 CompilerInstance &ci = this->getInstance(); 273 274 // Dump parse tree 275 auto &parseTree{getInstance().getParsing().parseTree()}; 276 llvm::outs() << "========================"; 277 llvm::outs() << " Flang: parse tree dump "; 278 llvm::outs() << "========================\n"; 279 Fortran::parser::DumpTree(llvm::outs(), parseTree, 280 &ci.getInvocation().getAsFortran()); 281 282 if (!ci.getRtTyTables().schemata) { 283 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 284 clang::DiagnosticsEngine::Error, 285 "could not find module file for __fortran_type_info"); 286 ci.getDiagnostics().Report(diagID); 287 llvm::errs() << "\n"; 288 return; 289 } 290 291 // Dump symbols 292 llvm::outs() << "====================="; 293 llvm::outs() << " Flang: symbols dump "; 294 llvm::outs() << "=====================\n"; 295 ci.getSemantics().DumpSymbols(llvm::outs()); 296 } 297 298 void DebugDumpParseTreeNoSemaAction::executeAction() { 299 auto &parseTree{getInstance().getParsing().parseTree()}; 300 301 // Dump parse tree 302 Fortran::parser::DumpTree( 303 llvm::outs(), parseTree, 304 &this->getInstance().getInvocation().getAsFortran()); 305 } 306 307 void DebugDumpParseTreeAction::executeAction() { 308 auto &parseTree{getInstance().getParsing().parseTree()}; 309 310 // Dump parse tree 311 Fortran::parser::DumpTree( 312 llvm::outs(), parseTree, 313 &this->getInstance().getInvocation().getAsFortran()); 314 315 // Report fatal semantic errors 316 reportFatalSemanticErrors(); 317 } 318 319 void DebugMeasureParseTreeAction::executeAction() { 320 CompilerInstance &ci = this->getInstance(); 321 322 // Parse. In case of failure, report and return. 323 ci.getParsing().Parse(llvm::outs()); 324 325 if (!ci.getParsing().messages().empty() && 326 (ci.getInvocation().getWarnAsErr() || 327 ci.getParsing().messages().AnyFatalError())) { 328 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 329 clang::DiagnosticsEngine::Error, "Could not parse %0"); 330 ci.getDiagnostics().Report(diagID) << getCurrentFileOrBufferName(); 331 332 ci.getParsing().messages().Emit(llvm::errs(), 333 this->getInstance().getAllCookedSources()); 334 return; 335 } 336 337 // Report the getDiagnostics from parsing 338 ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources()); 339 340 auto &parseTree{*ci.getParsing().parseTree()}; 341 342 // Measure the parse tree 343 MeasurementVisitor visitor; 344 Fortran::parser::Walk(parseTree, visitor); 345 llvm::outs() << "Parse tree comprises " << visitor.objects 346 << " objects and occupies " << visitor.bytes 347 << " total bytes.\n"; 348 } 349 350 void DebugPreFIRTreeAction::executeAction() { 351 CompilerInstance &ci = this->getInstance(); 352 // Report and exit if fatal semantic errors are present 353 if (reportFatalSemanticErrors()) { 354 return; 355 } 356 357 auto &parseTree{*ci.getParsing().parseTree()}; 358 359 // Dump pre-FIR tree 360 if (auto ast{Fortran::lower::createPFT( 361 parseTree, ci.getInvocation().getSemanticsContext())}) { 362 Fortran::lower::dumpPFT(llvm::outs(), *ast); 363 } else { 364 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 365 clang::DiagnosticsEngine::Error, "Pre FIR Tree is NULL."); 366 ci.getDiagnostics().Report(diagID); 367 } 368 } 369 370 void DebugDumpParsingLogAction::executeAction() { 371 CompilerInstance &ci = this->getInstance(); 372 373 ci.getParsing().Parse(llvm::errs()); 374 ci.getParsing().DumpParsingLog(llvm::outs()); 375 } 376 377 void GetDefinitionAction::executeAction() { 378 CompilerInstance &ci = this->getInstance(); 379 380 // Report and exit if fatal semantic errors are present 381 if (reportFatalSemanticErrors()) { 382 return; 383 } 384 385 parser::AllCookedSources &cs = ci.getAllCookedSources(); 386 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 387 clang::DiagnosticsEngine::Error, "Symbol not found"); 388 389 auto gdv = ci.getInvocation().getFrontendOpts().getDefVals; 390 auto charBlock{cs.GetCharBlockFromLineAndColumns( 391 gdv.line, gdv.startColumn, gdv.endColumn)}; 392 if (!charBlock) { 393 ci.getDiagnostics().Report(diagID); 394 return; 395 } 396 397 llvm::outs() << "String range: >" << charBlock->ToString() << "<\n"; 398 399 auto *symbol{ci.getInvocation() 400 .getSemanticsContext() 401 .FindScope(*charBlock) 402 .FindSymbol(*charBlock)}; 403 if (!symbol) { 404 ci.getDiagnostics().Report(diagID); 405 return; 406 } 407 408 llvm::outs() << "Found symbol name: " << symbol->name().ToString() << "\n"; 409 410 auto sourceInfo{cs.GetSourcePositionRange(symbol->name())}; 411 if (!sourceInfo) { 412 llvm_unreachable( 413 "Failed to obtain SourcePosition." 414 "TODO: Please, write a test and replace this with a diagnostic!"); 415 return; 416 } 417 418 llvm::outs() << "Found symbol name: " << symbol->name().ToString() << "\n"; 419 llvm::outs() << symbol->name().ToString() << ": " 420 << sourceInfo->first.file.path() << ", " 421 << sourceInfo->first.line << ", " << sourceInfo->first.column 422 << "-" << sourceInfo->second.column << "\n"; 423 } 424 425 void GetSymbolsSourcesAction::executeAction() { 426 CompilerInstance &ci = this->getInstance(); 427 428 // Report and exit if fatal semantic errors are present 429 if (reportFatalSemanticErrors()) { 430 return; 431 } 432 433 ci.getSemantics().DumpSymbolsSources(llvm::outs()); 434 } 435 436 //===----------------------------------------------------------------------===// 437 // CodeGenActions 438 //===----------------------------------------------------------------------===// 439 440 CodeGenAction::~CodeGenAction() = default; 441 442 #include "flang/Tools/CLOptions.inc" 443 444 // Lower the previously generated MLIR module into an LLVM IR module 445 void CodeGenAction::generateLLVMIR() { 446 assert(mlirModule && "The MLIR module has not been generated yet."); 447 448 CompilerInstance &ci = this->getInstance(); 449 450 fir::support::loadDialects(*mlirCtx); 451 fir::support::registerLLVMTranslation(*mlirCtx); 452 453 // Set-up the MLIR pass manager 454 mlir::PassManager pm(mlirCtx.get(), mlir::OpPassManager::Nesting::Implicit); 455 456 pm.addPass(std::make_unique<Fortran::lower::VerifierPass>()); 457 pm.enableVerifier(/*verifyPasses=*/true); 458 459 // Create the pass pipeline 460 fir::createMLIRToLLVMPassPipeline(pm); 461 mlir::applyPassManagerCLOptions(pm); 462 463 // run the pass manager 464 if (!mlir::succeeded(pm.run(*mlirModule))) { 465 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 466 clang::DiagnosticsEngine::Error, "Lowering to LLVM IR failed"); 467 ci.getDiagnostics().Report(diagID); 468 } 469 470 // Translate to LLVM IR 471 llvm::Optional<llvm::StringRef> moduleName = mlirModule->getName(); 472 llvmModule = mlir::translateModuleToLLVMIR( 473 *mlirModule, *llvmCtx, moduleName ? *moduleName : "FIRModule"); 474 475 if (!llvmModule) { 476 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 477 clang::DiagnosticsEngine::Error, "failed to create the LLVM module"); 478 ci.getDiagnostics().Report(diagID); 479 return; 480 } 481 } 482 483 void CodeGenAction::setUpTargetMachine() { 484 CompilerInstance &ci = this->getInstance(); 485 486 // Set the triple based on the CompilerInvocation set-up 487 const std::string &theTriple = ci.getInvocation().getTargetOpts().triple; 488 if (llvmModule->getTargetTriple() != theTriple) { 489 ci.getDiagnostics().Report(clang::diag::warn_fe_override_module) 490 << theTriple; 491 llvmModule->setTargetTriple(theTriple); 492 } 493 494 // Create `Target` 495 std::string error; 496 const llvm::Target *theTarget = 497 llvm::TargetRegistry::lookupTarget(theTriple, error); 498 assert(theTarget && "Failed to create Target"); 499 500 // Create `TargetMachine` 501 tm.reset(theTarget->createTargetMachine(theTriple, /*CPU=*/"", 502 /*Features=*/"", 503 llvm::TargetOptions(), llvm::None)); 504 assert(tm && "Failed to create TargetMachine"); 505 llvmModule->setDataLayout(tm->createDataLayout()); 506 } 507 508 static std::unique_ptr<llvm::raw_pwrite_stream> 509 getOutputStream(CompilerInstance &ci, llvm::StringRef inFile, 510 BackendActionTy action) { 511 switch (action) { 512 case BackendActionTy::Backend_EmitAssembly: 513 return ci.createDefaultOutputFile( 514 /*Binary=*/false, inFile, /*extension=*/"s"); 515 case BackendActionTy::Backend_EmitLL: 516 return ci.createDefaultOutputFile( 517 /*Binary=*/false, inFile, /*extension=*/"ll"); 518 case BackendActionTy::Backend_EmitMLIR: 519 return ci.createDefaultOutputFile( 520 /*Binary=*/false, inFile, /*extension=*/"mlir"); 521 case BackendActionTy::Backend_EmitBC: 522 return ci.createDefaultOutputFile( 523 /*Binary=*/true, inFile, /*extension=*/"bc"); 524 case BackendActionTy::Backend_EmitObj: 525 return ci.createDefaultOutputFile( 526 /*Binary=*/true, inFile, /*extension=*/"o"); 527 } 528 529 llvm_unreachable("Invalid action!"); 530 } 531 532 /// Generate target-specific machine-code or assembly file from the input LLVM 533 /// module. 534 /// 535 /// \param [in] diags Diagnostics engine for reporting errors 536 /// \param [in] tm Target machine to aid the code-gen pipeline set-up 537 /// \param [in] act Backend act to run (assembly vs machine-code generation) 538 /// \param [in] llvmModule LLVM module to lower to assembly/machine-code 539 /// \param [out] os Output stream to emit the generated code to 540 static void generateMachineCodeOrAssemblyImpl(clang::DiagnosticsEngine &diags, 541 llvm::TargetMachine &tm, 542 BackendActionTy act, 543 llvm::Module &llvmModule, 544 llvm::raw_pwrite_stream &os) { 545 assert(((act == BackendActionTy::Backend_EmitObj) || 546 (act == BackendActionTy::Backend_EmitAssembly)) && 547 "Unsupported action"); 548 549 // Set-up the pass manager, i.e create an LLVM code-gen pass pipeline. 550 // Currently only the legacy pass manager is supported. 551 // TODO: Switch to the new PM once it's available in the backend. 552 llvm::legacy::PassManager codeGenPasses; 553 codeGenPasses.add( 554 createTargetTransformInfoWrapperPass(tm.getTargetIRAnalysis())); 555 556 llvm::Triple triple(llvmModule.getTargetTriple()); 557 std::unique_ptr<llvm::TargetLibraryInfoImpl> tlii = 558 std::make_unique<llvm::TargetLibraryInfoImpl>(triple); 559 assert(tlii && "Failed to create TargetLibraryInfo"); 560 codeGenPasses.add(new llvm::TargetLibraryInfoWrapperPass(*tlii)); 561 562 llvm::CodeGenFileType cgft = (act == BackendActionTy::Backend_EmitAssembly) 563 ? llvm::CodeGenFileType::CGFT_AssemblyFile 564 : llvm::CodeGenFileType::CGFT_ObjectFile; 565 if (tm.addPassesToEmitFile(codeGenPasses, os, nullptr, cgft)) { 566 unsigned diagID = 567 diags.getCustomDiagID(clang::DiagnosticsEngine::Error, 568 "emission of this file type is not supported"); 569 diags.Report(diagID); 570 return; 571 } 572 573 // Run the passes 574 codeGenPasses.run(llvmModule); 575 } 576 577 /// Generate LLVM byte code file from the input LLVM module. 578 /// 579 /// \param [in] tm Target machine to aid the code-gen pipeline set-up 580 /// \param [in] llvmModule LLVM module to lower to assembly/machine-code 581 /// \param [out] os Output stream to emit the generated code to 582 static void generateLLVMBCImpl(llvm::TargetMachine &tm, 583 llvm::Module &llvmModule, 584 llvm::raw_pwrite_stream &os) { 585 // Set-up the pass manager 586 llvm::ModulePassManager mpm; 587 llvm::ModuleAnalysisManager mam; 588 llvm::PassBuilder pb(&tm); 589 pb.registerModuleAnalyses(mam); 590 mpm.addPass(llvm::BitcodeWriterPass(os)); 591 592 // run the passes 593 mpm.run(llvmModule, mam); 594 } 595 596 void CodeGenAction::executeAction() { 597 CompilerInstance &ci = this->getInstance(); 598 599 // If the output stream is a file, generate it and define the corresponding 600 // output stream. If a pre-defined output stream is available, we will use 601 // that instead. 602 // 603 // NOTE: `os` is a smart pointer that will be destroyed at the end of this 604 // method. However, it won't be written to until `codeGenPasses` is 605 // destroyed. By defining `os` before `codeGenPasses`, we make sure that the 606 // output stream won't be destroyed before it is written to. This only 607 // applies when an output file is used (i.e. there is no pre-defined output 608 // stream). 609 // TODO: Revisit once the new PM is ready (i.e. when `codeGenPasses` is 610 // updated to use it). 611 std::unique_ptr<llvm::raw_pwrite_stream> os; 612 if (ci.isOutputStreamNull()) { 613 os = getOutputStream(ci, getCurrentFileOrBufferName(), action); 614 615 if (!os) { 616 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 617 clang::DiagnosticsEngine::Error, "failed to create the output file"); 618 ci.getDiagnostics().Report(diagID); 619 return; 620 } 621 } 622 623 if (action == BackendActionTy::Backend_EmitMLIR) { 624 mlirModule->print(ci.isOutputStreamNull() ? *os : ci.getOutputStream()); 625 return; 626 } 627 628 // generate an LLVM module if it's not already present (it will already be 629 // present if the input file is an LLVM IR/BC file). 630 if (!llvmModule) 631 generateLLVMIR(); 632 633 if (action == BackendActionTy::Backend_EmitLL) { 634 llvmModule->print(ci.isOutputStreamNull() ? *os : ci.getOutputStream(), 635 /*AssemblyAnnotationWriter=*/nullptr); 636 return; 637 } 638 639 setUpTargetMachine(); 640 if (action == BackendActionTy::Backend_EmitBC) { 641 generateLLVMBCImpl(*tm, *llvmModule, *os); 642 return; 643 } 644 645 if (action == BackendActionTy::Backend_EmitAssembly || 646 action == BackendActionTy::Backend_EmitObj) { 647 generateMachineCodeOrAssemblyImpl( 648 ci.getDiagnostics(), *tm, action, *llvmModule, 649 ci.isOutputStreamNull() ? *os : ci.getOutputStream()); 650 return; 651 } 652 } 653 654 void InitOnlyAction::executeAction() { 655 CompilerInstance &ci = this->getInstance(); 656 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 657 clang::DiagnosticsEngine::Warning, 658 "Use `-init-only` for testing purposes only"); 659 ci.getDiagnostics().Report(diagID); 660 } 661 662 void PluginParseTreeAction::executeAction() {} 663 664 void DebugDumpPFTAction::executeAction() { 665 CompilerInstance &ci = this->getInstance(); 666 667 if (auto ast = Fortran::lower::createPFT(*ci.getParsing().parseTree(), 668 ci.getSemantics().context())) { 669 Fortran::lower::dumpPFT(llvm::outs(), *ast); 670 return; 671 } 672 673 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 674 clang::DiagnosticsEngine::Error, "Pre FIR Tree is NULL."); 675 ci.getDiagnostics().Report(diagID); 676 } 677 678 Fortran::parser::Parsing &PluginParseTreeAction::getParsing() { 679 return getInstance().getParsing(); 680 } 681 682 std::unique_ptr<llvm::raw_pwrite_stream> 683 PluginParseTreeAction::createOutputFile(llvm::StringRef extension = "") { 684 685 std::unique_ptr<llvm::raw_pwrite_stream> os{ 686 getInstance().createDefaultOutputFile( 687 /*Binary=*/false, /*InFile=*/getCurrentFileOrBufferName(), 688 extension)}; 689 return os; 690 } 691