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