brintos

brintos / llvm-project-archived public Read only

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