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