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