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