14c5906cfSCaroline Concatto //===--- FrontendActions.cpp ----------------------------------------------===// 24c5906cfSCaroline Concatto // 34c5906cfSCaroline Concatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 44c5906cfSCaroline Concatto // See https://llvm.org/LICENSE.txt for license information. 54c5906cfSCaroline Concatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 64c5906cfSCaroline Concatto // 74c5906cfSCaroline Concatto //===----------------------------------------------------------------------===// 81e462fafSAndrzej Warzynski // 91e462fafSAndrzej Warzynski // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ 101e462fafSAndrzej Warzynski // 111e462fafSAndrzej Warzynski //===----------------------------------------------------------------------===// 12d28de0d7SCaroline Concatto 134c5906cfSCaroline Concatto #include "flang/Frontend/FrontendActions.h" 147d246cb1SAndrzej Warzynski #include "flang/Common/default-kinds.h" 154c5906cfSCaroline Concatto #include "flang/Frontend/CompilerInstance.h" 1633be8341SSergio Afonso #include "flang/Frontend/CompilerInvocation.h" 1796d229c9SAndrzej Warzynski #include "flang/Frontend/FrontendOptions.h" 18b83a4450SAndrzej Warzynski #include "flang/Frontend/PreprocessorOptions.h" 1969c3309dSAndrzej Warzynski #include "flang/Lower/Bridge.h" 20529f7181SFaris Rehman #include "flang/Lower/PFTBuilder.h" 2169c3309dSAndrzej Warzynski #include "flang/Lower/Support/Verifier.h" 22b07ef9e7SRenaud-K #include "flang/Optimizer/Dialect/Support/FIRContext.h" 23b07ef9e7SRenaud-K #include "flang/Optimizer/Dialect/Support/KindMapping.h" 24c3201ddaSTarun Prabhu #include "flang/Optimizer/Passes/Pipelines.h" 25e59e8488SjeanPerier #include "flang/Optimizer/Support/DataLayout.h" 2669c3309dSAndrzej Warzynski #include "flang/Optimizer/Support/InitFIR.h" 2769c3309dSAndrzej Warzynski #include "flang/Optimizer/Support/Utils.h" 2845a96044SJan Sjodin #include "flang/Optimizer/Transforms/Passes.h" 294bd08dabSFaris Rehman #include "flang/Parser/dump-parse-tree.h" 30d28de0d7SCaroline Concatto #include "flang/Parser/parsing.h" 31d28de0d7SCaroline Concatto #include "flang/Parser/provenance.h" 324c5906cfSCaroline Concatto #include "flang/Parser/source.h" 3396d229c9SAndrzej Warzynski #include "flang/Parser/unparse.h" 34eefda605SAndrzej Warzynski #include "flang/Semantics/runtime-type-info.h" 357d246cb1SAndrzej Warzynski #include "flang/Semantics/semantics.h" 3696d229c9SAndrzej Warzynski #include "flang/Semantics/unparse-with-symbols.h" 37132feb7cSAndrew Gozillon #include "flang/Tools/CrossToolHelpers.h" 3869c3309dSAndrzej Warzynski 3969c3309dSAndrzej Warzynski #include "mlir/IR/Dialect.h" 40cc3c6b61SAndrzej Warzynski #include "mlir/Parser/Parser.h" 4169c3309dSAndrzej Warzynski #include "mlir/Pass/PassManager.h" 4281181089SMats Petersson #include "mlir/Support/LLVM.h" 4381181089SMats Petersson #include "mlir/Target/LLVMIR/Import.h" 44e993b20cSAndrzej Warzynski #include "mlir/Target/LLVMIR/ModuleTranslation.h" 451e462fafSAndrzej Warzynski #include "clang/Basic/Diagnostic.h" 4602fb5b77SAndrzej Warzynski #include "clang/Basic/DiagnosticFrontend.h" 47b75e7c61SJan Leyonberg #include "clang/Basic/FileManager.h" 48b75e7c61SJan Leyonberg #include "clang/Basic/FileSystemOptions.h" 49f04ccadfSVictor Kingi #include "clang/Driver/DriverDiagnostic.h" 5033be8341SSergio Afonso #include "llvm/ADT/SmallString.h" 514bd08dabSFaris Rehman #include "llvm/ADT/StringRef.h" 5238101b4eSAndrzej Warzynski #include "llvm/Analysis/TargetLibraryInfo.h" 5338101b4eSAndrzej Warzynski #include "llvm/Analysis/TargetTransformInfo.h" 54dd56939aSAndrzej Warzynski #include "llvm/Bitcode/BitcodeWriterPass.h" 55e87d2d2cSVictor Kingi #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" 56f04ccadfSVictor Kingi #include "llvm/IR/LLVMRemarkStreamer.h" 5738101b4eSAndrzej Warzynski #include "llvm/IR/LegacyPassManager.h" 583e782ba2SAndrzej Warzynski #include "llvm/IR/Verifier.h" 599b468388SStephen Tozer #include "llvm/IRPrinter/IRPrintingPasses.h" 60bb177edcSAndrzej Warzynski #include "llvm/IRReader/IRReader.h" 61b75e7c61SJan Leyonberg #include "llvm/Linker/Linker.h" 6240d8c066SJan Sjodin #include "llvm/Object/OffloadBinary.h" 6338101b4eSAndrzej Warzynski #include "llvm/Passes/PassBuilder.h" 64c3821b8dSTarun Prabhu #include "llvm/Passes/PassPlugin.h" 65869385b1SAndrzej Warzynski #include "llvm/Passes/StandardInstrumentations.h" 66276a024bSDominik Adamski #include "llvm/Support/AMDGPUAddrSpace.h" 67f04ccadfSVictor Kingi #include "llvm/Support/Error.h" 68dc256a44SAndrzej Warzynski #include "llvm/Support/ErrorHandling.h" 6933be8341SSergio Afonso #include "llvm/Support/FileSystem.h" 7033be8341SSergio Afonso #include "llvm/Support/Path.h" 71bb177edcSAndrzej Warzynski #include "llvm/Support/SourceMgr.h" 7233be8341SSergio Afonso #include "llvm/Support/ToolOutputFile.h" 7338101b4eSAndrzej Warzynski #include "llvm/Target/TargetMachine.h" 74733a8778SCraig Topper #include "llvm/TargetParser/RISCVISAInfo.h" 75c4b591a1SLuke Lau #include "llvm/TargetParser/RISCVTargetParser.h" 76b75e7c61SJan Leyonberg #include "llvm/Transforms/IPO/Internalize.h" 7740d8c066SJan Sjodin #include "llvm/Transforms/Utils/ModuleUtils.h" 784bd08dabSFaris Rehman #include <memory> 7933be8341SSergio Afonso #include <system_error> 804c5906cfSCaroline Concatto 81a1441ca7STarun Prabhu namespace llvm { 82a1441ca7STarun Prabhu extern cl::opt<bool> PrintPipelinePasses; 83a1441ca7STarun Prabhu } // namespace llvm 84a1441ca7STarun Prabhu 854c5906cfSCaroline Concatto using namespace Fortran::frontend; 864c5906cfSCaroline Concatto 87310c281bSmacurtis-amd constexpr llvm::StringLiteral timingIdParse = "Parse"; 88310c281bSmacurtis-amd constexpr llvm::StringLiteral timingIdMLIRGen = "MLIR generation"; 89310c281bSmacurtis-amd constexpr llvm::StringLiteral timingIdMLIRPasses = 90310c281bSmacurtis-amd "MLIR translation/optimization"; 91310c281bSmacurtis-amd constexpr llvm::StringLiteral timingIdLLVMIRGen = "LLVM IR generation"; 92310c281bSmacurtis-amd constexpr llvm::StringLiteral timingIdLLVMIRPasses = "LLVM IR optimizations"; 93310c281bSmacurtis-amd constexpr llvm::StringLiteral timingIdBackend = 94310c281bSmacurtis-amd "Assembly/Object code generation"; 95310c281bSmacurtis-amd 96d34dce25SUsman Nadeem // Declare plugin extension function declarations. 97d34dce25SUsman Nadeem #define HANDLE_EXTENSION(Ext) \ 98d34dce25SUsman Nadeem llvm::PassPluginLibraryInfo get##Ext##PluginInfo(); 99d34dce25SUsman Nadeem #include "llvm/Support/Extension.def" 100d34dce25SUsman Nadeem 10133be8341SSergio Afonso /// Save the given \c mlirModule to a temporary .mlir file, in a location 10233be8341SSergio Afonso /// decided by the -save-temps flag. No files are produced if the flag is not 10333be8341SSergio Afonso /// specified. 10433be8341SSergio Afonso static bool saveMLIRTempFile(const CompilerInvocation &ci, 10533be8341SSergio Afonso mlir::ModuleOp mlirModule, 10633be8341SSergio Afonso llvm::StringRef inputFile, 10733be8341SSergio Afonso llvm::StringRef outputTag) { 10833be8341SSergio Afonso if (!ci.getCodeGenOpts().SaveTempsDir.has_value()) 10933be8341SSergio Afonso return true; 11033be8341SSergio Afonso 11133be8341SSergio Afonso const llvm::StringRef compilerOutFile = ci.getFrontendOpts().outputFile; 11233be8341SSergio Afonso const llvm::StringRef saveTempsDir = ci.getCodeGenOpts().SaveTempsDir.value(); 11333be8341SSergio Afonso auto dir = llvm::StringSwitch<llvm::StringRef>(saveTempsDir) 11433be8341SSergio Afonso .Case("cwd", "") 11533be8341SSergio Afonso .Case("obj", llvm::sys::path::parent_path(compilerOutFile)) 11633be8341SSergio Afonso .Default(saveTempsDir); 11733be8341SSergio Afonso 11833be8341SSergio Afonso // Build path from the compiler output file name, triple, cpu and OpenMP 11933be8341SSergio Afonso // information 12033be8341SSergio Afonso llvm::SmallString<256> path(dir); 12133be8341SSergio Afonso llvm::sys::path::append(path, llvm::sys::path::stem(inputFile) + "-" + 12233be8341SSergio Afonso outputTag + ".mlir"); 12333be8341SSergio Afonso 12433be8341SSergio Afonso std::error_code ec; 12533be8341SSergio Afonso llvm::ToolOutputFile out(path, ec, llvm::sys::fs::OF_Text); 12633be8341SSergio Afonso if (ec) 12733be8341SSergio Afonso return false; 12833be8341SSergio Afonso 12933be8341SSergio Afonso mlirModule->print(out.os()); 13033be8341SSergio Afonso out.os().close(); 13133be8341SSergio Afonso out.keep(); 13233be8341SSergio Afonso 13333be8341SSergio Afonso return true; 13433be8341SSergio Afonso } 13533be8341SSergio Afonso 1364f21e6aeSAndrzej Warzynski //===----------------------------------------------------------------------===// 1374f21e6aeSAndrzej Warzynski // Custom BeginSourceFileAction 1384f21e6aeSAndrzej Warzynski //===----------------------------------------------------------------------===// 139bb177edcSAndrzej Warzynski 1401e462fafSAndrzej Warzynski bool PrescanAction::beginSourceFileAction() { return runPrescan(); } 1414f21e6aeSAndrzej Warzynski 1421e462fafSAndrzej Warzynski bool PrescanAndParseAction::beginSourceFileAction() { 143f2e80893SPeter Klausler return runPrescan() && runParse(/*emitMessages=*/true); 1444bd08dabSFaris Rehman } 1454bd08dabSFaris Rehman 1461e462fafSAndrzej Warzynski bool PrescanAndSemaAction::beginSourceFileAction() { 147f2e80893SPeter Klausler return runPrescan() && runParse(/*emitMessages=*/false) && 148f2e80893SPeter Klausler runSemanticChecks() && generateRtTypeTables(); 149dfce2909SAsher Mancinelli } 150dfce2909SAsher Mancinelli 1511e462fafSAndrzej Warzynski bool PrescanAndSemaDebugAction::beginSourceFileAction() { 15216a91a1cSAndrzej Warzynski // This is a "debug" action for development purposes. To facilitate this, the 15316a91a1cSAndrzej Warzynski // semantic checks are made to succeed unconditionally to prevent this action 15416a91a1cSAndrzej Warzynski // from exiting early (i.e. in the presence of semantic errors). We should 15516a91a1cSAndrzej Warzynski // never do this in actions intended for end-users or otherwise regular 15616a91a1cSAndrzej Warzynski // compiler workflows! 157f2e80893SPeter Klausler return runPrescan() && runParse(/*emitMessages=*/false) && 158f2e80893SPeter Klausler (runSemanticChecks() || true) && (generateRtTypeTables() || true); 1596f8ef1d6SAndrzej Warzynski } 1606f8ef1d6SAndrzej Warzynski 161c870632eSMatthias Springer static void addDependentLibs(mlir::ModuleOp mlirModule, CompilerInstance &ci) { 16277ecb9a4SDavid Truby const std::vector<std::string> &libs = 16377ecb9a4SDavid Truby ci.getInvocation().getCodeGenOpts().DependentLibs; 16477ecb9a4SDavid Truby if (libs.empty()) { 16577ecb9a4SDavid Truby return; 16677ecb9a4SDavid Truby } 16777ecb9a4SDavid Truby // dependent-lib is currently only supported on Windows, so the list should be 16877ecb9a4SDavid Truby // empty on non-Windows platforms 16977ecb9a4SDavid Truby assert( 17077ecb9a4SDavid Truby llvm::Triple(ci.getInvocation().getTargetOpts().triple).isOSWindows() && 17177ecb9a4SDavid Truby "--dependent-lib is only supported on Windows"); 17277ecb9a4SDavid Truby // Add linker options specified by --dependent-lib 17377ecb9a4SDavid Truby auto builder = mlir::OpBuilder(mlirModule.getRegion()); 17477ecb9a4SDavid Truby for (const std::string &lib : libs) { 17577ecb9a4SDavid Truby builder.create<mlir::LLVM::LinkerOptionsOp>( 1765e36c64cSDavid Truby mlirModule.getLoc(), builder.getStrArrayAttr({"/DEFAULTLIB:" + lib})); 17777ecb9a4SDavid Truby } 17877ecb9a4SDavid Truby } 17977ecb9a4SDavid Truby 18095943d2fSDominik Adamski // Add to MLIR code target specific items which are dependent on target 18195943d2fSDominik Adamski // configuration specified by the user. 18295943d2fSDominik Adamski // Clang equivalent function: AMDGPUTargetCodeGenInfo::emitTargetGlobals 183c870632eSMatthias Springer static void addAMDGPUSpecificMLIRItems(mlir::ModuleOp mlirModule, 18495943d2fSDominik Adamski CompilerInstance &ci) { 18595943d2fSDominik Adamski const TargetOptions &targetOpts = ci.getInvocation().getTargetOpts(); 18695943d2fSDominik Adamski const llvm::Triple triple(targetOpts.triple); 18795943d2fSDominik Adamski const llvm::StringRef codeObjectVersionGlobalOpName = "__oclc_ABI_version"; 18895943d2fSDominik Adamski 18995943d2fSDominik Adamski if (!triple.isAMDGPU()) { 19095943d2fSDominik Adamski return; 19195943d2fSDominik Adamski } 19295943d2fSDominik Adamski const CodeGenOptions &codeGenOpts = ci.getInvocation().getCodeGenOpts(); 19395943d2fSDominik Adamski if (codeGenOpts.CodeObjectVersion == llvm::CodeObjectVersionKind::COV_None) { 19495943d2fSDominik Adamski return; 19595943d2fSDominik Adamski } 19695943d2fSDominik Adamski 197a622b21fSMatthias Springer mlir::IRRewriter builder(mlirModule.getContext()); 19895943d2fSDominik Adamski unsigned oclcABIVERsion = codeGenOpts.CodeObjectVersion; 19995943d2fSDominik Adamski auto int32Type = builder.getI32Type(); 20095943d2fSDominik Adamski 20195943d2fSDominik Adamski std::optional<mlir::LLVM::GlobalOp> originalGV; 20295943d2fSDominik Adamski 20395943d2fSDominik Adamski mlirModule.walk([&originalGV, codeObjectVersionGlobalOpName]( 20495943d2fSDominik Adamski mlir::LLVM::GlobalOp globalOp) { 20595943d2fSDominik Adamski if (globalOp.getName() == codeObjectVersionGlobalOpName) 20695943d2fSDominik Adamski originalGV = globalOp; 20795943d2fSDominik Adamski }); 20895943d2fSDominik Adamski if (originalGV.has_value()) { 20995943d2fSDominik Adamski mlir::LLVM::GlobalOp originalGVOp = originalGV.value(); 21095943d2fSDominik Adamski if (originalGVOp.getLinkage() != mlir::LLVM::Linkage::External) { 21195943d2fSDominik Adamski return; 21295943d2fSDominik Adamski } 21395943d2fSDominik Adamski // Update the variable if it is already present in MLIR but it was marked 21495943d2fSDominik Adamski // as external linkage variable 21595943d2fSDominik Adamski originalGVOp.setLinkage(mlir::LLVM::Linkage::WeakODR); 21695943d2fSDominik Adamski originalGVOp.setValueAttr( 21795943d2fSDominik Adamski builder.getIntegerAttr(int32Type, oclcABIVERsion)); 21895943d2fSDominik Adamski originalGVOp.setUnnamedAddr(mlir::LLVM::UnnamedAddr::Local); 219276a024bSDominik Adamski originalGVOp.setAddrSpace(llvm::AMDGPUAS::CONSTANT_ADDRESS); 22095943d2fSDominik Adamski originalGVOp.setVisibility_(mlir::LLVM::Visibility::Hidden); 22195943d2fSDominik Adamski return; 22295943d2fSDominik Adamski } 22395943d2fSDominik Adamski 22495943d2fSDominik Adamski mlir::LLVM::GlobalOp covInfo = builder.create<mlir::LLVM::GlobalOp>( 22595943d2fSDominik Adamski /* Location */ mlirModule.getLoc(), /* Type */ int32Type, 22695943d2fSDominik Adamski /* IsConstant */ true, /* Linkage */ mlir::LLVM::Linkage::WeakODR, 22795943d2fSDominik Adamski /* Name */ codeObjectVersionGlobalOpName, 22895943d2fSDominik Adamski /* Value */ builder.getIntegerAttr(int32Type, oclcABIVERsion)); 22995943d2fSDominik Adamski covInfo.setUnnamedAddr(mlir::LLVM::UnnamedAddr::Local); 230276a024bSDominik Adamski covInfo.setAddrSpace(llvm::AMDGPUAS::CONSTANT_ADDRESS); 23195943d2fSDominik Adamski covInfo.setVisibility_(mlir::LLVM::Visibility::Hidden); 23295943d2fSDominik Adamski builder.setInsertionPointToStart(mlirModule.getBody()); 23395943d2fSDominik Adamski builder.insert(covInfo); 23495943d2fSDominik Adamski } 23595943d2fSDominik Adamski 2361e462fafSAndrzej Warzynski bool CodeGenAction::beginSourceFileAction() { 237b9f3b7f8SAndrzej Warzynski llvmCtx = std::make_unique<llvm::LLVMContext>(); 2383e782ba2SAndrzej Warzynski CompilerInstance &ci = this->getInstance(); 239310c281bSmacurtis-amd mlir::DefaultTimingManager &timingMgr = ci.getTimingManager(); 240310c281bSmacurtis-amd mlir::TimingScope &timingScopeRoot = ci.getTimingScopeRoot(); 241310c281bSmacurtis-amd 242310c281bSmacurtis-amd // This will provide timing information even when the input is an LLVM IR or 243310c281bSmacurtis-amd // MLIR file. That is fine because those do have to be parsed, so the label 244310c281bSmacurtis-amd // is still accurate. 245310c281bSmacurtis-amd mlir::TimingScope timingScopeParse = timingScopeRoot.nest( 246310c281bSmacurtis-amd mlir::TimingIdentifier::get(timingIdParse, timingMgr)); 247b9f3b7f8SAndrzej Warzynski 248b9f3b7f8SAndrzej Warzynski // If the input is an LLVM file, just parse it and return. 2491e462fafSAndrzej Warzynski if (this->getCurrentInput().getKind().getLanguage() == Language::LLVM_IR) { 250b9f3b7f8SAndrzej Warzynski llvm::SMDiagnostic err; 2511e462fafSAndrzej Warzynski llvmModule = llvm::parseIRFile(getCurrentInput().getFile(), err, *llvmCtx); 2523e782ba2SAndrzej Warzynski if (!llvmModule || llvm::verifyModule(*llvmModule, &llvm::errs())) { 25306eb10daSBrad Richardson err.print("flang", llvm::errs()); 2543e782ba2SAndrzej Warzynski unsigned diagID = ci.getDiagnostics().getCustomDiagID( 2553e782ba2SAndrzej Warzynski clang::DiagnosticsEngine::Error, "Could not parse IR"); 2563e782ba2SAndrzej Warzynski ci.getDiagnostics().Report(diagID); 2573e782ba2SAndrzej Warzynski return false; 2583e782ba2SAndrzej Warzynski } 259b9f3b7f8SAndrzej Warzynski 2603e782ba2SAndrzej Warzynski return true; 261b9f3b7f8SAndrzej Warzynski } 262b9f3b7f8SAndrzej Warzynski 263cc3c6b61SAndrzej Warzynski // Load the MLIR dialects required by Flang 264cc3c6b61SAndrzej Warzynski mlir::DialectRegistry registry; 265cc3c6b61SAndrzej Warzynski mlirCtx = std::make_unique<mlir::MLIRContext>(registry); 266cc3c6b61SAndrzej Warzynski fir::support::registerNonCodegenDialects(registry); 267cc3c6b61SAndrzej Warzynski fir::support::loadNonCodegenDialects(*mlirCtx); 268cc3c6b61SAndrzej Warzynski fir::support::loadDialects(*mlirCtx); 269cc3c6b61SAndrzej Warzynski fir::support::registerLLVMTranslation(*mlirCtx); 270cc3c6b61SAndrzej Warzynski 271e59e8488SjeanPerier const llvm::TargetMachine &targetMachine = ci.getTargetMachine(); 272e59e8488SjeanPerier 273cc3c6b61SAndrzej Warzynski // If the input is an MLIR file, just parse it and return. 274cc3c6b61SAndrzej Warzynski if (this->getCurrentInput().getKind().getLanguage() == Language::MLIR) { 275cc3c6b61SAndrzej Warzynski llvm::SourceMgr sourceMgr; 276cc3c6b61SAndrzej Warzynski llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> fileOrErr = 277cc3c6b61SAndrzej Warzynski llvm::MemoryBuffer::getFileOrSTDIN(getCurrentInput().getFile()); 278cc3c6b61SAndrzej Warzynski sourceMgr.AddNewSourceBuffer(std::move(*fileOrErr), llvm::SMLoc()); 279cc3c6b61SAndrzej Warzynski mlir::OwningOpRef<mlir::ModuleOp> module = 280cc3c6b61SAndrzej Warzynski mlir::parseSourceFile<mlir::ModuleOp>(sourceMgr, mlirCtx.get()); 281cc3c6b61SAndrzej Warzynski 282cc3c6b61SAndrzej Warzynski if (!module || mlir::failed(module->verifyInvariants())) { 283cc3c6b61SAndrzej Warzynski unsigned diagID = ci.getDiagnostics().getCustomDiagID( 284cc3c6b61SAndrzej Warzynski clang::DiagnosticsEngine::Error, "Could not parse FIR"); 285cc3c6b61SAndrzej Warzynski ci.getDiagnostics().Report(diagID); 286cc3c6b61SAndrzej Warzynski return false; 287cc3c6b61SAndrzej Warzynski } 288cc3c6b61SAndrzej Warzynski 289c870632eSMatthias Springer mlirModule = std::move(module); 290e59e8488SjeanPerier const llvm::DataLayout &dl = targetMachine.createDataLayout(); 291e59e8488SjeanPerier fir::support::setMLIRDataLayout(*mlirModule, dl); 292cc3c6b61SAndrzej Warzynski return true; 293cc3c6b61SAndrzej Warzynski } 294cc3c6b61SAndrzej Warzynski 295b9f3b7f8SAndrzej Warzynski // Otherwise, generate an MLIR module from the input Fortran source 2963e782ba2SAndrzej Warzynski if (getCurrentInput().getKind().getLanguage() != Language::Fortran) { 2973e782ba2SAndrzej Warzynski unsigned diagID = ci.getDiagnostics().getCustomDiagID( 2983e782ba2SAndrzej Warzynski clang::DiagnosticsEngine::Error, 299b9f3b7f8SAndrzej Warzynski "Invalid input type - expecting a Fortran file"); 3003e782ba2SAndrzej Warzynski ci.getDiagnostics().Report(diagID); 3013e782ba2SAndrzej Warzynski return false; 3023e782ba2SAndrzej Warzynski } 303f2e80893SPeter Klausler bool res = runPrescan() && runParse(/*emitMessages=*/false) && 304f2e80893SPeter Klausler runSemanticChecks() && generateRtTypeTables(); 30569c3309dSAndrzej Warzynski if (!res) 30669c3309dSAndrzej Warzynski return res; 30769c3309dSAndrzej Warzynski 308310c281bSmacurtis-amd timingScopeParse.stop(); 309310c281bSmacurtis-amd mlir::TimingScope timingScopeMLIRGen = timingScopeRoot.nest( 310310c281bSmacurtis-amd mlir::TimingIdentifier::get(timingIdMLIRGen, timingMgr)); 311310c281bSmacurtis-amd 31269c3309dSAndrzej Warzynski // Create a LoweringBridge 31369c3309dSAndrzej Warzynski const common::IntrinsicTypeDefaultKinds &defKinds = 314ae4d7ac9SAndrzej Warzyński ci.getSemanticsContext().defaultKinds(); 3158fc00247SValentin Clement fir::KindMapping kindMap(mlirCtx.get(), llvm::ArrayRef<fir::KindTy>{ 3168fc00247SValentin Clement fir::fromDefaultKinds(defKinds)}); 3171e462fafSAndrzej Warzynski lower::LoweringBridge lb = Fortran::lower::LoweringBridge::create( 318ae4d7ac9SAndrzej Warzyński *mlirCtx, ci.getSemanticsContext(), defKinds, 319ae4d7ac9SAndrzej Warzyński ci.getSemanticsContext().intrinsics(), 320ae4d7ac9SAndrzej Warzyński ci.getSemanticsContext().targetCharacteristics(), 3211e462fafSAndrzej Warzynski ci.getParsing().allCooked(), ci.getInvocation().getTargetOpts().triple, 3220ec3ac9bSJonathon Penix kindMap, ci.getInvocation().getLoweringOpts(), 3231c91d9bdSPeter Klausler ci.getInvocation().getFrontendOpts().envDefaults, 324f1d3fe7aSAlexis Perry-Holby ci.getInvocation().getFrontendOpts().features, targetMachine, 325839344f0STarun Prabhu ci.getInvocation().getTargetOpts(), ci.getInvocation().getCodeGenOpts()); 32669c3309dSAndrzej Warzynski 327e002a38bSAndrew Gozillon if (ci.getInvocation().getFrontendOpts().features.IsEnabled( 328e002a38bSAndrew Gozillon Fortran::common::LanguageFeature::OpenMP)) { 329c870632eSMatthias Springer setOffloadModuleInterfaceAttributes(lb.getModule(), 33053152f12SAndrew Gozillon ci.getInvocation().getLangOpts()); 331c870632eSMatthias Springer setOpenMPVersionAttribute(lb.getModule(), 332d93bdd8bSDominik Adamski ci.getInvocation().getLangOpts().OpenMPVersion); 333e002a38bSAndrew Gozillon } 334e002a38bSAndrew Gozillon 33569c3309dSAndrzej Warzynski // Create a parse tree and lower it to FIR 3361e462fafSAndrzej Warzynski Fortran::parser::Program &parseTree{*ci.getParsing().parseTree()}; 337ae4d7ac9SAndrzej Warzyński lb.lower(parseTree, ci.getSemanticsContext()); 33869c3309dSAndrzej Warzynski 339c870632eSMatthias Springer // Fetch module from lb, so we can set 340c870632eSMatthias Springer mlirModule = lb.getModuleAndRelease(); 341c870632eSMatthias Springer 34295943d2fSDominik Adamski // Add target specific items like dependent libraries, target specific 34395943d2fSDominik Adamski // constants etc. 34495943d2fSDominik Adamski addDependentLibs(*mlirModule, ci); 34595943d2fSDominik Adamski addAMDGPUSpecificMLIRItems(*mlirModule, ci); 346310c281bSmacurtis-amd timingScopeMLIRGen.stop(); 34777ecb9a4SDavid Truby 3481e462fafSAndrzej Warzynski // run the default passes. 34994a30928Srkayaith mlir::PassManager pm((*mlirModule)->getName(), 35094a30928Srkayaith mlir::OpPassManager::Nesting::Implicit); 3510ea0ecd6SjeanPerier (void)mlir::applyPassManagerCLOptions(pm); 35245a96044SJan Sjodin // Add OpenMP-related passes 35345a96044SJan Sjodin // WARNING: These passes must be run immediately after the lowering to ensure 35445a96044SJan Sjodin // that the FIR is correct with respect to OpenMP operations/attributes. 35545a96044SJan Sjodin if (ci.getInvocation().getFrontendOpts().features.IsEnabled( 35645a96044SJan Sjodin Fortran::common::LanguageFeature::OpenMP)) { 35745a96044SJan Sjodin bool isDevice = false; 35845a96044SJan Sjodin if (auto offloadMod = llvm::dyn_cast<mlir::omp::OffloadModuleInterface>( 35945a96044SJan Sjodin mlirModule->getOperation())) 36045a96044SJan Sjodin isDevice = offloadMod.getIsTargetDevice(); 361fb4bdf36SSergio Afonso // WARNING: This pipeline must be run immediately after the lowering to 362fb4bdf36SSergio Afonso // ensure that the FIR is correct with respect to OpenMP operations/ 363fb4bdf36SSergio Afonso // attributes. 364fb4bdf36SSergio Afonso fir::createOpenMPFIRPassPipeline(pm, isDevice); 36564f5a764SAndrew Gozillon } 36645a96044SJan Sjodin 36769c3309dSAndrzej Warzynski pm.enableVerifier(/*verifyPasses=*/true); 36869c3309dSAndrzej Warzynski pm.addPass(std::make_unique<Fortran::lower::VerifierPass>()); 369310c281bSmacurtis-amd pm.enableTiming(timingScopeMLIRGen); 37069c3309dSAndrzej Warzynski 37169c3309dSAndrzej Warzynski if (mlir::failed(pm.run(*mlirModule))) { 3721e462fafSAndrzej Warzynski unsigned diagID = ci.getDiagnostics().getCustomDiagID( 3731e462fafSAndrzej Warzynski clang::DiagnosticsEngine::Error, 37469c3309dSAndrzej Warzynski "verification of lowering to FIR failed"); 3751e462fafSAndrzej Warzynski ci.getDiagnostics().Report(diagID); 37669c3309dSAndrzej Warzynski return false; 37769c3309dSAndrzej Warzynski } 378310c281bSmacurtis-amd timingScopeMLIRGen.stop(); 37969c3309dSAndrzej Warzynski 38033be8341SSergio Afonso // Print initial full MLIR module, before lowering or transformations, if 38133be8341SSergio Afonso // -save-temps has been specified. 38233be8341SSergio Afonso if (!saveMLIRTempFile(ci.getInvocation(), *mlirModule, getCurrentFile(), 38333be8341SSergio Afonso "fir")) { 38433be8341SSergio Afonso unsigned diagID = ci.getDiagnostics().getCustomDiagID( 38533be8341SSergio Afonso clang::DiagnosticsEngine::Error, "Saving MLIR temp file failed"); 38633be8341SSergio Afonso ci.getDiagnostics().Report(diagID); 38733be8341SSergio Afonso return false; 38833be8341SSergio Afonso } 38933be8341SSergio Afonso 39069c3309dSAndrzej Warzynski return true; 39169c3309dSAndrzej Warzynski } 39269c3309dSAndrzej Warzynski 3934f21e6aeSAndrzej Warzynski //===----------------------------------------------------------------------===// 3944f21e6aeSAndrzej Warzynski // Custom ExecuteAction 3954f21e6aeSAndrzej Warzynski //===----------------------------------------------------------------------===// 3961e462fafSAndrzej Warzynski void InputOutputTestAction::executeAction() { 3971e462fafSAndrzej Warzynski CompilerInstance &ci = getInstance(); 398ba000628SAndrzej Warzynski 399ba000628SAndrzej Warzynski // Create a stream for errors 4004c5906cfSCaroline Concatto std::string buf; 4011e462fafSAndrzej Warzynski llvm::raw_string_ostream errorStream{buf}; 4024c5906cfSCaroline Concatto 403ba000628SAndrzej Warzynski // Read the input file 4041e462fafSAndrzej Warzynski Fortran::parser::AllSources &allSources{ci.getAllSources()}; 4051e462fafSAndrzej Warzynski std::string path{getCurrentFileOrBufferName()}; 4064c5906cfSCaroline Concatto const Fortran::parser::SourceFile *sf; 407ba000628SAndrzej Warzynski if (path == "-") 4081e462fafSAndrzej Warzynski sf = allSources.ReadStandardInput(errorStream); 409ba000628SAndrzej Warzynski else 4101e462fafSAndrzej Warzynski sf = allSources.Open(path, errorStream, std::optional<std::string>{"."s}); 4114c5906cfSCaroline Concatto llvm::ArrayRef<char> fileContent = sf->content(); 4124c5906cfSCaroline Concatto 413ba000628SAndrzej Warzynski // Output file descriptor to receive the contents of the input file. 4144c5906cfSCaroline Concatto std::unique_ptr<llvm::raw_ostream> os; 4154c5906cfSCaroline Concatto 416ba000628SAndrzej Warzynski // Copy the contents from the input file to the output file 4171e462fafSAndrzej Warzynski if (!ci.isOutputStreamNull()) { 418ba000628SAndrzej Warzynski // An output stream (outputStream_) was set earlier 4191e462fafSAndrzej Warzynski ci.writeOutputStream(fileContent.data()); 420ba000628SAndrzej Warzynski } else { 421ba000628SAndrzej Warzynski // No pre-set output stream - create an output file 4221e462fafSAndrzej Warzynski os = ci.createDefaultOutputFile( 4231e462fafSAndrzej Warzynski /*binary=*/true, getCurrentFileOrBufferName(), "txt"); 4244c5906cfSCaroline Concatto if (!os) 4254c5906cfSCaroline Concatto return; 4264c5906cfSCaroline Concatto (*os) << fileContent.data(); 4274c5906cfSCaroline Concatto } 4284c5906cfSCaroline Concatto } 429d28de0d7SCaroline Concatto 4301e462fafSAndrzej Warzynski void PrintPreprocessedAction::executeAction() { 431d28de0d7SCaroline Concatto std::string buf; 432d28de0d7SCaroline Concatto llvm::raw_string_ostream outForPP{buf}; 433d28de0d7SCaroline Concatto 4343338ef93Speter klausler // Format or dump the prescanner's output 4351e462fafSAndrzej Warzynski CompilerInstance &ci = this->getInstance(); 4367d60232bSKrzysztof Parzyszek if (ci.getInvocation().getPreprocessorOpts().showMacros) { 4377d60232bSKrzysztof Parzyszek ci.getParsing().EmitPreprocessorMacros(outForPP); 4387d60232bSKrzysztof Parzyszek } else if (ci.getInvocation().getPreprocessorOpts().noReformat) { 4391e462fafSAndrzej Warzynski ci.getParsing().DumpCookedChars(outForPP); 4403338ef93Speter klausler } else { 4411e462fafSAndrzej Warzynski ci.getParsing().EmitPreprocessedSource( 4421e462fafSAndrzej Warzynski outForPP, !ci.getInvocation().getPreprocessorOpts().noLineDirectives); 4433338ef93Speter klausler } 444d28de0d7SCaroline Concatto 4451e462fafSAndrzej Warzynski // Print getDiagnostics from the prescanner 4461e462fafSAndrzej Warzynski ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources()); 447787c443aSAndrzej Warzynski 448d28de0d7SCaroline Concatto // If a pre-defined output stream exists, dump the preprocessed content there 4491e462fafSAndrzej Warzynski if (!ci.isOutputStreamNull()) { 450d28de0d7SCaroline Concatto // Send the output to the pre-defined output buffer. 45184d7f294SYoungsuk Kim ci.writeOutputStream(buf); 452d28de0d7SCaroline Concatto return; 453d28de0d7SCaroline Concatto } 454d28de0d7SCaroline Concatto 455316be03fSAndrzej Warzynski // Create a file and save the preprocessed output there 4561e462fafSAndrzej Warzynski std::unique_ptr<llvm::raw_pwrite_stream> os{ci.createDefaultOutputFile( 4571e462fafSAndrzej Warzynski /*Binary=*/true, /*InFile=*/getCurrentFileOrBufferName())}; 458787c443aSAndrzej Warzynski if (!os) { 459787c443aSAndrzej Warzynski return; 460316be03fSAndrzej Warzynski } 461787c443aSAndrzej Warzynski 46284d7f294SYoungsuk Kim (*os) << buf; 463d28de0d7SCaroline Concatto } 4647d246cb1SAndrzej Warzynski 4651e462fafSAndrzej Warzynski void DebugDumpProvenanceAction::executeAction() { 4661e462fafSAndrzej Warzynski this->getInstance().getParsing().DumpProvenance(llvm::outs()); 4674bd08dabSFaris Rehman } 4684bd08dabSFaris Rehman 4691e462fafSAndrzej Warzynski void ParseSyntaxOnlyAction::executeAction() {} 4707d246cb1SAndrzej Warzynski 4711e462fafSAndrzej Warzynski void DebugUnparseNoSemaAction::executeAction() { 4721e462fafSAndrzej Warzynski auto &invoc = this->getInstance().getInvocation(); 4731e462fafSAndrzej Warzynski auto &parseTree{getInstance().getParsing().parseTree()}; 474e81b3401SAndrzej Warzynski 475e81b3401SAndrzej Warzynski // TODO: Options should come from CompilerInvocation 476e81b3401SAndrzej Warzynski Unparse(llvm::outs(), *parseTree, 477e81b3401SAndrzej Warzynski /*encoding=*/Fortran::parser::Encoding::UTF_8, 478e81b3401SAndrzej Warzynski /*capitalizeKeywords=*/true, /*backslashEscapes=*/false, 4792a7bb849SAndrzej Warzynski /*preStatement=*/nullptr, 4801e462fafSAndrzej Warzynski invoc.getUseAnalyzedObjectsForUnparse() ? &invoc.getAsFortran() 4811e462fafSAndrzej Warzynski : nullptr); 482e81b3401SAndrzej Warzynski } 483e81b3401SAndrzej Warzynski 4841e462fafSAndrzej Warzynski void DebugUnparseAction::executeAction() { 4851e462fafSAndrzej Warzynski auto &invoc = this->getInstance().getInvocation(); 4861e462fafSAndrzej Warzynski auto &parseTree{getInstance().getParsing().parseTree()}; 487e49dc298SAndrzej Warzynski 4881e462fafSAndrzej Warzynski CompilerInstance &ci = this->getInstance(); 4891e462fafSAndrzej Warzynski auto os{ci.createDefaultOutputFile( 4901e462fafSAndrzej Warzynski /*Binary=*/false, /*InFile=*/getCurrentFileOrBufferName())}; 491e77191c3SAndrzej Warzynski 49296d229c9SAndrzej Warzynski // TODO: Options should come from CompilerInvocation 493e77191c3SAndrzej Warzynski Unparse(*os, *parseTree, 49496d229c9SAndrzej Warzynski /*encoding=*/Fortran::parser::Encoding::UTF_8, 49596d229c9SAndrzej Warzynski /*capitalizeKeywords=*/true, /*backslashEscapes=*/false, 4962a7bb849SAndrzej Warzynski /*preStatement=*/nullptr, 4971e462fafSAndrzej Warzynski invoc.getUseAnalyzedObjectsForUnparse() ? &invoc.getAsFortran() 4981e462fafSAndrzej Warzynski : nullptr); 4994bd08dabSFaris Rehman 5004bd08dabSFaris Rehman // Report fatal semantic errors 5014f21e6aeSAndrzej Warzynski reportFatalSemanticErrors(); 502e49dc298SAndrzej Warzynski } 503e49dc298SAndrzej Warzynski 5041e462fafSAndrzej Warzynski void DebugUnparseWithSymbolsAction::executeAction() { 5051e462fafSAndrzej Warzynski auto &parseTree{*getInstance().getParsing().parseTree()}; 506a8f51ea2SFaris Rehman 50796d229c9SAndrzej Warzynski Fortran::semantics::UnparseWithSymbols( 50896d229c9SAndrzej Warzynski llvm::outs(), parseTree, /*encoding=*/Fortran::parser::Encoding::UTF_8); 5094bd08dabSFaris Rehman 5104bd08dabSFaris Rehman // Report fatal semantic errors 5114f21e6aeSAndrzej Warzynski reportFatalSemanticErrors(); 5124bd08dabSFaris Rehman } 5134bd08dabSFaris Rehman 514e00a3ccfSPeter Klausler void DebugUnparseWithModulesAction::executeAction() { 515e00a3ccfSPeter Klausler auto &parseTree{*getInstance().getParsing().parseTree()}; 516e00a3ccfSPeter Klausler CompilerInstance &ci{getInstance()}; 517e00a3ccfSPeter Klausler Fortran::semantics::UnparseWithModules( 518e00a3ccfSPeter Klausler llvm::outs(), ci.getSemantics().context(), parseTree, 519e00a3ccfSPeter Klausler /*encoding=*/Fortran::parser::Encoding::UTF_8); 520e00a3ccfSPeter Klausler reportFatalSemanticErrors(); 521e00a3ccfSPeter Klausler } 522e00a3ccfSPeter Klausler 5231e462fafSAndrzej Warzynski void DebugDumpSymbolsAction::executeAction() { 5241e462fafSAndrzej Warzynski CompilerInstance &ci = this->getInstance(); 5254bd08dabSFaris Rehman 52616a91a1cSAndrzej Warzynski if (!ci.getRtTyTables().schemata) { 5271e462fafSAndrzej Warzynski unsigned diagID = ci.getDiagnostics().getCustomDiagID( 5281e462fafSAndrzej Warzynski clang::DiagnosticsEngine::Error, 529499f1ed5SAndrzej Warzynski "could not find module file for __fortran_type_info"); 5301e462fafSAndrzej Warzynski ci.getDiagnostics().Report(diagID); 531499f1ed5SAndrzej Warzynski llvm::errs() << "\n"; 53216a91a1cSAndrzej Warzynski return; 533499f1ed5SAndrzej Warzynski } 534499f1ed5SAndrzej Warzynski 5354bd08dabSFaris Rehman // Dump symbols 5361e462fafSAndrzej Warzynski ci.getSemantics().DumpSymbols(llvm::outs()); 5374bd08dabSFaris Rehman } 5384bd08dabSFaris Rehman 5391e462fafSAndrzej Warzynski void DebugDumpAllAction::executeAction() { 5401e462fafSAndrzej Warzynski CompilerInstance &ci = this->getInstance(); 541a6be6e31SAndrzej Warzynski 542a6be6e31SAndrzej Warzynski // Dump parse tree 5431e462fafSAndrzej Warzynski auto &parseTree{getInstance().getParsing().parseTree()}; 544a6be6e31SAndrzej Warzynski llvm::outs() << "========================"; 545a6be6e31SAndrzej Warzynski llvm::outs() << " Flang: parse tree dump "; 546a6be6e31SAndrzej Warzynski llvm::outs() << "========================\n"; 5471e462fafSAndrzej Warzynski Fortran::parser::DumpTree(llvm::outs(), parseTree, 5481e462fafSAndrzej Warzynski &ci.getInvocation().getAsFortran()); 549a6be6e31SAndrzej Warzynski 55016a91a1cSAndrzej Warzynski if (!ci.getRtTyTables().schemata) { 5511e462fafSAndrzej Warzynski unsigned diagID = ci.getDiagnostics().getCustomDiagID( 5521e462fafSAndrzej Warzynski clang::DiagnosticsEngine::Error, 553a6be6e31SAndrzej Warzynski "could not find module file for __fortran_type_info"); 5541e462fafSAndrzej Warzynski ci.getDiagnostics().Report(diagID); 555a6be6e31SAndrzej Warzynski llvm::errs() << "\n"; 55616a91a1cSAndrzej Warzynski return; 557a6be6e31SAndrzej Warzynski } 558a6be6e31SAndrzej Warzynski 559a6be6e31SAndrzej Warzynski // Dump symbols 560a6be6e31SAndrzej Warzynski llvm::outs() << "====================="; 561a6be6e31SAndrzej Warzynski llvm::outs() << " Flang: symbols dump "; 562a6be6e31SAndrzej Warzynski llvm::outs() << "=====================\n"; 5631e462fafSAndrzej Warzynski ci.getSemantics().DumpSymbols(llvm::outs()); 564a6be6e31SAndrzej Warzynski } 565a6be6e31SAndrzej Warzynski 5661e462fafSAndrzej Warzynski void DebugDumpParseTreeNoSemaAction::executeAction() { 5671e462fafSAndrzej Warzynski auto &parseTree{getInstance().getParsing().parseTree()}; 568e81b3401SAndrzej Warzynski 569e81b3401SAndrzej Warzynski // Dump parse tree 5702a7bb849SAndrzej Warzynski Fortran::parser::DumpTree( 5711e462fafSAndrzej Warzynski llvm::outs(), parseTree, 5721e462fafSAndrzej Warzynski &this->getInstance().getInvocation().getAsFortran()); 573e81b3401SAndrzej Warzynski } 574e81b3401SAndrzej Warzynski 5751e462fafSAndrzej Warzynski void DebugDumpParseTreeAction::executeAction() { 5761e462fafSAndrzej Warzynski auto &parseTree{getInstance().getParsing().parseTree()}; 5774bd08dabSFaris Rehman 5784bd08dabSFaris Rehman // Dump parse tree 5792a7bb849SAndrzej Warzynski Fortran::parser::DumpTree( 5801e462fafSAndrzej Warzynski llvm::outs(), parseTree, 5811e462fafSAndrzej Warzynski &this->getInstance().getInvocation().getAsFortran()); 5822a7bb849SAndrzej Warzynski 5834bd08dabSFaris Rehman // Report fatal semantic errors 5844f21e6aeSAndrzej Warzynski reportFatalSemanticErrors(); 5857d246cb1SAndrzej Warzynski } 586e5cdb6c5SAndrzej Warzynski 5871e462fafSAndrzej Warzynski void DebugMeasureParseTreeAction::executeAction() { 5881e462fafSAndrzej Warzynski CompilerInstance &ci = this->getInstance(); 589529f7181SFaris Rehman 590529f7181SFaris Rehman // Parse. In case of failure, report and return. 5911e462fafSAndrzej Warzynski ci.getParsing().Parse(llvm::outs()); 592529f7181SFaris Rehman 593d1ea605eSPeter Klausler if ((ci.getParsing().parseTree().has_value() && 594d1ea605eSPeter Klausler !ci.getParsing().consumedWholeFile()) || 595d1ea605eSPeter Klausler (!ci.getParsing().messages().empty() && 5961e462fafSAndrzej Warzynski (ci.getInvocation().getWarnAsErr() || 597d1ea605eSPeter Klausler ci.getParsing().messages().AnyFatalError()))) { 5981e462fafSAndrzej Warzynski unsigned diagID = ci.getDiagnostics().getCustomDiagID( 599529f7181SFaris Rehman clang::DiagnosticsEngine::Error, "Could not parse %0"); 6001e462fafSAndrzej Warzynski ci.getDiagnostics().Report(diagID) << getCurrentFileOrBufferName(); 601529f7181SFaris Rehman 6021e462fafSAndrzej Warzynski ci.getParsing().messages().Emit(llvm::errs(), 6031e462fafSAndrzej Warzynski this->getInstance().getAllCookedSources()); 604529f7181SFaris Rehman return; 605529f7181SFaris Rehman } 606529f7181SFaris Rehman 6071e462fafSAndrzej Warzynski // Report the getDiagnostics from parsing 6081e462fafSAndrzej Warzynski ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources()); 609529f7181SFaris Rehman 6101e462fafSAndrzej Warzynski auto &parseTree{*ci.getParsing().parseTree()}; 611529f7181SFaris Rehman 612529f7181SFaris Rehman // Measure the parse tree 613529f7181SFaris Rehman MeasurementVisitor visitor; 614529f7181SFaris Rehman Fortran::parser::Walk(parseTree, visitor); 615529f7181SFaris Rehman llvm::outs() << "Parse tree comprises " << visitor.objects 616529f7181SFaris Rehman << " objects and occupies " << visitor.bytes 617529f7181SFaris Rehman << " total bytes.\n"; 618529f7181SFaris Rehman } 619529f7181SFaris Rehman 6201e462fafSAndrzej Warzynski void DebugPreFIRTreeAction::executeAction() { 6211e462fafSAndrzej Warzynski CompilerInstance &ci = this->getInstance(); 622529f7181SFaris Rehman // Report and exit if fatal semantic errors are present 6234f21e6aeSAndrzej Warzynski if (reportFatalSemanticErrors()) { 624529f7181SFaris Rehman return; 625529f7181SFaris Rehman } 626529f7181SFaris Rehman 6271e462fafSAndrzej Warzynski auto &parseTree{*ci.getParsing().parseTree()}; 628529f7181SFaris Rehman 629529f7181SFaris Rehman // Dump pre-FIR tree 630ae4d7ac9SAndrzej Warzyński if (auto ast{ 631ae4d7ac9SAndrzej Warzyński Fortran::lower::createPFT(parseTree, ci.getSemanticsContext())}) { 632529f7181SFaris Rehman Fortran::lower::dumpPFT(llvm::outs(), *ast); 633529f7181SFaris Rehman } else { 6341e462fafSAndrzej Warzynski unsigned diagID = ci.getDiagnostics().getCustomDiagID( 635529f7181SFaris Rehman clang::DiagnosticsEngine::Error, "Pre FIR Tree is NULL."); 6361e462fafSAndrzej Warzynski ci.getDiagnostics().Report(diagID); 637529f7181SFaris Rehman } 638529f7181SFaris Rehman } 639529f7181SFaris Rehman 6401e462fafSAndrzej Warzynski void DebugDumpParsingLogAction::executeAction() { 6411e462fafSAndrzej Warzynski CompilerInstance &ci = this->getInstance(); 642523d7bc6SAndrzej Warzynski 6431e462fafSAndrzej Warzynski ci.getParsing().Parse(llvm::errs()); 6441e462fafSAndrzej Warzynski ci.getParsing().DumpParsingLog(llvm::outs()); 645523d7bc6SAndrzej Warzynski } 646523d7bc6SAndrzej Warzynski 6471e462fafSAndrzej Warzynski void GetDefinitionAction::executeAction() { 6481e462fafSAndrzej Warzynski CompilerInstance &ci = this->getInstance(); 649265a9961SAndrzej Warzynski 650dc256a44SAndrzej Warzynski // Report and exit if fatal semantic errors are present 6514f21e6aeSAndrzej Warzynski if (reportFatalSemanticErrors()) { 652dc256a44SAndrzej Warzynski return; 6534f21e6aeSAndrzej Warzynski } 654dc256a44SAndrzej Warzynski 6551e462fafSAndrzej Warzynski parser::AllCookedSources &cs = ci.getAllCookedSources(); 6561e462fafSAndrzej Warzynski unsigned diagID = ci.getDiagnostics().getCustomDiagID( 657dc256a44SAndrzej Warzynski clang::DiagnosticsEngine::Error, "Symbol not found"); 658dc256a44SAndrzej Warzynski 6591e462fafSAndrzej Warzynski auto gdv = ci.getInvocation().getFrontendOpts().getDefVals; 6608fc00247SValentin Clement auto charBlock{cs.GetCharBlockFromLineAndColumns(gdv.line, gdv.startColumn, 6618fc00247SValentin Clement gdv.endColumn)}; 662dc256a44SAndrzej Warzynski if (!charBlock) { 6631e462fafSAndrzej Warzynski ci.getDiagnostics().Report(diagID); 664dc256a44SAndrzej Warzynski return; 665dc256a44SAndrzej Warzynski } 666dc256a44SAndrzej Warzynski 667dc256a44SAndrzej Warzynski llvm::outs() << "String range: >" << charBlock->ToString() << "<\n"; 668dc256a44SAndrzej Warzynski 669ae4d7ac9SAndrzej Warzyński auto *symbol{ 670ae4d7ac9SAndrzej Warzyński ci.getSemanticsContext().FindScope(*charBlock).FindSymbol(*charBlock)}; 671dc256a44SAndrzej Warzynski if (!symbol) { 6721e462fafSAndrzej Warzynski ci.getDiagnostics().Report(diagID); 673dc256a44SAndrzej Warzynski return; 674dc256a44SAndrzej Warzynski } 675dc256a44SAndrzej Warzynski 676dc256a44SAndrzej Warzynski llvm::outs() << "Found symbol name: " << symbol->name().ToString() << "\n"; 677dc256a44SAndrzej Warzynski 678dc256a44SAndrzej Warzynski auto sourceInfo{cs.GetSourcePositionRange(symbol->name())}; 679dc256a44SAndrzej Warzynski if (!sourceInfo) { 680dc256a44SAndrzej Warzynski llvm_unreachable( 681dc256a44SAndrzej Warzynski "Failed to obtain SourcePosition." 682dc256a44SAndrzej Warzynski "TODO: Please, write a test and replace this with a diagnostic!"); 683dc256a44SAndrzej Warzynski return; 684dc256a44SAndrzej Warzynski } 685dc256a44SAndrzej Warzynski 686dc256a44SAndrzej Warzynski llvm::outs() << "Found symbol name: " << symbol->name().ToString() << "\n"; 687e12ffe6aSPeter Klausler llvm::outs() << symbol->name().ToString() << ": " << sourceInfo->first.path 688e12ffe6aSPeter Klausler << ", " << sourceInfo->first.line << ", " 689e12ffe6aSPeter Klausler << sourceInfo->first.column << "-" << sourceInfo->second.column 690e12ffe6aSPeter Klausler << "\n"; 691dc256a44SAndrzej Warzynski } 692dc256a44SAndrzej Warzynski 6931e462fafSAndrzej Warzynski void GetSymbolsSourcesAction::executeAction() { 6941e462fafSAndrzej Warzynski CompilerInstance &ci = this->getInstance(); 695265a9961SAndrzej Warzynski 696eefda605SAndrzej Warzynski // Report and exit if fatal semantic errors are present 6974f21e6aeSAndrzej Warzynski if (reportFatalSemanticErrors()) { 698eefda605SAndrzej Warzynski return; 6994f21e6aeSAndrzej Warzynski } 700eefda605SAndrzej Warzynski 7011e462fafSAndrzej Warzynski ci.getSemantics().DumpSymbolsSources(llvm::outs()); 702eefda605SAndrzej Warzynski } 703eefda605SAndrzej Warzynski 704bb177edcSAndrzej Warzynski //===----------------------------------------------------------------------===// 705bb177edcSAndrzej Warzynski // CodeGenActions 706bb177edcSAndrzej Warzynski //===----------------------------------------------------------------------===// 707bb177edcSAndrzej Warzynski 708bb177edcSAndrzej Warzynski CodeGenAction::~CodeGenAction() = default; 709bb177edcSAndrzej Warzynski 7109c0acc42SSlava Zakharin static llvm::OptimizationLevel 7119c0acc42SSlava Zakharin mapToLevel(const Fortran::frontend::CodeGenOptions &opts) { 7129c0acc42SSlava Zakharin switch (opts.OptimizationLevel) { 7139c0acc42SSlava Zakharin default: 7149c0acc42SSlava Zakharin llvm_unreachable("Invalid optimization level!"); 7159c0acc42SSlava Zakharin case 0: 7169c0acc42SSlava Zakharin return llvm::OptimizationLevel::O0; 7179c0acc42SSlava Zakharin case 1: 7189c0acc42SSlava Zakharin return llvm::OptimizationLevel::O1; 7199c0acc42SSlava Zakharin case 2: 7209c0acc42SSlava Zakharin return llvm::OptimizationLevel::O2; 7219c0acc42SSlava Zakharin case 3: 7229c0acc42SSlava Zakharin return llvm::OptimizationLevel::O3; 7239c0acc42SSlava Zakharin } 7249c0acc42SSlava Zakharin } 7259c0acc42SSlava Zakharin 72639ecf9d8STom Eccles // Lower using HLFIR then run the FIR to HLFIR pipeline 72739ecf9d8STom Eccles void CodeGenAction::lowerHLFIRToFIR() { 72839ecf9d8STom Eccles assert(mlirModule && "The MLIR module has not been generated yet."); 72939ecf9d8STom Eccles 73039ecf9d8STom Eccles CompilerInstance &ci = this->getInstance(); 731310c281bSmacurtis-amd const CodeGenOptions &opts = ci.getInvocation().getCodeGenOpts(); 73239ecf9d8STom Eccles llvm::OptimizationLevel level = mapToLevel(opts); 733310c281bSmacurtis-amd mlir::DefaultTimingManager &timingMgr = ci.getTimingManager(); 734310c281bSmacurtis-amd mlir::TimingScope &timingScopeRoot = ci.getTimingScopeRoot(); 73539ecf9d8STom Eccles 73639ecf9d8STom Eccles fir::support::loadDialects(*mlirCtx); 73739ecf9d8STom Eccles 73839ecf9d8STom Eccles // Set-up the MLIR pass manager 73939ecf9d8STom Eccles mlir::PassManager pm((*mlirModule)->getName(), 74039ecf9d8STom Eccles mlir::OpPassManager::Nesting::Implicit); 74139ecf9d8STom Eccles 74239ecf9d8STom Eccles pm.addPass(std::make_unique<Fortran::lower::VerifierPass>()); 74339ecf9d8STom Eccles pm.enableVerifier(/*verifyPasses=*/true); 74439ecf9d8STom Eccles 74539ecf9d8STom Eccles // Create the pass pipeline 746e7e55416SIvan R. Ivanov fir::createHLFIRToFIRPassPipeline( 747e7e55416SIvan R. Ivanov pm, 748e7e55416SIvan R. Ivanov ci.getInvocation().getFrontendOpts().features.IsEnabled( 749e7e55416SIvan R. Ivanov Fortran::common::LanguageFeature::OpenMP), 750e7e55416SIvan R. Ivanov level); 75139ecf9d8STom Eccles (void)mlir::applyPassManagerCLOptions(pm); 75239ecf9d8STom Eccles 753310c281bSmacurtis-amd mlir::TimingScope timingScopeMLIRPasses = timingScopeRoot.nest( 754310c281bSmacurtis-amd mlir::TimingIdentifier::get(timingIdMLIRPasses, timingMgr)); 755310c281bSmacurtis-amd pm.enableTiming(timingScopeMLIRPasses); 75639ecf9d8STom Eccles if (!mlir::succeeded(pm.run(*mlirModule))) { 75739ecf9d8STom Eccles unsigned diagID = ci.getDiagnostics().getCustomDiagID( 75839ecf9d8STom Eccles clang::DiagnosticsEngine::Error, "Lowering to FIR failed"); 75939ecf9d8STom Eccles ci.getDiagnostics().Report(diagID); 76039ecf9d8STom Eccles } 76139ecf9d8STom Eccles } 76239ecf9d8STom Eccles 7636180964aSMats Petersson static std::optional<std::pair<unsigned, unsigned>> 764c4b591a1SLuke Lau getAArch64VScaleRange(CompilerInstance &ci) { 765898db113SPhilip Reames const auto &langOpts = ci.getInvocation().getLangOpts(); 766c4b591a1SLuke Lau 7676180964aSMats Petersson if (langOpts.VScaleMin || langOpts.VScaleMax) 7686180964aSMats Petersson return std::pair<unsigned, unsigned>( 7696180964aSMats Petersson langOpts.VScaleMin ? langOpts.VScaleMin : 1, langOpts.VScaleMax); 7706180964aSMats Petersson 771e59e8488SjeanPerier std::string featuresStr = ci.getTargetFeatures(); 7726180964aSMats Petersson if (featuresStr.find("+sve") != std::string::npos) 7736180964aSMats Petersson return std::pair<unsigned, unsigned>(1, 16); 7746180964aSMats Petersson 7756180964aSMats Petersson return std::nullopt; 7766180964aSMats Petersson } 7776180964aSMats Petersson 778c4b591a1SLuke Lau static std::optional<std::pair<unsigned, unsigned>> 779c4b591a1SLuke Lau getRISCVVScaleRange(CompilerInstance &ci) { 780c4b591a1SLuke Lau const auto &langOpts = ci.getInvocation().getLangOpts(); 781c4b591a1SLuke Lau const auto targetOpts = ci.getInvocation().getTargetOpts(); 782c4b591a1SLuke Lau const llvm::Triple triple(targetOpts.triple); 783c4b591a1SLuke Lau 784c4b591a1SLuke Lau auto parseResult = llvm::RISCVISAInfo::parseFeatures( 785c4b591a1SLuke Lau triple.isRISCV64() ? 64 : 32, targetOpts.featuresAsWritten); 786c4b591a1SLuke Lau if (!parseResult) { 787c4b591a1SLuke Lau std::string buffer; 788c4b591a1SLuke Lau llvm::raw_string_ostream outputErrMsg(buffer); 789c4b591a1SLuke Lau handleAllErrors(parseResult.takeError(), [&](llvm::StringError &errMsg) { 790c4b591a1SLuke Lau outputErrMsg << errMsg.getMessage(); 791c4b591a1SLuke Lau }); 792c4b591a1SLuke Lau ci.getDiagnostics().Report(clang::diag::err_invalid_feature_combination) 79384d7f294SYoungsuk Kim << buffer; 794c4b591a1SLuke Lau return std::nullopt; 795c4b591a1SLuke Lau } 796c4b591a1SLuke Lau 797c4b591a1SLuke Lau llvm::RISCVISAInfo *const isaInfo = parseResult->get(); 798c4b591a1SLuke Lau 799c4b591a1SLuke Lau // RISCV::RVVBitsPerBlock is 64. 800c4b591a1SLuke Lau unsigned vscaleMin = isaInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock; 801c4b591a1SLuke Lau 802c4b591a1SLuke Lau if (langOpts.VScaleMin || langOpts.VScaleMax) { 803c4b591a1SLuke Lau // Treat Zvl*b as a lower bound on vscale. 804c4b591a1SLuke Lau vscaleMin = std::max(vscaleMin, langOpts.VScaleMin); 805c4b591a1SLuke Lau unsigned vscaleMax = langOpts.VScaleMax; 806c4b591a1SLuke Lau if (vscaleMax != 0 && vscaleMax < vscaleMin) 807c4b591a1SLuke Lau vscaleMax = vscaleMin; 808c4b591a1SLuke Lau return std::pair<unsigned, unsigned>(vscaleMin ? vscaleMin : 1, vscaleMax); 809c4b591a1SLuke Lau } 810c4b591a1SLuke Lau 811c4b591a1SLuke Lau if (vscaleMin > 0) { 812c4b591a1SLuke Lau unsigned vscaleMax = isaInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock; 813c4b591a1SLuke Lau return std::make_pair(vscaleMin, vscaleMax); 814c4b591a1SLuke Lau } 815c4b591a1SLuke Lau 816c4b591a1SLuke Lau return std::nullopt; 817c4b591a1SLuke Lau } 818c4b591a1SLuke Lau 819c4b591a1SLuke Lau // TODO: We should get this from TargetInfo. However, that depends on 820c4b591a1SLuke Lau // too much of clang, so for now, replicate the functionality. 821c4b591a1SLuke Lau static std::optional<std::pair<unsigned, unsigned>> 822c4b591a1SLuke Lau getVScaleRange(CompilerInstance &ci) { 823c4b591a1SLuke Lau const llvm::Triple triple(ci.getInvocation().getTargetOpts().triple); 824c4b591a1SLuke Lau 825c4b591a1SLuke Lau if (triple.isAArch64()) 826c4b591a1SLuke Lau return getAArch64VScaleRange(ci); 827c4b591a1SLuke Lau if (triple.isRISCV()) 828c4b591a1SLuke Lau return getRISCVVScaleRange(ci); 829c4b591a1SLuke Lau 830219c14a2SLuke Lau // All other architectures that don't support scalable vectors (i.e. don't 831219c14a2SLuke Lau // need vscale) 832c4b591a1SLuke Lau return std::nullopt; 833c4b591a1SLuke Lau } 834c4b591a1SLuke Lau 835e993b20cSAndrzej Warzynski // Lower the previously generated MLIR module into an LLVM IR module 8361e462fafSAndrzej Warzynski void CodeGenAction::generateLLVMIR() { 837e993b20cSAndrzej Warzynski assert(mlirModule && "The MLIR module has not been generated yet."); 838e993b20cSAndrzej Warzynski 8391e462fafSAndrzej Warzynski CompilerInstance &ci = this->getInstance(); 840310c281bSmacurtis-amd CompilerInvocation &invoc = ci.getInvocation(); 841310c281bSmacurtis-amd const CodeGenOptions &opts = invoc.getCodeGenOpts(); 842310c281bSmacurtis-amd const auto &mathOpts = invoc.getLoweringOpts().getMathOptions(); 8439c0acc42SSlava Zakharin llvm::OptimizationLevel level = mapToLevel(opts); 844310c281bSmacurtis-amd mlir::DefaultTimingManager &timingMgr = ci.getTimingManager(); 845310c281bSmacurtis-amd mlir::TimingScope &timingScopeRoot = ci.getTimingScopeRoot(); 846e993b20cSAndrzej Warzynski 847e993b20cSAndrzej Warzynski fir::support::loadDialects(*mlirCtx); 848369b8221SVijay Kandiah mlir::DialectRegistry registry; 849369b8221SVijay Kandiah fir::support::registerNonCodegenDialects(registry); 850369b8221SVijay Kandiah fir::support::addFIRExtensions(registry); 851369b8221SVijay Kandiah mlirCtx->appendDialectRegistry(registry); 852e993b20cSAndrzej Warzynski fir::support::registerLLVMTranslation(*mlirCtx); 853e993b20cSAndrzej Warzynski 854e993b20cSAndrzej Warzynski // Set-up the MLIR pass manager 85594a30928Srkayaith mlir::PassManager pm((*mlirModule)->getName(), 85694a30928Srkayaith mlir::OpPassManager::Nesting::Implicit); 857e993b20cSAndrzej Warzynski 858e993b20cSAndrzej Warzynski pm.addPass(std::make_unique<Fortran::lower::VerifierPass>()); 859e993b20cSAndrzej Warzynski pm.enableVerifier(/*verifyPasses=*/true); 860e993b20cSAndrzej Warzynski 86122544e2aSAlex Bradbury MLIRToLLVMPassPipelineConfig config(level, opts, mathOpts); 86286ab10c4SVijay Kandiah fir::registerDefaultInlinerPass(config); 8637006b90aSMats Petersson 864898db113SPhilip Reames if (auto vsr = getVScaleRange(ci)) { 8656180964aSMats Petersson config.VScaleMin = vsr->first; 8666180964aSMats Petersson config.VScaleMax = vsr->second; 8676180964aSMats Petersson } 8686180964aSMats Petersson 869e7e55416SIvan R. Ivanov if (ci.getInvocation().getFrontendOpts().features.IsEnabled( 870e7e55416SIvan R. Ivanov Fortran::common::LanguageFeature::OpenMP)) 871e7e55416SIvan R. Ivanov config.EnableOpenMP = true; 872e7e55416SIvan R. Ivanov 873a88677edSYusuke MINATO if (ci.getInvocation().getLoweringOpts().getIntegerWrapAround()) 874a88677edSYusuke MINATO config.NSWOnLoopVarInc = false; 875526553b2SYusuke MINATO 876e993b20cSAndrzej Warzynski // Create the pass pipeline 8775f3f9d1aSAbid Qadeer fir::createMLIRToLLVMPassPipeline(pm, config, getCurrentFile()); 878d270d363SJie Fu (void)mlir::applyPassManagerCLOptions(pm); 879e993b20cSAndrzej Warzynski 8801e462fafSAndrzej Warzynski // run the pass manager 881310c281bSmacurtis-amd mlir::TimingScope timingScopeMLIRPasses = timingScopeRoot.nest( 882310c281bSmacurtis-amd mlir::TimingIdentifier::get(timingIdMLIRPasses, timingMgr)); 883310c281bSmacurtis-amd pm.enableTiming(timingScopeMLIRPasses); 884e993b20cSAndrzej Warzynski if (!mlir::succeeded(pm.run(*mlirModule))) { 8851e462fafSAndrzej Warzynski unsigned diagID = ci.getDiagnostics().getCustomDiagID( 886e993b20cSAndrzej Warzynski clang::DiagnosticsEngine::Error, "Lowering to LLVM IR failed"); 8871e462fafSAndrzej Warzynski ci.getDiagnostics().Report(diagID); 888e993b20cSAndrzej Warzynski } 889310c281bSmacurtis-amd timingScopeMLIRPasses.stop(); 890e993b20cSAndrzej Warzynski 89133be8341SSergio Afonso // Print final MLIR module, just before translation into LLVM IR, if 89233be8341SSergio Afonso // -save-temps has been specified. 89333be8341SSergio Afonso if (!saveMLIRTempFile(ci.getInvocation(), *mlirModule, getCurrentFile(), 89433be8341SSergio Afonso "llvmir")) { 89533be8341SSergio Afonso unsigned diagID = ci.getDiagnostics().getCustomDiagID( 89633be8341SSergio Afonso clang::DiagnosticsEngine::Error, "Saving MLIR temp file failed"); 89733be8341SSergio Afonso ci.getDiagnostics().Report(diagID); 89833be8341SSergio Afonso return; 89933be8341SSergio Afonso } 90033be8341SSergio Afonso 901e993b20cSAndrzej Warzynski // Translate to LLVM IR 902310c281bSmacurtis-amd mlir::TimingScope timingScopeLLVMIRGen = timingScopeRoot.nest( 903310c281bSmacurtis-amd mlir::TimingIdentifier::get(timingIdLLVMIRGen, timingMgr)); 90422426110SRamkumar Ramachandra std::optional<llvm::StringRef> moduleName = mlirModule->getName(); 905e993b20cSAndrzej Warzynski llvmModule = mlir::translateModuleToLLVMIR( 906e993b20cSAndrzej Warzynski *mlirModule, *llvmCtx, moduleName ? *moduleName : "FIRModule"); 907e993b20cSAndrzej Warzynski 908723cd2e9SMehdi Amini if (!llvmModule) { 909723cd2e9SMehdi Amini unsigned diagID = ci.getDiagnostics().getCustomDiagID( 910723cd2e9SMehdi Amini clang::DiagnosticsEngine::Error, "failed to create the LLVM module"); 911723cd2e9SMehdi Amini ci.getDiagnostics().Report(diagID); 912723cd2e9SMehdi Amini return; 913723cd2e9SMehdi Amini } 914723cd2e9SMehdi Amini 915ef5ede52SUsman Nadeem // Set PIC/PIE level LLVM module flags. 916ef5ede52SUsman Nadeem if (opts.PICLevel > 0) { 917ef5ede52SUsman Nadeem llvmModule->setPICLevel(static_cast<llvm::PICLevel::Level>(opts.PICLevel)); 918ef5ede52SUsman Nadeem if (opts.IsPIE) 919ef5ede52SUsman Nadeem llvmModule->setPIELevel( 920ef5ede52SUsman Nadeem static_cast<llvm::PIELevel::Level>(opts.PICLevel)); 921ef5ede52SUsman Nadeem } 9229e6b46a9SDavid Truby 9239e6b46a9SDavid Truby // Set mcmodel level LLVM module flags 9249e6b46a9SDavid Truby std::optional<llvm::CodeModel::Model> cm = getCodeModel(opts.CodeModel); 9259e6b46a9SDavid Truby if (cm.has_value()) { 9269e6b46a9SDavid Truby const llvm::Triple triple(ci.getInvocation().getTargetOpts().triple); 9279e6b46a9SDavid Truby llvmModule->setCodeModel(*cm); 9289e6b46a9SDavid Truby if ((cm == llvm::CodeModel::Medium || cm == llvm::CodeModel::Large) && 9299e6b46a9SDavid Truby triple.getArch() == llvm::Triple::x86_64) { 9309e6b46a9SDavid Truby llvmModule->setLargeDataThreshold(opts.LargeDataThreshold); 9319e6b46a9SDavid Truby } 9329e6b46a9SDavid Truby } 933e993b20cSAndrzej Warzynski } 934e993b20cSAndrzej Warzynski 935bb177edcSAndrzej Warzynski static std::unique_ptr<llvm::raw_pwrite_stream> 9361e462fafSAndrzej Warzynski getOutputStream(CompilerInstance &ci, llvm::StringRef inFile, 937bb177edcSAndrzej Warzynski BackendActionTy action) { 938bb177edcSAndrzej Warzynski switch (action) { 939bb177edcSAndrzej Warzynski case BackendActionTy::Backend_EmitAssembly: 9401e462fafSAndrzej Warzynski return ci.createDefaultOutputFile( 941bb177edcSAndrzej Warzynski /*Binary=*/false, inFile, /*extension=*/"s"); 942bb177edcSAndrzej Warzynski case BackendActionTy::Backend_EmitLL: 9431e462fafSAndrzej Warzynski return ci.createDefaultOutputFile( 944bb177edcSAndrzej Warzynski /*Binary=*/false, inFile, /*extension=*/"ll"); 94539ecf9d8STom Eccles case BackendActionTy::Backend_EmitFIR: 94639ecf9d8STom Eccles case BackendActionTy::Backend_EmitHLFIR: 9471e462fafSAndrzej Warzynski return ci.createDefaultOutputFile( 948bb177edcSAndrzej Warzynski /*Binary=*/false, inFile, /*extension=*/"mlir"); 949bb177edcSAndrzej Warzynski case BackendActionTy::Backend_EmitBC: 9501e462fafSAndrzej Warzynski return ci.createDefaultOutputFile( 951bb177edcSAndrzej Warzynski /*Binary=*/true, inFile, /*extension=*/"bc"); 952bb177edcSAndrzej Warzynski case BackendActionTy::Backend_EmitObj: 9531e462fafSAndrzej Warzynski return ci.createDefaultOutputFile( 954bb177edcSAndrzej Warzynski /*Binary=*/true, inFile, /*extension=*/"o"); 955bb177edcSAndrzej Warzynski } 956bb177edcSAndrzej Warzynski 957bb177edcSAndrzej Warzynski llvm_unreachable("Invalid action!"); 958bb177edcSAndrzej Warzynski } 959bb177edcSAndrzej Warzynski 960bb177edcSAndrzej Warzynski /// Generate target-specific machine-code or assembly file from the input LLVM 961bb177edcSAndrzej Warzynski /// module. 962bb177edcSAndrzej Warzynski /// 963bb177edcSAndrzej Warzynski /// \param [in] diags Diagnostics engine for reporting errors 9641e462fafSAndrzej Warzynski /// \param [in] tm Target machine to aid the code-gen pipeline set-up 965bb177edcSAndrzej Warzynski /// \param [in] act Backend act to run (assembly vs machine-code generation) 966bb177edcSAndrzej Warzynski /// \param [in] llvmModule LLVM module to lower to assembly/machine-code 967a207e630STom Eccles /// \param [in] codeGenOpts options configuring codegen pipeline 968bb177edcSAndrzej Warzynski /// \param [out] os Output stream to emit the generated code to 9691e462fafSAndrzej Warzynski static void generateMachineCodeOrAssemblyImpl(clang::DiagnosticsEngine &diags, 9701e462fafSAndrzej Warzynski llvm::TargetMachine &tm, 971bb177edcSAndrzej Warzynski BackendActionTy act, 972bb177edcSAndrzej Warzynski llvm::Module &llvmModule, 973a207e630STom Eccles const CodeGenOptions &codeGenOpts, 974bb177edcSAndrzej Warzynski llvm::raw_pwrite_stream &os) { 975c12ef70dSAndrzej Warzynski assert(((act == BackendActionTy::Backend_EmitObj) || 976c12ef70dSAndrzej Warzynski (act == BackendActionTy::Backend_EmitAssembly)) && 977bb177edcSAndrzej Warzynski "Unsupported action"); 978bb177edcSAndrzej Warzynski 979bb177edcSAndrzej Warzynski // Set-up the pass manager, i.e create an LLVM code-gen pass pipeline. 980bb177edcSAndrzej Warzynski // Currently only the legacy pass manager is supported. 981bb177edcSAndrzej Warzynski // TODO: Switch to the new PM once it's available in the backend. 9821e462fafSAndrzej Warzynski llvm::legacy::PassManager codeGenPasses; 9831e462fafSAndrzej Warzynski codeGenPasses.add( 9841e462fafSAndrzej Warzynski createTargetTransformInfoWrapperPass(tm.getTargetIRAnalysis())); 985bb177edcSAndrzej Warzynski 986bb177edcSAndrzej Warzynski llvm::Triple triple(llvmModule.getTargetTriple()); 987a207e630STom Eccles llvm::TargetLibraryInfoImpl *tlii = 988a207e630STom Eccles llvm::driver::createTLII(triple, codeGenOpts.getVecLib()); 9891e462fafSAndrzej Warzynski codeGenPasses.add(new llvm::TargetLibraryInfoWrapperPass(*tlii)); 990bb177edcSAndrzej Warzynski 991bb177edcSAndrzej Warzynski llvm::CodeGenFileType cgft = (act == BackendActionTy::Backend_EmitAssembly) 9920a1aa6cdSArthur Eubanks ? llvm::CodeGenFileType::AssemblyFile 9930a1aa6cdSArthur Eubanks : llvm::CodeGenFileType::ObjectFile; 9941e462fafSAndrzej Warzynski if (tm.addPassesToEmitFile(codeGenPasses, os, nullptr, cgft)) { 995bb177edcSAndrzej Warzynski unsigned diagID = 996bb177edcSAndrzej Warzynski diags.getCustomDiagID(clang::DiagnosticsEngine::Error, 997bb177edcSAndrzej Warzynski "emission of this file type is not supported"); 998bb177edcSAndrzej Warzynski diags.Report(diagID); 999bb177edcSAndrzej Warzynski return; 1000bb177edcSAndrzej Warzynski } 1001bb177edcSAndrzej Warzynski 1002bb177edcSAndrzej Warzynski // Run the passes 10031e462fafSAndrzej Warzynski codeGenPasses.run(llvmModule); 1004c870632eSMatthias Springer 1005c870632eSMatthias Springer // Cleanup 1006c870632eSMatthias Springer delete tlii; 1007bb177edcSAndrzej Warzynski } 1008bb177edcSAndrzej Warzynski 1009869385b1SAndrzej Warzynski void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) { 1010310c281bSmacurtis-amd CompilerInstance &ci = getInstance(); 1011310c281bSmacurtis-amd const CodeGenOptions &opts = ci.getInvocation().getCodeGenOpts(); 1012310c281bSmacurtis-amd clang::DiagnosticsEngine &diags = ci.getDiagnostics(); 1013869385b1SAndrzej Warzynski llvm::OptimizationLevel level = mapToLevel(opts); 1014869385b1SAndrzej Warzynski 1015310c281bSmacurtis-amd llvm::TargetMachine *targetMachine = &ci.getTargetMachine(); 1016869385b1SAndrzej Warzynski // Create the analysis managers. 1017869385b1SAndrzej Warzynski llvm::LoopAnalysisManager lam; 1018869385b1SAndrzej Warzynski llvm::FunctionAnalysisManager fam; 1019869385b1SAndrzej Warzynski llvm::CGSCCAnalysisManager cgam; 10201e462fafSAndrzej Warzynski llvm::ModuleAnalysisManager mam; 1021869385b1SAndrzej Warzynski 1022869385b1SAndrzej Warzynski // Create the pass manager builder. 1023869385b1SAndrzej Warzynski llvm::PassInstrumentationCallbacks pic; 1024869385b1SAndrzej Warzynski llvm::PipelineTuningOptions pto; 102512f6ac39SFangrui Song std::optional<llvm::PGOOptions> pgoOpt; 1026eef02107SKiran Chandramohan llvm::StandardInstrumentations si(llvmModule->getContext(), 1027eef02107SKiran Chandramohan opts.DebugPassManager); 10286a6994ccSArthur Eubanks si.registerCallbacks(pic, &mam); 1029310c281bSmacurtis-amd if (ci.isTimingEnabled()) 1030310c281bSmacurtis-amd si.getTimePasses().setOutStream(ci.getTimingStreamLLVM()); 1031*0195ec45SDavid Truby pto.LoopUnrolling = opts.UnrollLoops; 1032*0195ec45SDavid Truby pto.LoopInterleaving = opts.UnrollLoops; 1033e59e8488SjeanPerier llvm::PassBuilder pb(targetMachine, pto, pgoOpt, &pic); 1034869385b1SAndrzej Warzynski 1035c3821b8dSTarun Prabhu // Attempt to load pass plugins and register their callbacks with PB. 1036c3821b8dSTarun Prabhu for (auto &pluginFile : opts.LLVMPassPlugins) { 1037c3821b8dSTarun Prabhu auto passPlugin = llvm::PassPlugin::Load(pluginFile); 1038c3821b8dSTarun Prabhu if (passPlugin) { 1039c3821b8dSTarun Prabhu passPlugin->registerPassBuilderCallbacks(pb); 1040c3821b8dSTarun Prabhu } else { 1041c3821b8dSTarun Prabhu diags.Report(clang::diag::err_fe_unable_to_load_plugin) 1042c3821b8dSTarun Prabhu << pluginFile << passPlugin.takeError(); 1043c3821b8dSTarun Prabhu } 1044c3821b8dSTarun Prabhu } 1045d34dce25SUsman Nadeem // Register static plugin extensions. 1046d34dce25SUsman Nadeem #define HANDLE_EXTENSION(Ext) \ 1047d34dce25SUsman Nadeem get##Ext##PluginInfo().RegisterPassBuilderCallbacks(pb); 1048d34dce25SUsman Nadeem #include "llvm/Support/Extension.def" 1049c3821b8dSTarun Prabhu 1050a207e630STom Eccles // Register the target library analysis directly and give it a customized 1051a207e630STom Eccles // preset TLI depending on -fveclib 1052a207e630STom Eccles llvm::Triple triple(llvmModule->getTargetTriple()); 1053a207e630STom Eccles llvm::TargetLibraryInfoImpl *tlii = 1054a207e630STom Eccles llvm::driver::createTLII(triple, opts.getVecLib()); 1055a207e630STom Eccles fam.registerPass([&] { return llvm::TargetLibraryAnalysis(*tlii); }); 1056a207e630STom Eccles 1057869385b1SAndrzej Warzynski // Register all the basic analyses with the managers. 10581e462fafSAndrzej Warzynski pb.registerModuleAnalyses(mam); 1059869385b1SAndrzej Warzynski pb.registerCGSCCAnalyses(cgam); 1060869385b1SAndrzej Warzynski pb.registerFunctionAnalyses(fam); 1061869385b1SAndrzej Warzynski pb.registerLoopAnalyses(lam); 1062869385b1SAndrzej Warzynski pb.crossRegisterProxies(lam, fam, cgam, mam); 1063869385b1SAndrzej Warzynski 1064869385b1SAndrzej Warzynski // Create the pass manager. 1065869385b1SAndrzej Warzynski llvm::ModulePassManager mpm; 1066a8f6b576SNikita Popov if (opts.PrepareForFullLTO) 10670fdfb65eSNadeem, Usman mpm = pb.buildLTOPreLinkDefaultPipeline(level); 10680fdfb65eSNadeem, Usman else if (opts.PrepareForThinLTO) 10690fdfb65eSNadeem, Usman mpm = pb.buildThinLTOPreLinkDefaultPipeline(level); 1070869385b1SAndrzej Warzynski else 1071869385b1SAndrzej Warzynski mpm = pb.buildPerModuleDefaultPipeline(level); 1072869385b1SAndrzej Warzynski 1073869385b1SAndrzej Warzynski if (action == BackendActionTy::Backend_EmitBC) 10741e462fafSAndrzej Warzynski mpm.addPass(llvm::BitcodeWriterPass(os)); 10759b468388SStephen Tozer else if (action == BackendActionTy::Backend_EmitLL) 10769b468388SStephen Tozer mpm.addPass(llvm::PrintModulePass(os)); 1077bb177edcSAndrzej Warzynski 1078a1441ca7STarun Prabhu // FIXME: This should eventually be replaced by a first-class driver option. 1079a1441ca7STarun Prabhu // This should be done for both flang and clang simultaneously. 1080a1441ca7STarun Prabhu // Print a textual, '-passes=' compatible, representation of pipeline if 1081a1441ca7STarun Prabhu // requested. In this case, don't run the passes. This mimics the behavior of 1082a1441ca7STarun Prabhu // clang. 1083a1441ca7STarun Prabhu if (llvm::PrintPipelinePasses) { 1084a1441ca7STarun Prabhu mpm.printPipeline(llvm::outs(), [&pic](llvm::StringRef className) { 1085a1441ca7STarun Prabhu auto passName = pic.getPassNameForClassName(className); 1086a1441ca7STarun Prabhu return passName.empty() ? className : passName; 1087a1441ca7STarun Prabhu }); 1088a1441ca7STarun Prabhu llvm::outs() << "\n"; 1089a1441ca7STarun Prabhu return; 1090a1441ca7STarun Prabhu } 1091a1441ca7STarun Prabhu 1092869385b1SAndrzej Warzynski // Run the passes. 1093869385b1SAndrzej Warzynski mpm.run(*llvmModule, mam); 1094c870632eSMatthias Springer 1095310c281bSmacurtis-amd // Print the timers to the associated output stream and reset them. 1096310c281bSmacurtis-amd if (ci.isTimingEnabled()) 1097310c281bSmacurtis-amd si.getTimePasses().print(); 1098310c281bSmacurtis-amd 1099c870632eSMatthias Springer // Cleanup 1100c870632eSMatthias Springer delete tlii; 1101bb177edcSAndrzej Warzynski } 1102bb177edcSAndrzej Warzynski 110391989c67SVictor Kingi // This class handles optimization remark messages requested if 110491989c67SVictor Kingi // any of -Rpass, -Rpass-analysis or -Rpass-missed flags were provided 110591989c67SVictor Kingi class BackendRemarkConsumer : public llvm::DiagnosticHandler { 110691989c67SVictor Kingi 110791989c67SVictor Kingi const CodeGenOptions &codeGenOpts; 110891989c67SVictor Kingi clang::DiagnosticsEngine &diags; 110991989c67SVictor Kingi 111091989c67SVictor Kingi public: 111191989c67SVictor Kingi BackendRemarkConsumer(clang::DiagnosticsEngine &diags, 111291989c67SVictor Kingi const CodeGenOptions &codeGenOpts) 111391989c67SVictor Kingi : codeGenOpts(codeGenOpts), diags(diags) {} 111491989c67SVictor Kingi 111591989c67SVictor Kingi bool isAnalysisRemarkEnabled(llvm::StringRef passName) const override { 111691989c67SVictor Kingi return codeGenOpts.OptimizationRemarkAnalysis.patternMatches(passName); 111791989c67SVictor Kingi } 111891989c67SVictor Kingi bool isMissedOptRemarkEnabled(llvm::StringRef passName) const override { 111991989c67SVictor Kingi return codeGenOpts.OptimizationRemarkMissed.patternMatches(passName); 112091989c67SVictor Kingi } 112191989c67SVictor Kingi bool isPassedOptRemarkEnabled(llvm::StringRef passName) const override { 112291989c67SVictor Kingi return codeGenOpts.OptimizationRemark.patternMatches(passName); 112391989c67SVictor Kingi } 112491989c67SVictor Kingi 112591989c67SVictor Kingi bool isAnyRemarkEnabled() const override { 112691989c67SVictor Kingi return codeGenOpts.OptimizationRemarkAnalysis.hasValidPattern() || 112791989c67SVictor Kingi codeGenOpts.OptimizationRemarkMissed.hasValidPattern() || 112891989c67SVictor Kingi codeGenOpts.OptimizationRemark.hasValidPattern(); 112991989c67SVictor Kingi } 113091989c67SVictor Kingi 113191989c67SVictor Kingi void 113291989c67SVictor Kingi emitOptimizationMessage(const llvm::DiagnosticInfoOptimizationBase &diagInfo, 113391989c67SVictor Kingi unsigned diagID) { 113491989c67SVictor Kingi // We only support warnings and remarks. 113591989c67SVictor Kingi assert(diagInfo.getSeverity() == llvm::DS_Remark || 113691989c67SVictor Kingi diagInfo.getSeverity() == llvm::DS_Warning); 113791989c67SVictor Kingi 113891989c67SVictor Kingi std::string msg; 113991989c67SVictor Kingi llvm::raw_string_ostream msgStream(msg); 114012da8ef0SVictor Kingi 114112da8ef0SVictor Kingi if (diagInfo.isLocationAvailable()) { 114212da8ef0SVictor Kingi // Clang contains a SourceManager class which handles loading 114312da8ef0SVictor Kingi // and caching of source files into memory and it can be used to 114412da8ef0SVictor Kingi // query SourceLocation data. The SourceLocation data is what is 114512da8ef0SVictor Kingi // needed here as it contains the full include stack which gives 114612da8ef0SVictor Kingi // line and column number as well as file name and location. 114712da8ef0SVictor Kingi // Since Flang doesn't have SourceManager, send file name and absolute 114812da8ef0SVictor Kingi // path through msgStream, to use for printing. 114912da8ef0SVictor Kingi msgStream << diagInfo.getLocationStr() << ";;" 115012da8ef0SVictor Kingi << diagInfo.getAbsolutePath() << ";;"; 115112da8ef0SVictor Kingi } 115212da8ef0SVictor Kingi 115391989c67SVictor Kingi msgStream << diagInfo.getMsg(); 115491989c67SVictor Kingi 115591989c67SVictor Kingi // Emit message. 115684d7f294SYoungsuk Kim diags.Report(diagID) << clang::AddFlagValue(diagInfo.getPassName()) << msg; 115791989c67SVictor Kingi } 115891989c67SVictor Kingi 115991989c67SVictor Kingi void optimizationRemarkHandler( 116091989c67SVictor Kingi const llvm::DiagnosticInfoOptimizationBase &diagInfo) { 116191989c67SVictor Kingi auto passName = diagInfo.getPassName(); 116291989c67SVictor Kingi if (diagInfo.isPassed()) { 116391989c67SVictor Kingi if (codeGenOpts.OptimizationRemark.patternMatches(passName)) 116491989c67SVictor Kingi // Optimization remarks are active only if the -Rpass flag has a regular 116591989c67SVictor Kingi // expression that matches the name of the pass name in \p d. 116691989c67SVictor Kingi emitOptimizationMessage( 116791989c67SVictor Kingi diagInfo, clang::diag::remark_fe_backend_optimization_remark); 116891989c67SVictor Kingi 116991989c67SVictor Kingi return; 117091989c67SVictor Kingi } 117191989c67SVictor Kingi 117291989c67SVictor Kingi if (diagInfo.isMissed()) { 117391989c67SVictor Kingi if (codeGenOpts.OptimizationRemarkMissed.patternMatches(passName)) 117491989c67SVictor Kingi // Missed optimization remarks are active only if the -Rpass-missed 117591989c67SVictor Kingi // flag has a regular expression that matches the name of the pass 117691989c67SVictor Kingi // name in \p d. 117791989c67SVictor Kingi emitOptimizationMessage( 117891989c67SVictor Kingi diagInfo, 117991989c67SVictor Kingi clang::diag::remark_fe_backend_optimization_remark_missed); 118091989c67SVictor Kingi 118191989c67SVictor Kingi return; 118291989c67SVictor Kingi } 118391989c67SVictor Kingi 118491989c67SVictor Kingi assert(diagInfo.isAnalysis() && "Unknown remark type"); 118591989c67SVictor Kingi 118691989c67SVictor Kingi bool shouldAlwaysPrint = false; 118791989c67SVictor Kingi auto *ora = llvm::dyn_cast<llvm::OptimizationRemarkAnalysis>(&diagInfo); 118891989c67SVictor Kingi if (ora) 118991989c67SVictor Kingi shouldAlwaysPrint = ora->shouldAlwaysPrint(); 119091989c67SVictor Kingi 119191989c67SVictor Kingi if (shouldAlwaysPrint || 119291989c67SVictor Kingi codeGenOpts.OptimizationRemarkAnalysis.patternMatches(passName)) 119391989c67SVictor Kingi emitOptimizationMessage( 119491989c67SVictor Kingi diagInfo, 119591989c67SVictor Kingi clang::diag::remark_fe_backend_optimization_remark_analysis); 119691989c67SVictor Kingi } 119791989c67SVictor Kingi 119891989c67SVictor Kingi bool handleDiagnostics(const llvm::DiagnosticInfo &di) override { 119991989c67SVictor Kingi switch (di.getKind()) { 120091989c67SVictor Kingi case llvm::DK_OptimizationRemark: 120191989c67SVictor Kingi optimizationRemarkHandler(llvm::cast<llvm::OptimizationRemark>(di)); 120291989c67SVictor Kingi break; 120391989c67SVictor Kingi case llvm::DK_OptimizationRemarkMissed: 120491989c67SVictor Kingi optimizationRemarkHandler(llvm::cast<llvm::OptimizationRemarkMissed>(di)); 120591989c67SVictor Kingi break; 120691989c67SVictor Kingi case llvm::DK_OptimizationRemarkAnalysis: 120791989c67SVictor Kingi optimizationRemarkHandler( 120891989c67SVictor Kingi llvm::cast<llvm::OptimizationRemarkAnalysis>(di)); 120991989c67SVictor Kingi break; 1210e87d2d2cSVictor Kingi case llvm::DK_MachineOptimizationRemark: 1211e87d2d2cSVictor Kingi optimizationRemarkHandler( 1212e87d2d2cSVictor Kingi llvm::cast<llvm::MachineOptimizationRemark>(di)); 1213e87d2d2cSVictor Kingi break; 1214e87d2d2cSVictor Kingi case llvm::DK_MachineOptimizationRemarkMissed: 1215e87d2d2cSVictor Kingi optimizationRemarkHandler( 1216e87d2d2cSVictor Kingi llvm::cast<llvm::MachineOptimizationRemarkMissed>(di)); 1217e87d2d2cSVictor Kingi break; 1218e87d2d2cSVictor Kingi case llvm::DK_MachineOptimizationRemarkAnalysis: 1219e87d2d2cSVictor Kingi optimizationRemarkHandler( 1220e87d2d2cSVictor Kingi llvm::cast<llvm::MachineOptimizationRemarkAnalysis>(di)); 1221e87d2d2cSVictor Kingi break; 122291989c67SVictor Kingi default: 122391989c67SVictor Kingi break; 122491989c67SVictor Kingi } 122591989c67SVictor Kingi return true; 122691989c67SVictor Kingi } 122791989c67SVictor Kingi }; 122891989c67SVictor Kingi 122940d8c066SJan Sjodin void CodeGenAction::embedOffloadObjects() { 123040d8c066SJan Sjodin CompilerInstance &ci = this->getInstance(); 123140d8c066SJan Sjodin const auto &cgOpts = ci.getInvocation().getCodeGenOpts(); 123240d8c066SJan Sjodin 123340d8c066SJan Sjodin for (llvm::StringRef offloadObject : cgOpts.OffloadObjects) { 123440d8c066SJan Sjodin llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> objectOrErr = 123540d8c066SJan Sjodin llvm::MemoryBuffer::getFileOrSTDIN(offloadObject); 123640d8c066SJan Sjodin if (std::error_code ec = objectOrErr.getError()) { 123740d8c066SJan Sjodin auto diagID = ci.getDiagnostics().getCustomDiagID( 123840d8c066SJan Sjodin clang::DiagnosticsEngine::Error, "could not open '%0' for embedding"); 123940d8c066SJan Sjodin ci.getDiagnostics().Report(diagID) << offloadObject; 124040d8c066SJan Sjodin return; 124140d8c066SJan Sjodin } 124240d8c066SJan Sjodin llvm::embedBufferInModule( 124340d8c066SJan Sjodin *llvmModule, **objectOrErr, ".llvm.offloading", 124440d8c066SJan Sjodin llvm::Align(llvm::object::OffloadBinary::getAlignment())); 124540d8c066SJan Sjodin } 124640d8c066SJan Sjodin } 124740d8c066SJan Sjodin 1248b75e7c61SJan Leyonberg void CodeGenAction::linkBuiltinBCLibs() { 1249b75e7c61SJan Leyonberg auto options = clang::FileSystemOptions(); 1250b75e7c61SJan Leyonberg clang::FileManager fileManager(options); 1251b75e7c61SJan Leyonberg CompilerInstance &ci = this->getInstance(); 1252b75e7c61SJan Leyonberg const auto &cgOpts = ci.getInvocation().getCodeGenOpts(); 1253b75e7c61SJan Leyonberg 1254b75e7c61SJan Leyonberg std::vector<std::unique_ptr<llvm::Module>> modules; 1255b75e7c61SJan Leyonberg 1256b75e7c61SJan Leyonberg // Load LLVM modules 1257b75e7c61SJan Leyonberg for (llvm::StringRef bcLib : cgOpts.BuiltinBCLibs) { 1258b75e7c61SJan Leyonberg auto BCBuf = fileManager.getBufferForFile(bcLib); 1259b75e7c61SJan Leyonberg if (!BCBuf) { 1260b75e7c61SJan Leyonberg auto diagID = ci.getDiagnostics().getCustomDiagID( 1261b75e7c61SJan Leyonberg clang::DiagnosticsEngine::Error, "could not open '%0' for linking"); 1262b75e7c61SJan Leyonberg ci.getDiagnostics().Report(diagID) << bcLib; 1263b75e7c61SJan Leyonberg return; 1264b75e7c61SJan Leyonberg } 1265b75e7c61SJan Leyonberg 1266b75e7c61SJan Leyonberg llvm::Expected<std::unique_ptr<llvm::Module>> ModuleOrErr = 1267b75e7c61SJan Leyonberg getOwningLazyBitcodeModule(std::move(*BCBuf), *llvmCtx); 1268b75e7c61SJan Leyonberg if (!ModuleOrErr) { 1269b75e7c61SJan Leyonberg auto diagID = ci.getDiagnostics().getCustomDiagID( 1270b75e7c61SJan Leyonberg clang::DiagnosticsEngine::Error, "error loading '%0' for linking"); 1271b75e7c61SJan Leyonberg ci.getDiagnostics().Report(diagID) << bcLib; 1272b75e7c61SJan Leyonberg return; 1273b75e7c61SJan Leyonberg } 1274b75e7c61SJan Leyonberg modules.push_back(std::move(ModuleOrErr.get())); 1275b75e7c61SJan Leyonberg } 1276b75e7c61SJan Leyonberg 1277b75e7c61SJan Leyonberg // Link modules and internalize functions 1278b75e7c61SJan Leyonberg for (auto &module : modules) { 1279b75e7c61SJan Leyonberg bool Err; 1280b75e7c61SJan Leyonberg Err = llvm::Linker::linkModules( 1281b75e7c61SJan Leyonberg *llvmModule, std::move(module), llvm::Linker::Flags::LinkOnlyNeeded, 1282b75e7c61SJan Leyonberg [](llvm::Module &M, const llvm::StringSet<> &GVS) { 1283b75e7c61SJan Leyonberg llvm::internalizeModule(M, [&GVS](const llvm::GlobalValue &GV) { 1284b75e7c61SJan Leyonberg return !GV.hasName() || (GVS.count(GV.getName()) == 0); 1285b75e7c61SJan Leyonberg }); 1286b75e7c61SJan Leyonberg }); 1287b75e7c61SJan Leyonberg if (Err) { 1288b75e7c61SJan Leyonberg auto diagID = ci.getDiagnostics().getCustomDiagID( 1289b75e7c61SJan Leyonberg clang::DiagnosticsEngine::Error, "link error when linking '%0'"); 1290b75e7c61SJan Leyonberg ci.getDiagnostics().Report(diagID) << module->getSourceFileName(); 1291b75e7c61SJan Leyonberg return; 1292b75e7c61SJan Leyonberg } 1293b75e7c61SJan Leyonberg } 1294b75e7c61SJan Leyonberg } 1295b75e7c61SJan Leyonberg 1296f04ccadfSVictor Kingi static void reportOptRecordError(llvm::Error e, clang::DiagnosticsEngine &diags, 1297f04ccadfSVictor Kingi const CodeGenOptions &codeGenOpts) { 1298f04ccadfSVictor Kingi handleAllErrors( 1299f04ccadfSVictor Kingi std::move(e), 1300f04ccadfSVictor Kingi [&](const llvm::LLVMRemarkSetupFileError &e) { 1301f04ccadfSVictor Kingi diags.Report(clang::diag::err_cannot_open_file) 1302f04ccadfSVictor Kingi << codeGenOpts.OptRecordFile << e.message(); 1303f04ccadfSVictor Kingi }, 1304f04ccadfSVictor Kingi [&](const llvm::LLVMRemarkSetupPatternError &e) { 1305f04ccadfSVictor Kingi diags.Report(clang::diag::err_drv_optimization_remark_pattern) 1306f04ccadfSVictor Kingi << e.message() << codeGenOpts.OptRecordPasses; 1307f04ccadfSVictor Kingi }, 1308f04ccadfSVictor Kingi [&](const llvm::LLVMRemarkSetupFormatError &e) { 1309f04ccadfSVictor Kingi diags.Report(clang::diag::err_drv_optimization_remark_format) 1310f04ccadfSVictor Kingi << codeGenOpts.OptRecordFormat; 1311f04ccadfSVictor Kingi }); 1312f04ccadfSVictor Kingi } 1313f04ccadfSVictor Kingi 13141e462fafSAndrzej Warzynski void CodeGenAction::executeAction() { 13151e462fafSAndrzej Warzynski CompilerInstance &ci = this->getInstance(); 131638101b4eSAndrzej Warzynski 1317f04ccadfSVictor Kingi clang::DiagnosticsEngine &diags = ci.getDiagnostics(); 1318f04ccadfSVictor Kingi const CodeGenOptions &codeGenOpts = ci.getInvocation().getCodeGenOpts(); 1319f04ccadfSVictor Kingi Fortran::lower::LoweringOptions &loweringOpts = 1320f04ccadfSVictor Kingi ci.getInvocation().getLoweringOpts(); 1321310c281bSmacurtis-amd mlir::DefaultTimingManager &timingMgr = ci.getTimingManager(); 1322310c281bSmacurtis-amd mlir::TimingScope &timingScopeRoot = ci.getTimingScopeRoot(); 1323f04ccadfSVictor Kingi 132438101b4eSAndrzej Warzynski // If the output stream is a file, generate it and define the corresponding 132538101b4eSAndrzej Warzynski // output stream. If a pre-defined output stream is available, we will use 132638101b4eSAndrzej Warzynski // that instead. 132738101b4eSAndrzej Warzynski // 132838101b4eSAndrzej Warzynski // NOTE: `os` is a smart pointer that will be destroyed at the end of this 13291e462fafSAndrzej Warzynski // method. However, it won't be written to until `codeGenPasses` is 13301e462fafSAndrzej Warzynski // destroyed. By defining `os` before `codeGenPasses`, we make sure that the 133138101b4eSAndrzej Warzynski // output stream won't be destroyed before it is written to. This only 133238101b4eSAndrzej Warzynski // applies when an output file is used (i.e. there is no pre-defined output 133338101b4eSAndrzej Warzynski // stream). 13341e462fafSAndrzej Warzynski // TODO: Revisit once the new PM is ready (i.e. when `codeGenPasses` is 133538101b4eSAndrzej Warzynski // updated to use it). 133638101b4eSAndrzej Warzynski std::unique_ptr<llvm::raw_pwrite_stream> os; 13371e462fafSAndrzej Warzynski if (ci.isOutputStreamNull()) { 13381e462fafSAndrzej Warzynski os = getOutputStream(ci, getCurrentFileOrBufferName(), action); 1339bb177edcSAndrzej Warzynski 134038101b4eSAndrzej Warzynski if (!os) { 1341f04ccadfSVictor Kingi unsigned diagID = diags.getCustomDiagID( 134238101b4eSAndrzej Warzynski clang::DiagnosticsEngine::Error, "failed to create the output file"); 1343f04ccadfSVictor Kingi diags.Report(diagID); 134438101b4eSAndrzej Warzynski return; 134538101b4eSAndrzej Warzynski } 134638101b4eSAndrzej Warzynski } 134738101b4eSAndrzej Warzynski 134839ecf9d8STom Eccles if (action == BackendActionTy::Backend_EmitFIR) { 1349f04ccadfSVictor Kingi if (loweringOpts.getLowerToHighLevelFIR()) { 135039ecf9d8STom Eccles lowerHLFIRToFIR(); 135139ecf9d8STom Eccles } 135239ecf9d8STom Eccles mlirModule->print(ci.isOutputStreamNull() ? *os : ci.getOutputStream()); 135339ecf9d8STom Eccles return; 135439ecf9d8STom Eccles } 135539ecf9d8STom Eccles 135639ecf9d8STom Eccles if (action == BackendActionTy::Backend_EmitHLFIR) { 1357f04ccadfSVictor Kingi assert(loweringOpts.getLowerToHighLevelFIR() && 135839ecf9d8STom Eccles "Lowering must have been configured to emit HLFIR"); 13591e462fafSAndrzej Warzynski mlirModule->print(ci.isOutputStreamNull() ? *os : ci.getOutputStream()); 136038101b4eSAndrzej Warzynski return; 136138101b4eSAndrzej Warzynski } 136238101b4eSAndrzej Warzynski 1363869385b1SAndrzej Warzynski // Generate an LLVM module if it's not already present (it will already be 1364bb177edcSAndrzej Warzynski // present if the input file is an LLVM IR/BC file). 1365bb177edcSAndrzej Warzynski if (!llvmModule) 13661e462fafSAndrzej Warzynski generateLLVMIR(); 1367bb177edcSAndrzej Warzynski 1368310c281bSmacurtis-amd // This will already have been started in generateLLVMIR(). But we need to 1369310c281bSmacurtis-amd // continue operating on the module, so we continue timing it. 1370310c281bSmacurtis-amd mlir::TimingScope timingScopeLLVMIRGen = timingScopeRoot.nest( 1371310c281bSmacurtis-amd mlir::TimingIdentifier::get(timingIdLLVMIRGen, timingMgr)); 1372310c281bSmacurtis-amd 137310317da2SKareem Ergawy // If generating the LLVM module failed, abort! No need for further error 137410317da2SKareem Ergawy // reporting since generateLLVMIR() does this already. 137510317da2SKareem Ergawy if (!llvmModule) 137610317da2SKareem Ergawy return; 137710317da2SKareem Ergawy 137881181089SMats Petersson // Set the triple based on the targetmachine (this comes compiler invocation 137981181089SMats Petersson // and the command-line target option if specified, or the default if not 138081181089SMats Petersson // given on the command-line). 1381e59e8488SjeanPerier llvm::TargetMachine &targetMachine = ci.getTargetMachine(); 13829e6b46a9SDavid Truby 1383e59e8488SjeanPerier const std::string &theTriple = targetMachine.getTargetTriple().str(); 138481181089SMats Petersson 138581181089SMats Petersson if (llvmModule->getTargetTriple() != theTriple) { 1386f04ccadfSVictor Kingi diags.Report(clang::diag::warn_fe_override_module) << theTriple; 138781181089SMats Petersson } 138840d8c066SJan Sjodin 138981181089SMats Petersson // Always set the triple and data layout, to make sure they match and are set. 139081181089SMats Petersson // Note that this overwrites any datalayout stored in the LLVM-IR. This avoids 139181181089SMats Petersson // an assert for incompatible data layout when the code-generation happens. 139281181089SMats Petersson llvmModule->setTargetTriple(theTriple); 1393e59e8488SjeanPerier llvmModule->setDataLayout(targetMachine.createDataLayout()); 139481181089SMats Petersson 1395b75e7c61SJan Leyonberg // Link in builtin bitcode libraries 1396b75e7c61SJan Leyonberg if (!codeGenOpts.BuiltinBCLibs.empty()) 1397b75e7c61SJan Leyonberg linkBuiltinBCLibs(); 1398b75e7c61SJan Leyonberg 139940d8c066SJan Sjodin // Embed offload objects specified with -fembed-offload-object 1400f04ccadfSVictor Kingi if (!codeGenOpts.OffloadObjects.empty()) 140140d8c066SJan Sjodin embedOffloadObjects(); 1402310c281bSmacurtis-amd timingScopeLLVMIRGen.stop(); 140340d8c066SJan Sjodin 140491989c67SVictor Kingi BackendRemarkConsumer remarkConsumer(diags, codeGenOpts); 140591989c67SVictor Kingi 140691989c67SVictor Kingi llvmModule->getContext().setDiagnosticHandler( 140791989c67SVictor Kingi std::make_unique<BackendRemarkConsumer>(remarkConsumer)); 140891989c67SVictor Kingi 1409f04ccadfSVictor Kingi // write optimization-record 1410f04ccadfSVictor Kingi llvm::Expected<std::unique_ptr<llvm::ToolOutputFile>> optRecordFileOrErr = 1411f04ccadfSVictor Kingi setupLLVMOptimizationRemarks( 1412f04ccadfSVictor Kingi llvmModule->getContext(), codeGenOpts.OptRecordFile, 1413f04ccadfSVictor Kingi codeGenOpts.OptRecordPasses, codeGenOpts.OptRecordFormat, 1414f04ccadfSVictor Kingi /*DiagnosticsWithHotness=*/false, 1415f04ccadfSVictor Kingi /*DiagnosticsHotnessThreshold=*/0); 1416f04ccadfSVictor Kingi 1417f04ccadfSVictor Kingi if (llvm::Error e = optRecordFileOrErr.takeError()) { 1418f04ccadfSVictor Kingi reportOptRecordError(std::move(e), diags, codeGenOpts); 1419f04ccadfSVictor Kingi return; 1420f04ccadfSVictor Kingi } 1421f04ccadfSVictor Kingi 1422f04ccadfSVictor Kingi std::unique_ptr<llvm::ToolOutputFile> optRecordFile = 1423f04ccadfSVictor Kingi std::move(*optRecordFileOrErr); 1424f04ccadfSVictor Kingi 1425f04ccadfSVictor Kingi if (optRecordFile) { 1426f04ccadfSVictor Kingi optRecordFile->keep(); 1427f04ccadfSVictor Kingi optRecordFile->os().flush(); 1428f04ccadfSVictor Kingi } 1429f04ccadfSVictor Kingi 1430869385b1SAndrzej Warzynski // Run LLVM's middle-end (i.e. the optimizer). 1431310c281bSmacurtis-amd mlir::TimingScope timingScopeLLVMIRPasses = timingScopeRoot.nest( 1432310c281bSmacurtis-amd mlir::TimingIdentifier::get(timingIdLLVMIRPasses, timingMgr)); 1433e054e0daSSlava Zakharin runOptimizationPipeline(ci.isOutputStreamNull() ? *os : ci.getOutputStream()); 1434310c281bSmacurtis-amd timingScopeLLVMIRPasses.stop(); 1435869385b1SAndrzej Warzynski 14369b468388SStephen Tozer if (action == BackendActionTy::Backend_EmitLL || 14379b468388SStephen Tozer action == BackendActionTy::Backend_EmitBC) { 1438869385b1SAndrzej Warzynski // This action has effectively been completed in runOptimizationPipeline. 1439bb177edcSAndrzej Warzynski return; 1440bb177edcSAndrzej Warzynski } 1441bb177edcSAndrzej Warzynski 1442869385b1SAndrzej Warzynski // Run LLVM's backend and generate either assembly or machine code 1443310c281bSmacurtis-amd mlir::TimingScope timingScopeBackend = timingScopeRoot.nest( 1444310c281bSmacurtis-amd mlir::TimingIdentifier::get(timingIdBackend, timingMgr)); 1445bb177edcSAndrzej Warzynski if (action == BackendActionTy::Backend_EmitAssembly || 1446bb177edcSAndrzej Warzynski action == BackendActionTy::Backend_EmitObj) { 14471e462fafSAndrzej Warzynski generateMachineCodeOrAssemblyImpl( 1448e59e8488SjeanPerier diags, targetMachine, action, *llvmModule, codeGenOpts, 14491e462fafSAndrzej Warzynski ci.isOutputStreamNull() ? *os : ci.getOutputStream()); 1450310c281bSmacurtis-amd if (timingMgr.isEnabled()) 1451310c281bSmacurtis-amd llvm::reportAndResetTimings(&ci.getTimingStreamCodeGen()); 1452bb177edcSAndrzej Warzynski return; 1453bb177edcSAndrzej Warzynski } 1454e5cdb6c5SAndrzej Warzynski } 1455e1da3297SStuart Ellis 14561e462fafSAndrzej Warzynski void InitOnlyAction::executeAction() { 14571e462fafSAndrzej Warzynski CompilerInstance &ci = this->getInstance(); 14581e462fafSAndrzej Warzynski unsigned diagID = ci.getDiagnostics().getCustomDiagID( 14591e462fafSAndrzej Warzynski clang::DiagnosticsEngine::Warning, 1460e1da3297SStuart Ellis "Use `-init-only` for testing purposes only"); 14611e462fafSAndrzej Warzynski ci.getDiagnostics().Report(diagID); 1462e1da3297SStuart Ellis } 1463f52fc591SStuart Ellis 14641e462fafSAndrzej Warzynski void PluginParseTreeAction::executeAction() {} 14658321579bSAndrzej Warzynski 14661e462fafSAndrzej Warzynski void DebugDumpPFTAction::executeAction() { 14671e462fafSAndrzej Warzynski CompilerInstance &ci = this->getInstance(); 14688321579bSAndrzej Warzynski 14691e462fafSAndrzej Warzynski if (auto ast = Fortran::lower::createPFT(*ci.getParsing().parseTree(), 14701e462fafSAndrzej Warzynski ci.getSemantics().context())) { 14718321579bSAndrzej Warzynski Fortran::lower::dumpPFT(llvm::outs(), *ast); 14728321579bSAndrzej Warzynski return; 14738321579bSAndrzej Warzynski } 14748321579bSAndrzej Warzynski 14751e462fafSAndrzej Warzynski unsigned diagID = ci.getDiagnostics().getCustomDiagID( 14768321579bSAndrzej Warzynski clang::DiagnosticsEngine::Error, "Pre FIR Tree is NULL."); 14771e462fafSAndrzej Warzynski ci.getDiagnostics().Report(diagID); 14788321579bSAndrzej Warzynski } 14792186a4aeSAndrzej Warzynski 14802186a4aeSAndrzej Warzynski Fortran::parser::Parsing &PluginParseTreeAction::getParsing() { 14811e462fafSAndrzej Warzynski return getInstance().getParsing(); 14822186a4aeSAndrzej Warzynski } 14832186a4aeSAndrzej Warzynski 14842186a4aeSAndrzej Warzynski std::unique_ptr<llvm::raw_pwrite_stream> 14852186a4aeSAndrzej Warzynski PluginParseTreeAction::createOutputFile(llvm::StringRef extension = "") { 14862186a4aeSAndrzej Warzynski 14871e462fafSAndrzej Warzynski std::unique_ptr<llvm::raw_pwrite_stream> os{ 14881e462fafSAndrzej Warzynski getInstance().createDefaultOutputFile( 14891e462fafSAndrzej Warzynski /*Binary=*/false, /*InFile=*/getCurrentFileOrBufferName(), 14902186a4aeSAndrzej Warzynski extension)}; 14911e462fafSAndrzej Warzynski return os; 14922186a4aeSAndrzej Warzynski } 1493