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/CompilerInvocation.h" 17 #include "flang/Frontend/FrontendOptions.h" 18 #include "flang/Frontend/PreprocessorOptions.h" 19 #include "flang/Lower/Bridge.h" 20 #include "flang/Lower/PFTBuilder.h" 21 #include "flang/Lower/Support/Verifier.h" 22 #include "flang/Optimizer/Dialect/Support/FIRContext.h" 23 #include "flang/Optimizer/Dialect/Support/KindMapping.h" 24 #include "flang/Optimizer/Passes/Pipelines.h" 25 #include "flang/Optimizer/Support/DataLayout.h" 26 #include "flang/Optimizer/Support/InitFIR.h" 27 #include "flang/Optimizer/Support/Utils.h" 28 #include "flang/Optimizer/Transforms/Passes.h" 29 #include "flang/Parser/dump-parse-tree.h" 30 #include "flang/Parser/parsing.h" 31 #include "flang/Parser/provenance.h" 32 #include "flang/Parser/source.h" 33 #include "flang/Parser/unparse.h" 34 #include "flang/Semantics/runtime-type-info.h" 35 #include "flang/Semantics/semantics.h" 36 #include "flang/Semantics/unparse-with-symbols.h" 37 #include "flang/Tools/CrossToolHelpers.h" 38 39 #include "mlir/IR/Dialect.h" 40 #include "mlir/Parser/Parser.h" 41 #include "mlir/Pass/PassManager.h" 42 #include "mlir/Support/LLVM.h" 43 #include "mlir/Target/LLVMIR/Import.h" 44 #include "mlir/Target/LLVMIR/ModuleTranslation.h" 45 #include "clang/Basic/Diagnostic.h" 46 #include "clang/Basic/DiagnosticFrontend.h" 47 #include "clang/Basic/FileManager.h" 48 #include "clang/Basic/FileSystemOptions.h" 49 #include "clang/Driver/DriverDiagnostic.h" 50 #include "llvm/ADT/SmallString.h" 51 #include "llvm/ADT/StringRef.h" 52 #include "llvm/Analysis/TargetLibraryInfo.h" 53 #include "llvm/Analysis/TargetTransformInfo.h" 54 #include "llvm/Bitcode/BitcodeWriterPass.h" 55 #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" 56 #include "llvm/IR/LLVMRemarkStreamer.h" 57 #include "llvm/IR/LegacyPassManager.h" 58 #include "llvm/IR/Verifier.h" 59 #include "llvm/IRPrinter/IRPrintingPasses.h" 60 #include "llvm/IRReader/IRReader.h" 61 #include "llvm/Linker/Linker.h" 62 #include "llvm/Object/OffloadBinary.h" 63 #include "llvm/Passes/PassBuilder.h" 64 #include "llvm/Passes/PassPlugin.h" 65 #include "llvm/Passes/StandardInstrumentations.h" 66 #include "llvm/Support/AMDGPUAddrSpace.h" 67 #include "llvm/Support/Error.h" 68 #include "llvm/Support/ErrorHandling.h" 69 #include "llvm/Support/FileSystem.h" 70 #include "llvm/Support/Path.h" 71 #include "llvm/Support/SourceMgr.h" 72 #include "llvm/Support/ToolOutputFile.h" 73 #include "llvm/Target/TargetMachine.h" 74 #include "llvm/TargetParser/RISCVISAInfo.h" 75 #include "llvm/TargetParser/RISCVTargetParser.h" 76 #include "llvm/Transforms/IPO/Internalize.h" 77 #include "llvm/Transforms/Utils/ModuleUtils.h" 78 #include <memory> 79 #include <system_error> 80 81 namespace llvm { 82 extern cl::opt<bool> PrintPipelinePasses; 83 } // namespace llvm 84 85 using namespace Fortran::frontend; 86 87 constexpr llvm::StringLiteral timingIdParse = "Parse"; 88 constexpr llvm::StringLiteral timingIdMLIRGen = "MLIR generation"; 89 constexpr llvm::StringLiteral timingIdMLIRPasses = 90 "MLIR translation/optimization"; 91 constexpr llvm::StringLiteral timingIdLLVMIRGen = "LLVM IR generation"; 92 constexpr llvm::StringLiteral timingIdLLVMIRPasses = "LLVM IR optimizations"; 93 constexpr llvm::StringLiteral timingIdBackend = 94 "Assembly/Object code generation"; 95 96 // Declare plugin extension function declarations. 97 #define HANDLE_EXTENSION(Ext) \ 98 llvm::PassPluginLibraryInfo get##Ext##PluginInfo(); 99 #include "llvm/Support/Extension.def" 100 101 /// Save the given \c mlirModule to a temporary .mlir file, in a location 102 /// decided by the -save-temps flag. No files are produced if the flag is not 103 /// specified. 104 static bool saveMLIRTempFile(const CompilerInvocation &ci, 105 mlir::ModuleOp mlirModule, 106 llvm::StringRef inputFile, 107 llvm::StringRef outputTag) { 108 if (!ci.getCodeGenOpts().SaveTempsDir.has_value()) 109 return true; 110 111 const llvm::StringRef compilerOutFile = ci.getFrontendOpts().outputFile; 112 const llvm::StringRef saveTempsDir = ci.getCodeGenOpts().SaveTempsDir.value(); 113 auto dir = llvm::StringSwitch<llvm::StringRef>(saveTempsDir) 114 .Case("cwd", "") 115 .Case("obj", llvm::sys::path::parent_path(compilerOutFile)) 116 .Default(saveTempsDir); 117 118 // Build path from the compiler output file name, triple, cpu and OpenMP 119 // information 120 llvm::SmallString<256> path(dir); 121 llvm::sys::path::append(path, llvm::sys::path::stem(inputFile) + "-" + 122 outputTag + ".mlir"); 123 124 std::error_code ec; 125 llvm::ToolOutputFile out(path, ec, llvm::sys::fs::OF_Text); 126 if (ec) 127 return false; 128 129 mlirModule->print(out.os()); 130 out.os().close(); 131 out.keep(); 132 133 return true; 134 } 135 136 //===----------------------------------------------------------------------===// 137 // Custom BeginSourceFileAction 138 //===----------------------------------------------------------------------===// 139 140 bool PrescanAction::beginSourceFileAction() { return runPrescan(); } 141 142 bool PrescanAndParseAction::beginSourceFileAction() { 143 return runPrescan() && runParse(/*emitMessages=*/true); 144 } 145 146 bool PrescanAndSemaAction::beginSourceFileAction() { 147 return runPrescan() && runParse(/*emitMessages=*/false) && 148 runSemanticChecks() && generateRtTypeTables(); 149 } 150 151 bool PrescanAndSemaDebugAction::beginSourceFileAction() { 152 // This is a "debug" action for development purposes. To facilitate this, the 153 // semantic checks are made to succeed unconditionally to prevent this action 154 // from exiting early (i.e. in the presence of semantic errors). We should 155 // never do this in actions intended for end-users or otherwise regular 156 // compiler workflows! 157 return runPrescan() && runParse(/*emitMessages=*/false) && 158 (runSemanticChecks() || true) && (generateRtTypeTables() || true); 159 } 160 161 static void addDependentLibs(mlir::ModuleOp mlirModule, CompilerInstance &ci) { 162 const std::vector<std::string> &libs = 163 ci.getInvocation().getCodeGenOpts().DependentLibs; 164 if (libs.empty()) { 165 return; 166 } 167 // dependent-lib is currently only supported on Windows, so the list should be 168 // empty on non-Windows platforms 169 assert( 170 llvm::Triple(ci.getInvocation().getTargetOpts().triple).isOSWindows() && 171 "--dependent-lib is only supported on Windows"); 172 // Add linker options specified by --dependent-lib 173 auto builder = mlir::OpBuilder(mlirModule.getRegion()); 174 for (const std::string &lib : libs) { 175 builder.create<mlir::LLVM::LinkerOptionsOp>( 176 mlirModule.getLoc(), builder.getStrArrayAttr({"/DEFAULTLIB:" + lib})); 177 } 178 } 179 180 // Add to MLIR code target specific items which are dependent on target 181 // configuration specified by the user. 182 // Clang equivalent function: AMDGPUTargetCodeGenInfo::emitTargetGlobals 183 static void addAMDGPUSpecificMLIRItems(mlir::ModuleOp mlirModule, 184 CompilerInstance &ci) { 185 const TargetOptions &targetOpts = ci.getInvocation().getTargetOpts(); 186 const llvm::Triple triple(targetOpts.triple); 187 const llvm::StringRef codeObjectVersionGlobalOpName = "__oclc_ABI_version"; 188 189 if (!triple.isAMDGPU()) { 190 return; 191 } 192 const CodeGenOptions &codeGenOpts = ci.getInvocation().getCodeGenOpts(); 193 if (codeGenOpts.CodeObjectVersion == llvm::CodeObjectVersionKind::COV_None) { 194 return; 195 } 196 197 mlir::IRRewriter builder(mlirModule.getContext()); 198 unsigned oclcABIVERsion = codeGenOpts.CodeObjectVersion; 199 auto int32Type = builder.getI32Type(); 200 201 std::optional<mlir::LLVM::GlobalOp> originalGV; 202 203 mlirModule.walk([&originalGV, codeObjectVersionGlobalOpName]( 204 mlir::LLVM::GlobalOp globalOp) { 205 if (globalOp.getName() == codeObjectVersionGlobalOpName) 206 originalGV = globalOp; 207 }); 208 if (originalGV.has_value()) { 209 mlir::LLVM::GlobalOp originalGVOp = originalGV.value(); 210 if (originalGVOp.getLinkage() != mlir::LLVM::Linkage::External) { 211 return; 212 } 213 // Update the variable if it is already present in MLIR but it was marked 214 // as external linkage variable 215 originalGVOp.setLinkage(mlir::LLVM::Linkage::WeakODR); 216 originalGVOp.setValueAttr( 217 builder.getIntegerAttr(int32Type, oclcABIVERsion)); 218 originalGVOp.setUnnamedAddr(mlir::LLVM::UnnamedAddr::Local); 219 originalGVOp.setAddrSpace(llvm::AMDGPUAS::CONSTANT_ADDRESS); 220 originalGVOp.setVisibility_(mlir::LLVM::Visibility::Hidden); 221 return; 222 } 223 224 mlir::LLVM::GlobalOp covInfo = builder.create<mlir::LLVM::GlobalOp>( 225 /* Location */ mlirModule.getLoc(), /* Type */ int32Type, 226 /* IsConstant */ true, /* Linkage */ mlir::LLVM::Linkage::WeakODR, 227 /* Name */ codeObjectVersionGlobalOpName, 228 /* Value */ builder.getIntegerAttr(int32Type, oclcABIVERsion)); 229 covInfo.setUnnamedAddr(mlir::LLVM::UnnamedAddr::Local); 230 covInfo.setAddrSpace(llvm::AMDGPUAS::CONSTANT_ADDRESS); 231 covInfo.setVisibility_(mlir::LLVM::Visibility::Hidden); 232 builder.setInsertionPointToStart(mlirModule.getBody()); 233 builder.insert(covInfo); 234 } 235 236 bool CodeGenAction::beginSourceFileAction() { 237 llvmCtx = std::make_unique<llvm::LLVMContext>(); 238 CompilerInstance &ci = this->getInstance(); 239 mlir::DefaultTimingManager &timingMgr = ci.getTimingManager(); 240 mlir::TimingScope &timingScopeRoot = ci.getTimingScopeRoot(); 241 242 // This will provide timing information even when the input is an LLVM IR or 243 // MLIR file. That is fine because those do have to be parsed, so the label 244 // is still accurate. 245 mlir::TimingScope timingScopeParse = timingScopeRoot.nest( 246 mlir::TimingIdentifier::get(timingIdParse, timingMgr)); 247 248 // If the input is an LLVM file, just parse it and return. 249 if (this->getCurrentInput().getKind().getLanguage() == Language::LLVM_IR) { 250 llvm::SMDiagnostic err; 251 llvmModule = llvm::parseIRFile(getCurrentInput().getFile(), err, *llvmCtx); 252 if (!llvmModule || llvm::verifyModule(*llvmModule, &llvm::errs())) { 253 err.print("flang", llvm::errs()); 254 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 255 clang::DiagnosticsEngine::Error, "Could not parse IR"); 256 ci.getDiagnostics().Report(diagID); 257 return false; 258 } 259 260 return true; 261 } 262 263 // Load the MLIR dialects required by Flang 264 mlir::DialectRegistry registry; 265 mlirCtx = std::make_unique<mlir::MLIRContext>(registry); 266 fir::support::registerNonCodegenDialects(registry); 267 fir::support::loadNonCodegenDialects(*mlirCtx); 268 fir::support::loadDialects(*mlirCtx); 269 fir::support::registerLLVMTranslation(*mlirCtx); 270 271 const llvm::TargetMachine &targetMachine = ci.getTargetMachine(); 272 273 // If the input is an MLIR file, just parse it and return. 274 if (this->getCurrentInput().getKind().getLanguage() == Language::MLIR) { 275 llvm::SourceMgr sourceMgr; 276 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> fileOrErr = 277 llvm::MemoryBuffer::getFileOrSTDIN(getCurrentInput().getFile()); 278 sourceMgr.AddNewSourceBuffer(std::move(*fileOrErr), llvm::SMLoc()); 279 mlir::OwningOpRef<mlir::ModuleOp> module = 280 mlir::parseSourceFile<mlir::ModuleOp>(sourceMgr, mlirCtx.get()); 281 282 if (!module || mlir::failed(module->verifyInvariants())) { 283 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 284 clang::DiagnosticsEngine::Error, "Could not parse FIR"); 285 ci.getDiagnostics().Report(diagID); 286 return false; 287 } 288 289 mlirModule = std::move(module); 290 const llvm::DataLayout &dl = targetMachine.createDataLayout(); 291 fir::support::setMLIRDataLayout(*mlirModule, dl); 292 return true; 293 } 294 295 // Otherwise, generate an MLIR module from the input Fortran source 296 if (getCurrentInput().getKind().getLanguage() != Language::Fortran) { 297 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 298 clang::DiagnosticsEngine::Error, 299 "Invalid input type - expecting a Fortran file"); 300 ci.getDiagnostics().Report(diagID); 301 return false; 302 } 303 bool res = runPrescan() && runParse(/*emitMessages=*/false) && 304 runSemanticChecks() && generateRtTypeTables(); 305 if (!res) 306 return res; 307 308 timingScopeParse.stop(); 309 mlir::TimingScope timingScopeMLIRGen = timingScopeRoot.nest( 310 mlir::TimingIdentifier::get(timingIdMLIRGen, timingMgr)); 311 312 // Create a LoweringBridge 313 const common::IntrinsicTypeDefaultKinds &defKinds = 314 ci.getSemanticsContext().defaultKinds(); 315 fir::KindMapping kindMap(mlirCtx.get(), llvm::ArrayRef<fir::KindTy>{ 316 fir::fromDefaultKinds(defKinds)}); 317 lower::LoweringBridge lb = Fortran::lower::LoweringBridge::create( 318 *mlirCtx, ci.getSemanticsContext(), defKinds, 319 ci.getSemanticsContext().intrinsics(), 320 ci.getSemanticsContext().targetCharacteristics(), 321 ci.getParsing().allCooked(), ci.getInvocation().getTargetOpts().triple, 322 kindMap, ci.getInvocation().getLoweringOpts(), 323 ci.getInvocation().getFrontendOpts().envDefaults, 324 ci.getInvocation().getFrontendOpts().features, targetMachine, 325 ci.getInvocation().getTargetOpts(), ci.getInvocation().getCodeGenOpts()); 326 327 if (ci.getInvocation().getFrontendOpts().features.IsEnabled( 328 Fortran::common::LanguageFeature::OpenMP)) { 329 setOffloadModuleInterfaceAttributes(lb.getModule(), 330 ci.getInvocation().getLangOpts()); 331 setOpenMPVersionAttribute(lb.getModule(), 332 ci.getInvocation().getLangOpts().OpenMPVersion); 333 } 334 335 // Create a parse tree and lower it to FIR 336 Fortran::parser::Program &parseTree{*ci.getParsing().parseTree()}; 337 lb.lower(parseTree, ci.getSemanticsContext()); 338 339 // Fetch module from lb, so we can set 340 mlirModule = lb.getModuleAndRelease(); 341 342 // Add target specific items like dependent libraries, target specific 343 // constants etc. 344 addDependentLibs(*mlirModule, ci); 345 addAMDGPUSpecificMLIRItems(*mlirModule, ci); 346 timingScopeMLIRGen.stop(); 347 348 // run the default passes. 349 mlir::PassManager pm((*mlirModule)->getName(), 350 mlir::OpPassManager::Nesting::Implicit); 351 (void)mlir::applyPassManagerCLOptions(pm); 352 // Add OpenMP-related passes 353 // WARNING: These passes must be run immediately after the lowering to ensure 354 // that the FIR is correct with respect to OpenMP operations/attributes. 355 if (ci.getInvocation().getFrontendOpts().features.IsEnabled( 356 Fortran::common::LanguageFeature::OpenMP)) { 357 bool isDevice = false; 358 if (auto offloadMod = llvm::dyn_cast<mlir::omp::OffloadModuleInterface>( 359 mlirModule->getOperation())) 360 isDevice = offloadMod.getIsTargetDevice(); 361 // WARNING: This pipeline must be run immediately after the lowering to 362 // ensure that the FIR is correct with respect to OpenMP operations/ 363 // attributes. 364 fir::createOpenMPFIRPassPipeline(pm, isDevice); 365 } 366 367 pm.enableVerifier(/*verifyPasses=*/true); 368 pm.addPass(std::make_unique<Fortran::lower::VerifierPass>()); 369 pm.enableTiming(timingScopeMLIRGen); 370 371 if (mlir::failed(pm.run(*mlirModule))) { 372 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 373 clang::DiagnosticsEngine::Error, 374 "verification of lowering to FIR failed"); 375 ci.getDiagnostics().Report(diagID); 376 return false; 377 } 378 timingScopeMLIRGen.stop(); 379 380 // Print initial full MLIR module, before lowering or transformations, if 381 // -save-temps has been specified. 382 if (!saveMLIRTempFile(ci.getInvocation(), *mlirModule, getCurrentFile(), 383 "fir")) { 384 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 385 clang::DiagnosticsEngine::Error, "Saving MLIR temp file failed"); 386 ci.getDiagnostics().Report(diagID); 387 return false; 388 } 389 390 return true; 391 } 392 393 //===----------------------------------------------------------------------===// 394 // Custom ExecuteAction 395 //===----------------------------------------------------------------------===// 396 void InputOutputTestAction::executeAction() { 397 CompilerInstance &ci = getInstance(); 398 399 // Create a stream for errors 400 std::string buf; 401 llvm::raw_string_ostream errorStream{buf}; 402 403 // Read the input file 404 Fortran::parser::AllSources &allSources{ci.getAllSources()}; 405 std::string path{getCurrentFileOrBufferName()}; 406 const Fortran::parser::SourceFile *sf; 407 if (path == "-") 408 sf = allSources.ReadStandardInput(errorStream); 409 else 410 sf = allSources.Open(path, errorStream, std::optional<std::string>{"."s}); 411 llvm::ArrayRef<char> fileContent = sf->content(); 412 413 // Output file descriptor to receive the contents of the input file. 414 std::unique_ptr<llvm::raw_ostream> os; 415 416 // Copy the contents from the input file to the output file 417 if (!ci.isOutputStreamNull()) { 418 // An output stream (outputStream_) was set earlier 419 ci.writeOutputStream(fileContent.data()); 420 } else { 421 // No pre-set output stream - create an output file 422 os = ci.createDefaultOutputFile( 423 /*binary=*/true, getCurrentFileOrBufferName(), "txt"); 424 if (!os) 425 return; 426 (*os) << fileContent.data(); 427 } 428 } 429 430 void PrintPreprocessedAction::executeAction() { 431 std::string buf; 432 llvm::raw_string_ostream outForPP{buf}; 433 434 // Format or dump the prescanner's output 435 CompilerInstance &ci = this->getInstance(); 436 if (ci.getInvocation().getPreprocessorOpts().showMacros) { 437 ci.getParsing().EmitPreprocessorMacros(outForPP); 438 } else if (ci.getInvocation().getPreprocessorOpts().noReformat) { 439 ci.getParsing().DumpCookedChars(outForPP); 440 } else { 441 ci.getParsing().EmitPreprocessedSource( 442 outForPP, !ci.getInvocation().getPreprocessorOpts().noLineDirectives); 443 } 444 445 // Print getDiagnostics from the prescanner 446 ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources()); 447 448 // If a pre-defined output stream exists, dump the preprocessed content there 449 if (!ci.isOutputStreamNull()) { 450 // Send the output to the pre-defined output buffer. 451 ci.writeOutputStream(buf); 452 return; 453 } 454 455 // Create a file and save the preprocessed output there 456 std::unique_ptr<llvm::raw_pwrite_stream> os{ci.createDefaultOutputFile( 457 /*Binary=*/true, /*InFile=*/getCurrentFileOrBufferName())}; 458 if (!os) { 459 return; 460 } 461 462 (*os) << buf; 463 } 464 465 void DebugDumpProvenanceAction::executeAction() { 466 this->getInstance().getParsing().DumpProvenance(llvm::outs()); 467 } 468 469 void ParseSyntaxOnlyAction::executeAction() {} 470 471 void DebugUnparseNoSemaAction::executeAction() { 472 auto &invoc = this->getInstance().getInvocation(); 473 auto &parseTree{getInstance().getParsing().parseTree()}; 474 475 // TODO: Options should come from CompilerInvocation 476 Unparse(llvm::outs(), *parseTree, 477 /*encoding=*/Fortran::parser::Encoding::UTF_8, 478 /*capitalizeKeywords=*/true, /*backslashEscapes=*/false, 479 /*preStatement=*/nullptr, 480 invoc.getUseAnalyzedObjectsForUnparse() ? &invoc.getAsFortran() 481 : nullptr); 482 } 483 484 void DebugUnparseAction::executeAction() { 485 auto &invoc = this->getInstance().getInvocation(); 486 auto &parseTree{getInstance().getParsing().parseTree()}; 487 488 CompilerInstance &ci = this->getInstance(); 489 auto os{ci.createDefaultOutputFile( 490 /*Binary=*/false, /*InFile=*/getCurrentFileOrBufferName())}; 491 492 // TODO: Options should come from CompilerInvocation 493 Unparse(*os, *parseTree, 494 /*encoding=*/Fortran::parser::Encoding::UTF_8, 495 /*capitalizeKeywords=*/true, /*backslashEscapes=*/false, 496 /*preStatement=*/nullptr, 497 invoc.getUseAnalyzedObjectsForUnparse() ? &invoc.getAsFortran() 498 : nullptr); 499 500 // Report fatal semantic errors 501 reportFatalSemanticErrors(); 502 } 503 504 void DebugUnparseWithSymbolsAction::executeAction() { 505 auto &parseTree{*getInstance().getParsing().parseTree()}; 506 507 Fortran::semantics::UnparseWithSymbols( 508 llvm::outs(), parseTree, /*encoding=*/Fortran::parser::Encoding::UTF_8); 509 510 // Report fatal semantic errors 511 reportFatalSemanticErrors(); 512 } 513 514 void DebugUnparseWithModulesAction::executeAction() { 515 auto &parseTree{*getInstance().getParsing().parseTree()}; 516 CompilerInstance &ci{getInstance()}; 517 Fortran::semantics::UnparseWithModules( 518 llvm::outs(), ci.getSemantics().context(), parseTree, 519 /*encoding=*/Fortran::parser::Encoding::UTF_8); 520 reportFatalSemanticErrors(); 521 } 522 523 void DebugDumpSymbolsAction::executeAction() { 524 CompilerInstance &ci = this->getInstance(); 525 526 if (!ci.getRtTyTables().schemata) { 527 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 528 clang::DiagnosticsEngine::Error, 529 "could not find module file for __fortran_type_info"); 530 ci.getDiagnostics().Report(diagID); 531 llvm::errs() << "\n"; 532 return; 533 } 534 535 // Dump symbols 536 ci.getSemantics().DumpSymbols(llvm::outs()); 537 } 538 539 void DebugDumpAllAction::executeAction() { 540 CompilerInstance &ci = this->getInstance(); 541 542 // Dump parse tree 543 auto &parseTree{getInstance().getParsing().parseTree()}; 544 llvm::outs() << "========================"; 545 llvm::outs() << " Flang: parse tree dump "; 546 llvm::outs() << "========================\n"; 547 Fortran::parser::DumpTree(llvm::outs(), parseTree, 548 &ci.getInvocation().getAsFortran()); 549 550 if (!ci.getRtTyTables().schemata) { 551 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 552 clang::DiagnosticsEngine::Error, 553 "could not find module file for __fortran_type_info"); 554 ci.getDiagnostics().Report(diagID); 555 llvm::errs() << "\n"; 556 return; 557 } 558 559 // Dump symbols 560 llvm::outs() << "====================="; 561 llvm::outs() << " Flang: symbols dump "; 562 llvm::outs() << "=====================\n"; 563 ci.getSemantics().DumpSymbols(llvm::outs()); 564 } 565 566 void DebugDumpParseTreeNoSemaAction::executeAction() { 567 auto &parseTree{getInstance().getParsing().parseTree()}; 568 569 // Dump parse tree 570 Fortran::parser::DumpTree( 571 llvm::outs(), parseTree, 572 &this->getInstance().getInvocation().getAsFortran()); 573 } 574 575 void DebugDumpParseTreeAction::executeAction() { 576 auto &parseTree{getInstance().getParsing().parseTree()}; 577 578 // Dump parse tree 579 Fortran::parser::DumpTree( 580 llvm::outs(), parseTree, 581 &this->getInstance().getInvocation().getAsFortran()); 582 583 // Report fatal semantic errors 584 reportFatalSemanticErrors(); 585 } 586 587 void DebugMeasureParseTreeAction::executeAction() { 588 CompilerInstance &ci = this->getInstance(); 589 590 // Parse. In case of failure, report and return. 591 ci.getParsing().Parse(llvm::outs()); 592 593 if ((ci.getParsing().parseTree().has_value() && 594 !ci.getParsing().consumedWholeFile()) || 595 (!ci.getParsing().messages().empty() && 596 (ci.getInvocation().getWarnAsErr() || 597 ci.getParsing().messages().AnyFatalError()))) { 598 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 599 clang::DiagnosticsEngine::Error, "Could not parse %0"); 600 ci.getDiagnostics().Report(diagID) << getCurrentFileOrBufferName(); 601 602 ci.getParsing().messages().Emit(llvm::errs(), 603 this->getInstance().getAllCookedSources()); 604 return; 605 } 606 607 // Report the getDiagnostics from parsing 608 ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources()); 609 610 auto &parseTree{*ci.getParsing().parseTree()}; 611 612 // Measure the parse tree 613 MeasurementVisitor visitor; 614 Fortran::parser::Walk(parseTree, visitor); 615 llvm::outs() << "Parse tree comprises " << visitor.objects 616 << " objects and occupies " << visitor.bytes 617 << " total bytes.\n"; 618 } 619 620 void DebugPreFIRTreeAction::executeAction() { 621 CompilerInstance &ci = this->getInstance(); 622 // Report and exit if fatal semantic errors are present 623 if (reportFatalSemanticErrors()) { 624 return; 625 } 626 627 auto &parseTree{*ci.getParsing().parseTree()}; 628 629 // Dump pre-FIR tree 630 if (auto ast{ 631 Fortran::lower::createPFT(parseTree, ci.getSemanticsContext())}) { 632 Fortran::lower::dumpPFT(llvm::outs(), *ast); 633 } else { 634 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 635 clang::DiagnosticsEngine::Error, "Pre FIR Tree is NULL."); 636 ci.getDiagnostics().Report(diagID); 637 } 638 } 639 640 void DebugDumpParsingLogAction::executeAction() { 641 CompilerInstance &ci = this->getInstance(); 642 643 ci.getParsing().Parse(llvm::errs()); 644 ci.getParsing().DumpParsingLog(llvm::outs()); 645 } 646 647 void GetDefinitionAction::executeAction() { 648 CompilerInstance &ci = this->getInstance(); 649 650 // Report and exit if fatal semantic errors are present 651 if (reportFatalSemanticErrors()) { 652 return; 653 } 654 655 parser::AllCookedSources &cs = ci.getAllCookedSources(); 656 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 657 clang::DiagnosticsEngine::Error, "Symbol not found"); 658 659 auto gdv = ci.getInvocation().getFrontendOpts().getDefVals; 660 auto charBlock{cs.GetCharBlockFromLineAndColumns(gdv.line, gdv.startColumn, 661 gdv.endColumn)}; 662 if (!charBlock) { 663 ci.getDiagnostics().Report(diagID); 664 return; 665 } 666 667 llvm::outs() << "String range: >" << charBlock->ToString() << "<\n"; 668 669 auto *symbol{ 670 ci.getSemanticsContext().FindScope(*charBlock).FindSymbol(*charBlock)}; 671 if (!symbol) { 672 ci.getDiagnostics().Report(diagID); 673 return; 674 } 675 676 llvm::outs() << "Found symbol name: " << symbol->name().ToString() << "\n"; 677 678 auto sourceInfo{cs.GetSourcePositionRange(symbol->name())}; 679 if (!sourceInfo) { 680 llvm_unreachable( 681 "Failed to obtain SourcePosition." 682 "TODO: Please, write a test and replace this with a diagnostic!"); 683 return; 684 } 685 686 llvm::outs() << "Found symbol name: " << symbol->name().ToString() << "\n"; 687 llvm::outs() << symbol->name().ToString() << ": " << sourceInfo->first.path 688 << ", " << sourceInfo->first.line << ", " 689 << sourceInfo->first.column << "-" << sourceInfo->second.column 690 << "\n"; 691 } 692 693 void GetSymbolsSourcesAction::executeAction() { 694 CompilerInstance &ci = this->getInstance(); 695 696 // Report and exit if fatal semantic errors are present 697 if (reportFatalSemanticErrors()) { 698 return; 699 } 700 701 ci.getSemantics().DumpSymbolsSources(llvm::outs()); 702 } 703 704 //===----------------------------------------------------------------------===// 705 // CodeGenActions 706 //===----------------------------------------------------------------------===// 707 708 CodeGenAction::~CodeGenAction() = default; 709 710 static llvm::OptimizationLevel 711 mapToLevel(const Fortran::frontend::CodeGenOptions &opts) { 712 switch (opts.OptimizationLevel) { 713 default: 714 llvm_unreachable("Invalid optimization level!"); 715 case 0: 716 return llvm::OptimizationLevel::O0; 717 case 1: 718 return llvm::OptimizationLevel::O1; 719 case 2: 720 return llvm::OptimizationLevel::O2; 721 case 3: 722 return llvm::OptimizationLevel::O3; 723 } 724 } 725 726 // Lower using HLFIR then run the FIR to HLFIR pipeline 727 void CodeGenAction::lowerHLFIRToFIR() { 728 assert(mlirModule && "The MLIR module has not been generated yet."); 729 730 CompilerInstance &ci = this->getInstance(); 731 const CodeGenOptions &opts = ci.getInvocation().getCodeGenOpts(); 732 llvm::OptimizationLevel level = mapToLevel(opts); 733 mlir::DefaultTimingManager &timingMgr = ci.getTimingManager(); 734 mlir::TimingScope &timingScopeRoot = ci.getTimingScopeRoot(); 735 736 fir::support::loadDialects(*mlirCtx); 737 738 // Set-up the MLIR pass manager 739 mlir::PassManager pm((*mlirModule)->getName(), 740 mlir::OpPassManager::Nesting::Implicit); 741 742 pm.addPass(std::make_unique<Fortran::lower::VerifierPass>()); 743 pm.enableVerifier(/*verifyPasses=*/true); 744 745 // Create the pass pipeline 746 fir::createHLFIRToFIRPassPipeline( 747 pm, 748 ci.getInvocation().getFrontendOpts().features.IsEnabled( 749 Fortran::common::LanguageFeature::OpenMP), 750 level); 751 (void)mlir::applyPassManagerCLOptions(pm); 752 753 mlir::TimingScope timingScopeMLIRPasses = timingScopeRoot.nest( 754 mlir::TimingIdentifier::get(timingIdMLIRPasses, timingMgr)); 755 pm.enableTiming(timingScopeMLIRPasses); 756 if (!mlir::succeeded(pm.run(*mlirModule))) { 757 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 758 clang::DiagnosticsEngine::Error, "Lowering to FIR failed"); 759 ci.getDiagnostics().Report(diagID); 760 } 761 } 762 763 static std::optional<std::pair<unsigned, unsigned>> 764 getAArch64VScaleRange(CompilerInstance &ci) { 765 const auto &langOpts = ci.getInvocation().getLangOpts(); 766 767 if (langOpts.VScaleMin || langOpts.VScaleMax) 768 return std::pair<unsigned, unsigned>( 769 langOpts.VScaleMin ? langOpts.VScaleMin : 1, langOpts.VScaleMax); 770 771 std::string featuresStr = ci.getTargetFeatures(); 772 if (featuresStr.find("+sve") != std::string::npos) 773 return std::pair<unsigned, unsigned>(1, 16); 774 775 return std::nullopt; 776 } 777 778 static std::optional<std::pair<unsigned, unsigned>> 779 getRISCVVScaleRange(CompilerInstance &ci) { 780 const auto &langOpts = ci.getInvocation().getLangOpts(); 781 const auto targetOpts = ci.getInvocation().getTargetOpts(); 782 const llvm::Triple triple(targetOpts.triple); 783 784 auto parseResult = llvm::RISCVISAInfo::parseFeatures( 785 triple.isRISCV64() ? 64 : 32, targetOpts.featuresAsWritten); 786 if (!parseResult) { 787 std::string buffer; 788 llvm::raw_string_ostream outputErrMsg(buffer); 789 handleAllErrors(parseResult.takeError(), [&](llvm::StringError &errMsg) { 790 outputErrMsg << errMsg.getMessage(); 791 }); 792 ci.getDiagnostics().Report(clang::diag::err_invalid_feature_combination) 793 << buffer; 794 return std::nullopt; 795 } 796 797 llvm::RISCVISAInfo *const isaInfo = parseResult->get(); 798 799 // RISCV::RVVBitsPerBlock is 64. 800 unsigned vscaleMin = isaInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock; 801 802 if (langOpts.VScaleMin || langOpts.VScaleMax) { 803 // Treat Zvl*b as a lower bound on vscale. 804 vscaleMin = std::max(vscaleMin, langOpts.VScaleMin); 805 unsigned vscaleMax = langOpts.VScaleMax; 806 if (vscaleMax != 0 && vscaleMax < vscaleMin) 807 vscaleMax = vscaleMin; 808 return std::pair<unsigned, unsigned>(vscaleMin ? vscaleMin : 1, vscaleMax); 809 } 810 811 if (vscaleMin > 0) { 812 unsigned vscaleMax = isaInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock; 813 return std::make_pair(vscaleMin, vscaleMax); 814 } 815 816 return std::nullopt; 817 } 818 819 // TODO: We should get this from TargetInfo. However, that depends on 820 // too much of clang, so for now, replicate the functionality. 821 static std::optional<std::pair<unsigned, unsigned>> 822 getVScaleRange(CompilerInstance &ci) { 823 const llvm::Triple triple(ci.getInvocation().getTargetOpts().triple); 824 825 if (triple.isAArch64()) 826 return getAArch64VScaleRange(ci); 827 if (triple.isRISCV()) 828 return getRISCVVScaleRange(ci); 829 830 // All other architectures that don't support scalable vectors (i.e. don't 831 // need vscale) 832 return std::nullopt; 833 } 834 835 // Lower the previously generated MLIR module into an LLVM IR module 836 void CodeGenAction::generateLLVMIR() { 837 assert(mlirModule && "The MLIR module has not been generated yet."); 838 839 CompilerInstance &ci = this->getInstance(); 840 CompilerInvocation &invoc = ci.getInvocation(); 841 const CodeGenOptions &opts = invoc.getCodeGenOpts(); 842 const auto &mathOpts = invoc.getLoweringOpts().getMathOptions(); 843 llvm::OptimizationLevel level = mapToLevel(opts); 844 mlir::DefaultTimingManager &timingMgr = ci.getTimingManager(); 845 mlir::TimingScope &timingScopeRoot = ci.getTimingScopeRoot(); 846 847 fir::support::loadDialects(*mlirCtx); 848 mlir::DialectRegistry registry; 849 fir::support::registerNonCodegenDialects(registry); 850 fir::support::addFIRExtensions(registry); 851 mlirCtx->appendDialectRegistry(registry); 852 fir::support::registerLLVMTranslation(*mlirCtx); 853 854 // Set-up the MLIR pass manager 855 mlir::PassManager pm((*mlirModule)->getName(), 856 mlir::OpPassManager::Nesting::Implicit); 857 858 pm.addPass(std::make_unique<Fortran::lower::VerifierPass>()); 859 pm.enableVerifier(/*verifyPasses=*/true); 860 861 MLIRToLLVMPassPipelineConfig config(level, opts, mathOpts); 862 fir::registerDefaultInlinerPass(config); 863 864 if (auto vsr = getVScaleRange(ci)) { 865 config.VScaleMin = vsr->first; 866 config.VScaleMax = vsr->second; 867 } 868 869 if (ci.getInvocation().getFrontendOpts().features.IsEnabled( 870 Fortran::common::LanguageFeature::OpenMP)) 871 config.EnableOpenMP = true; 872 873 if (ci.getInvocation().getLoweringOpts().getIntegerWrapAround()) 874 config.NSWOnLoopVarInc = false; 875 876 // Create the pass pipeline 877 fir::createMLIRToLLVMPassPipeline(pm, config, getCurrentFile()); 878 (void)mlir::applyPassManagerCLOptions(pm); 879 880 // run the pass manager 881 mlir::TimingScope timingScopeMLIRPasses = timingScopeRoot.nest( 882 mlir::TimingIdentifier::get(timingIdMLIRPasses, timingMgr)); 883 pm.enableTiming(timingScopeMLIRPasses); 884 if (!mlir::succeeded(pm.run(*mlirModule))) { 885 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 886 clang::DiagnosticsEngine::Error, "Lowering to LLVM IR failed"); 887 ci.getDiagnostics().Report(diagID); 888 } 889 timingScopeMLIRPasses.stop(); 890 891 // Print final MLIR module, just before translation into LLVM IR, if 892 // -save-temps has been specified. 893 if (!saveMLIRTempFile(ci.getInvocation(), *mlirModule, getCurrentFile(), 894 "llvmir")) { 895 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 896 clang::DiagnosticsEngine::Error, "Saving MLIR temp file failed"); 897 ci.getDiagnostics().Report(diagID); 898 return; 899 } 900 901 // Translate to LLVM IR 902 mlir::TimingScope timingScopeLLVMIRGen = timingScopeRoot.nest( 903 mlir::TimingIdentifier::get(timingIdLLVMIRGen, timingMgr)); 904 std::optional<llvm::StringRef> moduleName = mlirModule->getName(); 905 llvmModule = mlir::translateModuleToLLVMIR( 906 *mlirModule, *llvmCtx, moduleName ? *moduleName : "FIRModule"); 907 908 if (!llvmModule) { 909 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 910 clang::DiagnosticsEngine::Error, "failed to create the LLVM module"); 911 ci.getDiagnostics().Report(diagID); 912 return; 913 } 914 915 // Set PIC/PIE level LLVM module flags. 916 if (opts.PICLevel > 0) { 917 llvmModule->setPICLevel(static_cast<llvm::PICLevel::Level>(opts.PICLevel)); 918 if (opts.IsPIE) 919 llvmModule->setPIELevel( 920 static_cast<llvm::PIELevel::Level>(opts.PICLevel)); 921 } 922 923 // Set mcmodel level LLVM module flags 924 std::optional<llvm::CodeModel::Model> cm = getCodeModel(opts.CodeModel); 925 if (cm.has_value()) { 926 const llvm::Triple triple(ci.getInvocation().getTargetOpts().triple); 927 llvmModule->setCodeModel(*cm); 928 if ((cm == llvm::CodeModel::Medium || cm == llvm::CodeModel::Large) && 929 triple.getArch() == llvm::Triple::x86_64) { 930 llvmModule->setLargeDataThreshold(opts.LargeDataThreshold); 931 } 932 } 933 } 934 935 static std::unique_ptr<llvm::raw_pwrite_stream> 936 getOutputStream(CompilerInstance &ci, llvm::StringRef inFile, 937 BackendActionTy action) { 938 switch (action) { 939 case BackendActionTy::Backend_EmitAssembly: 940 return ci.createDefaultOutputFile( 941 /*Binary=*/false, inFile, /*extension=*/"s"); 942 case BackendActionTy::Backend_EmitLL: 943 return ci.createDefaultOutputFile( 944 /*Binary=*/false, inFile, /*extension=*/"ll"); 945 case BackendActionTy::Backend_EmitFIR: 946 case BackendActionTy::Backend_EmitHLFIR: 947 return ci.createDefaultOutputFile( 948 /*Binary=*/false, inFile, /*extension=*/"mlir"); 949 case BackendActionTy::Backend_EmitBC: 950 return ci.createDefaultOutputFile( 951 /*Binary=*/true, inFile, /*extension=*/"bc"); 952 case BackendActionTy::Backend_EmitObj: 953 return ci.createDefaultOutputFile( 954 /*Binary=*/true, inFile, /*extension=*/"o"); 955 } 956 957 llvm_unreachable("Invalid action!"); 958 } 959 960 /// Generate target-specific machine-code or assembly file from the input LLVM 961 /// module. 962 /// 963 /// \param [in] diags Diagnostics engine for reporting errors 964 /// \param [in] tm Target machine to aid the code-gen pipeline set-up 965 /// \param [in] act Backend act to run (assembly vs machine-code generation) 966 /// \param [in] llvmModule LLVM module to lower to assembly/machine-code 967 /// \param [in] codeGenOpts options configuring codegen pipeline 968 /// \param [out] os Output stream to emit the generated code to 969 static void generateMachineCodeOrAssemblyImpl(clang::DiagnosticsEngine &diags, 970 llvm::TargetMachine &tm, 971 BackendActionTy act, 972 llvm::Module &llvmModule, 973 const CodeGenOptions &codeGenOpts, 974 llvm::raw_pwrite_stream &os) { 975 assert(((act == BackendActionTy::Backend_EmitObj) || 976 (act == BackendActionTy::Backend_EmitAssembly)) && 977 "Unsupported action"); 978 979 // Set-up the pass manager, i.e create an LLVM code-gen pass pipeline. 980 // Currently only the legacy pass manager is supported. 981 // TODO: Switch to the new PM once it's available in the backend. 982 llvm::legacy::PassManager codeGenPasses; 983 codeGenPasses.add( 984 createTargetTransformInfoWrapperPass(tm.getTargetIRAnalysis())); 985 986 llvm::Triple triple(llvmModule.getTargetTriple()); 987 llvm::TargetLibraryInfoImpl *tlii = 988 llvm::driver::createTLII(triple, codeGenOpts.getVecLib()); 989 codeGenPasses.add(new llvm::TargetLibraryInfoWrapperPass(*tlii)); 990 991 llvm::CodeGenFileType cgft = (act == BackendActionTy::Backend_EmitAssembly) 992 ? llvm::CodeGenFileType::AssemblyFile 993 : llvm::CodeGenFileType::ObjectFile; 994 if (tm.addPassesToEmitFile(codeGenPasses, os, nullptr, cgft)) { 995 unsigned diagID = 996 diags.getCustomDiagID(clang::DiagnosticsEngine::Error, 997 "emission of this file type is not supported"); 998 diags.Report(diagID); 999 return; 1000 } 1001 1002 // Run the passes 1003 codeGenPasses.run(llvmModule); 1004 1005 // Cleanup 1006 delete tlii; 1007 } 1008 1009 void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) { 1010 CompilerInstance &ci = getInstance(); 1011 const CodeGenOptions &opts = ci.getInvocation().getCodeGenOpts(); 1012 clang::DiagnosticsEngine &diags = ci.getDiagnostics(); 1013 llvm::OptimizationLevel level = mapToLevel(opts); 1014 1015 llvm::TargetMachine *targetMachine = &ci.getTargetMachine(); 1016 // Create the analysis managers. 1017 llvm::LoopAnalysisManager lam; 1018 llvm::FunctionAnalysisManager fam; 1019 llvm::CGSCCAnalysisManager cgam; 1020 llvm::ModuleAnalysisManager mam; 1021 1022 // Create the pass manager builder. 1023 llvm::PassInstrumentationCallbacks pic; 1024 llvm::PipelineTuningOptions pto; 1025 std::optional<llvm::PGOOptions> pgoOpt; 1026 llvm::StandardInstrumentations si(llvmModule->getContext(), 1027 opts.DebugPassManager); 1028 si.registerCallbacks(pic, &mam); 1029 if (ci.isTimingEnabled()) 1030 si.getTimePasses().setOutStream(ci.getTimingStreamLLVM()); 1031 pto.LoopUnrolling = opts.UnrollLoops; 1032 pto.LoopInterleaving = opts.UnrollLoops; 1033 llvm::PassBuilder pb(targetMachine, pto, pgoOpt, &pic); 1034 1035 // Attempt to load pass plugins and register their callbacks with PB. 1036 for (auto &pluginFile : opts.LLVMPassPlugins) { 1037 auto passPlugin = llvm::PassPlugin::Load(pluginFile); 1038 if (passPlugin) { 1039 passPlugin->registerPassBuilderCallbacks(pb); 1040 } else { 1041 diags.Report(clang::diag::err_fe_unable_to_load_plugin) 1042 << pluginFile << passPlugin.takeError(); 1043 } 1044 } 1045 // Register static plugin extensions. 1046 #define HANDLE_EXTENSION(Ext) \ 1047 get##Ext##PluginInfo().RegisterPassBuilderCallbacks(pb); 1048 #include "llvm/Support/Extension.def" 1049 1050 // Register the target library analysis directly and give it a customized 1051 // preset TLI depending on -fveclib 1052 llvm::Triple triple(llvmModule->getTargetTriple()); 1053 llvm::TargetLibraryInfoImpl *tlii = 1054 llvm::driver::createTLII(triple, opts.getVecLib()); 1055 fam.registerPass([&] { return llvm::TargetLibraryAnalysis(*tlii); }); 1056 1057 // Register all the basic analyses with the managers. 1058 pb.registerModuleAnalyses(mam); 1059 pb.registerCGSCCAnalyses(cgam); 1060 pb.registerFunctionAnalyses(fam); 1061 pb.registerLoopAnalyses(lam); 1062 pb.crossRegisterProxies(lam, fam, cgam, mam); 1063 1064 // Create the pass manager. 1065 llvm::ModulePassManager mpm; 1066 if (opts.PrepareForFullLTO) 1067 mpm = pb.buildLTOPreLinkDefaultPipeline(level); 1068 else if (opts.PrepareForThinLTO) 1069 mpm = pb.buildThinLTOPreLinkDefaultPipeline(level); 1070 else 1071 mpm = pb.buildPerModuleDefaultPipeline(level); 1072 1073 if (action == BackendActionTy::Backend_EmitBC) 1074 mpm.addPass(llvm::BitcodeWriterPass(os)); 1075 else if (action == BackendActionTy::Backend_EmitLL) 1076 mpm.addPass(llvm::PrintModulePass(os)); 1077 1078 // FIXME: This should eventually be replaced by a first-class driver option. 1079 // This should be done for both flang and clang simultaneously. 1080 // Print a textual, '-passes=' compatible, representation of pipeline if 1081 // requested. In this case, don't run the passes. This mimics the behavior of 1082 // clang. 1083 if (llvm::PrintPipelinePasses) { 1084 mpm.printPipeline(llvm::outs(), [&pic](llvm::StringRef className) { 1085 auto passName = pic.getPassNameForClassName(className); 1086 return passName.empty() ? className : passName; 1087 }); 1088 llvm::outs() << "\n"; 1089 return; 1090 } 1091 1092 // Run the passes. 1093 mpm.run(*llvmModule, mam); 1094 1095 // Print the timers to the associated output stream and reset them. 1096 if (ci.isTimingEnabled()) 1097 si.getTimePasses().print(); 1098 1099 // Cleanup 1100 delete tlii; 1101 } 1102 1103 // This class handles optimization remark messages requested if 1104 // any of -Rpass, -Rpass-analysis or -Rpass-missed flags were provided 1105 class BackendRemarkConsumer : public llvm::DiagnosticHandler { 1106 1107 const CodeGenOptions &codeGenOpts; 1108 clang::DiagnosticsEngine &diags; 1109 1110 public: 1111 BackendRemarkConsumer(clang::DiagnosticsEngine &diags, 1112 const CodeGenOptions &codeGenOpts) 1113 : codeGenOpts(codeGenOpts), diags(diags) {} 1114 1115 bool isAnalysisRemarkEnabled(llvm::StringRef passName) const override { 1116 return codeGenOpts.OptimizationRemarkAnalysis.patternMatches(passName); 1117 } 1118 bool isMissedOptRemarkEnabled(llvm::StringRef passName) const override { 1119 return codeGenOpts.OptimizationRemarkMissed.patternMatches(passName); 1120 } 1121 bool isPassedOptRemarkEnabled(llvm::StringRef passName) const override { 1122 return codeGenOpts.OptimizationRemark.patternMatches(passName); 1123 } 1124 1125 bool isAnyRemarkEnabled() const override { 1126 return codeGenOpts.OptimizationRemarkAnalysis.hasValidPattern() || 1127 codeGenOpts.OptimizationRemarkMissed.hasValidPattern() || 1128 codeGenOpts.OptimizationRemark.hasValidPattern(); 1129 } 1130 1131 void 1132 emitOptimizationMessage(const llvm::DiagnosticInfoOptimizationBase &diagInfo, 1133 unsigned diagID) { 1134 // We only support warnings and remarks. 1135 assert(diagInfo.getSeverity() == llvm::DS_Remark || 1136 diagInfo.getSeverity() == llvm::DS_Warning); 1137 1138 std::string msg; 1139 llvm::raw_string_ostream msgStream(msg); 1140 1141 if (diagInfo.isLocationAvailable()) { 1142 // Clang contains a SourceManager class which handles loading 1143 // and caching of source files into memory and it can be used to 1144 // query SourceLocation data. The SourceLocation data is what is 1145 // needed here as it contains the full include stack which gives 1146 // line and column number as well as file name and location. 1147 // Since Flang doesn't have SourceManager, send file name and absolute 1148 // path through msgStream, to use for printing. 1149 msgStream << diagInfo.getLocationStr() << ";;" 1150 << diagInfo.getAbsolutePath() << ";;"; 1151 } 1152 1153 msgStream << diagInfo.getMsg(); 1154 1155 // Emit message. 1156 diags.Report(diagID) << clang::AddFlagValue(diagInfo.getPassName()) << msg; 1157 } 1158 1159 void optimizationRemarkHandler( 1160 const llvm::DiagnosticInfoOptimizationBase &diagInfo) { 1161 auto passName = diagInfo.getPassName(); 1162 if (diagInfo.isPassed()) { 1163 if (codeGenOpts.OptimizationRemark.patternMatches(passName)) 1164 // Optimization remarks are active only if the -Rpass flag has a regular 1165 // expression that matches the name of the pass name in \p d. 1166 emitOptimizationMessage( 1167 diagInfo, clang::diag::remark_fe_backend_optimization_remark); 1168 1169 return; 1170 } 1171 1172 if (diagInfo.isMissed()) { 1173 if (codeGenOpts.OptimizationRemarkMissed.patternMatches(passName)) 1174 // Missed optimization remarks are active only if the -Rpass-missed 1175 // flag has a regular expression that matches the name of the pass 1176 // name in \p d. 1177 emitOptimizationMessage( 1178 diagInfo, 1179 clang::diag::remark_fe_backend_optimization_remark_missed); 1180 1181 return; 1182 } 1183 1184 assert(diagInfo.isAnalysis() && "Unknown remark type"); 1185 1186 bool shouldAlwaysPrint = false; 1187 auto *ora = llvm::dyn_cast<llvm::OptimizationRemarkAnalysis>(&diagInfo); 1188 if (ora) 1189 shouldAlwaysPrint = ora->shouldAlwaysPrint(); 1190 1191 if (shouldAlwaysPrint || 1192 codeGenOpts.OptimizationRemarkAnalysis.patternMatches(passName)) 1193 emitOptimizationMessage( 1194 diagInfo, 1195 clang::diag::remark_fe_backend_optimization_remark_analysis); 1196 } 1197 1198 bool handleDiagnostics(const llvm::DiagnosticInfo &di) override { 1199 switch (di.getKind()) { 1200 case llvm::DK_OptimizationRemark: 1201 optimizationRemarkHandler(llvm::cast<llvm::OptimizationRemark>(di)); 1202 break; 1203 case llvm::DK_OptimizationRemarkMissed: 1204 optimizationRemarkHandler(llvm::cast<llvm::OptimizationRemarkMissed>(di)); 1205 break; 1206 case llvm::DK_OptimizationRemarkAnalysis: 1207 optimizationRemarkHandler( 1208 llvm::cast<llvm::OptimizationRemarkAnalysis>(di)); 1209 break; 1210 case llvm::DK_MachineOptimizationRemark: 1211 optimizationRemarkHandler( 1212 llvm::cast<llvm::MachineOptimizationRemark>(di)); 1213 break; 1214 case llvm::DK_MachineOptimizationRemarkMissed: 1215 optimizationRemarkHandler( 1216 llvm::cast<llvm::MachineOptimizationRemarkMissed>(di)); 1217 break; 1218 case llvm::DK_MachineOptimizationRemarkAnalysis: 1219 optimizationRemarkHandler( 1220 llvm::cast<llvm::MachineOptimizationRemarkAnalysis>(di)); 1221 break; 1222 default: 1223 break; 1224 } 1225 return true; 1226 } 1227 }; 1228 1229 void CodeGenAction::embedOffloadObjects() { 1230 CompilerInstance &ci = this->getInstance(); 1231 const auto &cgOpts = ci.getInvocation().getCodeGenOpts(); 1232 1233 for (llvm::StringRef offloadObject : cgOpts.OffloadObjects) { 1234 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> objectOrErr = 1235 llvm::MemoryBuffer::getFileOrSTDIN(offloadObject); 1236 if (std::error_code ec = objectOrErr.getError()) { 1237 auto diagID = ci.getDiagnostics().getCustomDiagID( 1238 clang::DiagnosticsEngine::Error, "could not open '%0' for embedding"); 1239 ci.getDiagnostics().Report(diagID) << offloadObject; 1240 return; 1241 } 1242 llvm::embedBufferInModule( 1243 *llvmModule, **objectOrErr, ".llvm.offloading", 1244 llvm::Align(llvm::object::OffloadBinary::getAlignment())); 1245 } 1246 } 1247 1248 void CodeGenAction::linkBuiltinBCLibs() { 1249 auto options = clang::FileSystemOptions(); 1250 clang::FileManager fileManager(options); 1251 CompilerInstance &ci = this->getInstance(); 1252 const auto &cgOpts = ci.getInvocation().getCodeGenOpts(); 1253 1254 std::vector<std::unique_ptr<llvm::Module>> modules; 1255 1256 // Load LLVM modules 1257 for (llvm::StringRef bcLib : cgOpts.BuiltinBCLibs) { 1258 auto BCBuf = fileManager.getBufferForFile(bcLib); 1259 if (!BCBuf) { 1260 auto diagID = ci.getDiagnostics().getCustomDiagID( 1261 clang::DiagnosticsEngine::Error, "could not open '%0' for linking"); 1262 ci.getDiagnostics().Report(diagID) << bcLib; 1263 return; 1264 } 1265 1266 llvm::Expected<std::unique_ptr<llvm::Module>> ModuleOrErr = 1267 getOwningLazyBitcodeModule(std::move(*BCBuf), *llvmCtx); 1268 if (!ModuleOrErr) { 1269 auto diagID = ci.getDiagnostics().getCustomDiagID( 1270 clang::DiagnosticsEngine::Error, "error loading '%0' for linking"); 1271 ci.getDiagnostics().Report(diagID) << bcLib; 1272 return; 1273 } 1274 modules.push_back(std::move(ModuleOrErr.get())); 1275 } 1276 1277 // Link modules and internalize functions 1278 for (auto &module : modules) { 1279 bool Err; 1280 Err = llvm::Linker::linkModules( 1281 *llvmModule, std::move(module), llvm::Linker::Flags::LinkOnlyNeeded, 1282 [](llvm::Module &M, const llvm::StringSet<> &GVS) { 1283 llvm::internalizeModule(M, [&GVS](const llvm::GlobalValue &GV) { 1284 return !GV.hasName() || (GVS.count(GV.getName()) == 0); 1285 }); 1286 }); 1287 if (Err) { 1288 auto diagID = ci.getDiagnostics().getCustomDiagID( 1289 clang::DiagnosticsEngine::Error, "link error when linking '%0'"); 1290 ci.getDiagnostics().Report(diagID) << module->getSourceFileName(); 1291 return; 1292 } 1293 } 1294 } 1295 1296 static void reportOptRecordError(llvm::Error e, clang::DiagnosticsEngine &diags, 1297 const CodeGenOptions &codeGenOpts) { 1298 handleAllErrors( 1299 std::move(e), 1300 [&](const llvm::LLVMRemarkSetupFileError &e) { 1301 diags.Report(clang::diag::err_cannot_open_file) 1302 << codeGenOpts.OptRecordFile << e.message(); 1303 }, 1304 [&](const llvm::LLVMRemarkSetupPatternError &e) { 1305 diags.Report(clang::diag::err_drv_optimization_remark_pattern) 1306 << e.message() << codeGenOpts.OptRecordPasses; 1307 }, 1308 [&](const llvm::LLVMRemarkSetupFormatError &e) { 1309 diags.Report(clang::diag::err_drv_optimization_remark_format) 1310 << codeGenOpts.OptRecordFormat; 1311 }); 1312 } 1313 1314 void CodeGenAction::executeAction() { 1315 CompilerInstance &ci = this->getInstance(); 1316 1317 clang::DiagnosticsEngine &diags = ci.getDiagnostics(); 1318 const CodeGenOptions &codeGenOpts = ci.getInvocation().getCodeGenOpts(); 1319 Fortran::lower::LoweringOptions &loweringOpts = 1320 ci.getInvocation().getLoweringOpts(); 1321 mlir::DefaultTimingManager &timingMgr = ci.getTimingManager(); 1322 mlir::TimingScope &timingScopeRoot = ci.getTimingScopeRoot(); 1323 1324 // If the output stream is a file, generate it and define the corresponding 1325 // output stream. If a pre-defined output stream is available, we will use 1326 // that instead. 1327 // 1328 // NOTE: `os` is a smart pointer that will be destroyed at the end of this 1329 // method. However, it won't be written to until `codeGenPasses` is 1330 // destroyed. By defining `os` before `codeGenPasses`, we make sure that the 1331 // output stream won't be destroyed before it is written to. This only 1332 // applies when an output file is used (i.e. there is no pre-defined output 1333 // stream). 1334 // TODO: Revisit once the new PM is ready (i.e. when `codeGenPasses` is 1335 // updated to use it). 1336 std::unique_ptr<llvm::raw_pwrite_stream> os; 1337 if (ci.isOutputStreamNull()) { 1338 os = getOutputStream(ci, getCurrentFileOrBufferName(), action); 1339 1340 if (!os) { 1341 unsigned diagID = diags.getCustomDiagID( 1342 clang::DiagnosticsEngine::Error, "failed to create the output file"); 1343 diags.Report(diagID); 1344 return; 1345 } 1346 } 1347 1348 if (action == BackendActionTy::Backend_EmitFIR) { 1349 if (loweringOpts.getLowerToHighLevelFIR()) { 1350 lowerHLFIRToFIR(); 1351 } 1352 mlirModule->print(ci.isOutputStreamNull() ? *os : ci.getOutputStream()); 1353 return; 1354 } 1355 1356 if (action == BackendActionTy::Backend_EmitHLFIR) { 1357 assert(loweringOpts.getLowerToHighLevelFIR() && 1358 "Lowering must have been configured to emit HLFIR"); 1359 mlirModule->print(ci.isOutputStreamNull() ? *os : ci.getOutputStream()); 1360 return; 1361 } 1362 1363 // Generate an LLVM module if it's not already present (it will already be 1364 // present if the input file is an LLVM IR/BC file). 1365 if (!llvmModule) 1366 generateLLVMIR(); 1367 1368 // This will already have been started in generateLLVMIR(). But we need to 1369 // continue operating on the module, so we continue timing it. 1370 mlir::TimingScope timingScopeLLVMIRGen = timingScopeRoot.nest( 1371 mlir::TimingIdentifier::get(timingIdLLVMIRGen, timingMgr)); 1372 1373 // If generating the LLVM module failed, abort! No need for further error 1374 // reporting since generateLLVMIR() does this already. 1375 if (!llvmModule) 1376 return; 1377 1378 // Set the triple based on the targetmachine (this comes compiler invocation 1379 // and the command-line target option if specified, or the default if not 1380 // given on the command-line). 1381 llvm::TargetMachine &targetMachine = ci.getTargetMachine(); 1382 1383 const std::string &theTriple = targetMachine.getTargetTriple().str(); 1384 1385 if (llvmModule->getTargetTriple() != theTriple) { 1386 diags.Report(clang::diag::warn_fe_override_module) << theTriple; 1387 } 1388 1389 // Always set the triple and data layout, to make sure they match and are set. 1390 // Note that this overwrites any datalayout stored in the LLVM-IR. This avoids 1391 // an assert for incompatible data layout when the code-generation happens. 1392 llvmModule->setTargetTriple(theTriple); 1393 llvmModule->setDataLayout(targetMachine.createDataLayout()); 1394 1395 // Link in builtin bitcode libraries 1396 if (!codeGenOpts.BuiltinBCLibs.empty()) 1397 linkBuiltinBCLibs(); 1398 1399 // Embed offload objects specified with -fembed-offload-object 1400 if (!codeGenOpts.OffloadObjects.empty()) 1401 embedOffloadObjects(); 1402 timingScopeLLVMIRGen.stop(); 1403 1404 BackendRemarkConsumer remarkConsumer(diags, codeGenOpts); 1405 1406 llvmModule->getContext().setDiagnosticHandler( 1407 std::make_unique<BackendRemarkConsumer>(remarkConsumer)); 1408 1409 // write optimization-record 1410 llvm::Expected<std::unique_ptr<llvm::ToolOutputFile>> optRecordFileOrErr = 1411 setupLLVMOptimizationRemarks( 1412 llvmModule->getContext(), codeGenOpts.OptRecordFile, 1413 codeGenOpts.OptRecordPasses, codeGenOpts.OptRecordFormat, 1414 /*DiagnosticsWithHotness=*/false, 1415 /*DiagnosticsHotnessThreshold=*/0); 1416 1417 if (llvm::Error e = optRecordFileOrErr.takeError()) { 1418 reportOptRecordError(std::move(e), diags, codeGenOpts); 1419 return; 1420 } 1421 1422 std::unique_ptr<llvm::ToolOutputFile> optRecordFile = 1423 std::move(*optRecordFileOrErr); 1424 1425 if (optRecordFile) { 1426 optRecordFile->keep(); 1427 optRecordFile->os().flush(); 1428 } 1429 1430 // Run LLVM's middle-end (i.e. the optimizer). 1431 mlir::TimingScope timingScopeLLVMIRPasses = timingScopeRoot.nest( 1432 mlir::TimingIdentifier::get(timingIdLLVMIRPasses, timingMgr)); 1433 runOptimizationPipeline(ci.isOutputStreamNull() ? *os : ci.getOutputStream()); 1434 timingScopeLLVMIRPasses.stop(); 1435 1436 if (action == BackendActionTy::Backend_EmitLL || 1437 action == BackendActionTy::Backend_EmitBC) { 1438 // This action has effectively been completed in runOptimizationPipeline. 1439 return; 1440 } 1441 1442 // Run LLVM's backend and generate either assembly or machine code 1443 mlir::TimingScope timingScopeBackend = timingScopeRoot.nest( 1444 mlir::TimingIdentifier::get(timingIdBackend, timingMgr)); 1445 if (action == BackendActionTy::Backend_EmitAssembly || 1446 action == BackendActionTy::Backend_EmitObj) { 1447 generateMachineCodeOrAssemblyImpl( 1448 diags, targetMachine, action, *llvmModule, codeGenOpts, 1449 ci.isOutputStreamNull() ? *os : ci.getOutputStream()); 1450 if (timingMgr.isEnabled()) 1451 llvm::reportAndResetTimings(&ci.getTimingStreamCodeGen()); 1452 return; 1453 } 1454 } 1455 1456 void InitOnlyAction::executeAction() { 1457 CompilerInstance &ci = this->getInstance(); 1458 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 1459 clang::DiagnosticsEngine::Warning, 1460 "Use `-init-only` for testing purposes only"); 1461 ci.getDiagnostics().Report(diagID); 1462 } 1463 1464 void PluginParseTreeAction::executeAction() {} 1465 1466 void DebugDumpPFTAction::executeAction() { 1467 CompilerInstance &ci = this->getInstance(); 1468 1469 if (auto ast = Fortran::lower::createPFT(*ci.getParsing().parseTree(), 1470 ci.getSemantics().context())) { 1471 Fortran::lower::dumpPFT(llvm::outs(), *ast); 1472 return; 1473 } 1474 1475 unsigned diagID = ci.getDiagnostics().getCustomDiagID( 1476 clang::DiagnosticsEngine::Error, "Pre FIR Tree is NULL."); 1477 ci.getDiagnostics().Report(diagID); 1478 } 1479 1480 Fortran::parser::Parsing &PluginParseTreeAction::getParsing() { 1481 return getInstance().getParsing(); 1482 } 1483 1484 std::unique_ptr<llvm::raw_pwrite_stream> 1485 PluginParseTreeAction::createOutputFile(llvm::StringRef extension = "") { 1486 1487 std::unique_ptr<llvm::raw_pwrite_stream> os{ 1488 getInstance().createDefaultOutputFile( 1489 /*Binary=*/false, /*InFile=*/getCurrentFileOrBufferName(), 1490 extension)}; 1491 return os; 1492 } 1493