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