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